背景
上一章
Go语言开发基于SQLite数据库实现用户表增删改查项目搭建(一)
这一章我们实现用户表的添加
代码实现
mapper层
type UserMapper interface {
Insert(user *model.User) error
}
type userMapper struct {
}
func (m *userMapper) Insert(u *model.User) error {
return model.Insert(u)
}
ModelTable实现
func Insert(model interface{}) error {
// 获取具体类型的表名
tableName := model.(*User).TableName()
// 使用反射获取 model 类型的字段信息
val := reflect.ValueOf(model).Elem()
typ := val.Type()
// 构建 INSERT 语句的字段名和占位符部分
var columns []string
var placeholders []string
var values []interface{}
for i := 0; i < typ.NumField(); i++ {
field := typ.Field(i)
// 过滤掉 ModelTable 这样的嵌入结构体字段(如果有的话)
if field.Name == "ModelTable" {
continue
}
// 获取 db 标签
dbTag := field.Tag.Get("db")
if dbTag == "" {
// 如果没有 db 标签,跳过该字段
continue
}
// 添加字段名、占位符和字段值
columns = append(columns, dbTag)
placeholders = append(placeholders, "?")
values = append(values, val.Field(i).Interface()) // 获取字段的值
}
// 构建最终的 INSERT SQL 语句
insertSQL := fmt.Sprintf(
"INSERT INTO %s (%s) VALUES (%s)",
tableName,
strings.Join(columns, ", "), // 用逗号连接字段名
strings.Join(placeholders, ", "), // 用逗号连接占位符
)
// 执行插入操作
_, err := config.Db.Exec(insertSQL, values...)
if err != nil {
return err
}
return nil
}
这里我们映射的结构体中的对应db字段 , 这样的好处是我们这个方法是基础方法,其他结构体中只要有ModelTable结构体,我们就可以直接继续使用了。
service层
type UserService interface {
Insert(user *model.User) error
}
service实现层
type UserServiceImpl struct {
m mapper.UserMapper
}
func (u UserServiceImpl) Insert(user *model.User) error {
return u.m.Insert(user)
}
controller层
type UserController struct {
UserService service.UserService
}
func (u *UserController) Insert(rc *req.Ctx) {
user := new(model.User)
req.BindJsonAndValid(rc.GinCtx, user)
assert.IsTrue(user.Username != "" && user.PassWord != "", "账号密码为必传")
//不加密
//user.PassWord = utils.PwdHash(user.PassWord)
err := u.UserService.Insert(user)
assert.IsNil(err)
}
调用
这里我们在新增加一个application,将service初始化出来
var (
UserService service.UserService = imp.NewUserService()
)
func GetUserService() service.UserService {
return UserService
}
然后在路由那,进行对应的调用就可以了。
我们封装了下HandlerFunc
type HandlerFunc func(*Ctx)
type Ctx struct {
GinCtx *gin.Context // gin context
ReqParam any // 请求参数,主要用于记录日志
ResData any // 响应结果
ResHead map[string]string // 响应头
Err any // 请求错误
timed int64 // 执行时间
NoRes bool // 无需返回结果,即文件下载等
}
func (rc *Ctx) Handle(handler HandlerFunc) {
ginCtx := rc.GinCtx
defer func() {
if err := recover(); err != nil {
rc.Err = err
ErrorRes(ginCtx, err)
}
// 应用所有请求后置处理器
ApplyHandlerInterceptor(afterHandlers, rc)
}()
assert.IsTrue(ginCtx != nil, "ginContext == nil")
// 默认为不记录请求参数,可在handler回调函数中覆盖赋值
rc.ReqParam = nil
// 默认响应结果为nil,可在handler中赋值
rc.ResData = nil
if rc.ResHead != nil {
for key, value := range rc.ResHead {
ginCtx.Header(key, value)
}
}
// 调用请求前所有处理器
err := ApplyHandlerInterceptor(beforeHandlers, rc)
if err != nil {
panic(err)
}
begin := time.Now()
handler(rc)
rc.timed = time.Since(begin).Milliseconds()
if !rc.NoRes {
SuccessRes(ginCtx, rc.ResData)
}
}
func (rc *Ctx) Download(reader io.Reader, filename string) {
rc.NoRes = true
Download(rc.GinCtx, reader, filename)
}
func NewCtxWithGin(g *gin.Context) *Ctx {
return &Ctx{GinCtx: g}
}
// 处理器拦截器函数
type HandlerInterceptorFunc func(*Ctx) error
type HandlerInterceptors []HandlerInterceptorFunc
var (
beforeHandlers HandlerInterceptors
afterHandlers HandlerInterceptors
)
// 使用前置处理器函数
func UseBeforeHandlerInterceptor(b HandlerInterceptorFunc) {
beforeHandlers = append(beforeHandlers, b)
}
// 使用后置处理器函数
func UseAfterHandlerInterceptor(b HandlerInterceptorFunc) {
afterHandlers = append(afterHandlers, b)
}
// 应用指定处理器拦截器,如果有一个错误则直接返回错误
func ApplyHandlerInterceptor(his HandlerInterceptors, rc *Ctx) interface{} {
for _, handler := range his {
if err := handler(rc); err != nil {
return err
}
}
return nil
}
测试
我们在进行一个查询列表,就可以查询出对应的数据了(后续会写)
源码地址
使用Go语言开发基于SQLite数据库实现用户表相关接口项目示例,可进行扩展,拿来即用
参考
代码风格参考的mayfly-go ,SQLite这块是自己实现的