相关文章:
技能学习:学习使用golang(gin框架) + vue.js,开发前端全栈网站-1.工具和本地环境
技能学习:学习使用golang(gin框架) + vue.js,开发前端全栈网站-2.启动项目
技能学习:学习使用golang(gin框架) + vue.js,开发前端全栈网站-3.接收json数据
技能学习:学习使用golang(gin框架) + vue.js,开发前端全栈网站-4.连接mongodb数据库
技能学习:学习使用golang(gin框架) + vue.js,开发前端全栈网站-5.跨域并跨域传输数据
技能学习:学习使用golang(gin框架) + vue.js,开发前端全栈网站-6.GO语言做通用CRUD接口-1
技能学习:学习使用golang(gin框架) + vue.js,开发前端全栈网站-7.GO语言做通用CRUD接口-2
技能学习:学习使用golang(gin框架) + vue.js,开发前端全栈网站-8.模型的关联——无限层级分类
技能学习:学习使用golang(gin框架) + vue.js,开发前端全栈网站-9.管理员及登录注册功能的实现
技能学习:学习使用golang(gin框架) + vue.js,开发前端全栈网站-10.生产环境编译
CategoryList.vue:
<template>
<div>
<h1>分类列表h1>
<el-table :data="items">
<el-table-column prop="_id" label="ID" width="220">
el-table-column>
<el-table-column prop="parent.name" label="上级分类">
el-table-column>
<el-table-column prop="name" label="分类名称">
el-table-column>
<el-table-column
fixed="right"
label="操作"
width="100">
<template slot-scope="scope">
<el-button type="text" size="small" @click="$router.push('/categories/edit/' + scope.row._id)">编辑el-button>
<el-button @click="remove(scope.row)" type="text" size="small">删除el-button>
template>
el-table-column>
el-table>
div>
template>
<script>
export default {
data() {
return {
items: []
}
},
methods: {
async fetch(){
const res = await this.$http.get('rest/categories')
this.items = res.data
},
remove(row){
this.$confirm('是否确定要删除分类"' + row.name + '"?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(async () => {
// 要想使用await,函数必须使用async
// await异步执行,待调用接口获取数据完成后再将值传给res,进行下一步操作
const res = await this.$http.delete('rest/categories/' + row._id)
this.$message({
type: 'success',
message: '删除成功!'
});
if(res.status == 200){
// 接口调用成功后,刷新页面
this.fetch()
}
}).catch(() => {
this.$message({
type: 'info',
message: '已取消删除'
});
});
}
},
created() {
this.fetch()
}
}
script>
解释:
在首页导航中引入该页面:
在路由页面引入组件和路由:
保存进入admin端页面查看效果:
可以看到上方页面已经显示成功,但是里边的数据并没有呈现出来,是因为查询数据接口还没有完善,下面针对查找信息接口进行完善:
(1)接口地址:
接口地址正确,没问题。
(2)接口函数:
目前接口函数还是最开始我们学习接口路由时,测试使用user表的数据模型,与现在接口不匹配,所以我们要整改一下:
此时,编译测试,没问题。
在admin端页面进入分类列表页面:
接口调用成功,但没有成功后的数据。检查原因:
我们的接口传值为categories,但是表名和参数判断为category,所以把接口传递的参数改为category即可:
保存刷新admin端,测试还是不行,原来是因为没有将获取的数据以json格式返回:
重新编译进行测试:
查询所有数据成功,没问题。
检查接口:
优化删除接口:
由于删除字段的命令相同,不需要用到模型,所以免去了if-else判断模型字段的过程。
编译运行,测试:
此时可以看到过程都没问题,但是我们想删除的字段并没有删除成功,查看运行结果:
原因是web端中id值没有传成功,也就是没有找到该条信息中的id。
同时我也意识到之前的查询接口中,也没有成功查询到id字段:
经短时间查找原因,发现一个大BUG,虽然我们插入字段的过程中mongodb会自动生成_id,所以不需要在模型中定义id字段,但我们查询数据是需要通过模型进行查询的:
于是我们需要在模型中添加一个id字段:
保存编译,刷新页面测试:
_id字段就查询出来了,同时上方ID也显示。
此时再测试删除字段:
旭,居然还在:
检查问题!查看手册!!百度!!!!
原因是数据库中的id是个bson格式,而我们传来的id是string字符串格式,所以使用id字段需要把它变成bson格式:
我就不信,这次一定可以!
编译执行测试:
还!是!不!可!以!!!
啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊,接着查:
hehe,居然又是传参错误,改成category。
测试:
成功了,可以,研究一下午终于成了。
我们修改分类功能复用添加分类功能的组件categorySet.vue组件:
修改组件:
<template>
<div>
<h1>创建分类h1>
<el-form label-width="80px" style="margin-top:20px;" @submit.native.prevent="save">
<el-form-item label="分类名">
<el-input v-model="model.name">el-input>
el-form-item>
<el-form-item>
<el-button type="primary" native-type="submit">保存el-button>
el-form-item>
el-form>
div>
template>
<script>
export default {
data(){
return {
model: {}
}
},
methods: {
// 使用async..await异步请求方法
async save(){
let res
// 这里放axios方法,用来提交数据
if(this.id){
// 传id值,表明修改哪一条数据
res = await this.$http.put('rest/categories/' + this.id, this.model)
}else{
res = await this.$http.post('rest/categories', this.model)
}
this.$router.push('/categories/list')
// 提示信息,使用vue中自带的$message实例
this.$message({
type: 'success',
message: '保存成功'
})
},
async fetch(){
const res = await this.$http.get('rest/categories/' + this.id)
this.model = res.data
},
},
created(){
this.id && this.fetch()
}
}
script>
修改完成,测试:
说res没有被使用,小bug不足为虑,在下边console一个即可:
再测试,新建分类:
列表页面点击编辑,暂时没有页面生成:
应该是无法获取id,继续修改,给CategorySet.vue中添加props:
同时在admin/index.js路由文件中添加修改数据路由:
最后,在编辑按钮路由地址处将create改成edit:
保存,重新点击编辑:
页面出现,说明组件复用成功,但是数据没有查询成功。
(1)CRUD根据id查询数据接口:
第一步,还是改前端接口调用处的categories:
第二步,修改根据id查询数据接口:
编译启动,测试:
成功,没问题。
(2)CRUD修改数据 接口:
调用接口地址没问题,调整修改数据接口:
编译启动,测试,将123改为“node.js”:
接口调用成功,但数据没有成功修改:
经过二次测试,发现form没有值:
进一步搞懂,根据模型为form赋值的方法需要有.bind()方法进行数据的合并,同时&form已经是json格式,不需要使用bson.M方法,修改如下:
此时,重新编译启动,修改测试:
成功。
到此restful风格的CRUD接口全部完成,下面将全部后端接口贴给大家:
package db
import(
"github.com/gin-gonic/gin"
"gopkg.in/mgo.v2"
"gopkg.in/mgo.v2/bson"
"net/http"
"strings"
// "fmt"
// 引入模型
"server/models"
)
// 插入数据
func insert(ctx *gin.Context){
// 解析api参数
resource := ctx.Param("resource")
// 连接mongodb服务
url := "mongodb://127.0.0.1"
// 设置数据库一致性模式
// 连接数据库操作,该操作赋值给session
// err值必写,用于错误处理
session, err := mgo.Dial(url)
// 后边程序执行的err与go程序比对,若有错误则返回错误内容
if err != nil {
panic(err)
}else{
// 若没有错误,则在页面返回字符串,显示插入成功
ctx.String(http.StatusOK, "插入成功")
}
// defer用法大家自行百度,我解释不清
defer session.Close()
// 设置数据库一致性模式,就当作打开数据库
session.SetMode(mgo.Monotonic, true)
// 找到某数据库下的某数据表
c := session.DB("db_go").C(resource)
// 以上为连接数据库
if resource == "user" {
type modelName models.User
// 使用user数据模型
var form modelName
// 如果传值格式不符合上方定义的结构,则返回错误信息
if err := ctx.Bind(&form); err != nil {
ctx.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
// 此时&form就继承了上方定义的结构格式
// 插入数据,并将insert状态传值给err
err = c.Insert(&form)
} else if resource == "category" {
type modelName models.Category
// 使用user数据模型
var form modelName
// 如果传值格式不符合上方定义的结构,则返回错误信息
if err := ctx.Bind(&form); err != nil {
ctx.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
// 此时&form就继承了上方定义的结构格式
// 插入数据,并将insert状态传值给err
err = c.Insert(&form)
}
// ctx.String(http.StatusOK, fmt.Sprintf(resource))
}
// 查询数据
func find(ctx *gin.Context){
// 解析api参数
resource := ctx.Param("resource")
id := ctx.Param("id")
// 传来的id值为"/id",我们要把"/"截去
id = strings.Trim(id, "/")
// 将id转化为bson.ObjectId格式
var _id bson.ObjectId
_id = bson.ObjectIdHex(id)
url := "mongodb://127.0.0.1"
session, err := mgo.Dial(url)
if err != nil {
panic(err)
}
defer session.Close()
session.SetMode(mgo.Monotonic, true)
c := session.DB("db_go").C(resource)
// 以上为数据库连接
if resource == "user" {
type modelName models.User
modelNamer := modelName{}
// 查找数据
err = c.Find(bson.M{"_id": _id}).One(&modelNamer)
ctx.JSON(http.StatusOK, modelNamer)
} else if resource == "category" {
type modelName models.Category
modelNamer := modelName{}
// 查找数据
err = c.Find(bson.M{"_id": _id}).One(&modelNamer)
ctx.JSON(http.StatusOK, modelNamer)
}
}
// 查询全部数据
func findAll(ctx *gin.Context){
// 解析api参数
resource := ctx.Param("resource")
url := "mongodb://127.0.0.1"
session, err := mgo.Dial(url)
if err != nil {
panic(err)
}
defer session.Close()
session.SetMode(mgo.Monotonic, true)
c := session.DB("db_go").C(resource)
if resource == "user" {
// 使用user数据模型
type modelName models.User
// 查找10条数据
modelNames := make([]modelName, 10)
// 查找全部
err = c.Find(nil).All(&modelNames)
// 返回数据
ctx.JSON(http.StatusOK, modelNames)
} else if resource == "category" {
// 使用user数据模型
type modelName models.Category
// 查找10条数据
modelNames := make([]modelName, 10)
// 查找全部
err = c.Find(nil).All(&modelNames)
// 返回数据
ctx.JSON(http.StatusOK, modelNames)
}
}
// 删除数据
func delete(ctx *gin.Context){
// 解析api参数
resource := ctx.Param("resource")
id := ctx.Param("id")
// 传来的id值为"/id",我们要把"/"截去
id = strings.Trim(id, "/")
// 将id转化为bson.ObjectId格式
var _id bson.ObjectId
_id = bson.ObjectIdHex(id)
url := "mongodb://127.0.0.1"
session, err := mgo.Dial(url)
if err != nil {
panic(err)
}else{
ctx.String(http.StatusOK, id)
}
defer session.Close()
session.SetMode(mgo.Monotonic, true)
c := session.DB("db_go").C(resource)
// 根据获取到的id删除内容
err = c.Remove(bson.M{"_id": _id})
}
// 修改数据
func update(ctx *gin.Context){
// 解析api参数
resource := ctx.Param("resource")
id := ctx.Param("id")
// 传来的id值为"/id",我们要把"/"截去
id = strings.Trim(id, "/")
// 将id转化为bson.ObjectId格式
var _id bson.ObjectId
_id = bson.ObjectIdHex(id)
url := "mongodb://127.0.0.1"
session, err := mgo.Dial(url)
if err != nil {
panic(err)
}else{
ctx.String(http.StatusOK, "修改成功")
}
defer session.Close()
session.SetMode(mgo.Monotonic, true)
c := session.DB("db_go").C(resource)
// 以上为连接数据库
if resource == "user" {
type modelName models.User
// 使用user数据模型
var form modelName
// 合并数据,如果传值格式不符合上方定义的结构,则返回错误信息
if err := ctx.Bind(&form); err != nil {
ctx.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
// 如果传值格式不符合上方定义的结构,则返回错误信息
err = c.Update(bson.M{"_id": _id}, &form)
ctx.JSON(http.StatusOK, &form)
} else if resource == "category" {
type modelName models.Category
// 使用user数据模型
var form modelName
// 合并数据,如果传值格式不符合上方定义的结构,则返回错误信息
if err := ctx.Bind(&form); err != nil {
ctx.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
// 如果传值格式不符合上方定义的结构,则返回错误信息
err = c.Update(bson.M{"_id": _id}, &form)
ctx.JSON(http.StatusOK, &form)
}
}
// 处理跨域请求,将跨域请求函数作为中间件处理
func Cors() gin.HandlerFunc {
return func(c *gin.Context) {
method := c.Request.Method
c.Header("Access-Control-Allow-Origin", "*") // 允许访问所有域,可以换成具体url,注意仅具体url才能带cookie信息
c.Header("Access-Control-Allow-Headers", "Content-Type,AccessToken,X-CSRF-Token, Authorization, Token") //header的类型
c.Header("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE") //允许请求方法
c.Header("Access-Control-Expose-Headers", "Content-Length, Access-Control-Allow-Origin, Access-Control-Allow-Headers, Content-Type") //返回数据格式
c.Header("Access-Control-Allow-Credentials", "true") //设置为true,允许ajax异步请求带cookie信息
//放行所有OPTIONS方法
if method == "OPTIONS" {
c.AbortWithStatus(http.StatusNoContent)
}
// 处理请求
c.Next()
}
}
// 配置路由
func Main(e *gin.Engine) {
// 全局使用中间件
e.Use(Cors())
// 定义路由,调用接口函数
// 增
e.POST("/admin/api/rest/:resource", insert)
// 删
e.DELETE("/admin/api/rest/:resource/*id", delete)
// 改
e.PUT("/admin/api/rest/:resource/*id", update)
// 查
e.GET("/admin/api/rest/:resource", findAll)
// 根据id查某数据
e.GET("/admin/api/rest/:resource/*id", find)
}
大家学习过程有任何疑问可以留言,我研究好后进行回复。
下篇文章我们开始研究mongodb数据库特有的关联方法(无限级分类)。
更多设计、功能的学习经验,大家也可以去我的公众号查看!
————