基于gin-vue-admin[gin+gorm]手动实现crud(全)

news2024/11/17 17:38:21

使用Gin-Vue- Admin框架手动实现crud

在gva框架下自己手动实现一个CRUD的操作,该操作将会结合gen进行探讨学习,具体实现可以看下面代码的实现,项目目录层级分为api层,service层,model层,common层,router层,gen层。
我的这个实现方式有些许不太一样就是,我的修改并非传统的restful风格通过json方式进行传递这个id,也确保安全,所以这里的请求我不会用Get请求

创建一个Banner

在gva下的server文件夹中找到plugin文件,然后在这里创建一个banner文件夹,我们的手动CRUD实现的代码就放置在这里,查看项目目录结构,banner包的路径是/server/plugin/banner
在这里插入图片描述

model层

在model层中我们分为前端请求的参数request,以及后端返回的只response。在我们的model下会有一个创建表的结构体,也就是对应数据库字段的一个struct

banner的结构体

package model

import "github.com/flipped-aurora/gin-vue-admin/server/global"

type Banner struct {
	global.GVA_MODEL
	Url         string `json:"url" gorm:"column:url;comment:图片地址"`
	Path        string `json:"path" gorm:"column:path;comment:轮播图跳转地址"`
	Description string `json:"description" gorm:"column:description;comment:轮播介绍"`
}

model.request层

用于接收前端的参数

package request

import (
	"github.com/flipped-aurora/gin-vue-admin/server/plugin/banner/common"
	"github.com/flipped-aurora/gin-vue-admin/server/plugin/banner/model"
	"github.com/flipped-aurora/gin-vue-admin/server/plugin/banner/model/dao"
	"gorm.io/gen"
)

type BannerList struct {
	common.PageInfo
	Url         string `json:"url" gorm:"column:url;comment:图片地址"`
	Path        string `json:"path" gorm:"column:path;comment:轮播图跳转地址"`
	Description string `json:"description" gorm:"column:description;comment:轮播介绍"`
}

func (r BannerList) BannerList() model.Banner {
	return model.Banner{
		Url:         r.Url,
		Path:        r.Path,
		Description: r.Description,
	}
}

type BannerCreate struct {
	Url         string `json:"url" gorm:"column:url;comment:图片地址"`
	Path        string `json:"path" gorm:"column:path;comment:轮播图跳转地址"`
	Description string `json:"description" gorm:"column:description;comment:轮播介绍"`
}

func (r BannerCreate) BannerCreate() model.Banner {
	return model.Banner{
		Url:         r.Url,
		Path:        r.Path,
		Description: r.Description,
	}
}

type BannerUpdate struct {
	common.GetById
	Url         string `json:"url" gorm:"column:url;comment:图片地址"`
	Path        string `json:"path" gorm:"column:path;comment:轮播图跳转地址"`
	Description string `json:"description" gorm:"column:description;comment:轮播介绍"`
}

func (r BannerUpdate) BannerUpdate() model.Banner {
	return model.Banner{
		Url:         r.Url,
		Path:        r.Path,
		Description: r.Description,
	}
}

func (r *BannerList) Search() common.GenScopes {
	return func(tx gen.Dao) gen.Dao {
		if r.Url != "" {
			tx = tx.Where(dao.Banner.Url.Eq(r.Url))
		}
		if r.Path != "" {
			tx = tx.Where(dao.Banner.Path.Eq(r.Path))
		}
		if r.Description != "" {
			tx = tx.Where(dao.Banner.Description.Eq(r.Description))
		}
		return tx
	}
}

model.response

返回给前端的一个模型

package response

type Banner struct {
	Url         string `json:"url" gorm:"column:url;comment:图片地址"`
	Path        string `json:"path" gorm:"column:path;comment:轮播图跳转地址"`
	Description string `json:"description" gorm:"column:description;comment:轮播介绍"`
}

gen层

可以查看gorm的gen的使用,文档地址:https://gorm.io/gen/ 具体详细的看gorm的文档地址,关于gen的相关使用!!!(可以看目录结构我的文件存放地) gen是基于gorm封装的,在我们最后的banner/main.go中需要装配一下传入db,判断有没有db,没有db的调用需要传入db。

