個人blog系統 前后端分離 前端js后端go

系統設計:

1.使用語言:前端使用vue,并使用axios向后端發送數據。后端使用的是go的gin框架,并使用grom連接數據庫實現數據存儲讀取。

2.設計結構:

最終展示:僅展示添加模塊,其他模塊基本相似

?前端部分

基礎的頁面設計部分使用的是flex布局,這里就不過多的講解了。

由于vue是模塊化的,所以這個頁面可以分為三大模塊

1.就是app.vue這個是最主要的,我們的頁面是通過它來顯示的

2.就是左側的導航欄,它對應四個模塊,根據選擇模塊不同來顯示不同的頁面

3.就是右側的交互部分,四個交互頁面對應四個導航欄的選項

運行端口

運行端口有默認的端口,如果需要自定義端口。我們需要在項目文件中找到vue.config.js文件。然后在里面設置:

原來的文件內容:
const { defineConfig } = require('@vue/cli-service')
module.exports = defineConfig({transpileDependencies: true,})修改后
const { defineConfig } = require('@vue/cli-service')
module.exports = defineConfig({transpileDependencies: true,devServer:{//主要添加這個port: 3000,open: true,}
})

port指定端口,open指定程序運行的時候是否自動打開瀏覽器true為打開

?組件

想要使用組件就需要提前加載組件,也就是導入它(import ...)

加載之后才能掛載(router-view)

我們首先要明確的目標是:1 加載 2對應的組件? ?2 加載 3對應的組件

我們一步一步來看

大致的文件結構如下圖所示,僅做展示,為了方便了解結構

app.vue:

<template>
<div class="father"><div class="one"><h1>blog control center</h1></div><div><index /></div>
</div>
</template><script>
import index from "./views/index.vue"export default {name: "App",components: {index,}
}
</script><style>.father {display: flex;justify-content: center;align-items: center;flex-direction: column;
}
.one{width: 1380px;height: 100px;background: #8e96f1;text-align: center;display: flex;justify-content: center;
}</style>

?App.vue這是整個項目的根組件。其他所有的組件都是基于這個組件展開的

我們主要在這個組件內做了:

  1. 加載 index組件
  2. 制作了HTML的頭部區域,也就是顯示blog control center 的部分
  3. 規定了index的顯示區域(為頭部區域下方
  4. 給body設置了一個flex布局,讓網頁內容居中顯示

加載組件就是在組件的script部分通過import導入,加載分為全局加載組件內加載

在上面的代碼中我們使用的是組件內加載,它的特點是,在其組件內加載的組件只能在此組件內使用。而全局加載的特點是只要我們使用全局加載,那么在這個項目內所有組件都可以使用我們加載的組件。

全局加載步驟:首先在main.js里面加載需要用的組件。

import xxx from "相對路徑"? ?xxx就相當于我們給這個組件起的別名

然后我們會看到一個語句:const app = createApp(APP)

然后通過 app.conponent("組件名",組件名)

注意:如果沒有找到const app = createApp(APP)那就是被集成為了createApp(APP).use(router).mount('#app')放在最下方。這時候我們需要把它拆開

我們來看一個簡單的例子:

import index from  "./views/index.vue"const app =createApp(App)app.component("index",index)app.use(router).mount('#app')

這就是全局導入的基本步驟了。在這里導入之后就不需要在組件內搞import和components了。直接<index />就可以使用了

這里我們就講解完了,接下來我們來看index的設置

index:

<template>
<div class="body"><div ><div class="son" style="background-color: #42b983"><router-link to="/add" ><h1>添加博文</h1></router-link></div><div class="son" style="background-color: gold"><router-link to="/change"><h1>修改博文</h1></router-link></div><div class="son" style="background-color: pink"><router-link to="/discover"> <h1>查詢博文</h1></router-link></div><div class="son" style="background-color: coral"><router-link to="/del"> <h1>刪除博文</h1></router-link></div></div><div style="width: 1200px;height: 1120px;">
<router-view></router-view></div>
</div>
</template><script>export default {setup() {return{}},}
</script><style scoped>.son{width: 180px;height: 280px;display: flex;justify-content: center;align-items: center;
}
.body{display: flex;flex-direction: row;
}
</style>

這里主要要理解的是router-viewrouter-link?

router-view是組件要掛載到哪里的入口,也就是說我的router-view放在div里面,我的子組件展示的時候就只能在這個div里面展示。它起到一個占位符的作用,需要與router-link結合使用

router-link就相當于一個連接,這個連接里面設置的路徑是我們在router目錄里面提前設置好的。針對于這個項目我們來看一下router里面index.js的設置

import { createRouter, createWebHashHistory } from 'vue-router'
import index from "../views/index.vue"
import add from "../views/add.vue"
import change from "../views/change.vue"
import discover from "../views/discover.vue"
import del from "../views/del.vue"const routes = [{path: '/index',component: index,},{path: '/add',component: add,},{path: '/change',component: change,},{path: '/discover',component: discover,},{path: '/del',component: del,}
]const router = createRouter({history: createWebHashHistory(),routes
})export default router

路徑的設置主要是創建一個數組,數組存儲對象,對象存儲路徑信息(path和component)path是我們設置的路徑,component是我們導入的組件。由于它是一個.js文件不知道哪些組件被注冊為全局組件。所以需要重新加載一次?

最后我們再創建一個router,吧createRouter([])賦值給它。在這個函數里面有兩個參數。這里暫且略過,因為博主也沒有很理解這個。就暫且按照博主的寫法來吧(嘻嘻)

最后的export default router這個語句的作用是導出一個router對象。這樣問再main里面才可以使用(app.use(router))(注:使用之前需要import導入index.js所在的相對地址哦)

到此,router-view和router-link我們也大致的明白是怎么回事了,簡單來說就是router-link連接顯示的組件會顯示到router-view里面。

然后我們再來看四個不同模塊文件

add.vue:

<script>
import {ref} from "vue";
import axios from "axios"
export default{name:"add",setup(props,context) {let name = ref("")let text = ref("")let rese =ref("")function give(e) {e.preventDefault()axios.post("http://localhost:8081/Add",{name: name.value,text: text.value}).then(res => {console.log(res)alert(res.data.Error)rese.value = res.data.Error})}return{give,name,text,}}}
</script><template><div class="rit"><form method="post"  @submit="give" ><table><tr class="a"><td> 請輸入博文名稱: <input name="name" v-model="name" type="text" style="width: 500px"><input  type="submit" value="提交" class="submit-button"></td></tr><tr class="b"><td><textarea name="text" v-model="text" /></td></tr></table></form></div>
</template><style scoped>
div{display: flex;align-items: center;justify-content: center;
}
.rit{width: 1200px;height: 1120px;background: #42b882;
}
.a{
width:1200px;height: 100px;
}
.b{width:1200px;height: 1025px;
}
textarea{width:1100px;height:1000px;overflow:auto;
}
</style>
全局css樣式

?這里我們不怎么醬它的css樣式,只簡單了解一下:通常來說,組件之間的css樣式不會互相影響,也就是說我在哪個組件設置的樣式就只能用在哪個組件內。
如果有一個樣式會被運用到很多組件內,我們就可以設置全局css樣式

全局css樣式

設置全局css樣式我們需要單獨寫一個css文件,通常這個文件我們會存放在src/assets目錄下。

導入全局組件同樣需要在main.js里面導入(import "css樣式路徑(相對路徑)")

這樣就可以直接在組件內使用這個文件內的樣式了。

axios 傳遞數據

這里我們傳遞數據使用到了axios作為傳遞的工具。

我們首先導入這個axios,同樣的。既然是導入就會有全局導入和組件內導入

組件內導入很簡單,我們不過多贅述

我們主要來講一下全局導入

在main.js我們首先 import axios from "axios"導入

然后

axios.defaults.baseURL = 'http://localhost:8081'; // 設置默認的 baseURL

這里設置的作用是在組件內使用的時候就不需要寫完整的路徑了,只需要補出后面剩余路徑即可:.post("http://localhost:8081/Add" 就可以寫為.post("/Add"

這樣就會方便很多。

然后app.config.globalProperties.$axios = axios; 這一句的作用類似于起別名。我們在組件內導入的時候使用axios直接使用就可以了。但是全局導入就需要this.$axios了? ?$axios也可以改成別的名字,這個看自己需要。$也可以不寫,但是我們通常會寫上哦

?如果使用全局導入,我們剛才的代碼就需要改為:

 setup(props,context) {let name = ref("")let text = ref("")let rese =ref("")function give(e) {e.preventDefault()this.$axios.post("/Add",{name: name.value,text: text.value}).then(res => {console.log(res)alert(res.data.Error)rese.value = res.data.Error})}

this.$axios

這里要著重聲明的是,在vue3的里面這個方法就不是很適用了。因為setup沒有自己的this

我們需要

import {getCurrentInstance} from "vue";事先導入這個
const { proxy } = getCurrentInstance(); // 然后再在setup里面創建這個常量。通過

proxy.$axios進行使用,這里的差異要注意

我們使用this.$axios.post.("url",{json鍵值對數據})向后端發送請求。然后再.then(res=>{接收回應})接收后端返回的回應(一般都是res.data里面有回應的數據)。然后再.catch捕獲錯誤信息,這個在本系統內并沒有使用(不會)

ref變量

這個是vue3里面新出的一個,通過它來創建響應式變量,用于綁定頁面內元素。實現動態的變化。如果要在js所屬的代碼部分訪問它的值是不能直接用變量名的,而是需要使用? 變量名.value? 獲取變量的值。

v-model綁定

它的主要作用是把一個變量綁定到某個元素上,這個變量要是響應式變量。它有一個語法糖,就是先讀取后渲染。把它綜合到了v-model里面。

change.vue:

<script>
import { ref } from "vue";export default {name: "add",setup() {let change_text = ref("");let Blog_body = ref("");let Blog_title = ref("");function change_submit(e) {e.preventDefault();console.log("change_text:", change_text.value); // 檢查值this.$axios.post("/Change",{"Title": change_text.value}).then((response) => {console.log(response);Blog_body.value = response.data.Blog_body;Blog_title.value = response.data.Blog_title;alert("i get the blog");});}function change_out(e){e.preventDefault()alert("數據發送回后端",Blog_title,Blog_body)this.$axios.post("/Changeend", {BlogText: Blog_body.value,BlogName:Blog_title.value,}).then((response) => {alert(response.data.return);})}return {change_submit,change_text,Blog_title,Blog_body,change_out,};},
};
</script><template><div class="rit"><form method="post" @submit="change_submit"><table><tr class="a"><td>請輸入要修改的博文的名稱:<input type="text" style="width: 500px" v-model="change_text" /><input type="submit" value="提交" class="submit-button" /></td></tr></table></form><form @submit="change_out" id="f2"><table><tr class="a"><td>blog_name:<input type="text" style="width: 500px" v-model="Blog_title" /><input type="submit" value="確認提交" class="submit-button"></td></tr><tr class="b"><td><textarea v-model="Blog_body"></textarea></td></tr></table></form></div>
</template><style scoped>
div{display: flex;align-items: center;justify-content: center;
}
.rit{width: 1200px;height: 1120px;background: #fdd600;display: flex;flex-direction: column;justify-content: center;align-items: center;
}.a{width:1200px;height: 50px;text-align: center;
}
.b{width:1200px;height: 1025px;
}
textarea{width:1100px;height:1000px;overflow:auto;
}
</style>

這個里面就沒有什么特別新的內容了,我們簡單理解一下設計概念即可。在change模塊中。主要步驟如下

  1. 前端輸入blog的name
  2. 發送給后端,后端返還blog的name和內容? ?這是第一次前后端交流
  3. 用戶修改,再次返回給后端
  4. 后端接收,修改數據庫中的數據(是修改不是新建一個新的數據)這是第二次前后端交流

這里著重講一下的是使用了兩個路由,一個路由用于第一次前后端交流,另一個路由用于第二次前后端交流。

其他的部分都是之前講過的了。就不過多贅述了

后面的del.vue和discover.vue模塊都是重復的內容,我們只把代碼貼出來,剩下的就略過了

del.vue

<script>
import {ref} from "vue";export default{name:"add",setup() {let blogs_name = ref("")function del_blog(e){e.preventDefault()console.log("函數被觸發")this.$axios.post("/Delete",{"blog_name":blogs_name.value}).then(res=>{alert("blog 刪除"+res.data.return)console.log(res)})}return {blogs_name,del_blog,}}}
</script><template><div class="rit"><form method="post" @submit="del_blog" ><table><tr class="a"><td> 請輸入要刪除的博文名稱: <input type="text" style="width: 500px" v-model="blogs_name"><input type="submit" value="提交" class="submit-button" ></td></tr></table></form></div>
</template><style scoped>
div{display: flex;align-items: center;justify-content: center;
}
.rit{width: 1200px;height: 1120px;background: #fd7e50;
}
.a{width:1200px;height: 100px;
}textarea{width:1100px;height:1000px;overflow:auto;
}
</style>

discover.vue?

<script>
import {ref} from "vue";export default{name:"add",setup() {let change_text = ref("");let Blog_body = ref("");let Blog_title = ref("");function change_submit(e) {e.preventDefault();console.log("change_text:", change_text.value); // 檢查值this.$axios.post("/Discover",{"Title": change_text.value}).then((response) => {console.log(response);Blog_body.value = response.data.Blog_body;alert("i get the blog");});}return {Blog_body,Blog_title,change_text,change_submit,}}}
</script><template><div class="rit"><form method="post" @submit="change_submit"><table><tr class="a"><td> 請輸入要查詢的博文名稱: <input type="text" style="width: 500px" v-model="change_text"><input type="submit" value="提交"  class="submit-button"> </td></tr><tr class="b"><td><textarea v-model="Blog_body"/></td></tr></table></form></div>
</template><style scoped>
div{display: flex;align-items: center;justify-content: center;
}
.rit{width: 1200px;height: 1120px;background: #fdbfca;
}
.a{width:1200px;height: 100px;
}
.b{width:1200px;height: 1025px;
}
textarea{width:1100px;height:1000px;overflow:auto;
}
</style>

路由設置

路由的設置我們一般都在router/index.js文件內設置。這個目錄我們可以手動創建,也可以在項目創建的時候直接選定創建。

跟隨項目一起創建:

?這里有一個Router選項,勾選上就可以。

手動創建:

我們創建對應目錄以及文件,這個時候是不能使用的。我們還需要在main.js里面設置

  1. import router from './router'
    
  2. app.use(router)

設置完這兩個就說明我們啟用了路由系統。

具體路由的設置我們在index:對應的部分已經理解過了。這里就簡單贅述一下

路由的設置是設置一個數組,數組存放對象們,對象里面包含兩個參數,一個是path,另一個是component,path設置的是路徑,compoent設置的是路徑對應跳轉哪個界面。

如果有嵌套路徑的存在,就需要再在改對象里面添加一個屬性

children: []

這個里面存放的數據和外部的是一樣的,path,component如果還有嵌套內容就再寫一個children。并且嵌套的路徑不需要再寫 斜杠/? 直接寫路徑就可以了,這個斜杠會自動補充。

前端部分大概就講這一點吧。更加深層的還是需要看更權威的專家的講解或者去看官方文檔。

后端部分

后端我們使用的是go語言的gin框架

大致的架構我們講一下

主要是分為三個模塊,一個是路由模塊,一個是路由對應處理函數模塊,一個是與數據庫的連接模塊。

我們首先來講一下最重要的路由模塊(其實都很重要)

main.go:

這個文件主要負責路由的設置。

package mainimport ("github.com/gin-contrib/cors""github.com/gin-gonic/gin"
)// 同一目錄下,同一包內的.go文件內函數是共享的
func main() {router := gin.Default()router.Use(cors.Default())router.POST("/Add", Addpost)         //router.POST("/Change", Change)       //這是前端查詢并返回查詢結果的路徑router.POST("/Changeend", Changeend) //這是后端接收前端處理好的結果的路徑router.POST("./Discover", Discover)router.POST("/Delete", Delete)router.Run(":8081") //運行指定端口
}

我們既然要使用gin框架就需要實現導入這個框架。也就是:import ?"github.com/gin-gonic/gin"

,然后我們就可以設置路由了,這里需要注意設置的路由需要和前端對應上,而且要嚴格區分大小寫!!!我們先通過router:= gin.Default()創建了一個默認的gin路由引擎。

然后我們設置了很多條路由,通過? ?.請求方法("路由",對應的處理函數)

最后使用router.Run(":8081")運行。

這里提到了端口,我們前端運行的時候也是需要端口的。雙方端口不能一樣,如果一樣會導致端口占用錯誤,但是端口不一樣雖然不會導致錯誤出現。卻引發了一個新的問題:跨域

跨域問題的解決在前端后端都可以,但是我們還是默認在后端解決跨域問題。

router.Use(cors.Default())這條語句就是解決跨域問題的,它在"github.com/gin-contrib/cors"包下,所以要事先導入這個包。但是這部分博主并不是很精通,就不講了。只能說通過router.Use(cors.Default())語句我們可以設置一些默認的設定解決跨域問題。

然后就是路由后面跟著的處理函數,這個函數我們是寫在與main.go同級目錄下并且都屬于包main。所以可以直接使用不用導入對應的包。

至于為什么函數不加()是因為如果加了()就是直接使用這個函數。這并不是我們需要的。我們需要的是在特定情況下跳轉到對應的處理函數。所以沒有加上()

mysql.go:

package mainimport ("gorm.io/driver/mysql""gorm.io/gorm"
)type blog struct {BlogName string `gorm:"primaryKey type:varchar(255)"`BlogText string `gorm:"not null unique type:text"`
} //創建一個結構體,結構體用于存儲博文和博文名稱func sqlof() *gorm.DB { //這是一個數據庫連接函數,當我們調用它的時候會返回一個數據庫對象。我們用這個對象進行數據的增上改查dsn := "root:123456@tcp(127.0.0.1:3306)/web_of_blog"db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})if err != nil {panic(err)}db.AutoMigrate(&blog{})return db
}

這個文件的主要作用是連接數據庫并提供一個函數,函數返回一個數據庫對象。

我們需要創建一個結構體對象,這個對象的字段和數據庫里面的字段一一對應。

dsn是一個字符串,字符串的內容是用戶:密碼@協議(ip,端口)/數據庫名稱

ip使用的是127.0.0.1是說明這是本機的數據庫。

我們使用gorm.Open(mysql.Open(dsn),&gorm.Config{})連接數據庫,它會返會一個對象和錯誤信息。如果連接成功是沒有錯誤信息的,即err==nil

db.AutoMigrate(&blog{})的作用是確認數據庫里有對應的表(結構體名稱+s)如果沒有則自動創建,如果表的結構不同則更新結構。

我們把最后的連接好的對象作為返回值返回給調用者。

controller.go

這個部分可以說是后端的靈魂所在了

package mainimport ("fmt""github.com/gin-gonic/gin"
)var ch = make(chan string, 1)
var db = sqlof()      //創建數據庫全局對象
type Article struct { //這個結構體用于接收前端數據博文和博文名稱Name string `json:"name"`Text string `json:"text"`
}
type change_blog_title struct {Title string `json:"title"`
}func Addpost(c *gin.Context) {var article Articleif err := c.ShouldBindJSON(&article); err != nil {c.JSON(400, gin.H{"error": "解析 JSON 失敗"})return}var insert blog //創建一個結構體對象,用于存儲從前端讀取的數據insert.BlogName = article.Nameinsert.BlogText = article.Textif db.Create(&insert).Error != nil { //判斷數據庫插入操作是否成功,成功返回200不成功返回500c.JSON(500, gin.H{"Error": "error",})/*這里返回的是json數據格式,所以前端讀取的時候就需要使用.Error讀取對應的key值*/} else {c.JSON(200, gin.H{"Error": "no error",})}
}// Change /*前端發送一個title作為博文的名字給后端,后端讀取這個數據然后查詢,并返回查詢結果*/
func Change(c *gin.Context) {fmt.Println("change函數被成功調用,說明后端路由設置無誤")var title change_blog_title //這是一個博文的表頭的結構體實例對象var content blog//通過前端發送的數據來把title賦值給后端的title然后再通過db對象進行查詢,并把查詢結果的信息返回給后端err := c.ShouldBindJSON(&title)if err != nil {fmt.Println("error")}fmt.Println("jianche", title.Title)ch <- title.Titledb.Table("blogs").Where("blog_name = ?", title.Title).First(&content) //把查詢到的第一個結果返回給content進行數據綁定c.JSON(200, gin.H{                                                    //返回查詢到的文章和數據"Blog_body":  content.BlogText,"Blog_title": content.BlogName,})fmt.Println("數據已返回", content.BlogName, content.BlogText)}
func Changeend(c *gin.Context) { //接收數據并修改,然后返回修改完成還是錯誤blog_name := <-chdate := blog{}if err := c.ShouldBindJSON(&date); err != nil {c.JSON(400, gin.H{"return": "數據寫入錯誤",})}result := db.Table("blogs").Where("blog_name = ?", blog_name).Update("blog_text", date.BlogText)if result.Error != nil {c.JSON(500, gin.H{"return": "更新博文失敗"})return}result = db.Table("blogs").Where("blog_name = ?", blog_name).Update("blog_name", date.BlogName)if result.Error != nil {c.JSON(500, gin.H{"return": "更新博文失敗"})return} else {c.JSON(200, gin.H{"return": "修改成功",})}}func Discover(c *gin.Context) {fmt.Println("discover函數被成功調用,說明后端路由設置無誤")var title change_blog_title //這是一個博文的表頭的結構體實例對象var content blog//通過前端發送的數據來把title賦值給后端的title然后再通過db對象進行查詢,并把查詢結果的信息返回給后端err := c.ShouldBindJSON(&title)if err != nil {fmt.Println("error")}fmt.Println("jianche", title.Title)db.Table("blogs").Where("blog_name = ?", title.Title).First(&content) //把查詢到的第一個結果返回給content進行數據綁定c.JSON(200, gin.H{                                                    //返回查詢到的文章和數據"Blog_body": content.BlogText,})fmt.Println("數據已返回", content.BlogName, content.BlogText)}type DeleteRequest struct {BlogName string `json:"blog_name"`
}func Delete(c *gin.Context) {var request DeleteRequesterr := c.ShouldBindJSON(&request)if err != nil {c.JSON(400, gin.H{"return": "出現錯誤,啦啦啦",})return}blog_name := request.BlogNamefmt.Println("i get it: ", blog_name)resout := db.Where("blog_name = ?", blog_name).Delete(&blog{})if resout.Error != nil {c.JSON(500, gin.H{"return": "error",})} else {c.JSON(200, gin.H{"return": "ok",})}
}

它根據不同路由的設置來執行對應的函數,這一整個文件的核心就是c *gin.Context這個

c *gin.Context?是 Gin 框架中處理 HTTP 請求的核心對象,它的主要作用包括:

  • 獲取請求信息:如請求頭、請求體、查詢參數、路徑參數等。

  • 生成響應:如返回 JSON、HTML、文本等。

  • 管理中間件:在請求處理過程中傳遞數據。

  • 控制流程:如中止請求、重定向等。

我們通過它獲取前端發送的數據,并且返回給前端數據。

我們使用c.ShouldBindJSON(&結構體)把數據綁定到結構體,這需要我們提前創建一個空的結構體對象。對象的字段名稱要與前端通過axios傳遞過來的json數據的key值相同

也就是我前端傳遞數據{"Name":"123","age":18}后端的結構體字段就需要是Name和age默認的類型都是string字符串類型。同樣的,前端獲取后端的回應也是如此。只不過我們前端使用的是

.then(res=>{

我們需要使用res.data.返回json數據的key獲取對應的value

})

綁定完成之后我們就獲取到了前端發送的請求了。

然后就是與數據庫交互的部分了,這部分我們之前在gorm講過

使用gorm連接數據庫

至于為什么后端沒有用mvc架構,是因為代碼量不大,而且模塊也就三個用不上架構。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/73788.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/73788.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/73788.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

分支結構- P5717-三角形分類-第二十一天

洛谷題單 第二十一天&#xff1a;3.18&#xff08;周二&#xff09; 題目&#xff1a;分支結構–P5717 代碼 #include <stdio.h>//本題目卡住的點&#xff1a;1.邏輯問題 2.對if-else if-else結構的運行理解&#xff0c;導致了邏輯混亂//注意&#xff1a;程序會組個…

華為OD機試 - 最長回文字符串 - 貪心算法(Java 2024 E卷 100分)

題目描述 如果一個字符串正讀和反讀都一樣(大小寫敏感),則稱之為一個「回文串」。例如: level 是一個「回文串」,因為它的正讀和反讀都是 level。art 不是一個「回文串」,因為它的反讀 tra 與正讀不同。Level 不是一個「回文串」,因為它的反讀 leveL 與正讀不同(因大小…

C語言文件操作入門

本節重點 理解文件的形式與基本概念二進制文件與文本文件文件的打開與關閉文件讀寫函數、文件緩沖區 正文開始--------------------------------------------------------------------------------------------------------------------- 一、為什么使用文件 程序運行時數據存…

Doris:聯邦認證

LDAP? 接入第三方 LDAP 服務為 Doris 提供驗證登錄和組授權服務。 LDAP 驗證登錄? LDAP 驗證登錄指的是接入 LDAP 服務的密碼驗證來補充 Doris 的驗證登錄。Doris 優先使用 LDAP 驗證用戶密碼&#xff0c;如果 LDAP 服務中不存在該用戶則繼續使用 Doris 驗證密碼&#xff…

stm32第六天繼電器

一&#xff1a;繼電器 1.繼電器的工作原理 繼電器是一個電控開關&#xff0c;工作原理基于電磁感應&#xff0c;繼電器包括一個電磁線圈和一組觸點。常用于控制高電流或高電壓的電路&#xff0c;例如自動控制原理&#xff0c;電力系統和自動化設備中&#xff0c;由于可靠性和電…

Vue渲染函數 - render 函數

文章目錄 Vue渲染函數 - render 函數1. 什么是 render 函數2、頁面展示過程3、render 函數的參數4. 如何使用&#xff08;1&#xff09;基本渲染&#xff08;2&#xff09;傳遞屬性和事件&#xff08;3&#xff09;條件渲染 5. render 函數的實際使用6.View Design 組件中的使用…

單片機自學總結

自從工作以來&#xff0c;一直努力耕耘單片機&#xff0c;至今&#xff0c;頗有收獲。從51單片機&#xff0c;PIC單片機&#xff0c;直到STM32&#xff0c;以及RTOS和Linux&#xff0c;幾乎天天在搞:51單片機&#xff0c;STM8S207單片機&#xff0c;PY32F003單片機&#xff0c;…

go回調函數的使用

在Go語言中&#xff0c;回調函數可以有參數&#xff0c;也可以沒有參數。它們的定義和使用方式略有不同&#xff0c;但本質上都是將函數作為參數傳遞給另一個函數&#xff0c;并在適當的時候調用它。以下是帶參數和不帶參數的回調函數的示例和說明。 1. 不帶參數的回調函數 不…

在 Ubuntu 中配置 NFS 共享服務的完整指南

前言 網絡文件系統&#xff08;NFS&#xff09;作為 Linux 系統間實現文件共享的標準協議&#xff0c;在分布式計算和容器化部署場景中具有重要作用。本文將詳細演示如何在 Ubuntu 系統上配置 NFS 服務端與客戶端&#xff0c;并實現可靠的持久化掛載。 一、環境準備 系統要求…

TypeScript Symbols 深度解析:在 Vue3 中的高級應用實踐

一、Symbols 核心特性解析 1.1 什么是 Symbol&#xff1f; Symbol 是 ES6 引入的原始數據類型&#xff0c;表示唯一且不可變的值&#xff0c;主要解決對象屬性名沖突問題。在 TypeScript 中&#xff0c;我們通過 symbol 類型獲得完整的類型支持&#xff1a; const SERIAL_KE…

無需刷機、root,暢享原生安卓的絲滑體驗。

Apex Launcher 是一款歷史悠久的 Android 桌面啟動器&#xff0c;誕生于 Android 系統早期&#xff08;Android 4.0 時代&#xff09;。當時&#xff0c;Android 系統的默認界面被認為較為簡陋&#xff0c;無法滿足一些追求個性化和高效操作的用戶需求。因此&#xff0c;許多開…

Visual Studio Code安裝配置優化全攻略:打造高效開發環境

目錄 一、背景與意義 二、安裝與配置基礎 2.1 下載與安裝 2.2 核心配置目錄 三、深度優化配置指南 3.1 主題與界面優化 3.2 必裝效率插件&#xff08;精選TOP10&#xff09; 3.3 性能優化設置 四、實戰案例&#xff1a;前端開發環境配置 4.1 項目初始化 4.2 調試配置…

味覺傳送器E-Taste:開啟虛擬世界的味覺之門

味覺傳送器E-Taste&#xff1a;開啟虛擬世界的味覺之門 一、發明背景與動機 隨著虛擬現實&#xff08;VR&#xff09;和增強現實&#xff08;AR&#xff09;技術的飛速發展&#xff0c;人們在虛擬世界中的沉浸感不斷提升&#xff0c;視覺和聽覺體驗已經取得了顯著的突破。然而…

判斷質數與合數

判斷質數與合數的邏輯很相似&#xff0c;都是判斷一個屬除了1和它本身&#xff0c;能不能被其他數整除。 其他數包括質數與合數&#xff0c;合數能表示能質數的乘積&#xff0c;因此問題就轉化為&#xff1a;一個數能不能被除了1和它本身之外的其他質數整除。 質數2&#xff…

在Spring Boot項目中接入DeepSeek深度求索,感覺笨笨的呢

文章目錄 引言1. 什么是DeepSeek&#xff1f;2. 準備工作2.1 注冊DeepSeek賬號 3.實戰演示3.1 application增加DS配置3.2 編寫service3.3 編寫controller3.4 編寫前端界面chat.html3.5 測試 總結 引言 在當今快速發展的數據驅動時代&#xff0c;企業越來越重視數據的價值。為了…

Cursor在內網環境配置自定義DeepSeek API

關鍵字 Cursor、DeepSeek、API配置、內網代理、HTTP/2 背景環境 使用Cursor集成環境開發程序。但是我使用公司的內網并不能使用cursor自帶的模型&#xff0c;于是我就想使用DeepSeek官方的API服務。 環境&#xff1a;Windows 11系統 解決過程 網絡檢測 首先進行環境檢測&am…

RabbitMQ 集群降配

這里寫自定義目錄標題 摘要檢查狀態1. 檢查 RabbitMQ 服務狀態2. 檢查 RabbitMQ 端口監聽3. 檢查 RabbitMQ 管理插件是否啟用4. 檢查開機自啟狀態5. 確認集群高可用性6. 檢查使用該集群的服務是否做了斷開重連 實操1. 負載均衡配置2. 逐個節點降配&#xff08;滾動操作&#xf…

設計模式之外觀模式:原理、實現與應用

引言 外觀模式&#xff08;Facade Pattern&#xff09;是一種結構型設計模式&#xff0c;它通過提供一個統一的接口來簡化復雜系統的使用。外觀模式隱藏了系統的復雜性&#xff0c;使得客戶端可以通過一個簡單的接口與系統交互。本文將深入探討外觀模式的原理、實現方式以及實…

進行交通流預測,使用KAN+Transformer模型

理論基礎 KAN&#xff08;Knowledge Augmented Network&#xff09; KAN 是一種知識增強網絡&#xff0c;其核心思想是將先驗知識融入到神經網絡中&#xff0c;以此提升模型的性能與泛化能力。在交通流預測領域&#xff0c;先驗知識可以是交通規則、歷史交通模式等。通過把這…