当前位置: 首页 > article >正文

个人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架构,是因为代码量不大,而且模块也就三个用不上架构。

相关文章:

个人blog系统 前后端分离 前端js后端go

系统设计&#xff1a; 1.使用语言&#xff1a;前端使用vue&#xff0c;并使用axios向后端发送数据。后端使用的是go的gin框架&#xff0c;并使用grom连接数据库实现数据存储读取。 2.设计结构&#xff1a; 最终展示&#xff1a;仅展示添加模块&#xff0c;其他模块基本相似 前…...

单元测试mock

一、背景 现在有A类,B类,C类&#xff0c;A类依赖B类,依赖C类&#xff0c;如果想要测试A类中的某个方法的业务逻辑。A类依赖其他类&#xff0c;则把其他类给mock&#xff0c;然后A类需要真实对象。这样就可以测试A类中的方法。 举例&#xff1a;Ticket类需要调用Flight类和Pas…...

OpenGL 将屏幕上的二维坐标转换为三维空间中的一个点

本文主要介绍将屏幕上的二维坐标转换为三维空间中的一个点&#xff0c;该点位于 近 平面上&#xff08;即 Z 坐标为 -1&#xff09;。 一、步骤概述 屏幕坐标到标准化设备坐标 (NDC): 将屏幕坐标 (x, y) 转换为 NDC 坐标系。NDC 到相机空间: 使用逆投影矩阵将 NDC 坐标转换到相…...

golang接口用法-代码案例

文章目录 Go语言中接口&#xff08;interface&#xff09;的含义接口的常见应用场景示例1示例2&#xff08;Dog 和 Cat&#xff09;使用场景-多数据库 Go语言中接口&#xff08;interface&#xff09;的含义 接口在Go语言中是一种类型&#xff0c;它定义了一组方法的集合。一个…...

ORA-12162: TNS:net service name is incorrectly specified

1.现象 SQL plus 连接实例报错&#xff0c;已确定实例是open状态。 [rootlocalhost ~]# su - oracle [oraclelocalhost ~]$ sqlplus / as sysdbaSQL*Plus: Release 19.0.0.0.0 - Production on Sat Mar 15 10:20:56 2025 Version 19.11.0.0.0Copyright (c) 1982, 2020, Orac…...

基于 Verilog 的时序设计:从理论到实践的深度探索

在数字电路设计领域,时序设计是一个至关重要的环节,它涉及到组合逻辑电路与时序逻辑电路的设计差异、时钟信号的运用以及触发器的工作原理等多个方面。本文将围绕基于 Verilog 的时序设计实验展开,详细阐述实验过程、代码实现以及结果分析,帮助读者深入理解时序设计的核心概…...

GreenKGC: A Lightweight Knowledge Graph Completion Method(论文笔记)

CCF等级&#xff1a;A 发布时间&#xff1a;2023年7月 代码位置 25年3月17日交 目录 一、简介 二、原理 1.整体 2.表示学习 3.特征修剪 4.决策学习 三、实验性能 1.主要结果 2.消融实验 四、结论和未来工作 一、简介 传统知识图谱补全方法中&#xff0c;嵌入维度…...

SSM基础专项复习5——Maven私服搭建(2)

系列文章 1、SSM基础专项复习1——SSM项目整合-CSDN博客 2、SSM基础专项复习2——Spring 框架&#xff08;1&#xff09;-CSDN博客 3、SSM基础专项复习3——Spring框架&#xff08;2&#xff09;-CSDN博客 4、SSM基础专项复习4——Maven项目管理工具&#xff08;1&#xff…...

Linux中的epoll简单使用案例

I/O 多路复用允许一个进程或线程同时监控多个网络 sockets 的状态。它通过单个系统调用&#xff08;select&#xff09;来检查多个 sockets 是否有数据可读、可写或是否有异常。Linux 提供了多种 I/O 复用技术&#xff0c;包括上面提到的 select、以及 poll、epoll。 创建epol…...

ASP4644四通道降压稳压器的工业高效电源管理方案

ASP4644工业级型号&#xff08;ASP4644I6B&#xff09;是一款专为工业场景设计的四通道降压稳压器&#xff0c;支持-40C至85C工作温度。其核心特性包括&#xff1a; 宽输入电压范围&#xff1a;4V–14V&#xff0c;适配工业现场多变的电源环境。 高负载能力&#xff1a;单通道…...