$ go get -u gorm.io/gen

package main

import (
	"github.com/flipped-aurora/gin-vue-admin/server/plugin/banner/model"
	"os"
	"path/filepath"

	"gorm.io/gen"
)

// generate code
func main() {
	// 获取当前文件夹路径
	pwd, _ := os.Getwd()

	g := gen.NewGenerator(gen.Config{
		// 文件输出的位置(根据自己的情况而定)
		OutPath: filepath.Join(pwd, "plugin", "banner", "model", "dao"),
		// 输出的文件名
		OutFile: "query.go",
		// 输出模式
		Mode:    gen.WithDefaultQuery | gen.WithQueryInterface,

		FieldCoverable: true,

		WithUnitTest: false,
	})

	// 挂在自己的结构体在这里(根据自己的业务而定)
	g.ApplyBasic(
		new(model.Banner),
	)

	g.Execute()
}

common层

common层一般是放置一些公共资源需要使用的,比如一些返回信息,雪花算法生成id等。

common.common.go

package common

import (
	"gorm.io/gen"
)

type GetById struct {
	ID uint `json:"id" form:"id"`
}

type GetByIds struct {
	IDs []uint `json:"ids" form:"ids"`
}

// PageInfo 分页字段
type PageInfo struct {
	Page     int    `json:"page" form:"page"`         // 页码
	PageSize int    `json:"pageSize" form:"pageSize"` // 每页大小
	Keyword  string `json:"keyword" form:"keyword"`   //关键字
}

// 分页函数
func (c *PageInfo) Paginate() func(tx gen.Dao) gen.Dao {
	return func(tx gen.Dao) gen.Dao {
		switch {
		case c.PageSize > 100:
			c.PageSize = 100
		case c.PageSize <= 0:
			c.PageSize = 10
		}

		offset := (c.Page - 1) * c.PageSize
		return tx.Offset(offset).Limit(c.PageSize)
	}
}

type GenScopes func(tx gen.Dao) gen.Dao

// 前端传什么返回什么
type PageResult struct {
	PageInfo
	List  interface{} `json:"list" swaggertype:"string" example:"interface 数据"`
	Count int64       `json:"count" swaggertype:"string" example:"int64 总数"`
}

// list 返回函数
func NewPageResult(list interface{}, count int64, pageInfo PageInfo) PageResult {
	if list == nil {
		return PageResult{
			PageInfo: PageInfo{
				Page:     pageInfo.Page,
				PageSize: pageInfo.PageSize,
			},
			List:  []struct{}{},
			Count: count,
		}
	}
	return PageResult{
		PageInfo: PageInfo{
			Page:     pageInfo.Page,
			PageSize: pageInfo.PageSize,
		},
		List:  list,
		Count: count,
	}
}

common.message.go

存放返回信息还可以自定义一些返回状态码!

package common

const (
	SuccessCreate  = "创建成功"
	ErrorCreate    = "创建失败"
	SuccessUpdate  = "更新成功"
	ErrorUpdate    = "更新失败"
	SuccessDelete  = "删除成功"
	ErrorDelete    = "删除失败"
	SuccessDeletes = "批量删除成功"
	ErrorDeletes   = "批量删除失败"
	SuccessFirst   = "查询一条成功"
	ErrorFirst     = "查询一条失败"
	SuccessList    = "查询成功"
	ErrorList      = "查询失败"
	ErrorCount     = "查询条数失败"
	ErrorRequest   = "参数有误"
	SuccessServer  = "服务端返回成功"
	ErrorServer    = "服务端返回失败"
)

service层

这里我一般是用于业务处理。

service.banner.go

package service

import (
	"context"
	"github.com/flipped-aurora/gin-vue-admin/server/plugin/banner/common"
	"github.com/flipped-aurora/gin-vue-admin/server/plugin/banner/model"
	"github.com/flipped-aurora/gin-vue-admin/server/plugin/banner/model/dao"
	"github.com/flipped-aurora/gin-vue-admin/server/plugin/banner/model/request"
	"github.com/pkg/errors"
)

