| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209 |
- package base
- import (
- "encoding/json"
- "github.com/gin-gonic/gin"
- "go_server/model/common/response"
- "gorm.io/gorm"
- "reflect"
- )
- // gin 封装模型curd处理
- // 使用范型 较为鸡肋 不建议使用
- type ModelBaseHandler[T any] struct {
- }
- func NewBaseHandler[T any](t *T) *ModelBaseHandler[T] {
- return &ModelBaseHandler[T]{}
- }
- func (*ModelBaseHandler[T]) DeleteOne(c *gin.Context, db *gorm.DB) {
- req := new(BaseRequest)
- if err := c.ShouldBindJSON(req); err != nil {
- response.Resp(c, err.Error())
- return
- }
- if req.Id == 0 {
- response.Resp(c, "id is zero")
- return
- }
- tempInfo := new(T)
- // 先通过Id获取记录'
- if err := db.First(&tempInfo, req.Id).Error; err != nil {
- response.Resp(c, err.Error())
- return
- }
- exCmd := db.Model(&tempInfo).Delete(&tempInfo)
- if exCmd.RowsAffected != 1 {
- response.Resp(c, "delete fail")
- return
- }
- if exCmd.Error != nil {
- response.Resp(c, exCmd.Error.Error())
- return
- }
- response.Resp(c)
- return
- }
- func (*ModelBaseHandler[T]) UpdateOne(c *gin.Context, db *gorm.DB) {
- req := new(BaseRequest)
- if err := c.BindJSON(req); err != nil {
- response.Resp(c, err.Error())
- return
- }
- if req.Id == 0 {
- response.Resp(c, "id is zero")
- return
- }
- tempInfo := new(T)
- // 先通过Id获取记录'
- if err := db.First(&tempInfo, req.Id).Error; err != nil {
- response.Resp(c, err.Error())
- return
- }
- // 构建 json tag -> 数据库列名 的映射,用 map 更新以支持零值字段
- updateData := new(T)
- body, _ := json.Marshal(req.Data)
- if err := json.Unmarshal(body, updateData); err != nil {
- response.Resp(c, err.Error())
- return
- }
- // 将 struct 转为 map,保留零值字段
- updateMap := structToMapWithZero(updateData, req.Data)
- dbEx := db.Model(&tempInfo).Where("id", req.Id).
- Updates(updateMap)
- if dbEx.Error != nil {
- response.Resp(c, dbEx.Error.Error())
- return
- }
- // 重新查询最新数据返回
- if err := db.First(&tempInfo, req.Id).Error; err != nil {
- response.Resp(c, err.Error())
- return
- }
- response.Resp(c, map[string]any{
- "info": tempInfo,
- "rowsAffected": dbEx.RowsAffected,
- })
- return
- }
- func (*ModelBaseHandler[T]) Get(c *gin.Context, db *gorm.DB) {
- req := new(BaseRequest)
- if err := c.BindQuery(req); err != nil {
- response.Resp(c, err.Error())
- return
- }
- if req.Id == 0 {
- response.Resp(c, "id is zero")
- return
- }
- tempInfo := new(T)
- // 先通过Id获取记录'
- if err := db.First(&tempInfo, req.Id).Error; err != nil {
- response.Resp(c, err.Error())
- return
- }
- response.Resp(c, map[string]any{
- "info": tempInfo,
- })
- return
- }
- func (*ModelBaseHandler[T]) Create(c *gin.Context, db *gorm.DB) {
- req := new(BaseRequest)
- if err := c.BindJSON(req); err != nil {
- response.Resp(c, err.Error())
- return
- }
- info := new(T)
- body, _ := json.Marshal(req.Data)
- if err := json.Unmarshal(body, info); err != nil {
- response.Resp(c, err.Error())
- return
- }
- if err := db.Create(info).Error; err != nil {
- response.Resp(c, err.Error())
- return
- }
- response.Resp(c, map[string]any{
- "info": info,
- })
- }
- func (*ModelBaseHandler[T]) List(c *gin.Context, db *gorm.DB) {
- req := NewListRequest[T]()
- if err := c.BindQuery(req); err != nil {
- response.Resp(c, err.Error())
- return
- }
- resp, err := req.Query(db)
- if err != nil {
- response.Resp(c, err.Error())
- return
- }
- response.Resp(c, resp)
- return
- }
- // structToMapWithZero 将 struct 转为 map,只包含前端实际传递的字段(含零值)
- // dataMap 是前端传来的原始 map,用于判断哪些字段是前端实际传递的
- func structToMapWithZero(s any, dataMap map[string]any) map[string]any {
- result := make(map[string]any)
- v := reflect.ValueOf(s)
- if v.Kind() == reflect.Ptr {
- v = v.Elem()
- }
- t := v.Type()
- for i := 0; i < t.NumField(); i++ {
- field := t.Field(i)
- jsonTag := field.Tag.Get("json")
- if jsonTag == "" || jsonTag == "-" {
- continue
- }
- // 去掉 omitempty 等选项
- if idx := len(jsonTag); idx > 0 {
- parts := jsonTag
- for j := 0; j < len(parts); j++ {
- if parts[j] == ',' {
- jsonTag = parts[:j]
- break
- }
- }
- }
- // 只更新前端实际传递的字段
- if _, exists := dataMap[jsonTag]; !exists {
- continue
- }
- // 获取 gorm column tag 作为数据库列名
- gormTag := field.Tag.Get("gorm")
- colName := ""
- if gormTag != "" {
- for _, part := range splitGormTag(gormTag) {
- if len(part) > 7 && part[:7] == "column:" {
- colName = part[7:]
- break
- }
- }
- }
- if colName == "" {
- colName = jsonTag
- }
- result[colName] = v.Field(i).Interface()
- }
- return result
- }
- func splitGormTag(tag string) []string {
- var parts []string
- start := 0
- for i := 0; i <= len(tag); i++ {
- if i == len(tag) || tag[i] == ';' {
- parts = append(parts, tag[start:i])
- start = i + 1
- }
- }
- return parts
- }
|