kali破解Pdf/execl/word

一、准备工作 1.工具安装 Kali Linux 内置部分工具&#xff0c;需补充安装以下工具&#xff1a; sudo apt update sudo apt install pdfcrack hashcat john -y git clone https://github.com/magnumripper/JohnTheRipper # 更新版John 2.字典准备 常用字典&#xff1a;Kal…...

宇树科技纯技能要求总结

一、嵌入式开发与硬件设计 核心技能 嵌入式开发&#xff1a; 精通C/C&#xff0c;熟悉STM32、ARM开发熟悉Linux BSP开发及驱动框架&#xff08;SPI/UART/USB/FLASH/Camera/GPS/LCD&#xff09;掌握主流平台&#xff08;英伟达、全志、瑞芯微等&#xff09; 硬件设计&#xff1a…...

RabbitMq C++客户端的使用

1.RabbitMq介绍 RabbitMQ 是一款开源的消息队列中间件&#xff0c;基于 AMQP&#xff08;高级消息队列协议&#xff09;实现&#xff0c;支持多种编程语言和平台。以下是其核心特点和介绍&#xff1a; 核心特点 多语言支持 提供 Java、Python、C#、Go、JavaScript 等语言的客…...

用通义大模型写爬虫程序,汇总各科成绩

需求&#xff1a;根据各科网址&#xff0c;输入学号、姓名查询成绩。 中间反反复复很多次&#xff0c;本文只记下重点的几次和大模型的沟通历史。 输入界面 查询界面 round0&#xff08;最初的问题&#xff09; 请在windows下&#xff0c;使用python的selenium库&#xff0…...

电商项目Ts版本

文章目录 项目地址一、环境安装1.1 配置作为导入1.2 文件目录 二、路由2.1 publicRoutes 项目地址 教程作者&#xff1a;教程地址&#xff1a; 代码仓库地址&#xff1a; 所用到的框架和插件&#xff1a; dbt airflow一、环境安装 1.1 配置作为导入 vite.config.ts impor…...

HarmonyOS Next中的弹出框使用

HarmonyOS Next弹出框概述及分类 弹出框是一种模态窗口&#xff0c;通常用于在保持当前上下文环境的同时&#xff0c;临时展示用户需关注的信息或待处理的操作。用户需在模态弹出框内完成相关交互任务之后&#xff0c;才能退出模态模式。弹出框可以不与任何组件绑定&#xff0…...

C++实现的数据结构示例,涵盖链表、数组、树和图

使用C实现的数据结构示例&#xff0c;涵盖链表、数组、树和图的基本操作&#xff1a; 链表&#xff08;单向链表&#xff09; #include <iostream> using namespace std;struct Node {int data;Node* next;Node(int val) : data(val), next(nullptr) {} };class Linked…...

FPGA中级项目4——DDS实现

FPGA中级项目4——DDS实现 DDS简介 DDS&#xff08;直接数字频率合成器&#xff0c;Direct Digital Frequency Synthesis&#xff09;是一种基于数字信号处理技术的频率合成方法&#xff0c;广泛应用于通信、雷达、仪器仪表等领域。在 FPGA中实现 DDS 具有灵活性高、集成度强、…...

深度学习-149-langchain之如何不使用with_structured_output()从模型中返回结构化数据

文章目录 1 不使用with_structured_output()方法1.1 问题背景1.2 输出解析器1.3 远程deepseek大模型API2 基于提示词2.1 直接使用提示词2.2 少样本提示词3 直接提示和解析模型输出3.1 使用PydanticOutputParser3.1.1 构建解析器3.1.2 构建提示模板3.1.3 调用大模型3.1.4 调用链…...

STM32 DAC详解:从原理到实战输出正弦波

目录 一、DAC基础原理1.1 DAC的作用与特性1.2 DAC功能框图解析 二、DAC配置步骤2.1 硬件配置2.2 初始化结构体详解 三、DAC数据输出与波形生成3.1 数据格式与电压计算3.2 正弦波生成实战3.2.1 生成正弦波数组3.2.2 配置DMA传输3.2.3 定时器触发配置 四、常见问题与优化建议4.1 …...