var Banner = new(banner)

type banner struct{}

// List 查询多条
func (b *banner) List(ctx context.Context, info request.BannerList) (entity []*model.Banner, count int64, err error) {
	query := dao.Q.WithContext(ctx).Banner
	query = query.Scopes(info.Search())
	count, err = query.Count()
	if err != nil {
		return nil, 0, errors.Wrap(err, common.ErrorList)
	}
	entity, err = query.Scopes(info.Paginate()).Find()
	if err != nil {
		return nil, 0, errors.Wrap(err, common.ErrorCount)
	}
	return entity, count, nil
}

// First 查询单条
func (b *banner) First(ctx context.Context, info common.GetById) (entity *model.Banner, err error) {
	query := dao.Q.WithContext(ctx).Banner
	entity, err = query.Where(dao.Banner.ID.Eq(info.ID)).First()
	if err != nil {
		return nil, errors.Wrap(err, common.ErrorFirst)
	}
	return entity, nil
}

// Create 新增
func (b *banner) Create(ctx context.Context, info request.BannerCreate) error {
	create := info.BannerCreate()
	query := dao.Q.WithContext(ctx).Banner
	err := query.Create(&create)
	if err != nil {
		return errors.Wrap(err, common.ErrorCreate)
	}
	return nil
}

// Update 修改
func (b *banner) Update(ctx context.Context, info request.BannerUpdate) error {
	update := info.BannerUpdate()
	query := dao.Q.WithContext(ctx).Banner
	_, err := query.Where(dao.Banner.ID.Eq(info.ID)).Updates(update)
	if err != nil {
		return errors.Wrap(err, common.ErrorUpdate)
	}
	return nil
}

// Delete 单个删除
func (b banner) Delete(ctx context.Context, info common.GetById) error {
	query := dao.Q.WithContext(ctx).Banner
	_, err := query.Where(dao.Banner.ID.Eq(info.ID)).Delete()
	if err != nil {
		return errors.Wrap(err, common.ErrorDelete)
	}
	return nil
}

// Deletes 批量删除
func (b *banner) Deletes(ctx context.Context, info common.GetByIds) error {
	query := dao.Q.WithContext(ctx).Banner
	_, err := query.Where(dao.Banner.ID.In(info.IDs...)).Delete()
	if err != nil {
		return errors.Wrap(err, common.ErrorDeletes)
	}
	return nil
}

api层

这里我一般是处理接受前端的请求

api.banner.go

这里与service.banner.go的接口一一对应

package api

import (
	"github.com/flipped-aurora/gin-vue-admin/server/plugin/banner/common"
	"github.com/flipped-aurora/gin-vue-admin/server/plugin/banner/model/request"
	"github.com/flipped-aurora/gin-vue-admin/server/plugin/banner/response"
	"github.com/flipped-aurora/gin-vue-admin/server/plugin/banner/service"
	"github.com/gin-gonic/gin"
	"net/http"
)

var Banner = new(banner)

type banner struct{}

func (b banner) List(c *gin.Context) response.Response {
	var list request.BannerList
	err := c.ShouldBindJSON(&list)
	if err != nil {
		return response.Response{Code: http.StatusPaymentRequired, Message: common.ErrorRequest}
	}
	lists, count, err := service.Banner.List(c.Request.Context(), list)
	if err != nil {
		return response.Response{Code: http.StatusInternalServerError, Message: common.ErrorServer}
	}
	return response.Response{
		Code:    http.StatusOK,
		Data:    common.NewPageResult(lists, count, list.PageInfo),
		Message: common.SuccessList,
	}
}

func (b *banner) First(c *gin.Context) response.Response {
	var info common.GetById
	err := c.ShouldBindJSON(info)
	if err != nil {
		return response.Response{Code: http.StatusPaymentRequired, Message: common.ErrorRequest}
	}
	data, err := service.Banner.First(c.Request.Context(), info)
	if err != nil {
		return response.Response{Code: http.StatusInternalServerError, Message: common.ErrorServer}
	}
	return response.Response{
		Code:    http.StatusOK,
		Data:    data,
		Message: common.SuccessFirst,
	}
}

func (b *banner) Create(c *gin.Context) response.Response {
	var create request.BannerCreate
	err := c.ShouldBindJSON(&create)
	if err != nil {
		return response.Response{Code: http.StatusPaymentRequired, Message: common.ErrorRequest}
	}
	err = service.Banner.Create(c.Request.Context(), create)
	if err != nil {
		return response.Response{Code: http.StatusInternalServerError, Message: common.ErrorCreate}
	}
	return response.Response{Code: http.StatusOK, Message: common.SuccessCreate}
}

func (b *banner) Update(c *gin.Context) response.Response {
	var update request.BannerUpdate
	err := c.ShouldBindJSON(&update)
	if err != nil {
		return response.Response{Code: http.StatusPaymentRequired, Message: common.ErrorRequest}
	}
	err = service.Banner.Update(c.Request.Context(), update)
	if err != nil {
		return response.Response{Code: http.StatusInternalServerError, Message: common.ErrorUpdate}
	}
	return response.Response{Code: http.StatusOK, Message: common.SuccessUpdate}
}

func (b *banner) Delete(c *gin.Context) response.Response {
	var info common.GetById
	err := c.ShouldBindJSON(&info)
	if err != nil {
		return response.Response{Code: http.StatusPaymentRequired, Message: common.ErrorRequest}
	}
	err = service.Banner.Delete(c.Request.Context(), info)
	if err != nil {
		return response.Response{Code: http.StatusInternalServerError, Message: common.ErrorDelete}
	}
	return response.Response{Code: http.StatusOK, Message: common.SuccessDelete}
}

func (b *banner) Deletes(c *gin.Context) response.Response {
	var info common.GetByIds
	err := c.ShouldBindJSON(&info)
	if err != nil {
		return response.Response{Code: http.StatusPaymentRequired, Message: common.ErrorRequest}
	}
	err = service.Banner.Deletes(c.Request.Context(), info)
	if err != nil {
		return response.Response{Code: http.StatusInternalServerError, Message: common.ErrorDeletes}
	}
	return response.Response{Code: http.StatusOK, Message: common.SuccessDeletes}
}

router层

这里是路由注册的地方

router.router.go

package router

import (
	"github.com/flipped-aurora/gin-vue-admin/server/middleware"
	"github.com/flipped-aurora/gin-vue-admin/server/plugin/banner/api"
	"github.com/flipped-aurora/gin-vue-admin/server/plugin/banner/response"
	"github.com/gin-gonic/gin"
)

type Banner struct {
	router *gin.RouterGroup
}

func NewBanner(router *gin.RouterGroup) *Banner {
	return &Banner{router}
}

func (r Banner) Init() {
	group := r.router.Group("banner")
	{ // 不带日志中间件
		group.POST("list", response.Handler()(api.Banner.List))
		group.POST("first", response.Handler()(api.Banner.First))
	}
	{ // 带日志中间件
		group.Use(middleware.OperationRecord())
		group.POST("create", response.Handler()(api.Banner.Create))
		group.PUT("update", response.Handler()(api.Banner.Update))
		group.DELETE("delete", response.Handler()(api.Banner.Delete))
		group.DELETE("deletes", response.Handler()(api.Banner.Deletes))
	}
}

banner/main.go

package banner

import (
	"github.com/flipped-aurora/gin-vue-admin/server/global"
	"github.com/flipped-aurora/gin-vue-admin/server/plugin/banner/model/dao"
	"github.com/flipped-aurora/gin-vue-admin/server/plugin/banner/router"
	"github.com/gin-gonic/gin"
)

var Plugin = new(plugin)

type plugin struct{}

func (p plugin) Register(group *gin.RouterGroup) {
	router.NewBanner(group).Init()
	// 这里需要自动装配一下调用db
	if global.GVA_DB != nil {
		dao.SetDefault(global.GVA_DB)
	}
}