深度学习框架PyTorch——从入门到精通(5)构建神经网络

构建神经网络 获取训练设备定义类模型层nn.Flattennn.Linearnn.ReLUnn.Sequentialnn.Softmax 模型参数补充说明argmax 神经网络是由一些层或者模块组成的&#xff0c;这些层和模块会对数据进行各种操作。 在 PyTorch 里&#xff0c;torch.nn 这个命名空间提供了你搭建自己神经网…...

基于PyQt5与Open3D的轻量化BIM工具开发指南(下)‌

‌基于PyQt5与Open3D的轻量化BIM工具开发指南&#xff08;下&#xff09;‌ ‌——参数化建模、数据导出与性能优化‌ 【跳转】基于PyQt5与Open3D的轻量化BIM工具开发指南&#xff08;上&#xff09;‌ ‌四、详细实现步骤&#xff08;Part 2&#xff09;‌ ‌3. 参数化建模…...

Pytest项目_day01(HTTP接口)

HTTP HTTP是一个协议&#xff08;服务器传输超文本到浏览器的传送协议&#xff09;&#xff0c;是基于TCP/IP通信协议来传输数据&#xff08;HTML文件&#xff0c;图片文件&#xff0c;查询结果等&#xff09;。 访问域名 例如www.baidu.com就是百度的域名&#xff0c;我们想…...

在vue项目中,使用Patch请求,实现根据id修改某张发票的日结状态

目录 前言 一.问题描述 二.后端实现 1.分析 2.检查后端拦截器&#xff0c;看看是否允许接收Patch类型的请求 3.编写Dto 4.编写controller层 5.编写service层 6.mapper层 7.使用apifox&#xff0c;测试后端接口的可用性 三.前端实现 1.封装api&#xff08;本质是ax…...

Android Zygote的进程机制

目录 ✅ Android Zygote 进程机制详解 &#x1f6a9; 一、Zygote 的作用 ⚙️ 二、Zygote 启动流程 ✅ 1. init 进程启动 Zygote ✅ 2. Zygote 初始化虚拟机与核心类库 ✅ 3. Zygote 监听 Socket ✅ 4. Zygote fork 创建应用进程 &#x1f525; 三、Zygote 与应用进程之…...

某快餐店用户市场数据挖掘与可视化

1、必要库的载入 import pandas as pd import matplotlib.pyplot as plt import seaborn as sns2、加载并清洗数据 # 2.1 加载数据 df pd.read_csv(/home/mw/input/survey6263/mcdonalds.csv)# 2.2 数据清洗 # 2.2.1 检查缺失值 print(缺失值情况&#xff1a;) print(df.isn…...

[C++面试] 标准容器面试点

一、入门 1、vector和list的区别 [C面试] vector 面试点总结 vector 是动态数组&#xff0c;它将元素存储在连续的内存空间中。支持随机访问&#xff0c;即可以通过下标快速访问任意位置的元素&#xff0c;时间复杂度为 O(1)&#xff0c;准确点是均摊O(1)。但在中间或开头插…...

单片机学完开发板,如何继续提升自己的技能?

很多人学完开发板后都会卡在一个尴尬的阶段&#xff1a;觉得自己会的东西不少&#xff0c;但又不知道下一步该干啥。会点C语言&#xff0c;能烧录程序&#xff0c;能点亮LED&#xff0c;玩转按键&#xff0c;搞定串口等等&#xff0c;能用开发板做点小玩意儿&#xff0c;但面对…...

luogu「EZEC-10」打分 --- Python3 解法

题目链接&#xff1a; 「EZEC-10」打分 import sysdef max_score(n, m, scores):scores.remove(min(scores)) # 最小值的选取&#xff0c;不影响中间部分的处理scores.sort()max_ scores[-1]sum_ sum(scores[:-1]) # 中间部分len_ len(scores)needed (len_ - 1) * max_ …...

MySQL事务介绍

一、一个典型的事务场景 步骤操作描述SQL 语句1开启事务&#xff0c;确保转账操作的原子性START TRANSACTION;2从用户 A 的账户中扣除 100 元UPDATE account SET balance balance - 100 WHERE user A;3向用户 B 的账户中添加 100 元UPDATE account SET balance balance 1…...