func (p plugin) RouterPath() string {
	return ""
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/398640.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

1/4、1/2、整车悬架天棚主动控制仿真分析合集

目录 前言 1. 1/4悬架系统 1.1数学模型 1.2仿真分析 2. 1/2悬架系统 2.1数学模型 2.2仿真分析 3. 整车悬架系统 3.1数学模型 3.2仿真分析 4.总结 参考文献 前言 对于天棚控制相比大家不陌生&#xff0c;它是由美国的Karnopp提出&#xff0c;利用假设的与天棚固连…

【数据结构】链表相关题目(简单版)

&#x1f680;write in front&#x1f680; &#x1f4dc;所属专栏&#xff1a; 初阶数据结构 &#x1f6f0;️博客主页&#xff1a;睿睿的博客主页 &#x1f6f0;️代码仓库&#xff1a;&#x1f389;VS2022_C语言仓库 &#x1f3a1;您的点赞、关注、收藏、评论&#xff0c;是…

软件测试10

Linux和数据库 1.Linux命令&#xff1a;软件测试第一个任务&#xff0c;一般都需要进行环境搭建&#xff0c;一部分环境搭建内容是在服务器上实现的&#xff0c;跟服务器交互需要使用Linux命令。&#xff08;因为Linux没有图形化页面&#xff09; 2.数据库&#xff1a;所有的软…

ccf-csp 202112-3登机牌条码

题目背景 西西艾弗岛景色优美&#xff0c;游人如织。但是&#xff0c;由于和外界的交通只能靠渡船&#xff0c;交通的不便严重制约了岛上旅游业的发展。西西艾弗岛管委会经过努力&#xff0c;争取到了一笔投资&#xff0c;建设了一个通用航空机场。在三年紧锣密鼓的主体建设后…

Jetpack Compose 中的动态加载、插件化技术探索

在传统的 Android 开发模式中&#xff0c;由于界面过分依赖于 Activity、Fragment这样的组件&#xff0c;一个业务模块中往往会存在着大量的 Activity 类&#xff0c;因此诞生了很多的插件化框架&#xff0c;这些插件化框架基本都是想方设法的使用各种Hook/反射手段来解决使用未…

c++11auto

autoc11中auto并不代表一种实际的数据类型&#xff0c;它只是一个类型声明的占位符&#xff0c;auto也并不是再所有场景下都能推导出变量的实际类型&#xff0c;使用auto不需要进行初始化&#xff0c;让编译器推导出它的实际类型&#xff0c;再编译阶段将auto占位符替换为真正的…

没有比这更详细的-压测工具Jmeter介绍及使用了

一、压测工具选型 1.1、前言 压力测试是每一个Web应用程序上线之前都需要做的一个测试&#xff0c;他可以帮助我们发现系统中的瓶颈问题&#xff0c;减少发布到生产环境后出问题的几率&#xff1b;预估系统的承载能力&#xff0c;使我们能根据其做出一些应对措施。所以压力测…

【Linux基础篇】一、Linux入门基础命令

一、Linux基础命令 1、Linux的目录结构 /&#xff0c;根目录是最顶级的目录了Linux只有一个顶级目录&#xff1a;/路径描述的层次关系同样适用/来表示/home/itheima/a.txt&#xff0c;表示根目录下的home文件夹内有itheima文件夹&#xff0c;内有a.txt 2、ls命令 功能&#…

数字孪生GIS智慧风场Web3D可视化运维系统

随着国家双碳目标的实施&#xff0c;新能源发电方式逐渐代替了污染大气层的火力发电&#xff0c;其中风力发电相比于光伏发电具有能量密度高、发电小时数长、生命周期达20-25年之久等独特的优势。风能取之不尽、用之不竭&#xff0c;在新型能源互联网下&#xff0c;风力发电有可…

三、GC算法垃圾回收器

文章目录&#xff08;持续更新中... ...CMS and G1&#xff09;概述如何判断对象存活引用计数法根可达算法GC算法(垃圾回收算法)分代收集理论标记-清除算法复制算法标记-整理算法垃圾回收器概述Serial收集器Parallel收集器Parallel Old收集器CMS收集器G1收集器常用的收集器组合…

STM32实战项目-串口打印

前言&#xff1a; 本小结主要实现串口打印功能&#xff0c;主要将上一结的状态机运行次数&#xff0c;通过串口在串口终端上打印出来&#xff0c;硬件电路上主要是TTL转USB驱动电路&#xff0c;软件上主要有状态机函数&#xff0c;串口发送函数等调试工具是串口助手。 目录 1…

机器学习学习记录1:假设空间

我们可以把学习过程看作一个在所有假设组成的空间中进行搜索的过程&#xff0c;搜索目标是找到与训练集"匹配" 的假设&#xff0c;即能够将训练集中的瓜判断正确的假设.假设的表示一旦确定&#xff0c;假设空间及其规模大小就确定了.对于西瓜问题&#xff0c;这里我们…

[MySQL索引]2.索引的底层原理(一)

索引的底层原理&#xff08;一&#xff09;B-树索引B树索引tips: ​ 通过使用malloc/new来申请4字节的内存&#xff0c;但是操作系统不是说每一次用户申请4字节内存&#xff0c;我就只分配4字节&#xff0c;这样申请次数多了就要涉及频繁的用户态和内核态的切换&#xff0c;开销…

AM5728(AM5708)开发实战之安装Debian 10桌面操作系统

一 环境搭建 准备一个SD卡启动卡&#xff0c;能够正常引导板卡启动&#xff0c;后续会把Debian 10镜像安装到SD卡ext4分区 准备两个U盘&#xff0c;一个格式化成fat32文件系统&#xff0c;另一个格式化成ext4文件系统 下载Debian 10镜像&#xff0c;镜像名字为debian-10.4.0-a…

【前端】一个更底层库React,附教程

Reat是什么&#xff1f;React在UI里最火的也是最好的库&#xff0c;React是一个做UI的库&#xff0c;具体来说是做UI组件的库&#xff0c;专注于做mvc中的v&#xff0c;它是一个更底层的工具库。为你应用的每一个状态设计简洁的视图&#xff0c;当数据变动时 React 能高效更新并…

Linux发行版本与发行版的简单的介绍

Linux linux下有很多发行的版本&#xff0c;或者称之为魔改版本。以下介绍一些常见的版本&#xff0c;以避免名词的混淆。 linux是提供了一个内核&#xff0c;就像是谷歌的内核一样&#xff0c;QQ浏览器就是使用的谷歌的内核&#xff0c;也算是一个发行版本。 Ubuntu&#x…

课程项目简介

一、深度学习模型入门 1&#xff0c;什么是机器学习&#xff1f; Study of algorithms that improve their performance P at some task T with experience E. 研究在某个任务T上用经验E提高其性能P的算法。 well-defined learning task:<P,T,E> 明确的学习任务&#…

手把手开发一门程序语言JimLang (2)

根据爱因斯坦的相对论&#xff0c;物体的质量越大&#xff0c;时间过得越快&#xff0c;所以托更对于我的煎熬&#xff0c;远远比你们想象的还要痛苦…今天给大家来盘硬菜&#xff0c;也是前些时日预告过的JimLang的开发过程… Let’s go !!! 语法及解析 JimLang.g4 这里我们…

轮毂要怎么选?选大还是选小?

随着改装车的越来越火爆&#xff0c;汽车轮毂可选择的款式也越来越多&#xff0c;90%的人换轮毂&#xff0c;首先选的就是外观。大轮毂的款式多&#xff0c;外形大气好看&#xff0c;运动感十足&#xff0c; 那是不是选大轮毂就可以呢&#xff1f;不是的&#xff0c;汽车轮毂要…

全面吃透Java Stream流操作,让代码更加的优雅

文章目录1 认识Stream流1.1 什么是流1.2 流与集合1.2.1 流只能遍历一次1.2.2 外部迭代和内部迭代1.3 流操作1.3.1 中间操作1.3.2 终端操作1.3.3 使用流2 学会使用Stream流2.1 筛选和切片2.1.1 用谓词筛选2.1.2 筛选各异的元素2.1.3 截短流2.1.4 跳过元素2.2 映射2.2.1 map方法2…