package services import ( // "encoding/json" "errors" "fmt" "math" "reflect" "runtime" "strings" "time" "easydo-echo_win7/models" "easydo-echo_win7/utils" "database/sql" "github.com/jmoiron/sqlx" ) // DBClient 数据库客户端结构体 type DBClient struct { db *sqlx.DB log bool } // NewDBClient 创建新的数据库客户端 func NewDBClient(db *sqlx.DB, log bool) *DBClient { build_time := time.Now() build_time_str := build_time.Format(time.DateTime) fmt.Printf("%s 数据库的客户端初始化成功\n", build_time_str) return &DBClient{db: db, log: log} } // PageResult 分页查询结果 type PageResult struct { Total int64 `json:"total"` Records interface{} `json:"records"` } // TransactionFunc 事务处理函数类型 type TransactionFunc func(tx *sqlx.Tx) error // GetJdbcPage 单表分页查询 func (c *DBClient) GetJdbcPage(params map[string]interface{}, clazz interface{}, conn ...*sqlx.Tx) (*PageResult, error) { // 获取表名 tableName := utils.GetTableName(clazz) // 获取结构体字段列表 fields, err := c.getStructDBFields(clazz) if err != nil { println(err.Error()) return nil, err } if len(fields) == 0 { return nil, errors.New("no db fields found in struct") } // 构建字段列表字符串 fieldsStr := strings.Join(fields, ", ") // 构建查询条件 whereSQL, err := utils.BuildWhereCondition(params) if err != nil { println(err.Error()) return nil, err } // 执行查询 var querySQL string var total int64 if len(conn) > 0 { // 使用事务连接 tx := conn[0] // 查询数据列表 querySQL = fmt.Sprintf("SELECT %s FROM %s%s", fieldsStr, tableName, whereSQL) if c.log { build_time_str := time.Now().Format(time.DateTime) fmt.Printf("%s querySQL======>%s\n", build_time_str, querySQL) } rows, err := tx.Queryx(querySQL) if err != nil { println(err.Error()) return nil, err } defer rows.Close() // 将结果映射到结构体列表 resultList, err := c.scanRowsToList(rows, clazz) if err != nil { println(err.Error()) return nil, err } // 查询总数 paramsCopy := make(map[string]interface{}) for k, v := range params { if k != "current" && k != "size" && k != "orderBy" { paramsCopy[k] = v } } countSQL, err := utils.BuildWhereCondition(paramsCopy) if err != nil { println(err.Error()) return nil, err } querySQL = fmt.Sprintf("SELECT COUNT(1) FROM %s%s", tableName, countSQL) if c.log { build_time_str := time.Now().Format(time.DateTime) fmt.Printf("%s querySQL======>%s\n", build_time_str, querySQL) } err = tx.Get(&total, querySQL) if err != nil { println(err.Error()) return nil, err } return &PageResult{ Total: total, Records: resultList, }, nil } else { // 使用普通连接 querySQL = fmt.Sprintf("SELECT %s FROM %s%s", fieldsStr, tableName, whereSQL) if c.log { build_time_str := time.Now().Format(time.DateTime) fmt.Printf("%s querySQL======>%s\n", build_time_str, querySQL) } rows, err := c.db.Queryx(querySQL) if err != nil { println(err.Error()) return nil, err } defer rows.Close() resultList, err := c.scanRowsToList(rows, clazz) if err != nil { return nil, err } paramsCopy := make(map[string]interface{}) for k, v := range params { if k != "current" && k != "size" && k != "orderBy" { paramsCopy[k] = v } } countSQL, err := utils.BuildWhereCondition(paramsCopy) if err != nil { println(err.Error()) return nil, err } querySQL = fmt.Sprintf("SELECT COUNT(1) FROM %s%s", tableName, countSQL) if c.log { build_time_str := time.Now().Format(time.DateTime) fmt.Printf("%s querySQL======>%s\n", build_time_str, querySQL) } err = c.db.Get(&total, querySQL) if err != nil { println(err.Error()) return nil, err } return &PageResult{ Total: total, Records: resultList, }, nil } } // GetJdbcPageBySql 使用自定义SQL进行分页查询 func (c *DBClient) GetJdbcPageBySql(params map[string]interface{}, viewSQL string, clazz interface{}, conn ...*sqlx.Tx) (*PageResult, error) { var total int64 var resultList interface{} // 获取结构体字段列表 fields, err := c.getStructDBFields(clazz) if err != nil { println(err.Error()) return nil, err } if len(fields) == 0 { return nil, errors.New("no db fields found in struct") } // 构建字段列表字符串 fieldsStr := strings.Join(fields, ", ") // 替换原SQL中的SELECT *为SELECT 字段列表 lowerSQL := strings.ToLower(viewSQL) if strings.Contains(lowerSQL, "select *") { // 替换SELECT *为SELECT 字段列表 viewSQL = strings.Replace(lowerSQL, "select *", fmt.Sprintf("select %s", fieldsStr), 1) // 保持原SQL的大小写风格 parts := strings.SplitN(viewSQL, " ", 2) if len(parts) == 2 { viewSQL = fmt.Sprintf("SELECT %s %s", fieldsStr, parts[1]) } } // 构建查询条件 whereSQL, err := utils.BuildWhereCondition(params) if err != nil { println(err.Error()) return nil, err } querySQL := fmt.Sprintf("%s%s", viewSQL, whereSQL) querySQL = strings.ReplaceAll(querySQL, "`", "") if c.log { build_time_str := time.Now().Format(time.DateTime) fmt.Printf("%s querySQL======>%s\n", build_time_str, querySQL) } if len(conn) > 0 { tx := conn[0] rows, err := tx.Queryx(querySQL) if err != nil { println(err.Error()) return nil, err } defer rows.Close() resultList, err = c.scanRowsToList(rows, clazz) if err != nil { println(err.Error()) return nil, err } // 构建COUNT SQL paramsCopy := make(map[string]interface{}) for k, v := range params { if k != "current" && k != "size" && k != "orderBy" { paramsCopy[k] = v } } countSQL, err := utils.BuildWhereCondition(paramsCopy) if err != nil { println(err.Error()) return nil, err } // 转换视图SQL为COUNT SQL fromIndex := strings.Index(strings.ToLower(viewSQL), "from") if fromIndex == -1 { return nil, errors.New("invalid SQL: no FROM clause found") } countQuerySQL := fmt.Sprintf("SELECT COUNT(1) %s%s", viewSQL[fromIndex:], countSQL) countQuerySQL = strings.ReplaceAll(countQuerySQL, "`", "") if c.log { build_time_str := time.Now().Format(time.DateTime) fmt.Printf("%s querySQL======>%s\n", build_time_str, countQuerySQL) } err = tx.Get(&total, countQuerySQL) if err != nil { println(err.Error()) return nil, err } } else { rows, err := c.db.Queryx(querySQL) if err != nil { println(err.Error()) return nil, err } defer rows.Close() resultList, err = c.scanRowsToList(rows, clazz) if err != nil { println(err.Error()) return nil, err } paramsCopy := make(map[string]interface{}) for k, v := range params { if k != "current" && k != "size" && k != "orderBy" { paramsCopy[k] = v } } countSQL, err := utils.BuildWhereCondition(paramsCopy) if err != nil { println(err.Error()) return nil, err } fromIndex := strings.Index(strings.ToLower(viewSQL), "from") if fromIndex == -1 { return nil, errors.New("invalid SQL: no FROM clause found") } countQuerySQL := fmt.Sprintf("SELECT COUNT(1) %s%s", viewSQL[fromIndex:], countSQL) countQuerySQL = strings.ReplaceAll(countQuerySQL, "`", "") if c.log { build_time_str := time.Now().Format(time.DateTime) fmt.Printf("%s querySQL======>%s\n", build_time_str, countQuerySQL) } err = c.db.Get(&total, countQuerySQL) if err != nil { println(err.Error()) return nil, err } } return &PageResult{ Total: total, Records: resultList, }, nil } // GetJdbcList 单表查询列表 func (c *DBClient) GetJdbcList(params map[string]interface{}, clazz interface{}, conn ...*sqlx.Tx) (interface{}, error) { tableName := utils.GetTableName(clazz) // 获取结构体字段列表 fields, err := c.getStructDBFields(clazz) if err != nil { println(err.Error()) return nil, err } if len(fields) == 0 { return nil, errors.New("no db fields found in struct") } // 构建字段列表字符串 fieldsStr := strings.Join(fields, ", ") whereSQL, err := utils.BuildWhereCondition(params) if err != nil { println(err.Error()) return nil, err } querySQL := fmt.Sprintf("SELECT %s FROM %s%s", fieldsStr, tableName, whereSQL) if c.log { build_time_str := time.Now().Format(time.DateTime) fmt.Printf("%s querySQL======>%s\n", build_time_str, querySQL) } if len(conn) > 0 { tx := conn[0] rows, err := tx.Queryx(querySQL) if err != nil { println(err.Error()) return nil, err } defer rows.Close() return c.scanRowsToList(rows, clazz) } else { rows, err := c.db.Queryx(querySQL) if err != nil { println(err.Error()) return nil, err } defer rows.Close() return c.scanRowsToList(rows, clazz) } } // GetJdbcListByObject 根据对象查询列表 func (c *DBClient) GetJdbcListByObject(obj interface{}, conn ...*sqlx.Tx) (interface{}, error) { // 将对象转换为map paramMap, err := c.objectToMap(obj) if err != nil { println(err.Error()) return nil, err } tableName := utils.GetTableName(obj) // 获取结构体字段列表 fields, err := c.getStructDBFields(obj) if err != nil { println(err.Error()) return nil, err } if len(fields) == 0 { return nil, errors.New("no db fields found in struct") } // 构建字段列表字符串 fieldsStr := strings.Join(fields, ", ") whereSQL, err := utils.BuildWhereCondition(paramMap) if err != nil { println(err.Error()) return nil, err } querySQL := fmt.Sprintf("SELECT %s FROM %s%s", fieldsStr, tableName, whereSQL) if c.log { build_time_str := time.Now().Format(time.DateTime) fmt.Printf("%s querySQL======>%s\n", build_time_str, querySQL) } if len(conn) > 0 { tx := conn[0] rows, err := tx.Queryx(querySQL) if err != nil { println(err.Error()) return nil, err } defer rows.Close() return c.scanRowsToList(rows, obj) } else { rows, err := c.db.Queryx(querySQL) if err != nil { println(err.Error()) return nil, err } defer rows.Close() return c.scanRowsToList(rows, obj) } } // GetJdbcModel 查询单个模型(根据对象非空字段) func (c *DBClient) GetJdbcModel(obj interface{}, conn ...*sqlx.Tx) error { // 获取表名 tableName := utils.GetTableName(obj) // 获取结构体字段列表 fields, err := c.getStructDBFields(obj) if err != nil { println(err.Error()) return err } if len(fields) == 0 { return errors.New("no db fields found in struct") } // 构建字段列表字符串 fieldsStr := strings.Join(fields, ", ") // 将对象转换为map作为查询条件 whereMap, err := c.objectToMap(obj) if err != nil { println(err.Error()) return err } // 构建WHERE条件 whereSQL, err := utils.BuildWhereCondition(whereMap) if err != nil { println(err.Error()) return err } sqlStr := fmt.Sprintf("SELECT %s FROM %s%s", fieldsStr, tableName, whereSQL) if c.log { build_time_str := time.Now().Format(time.DateTime) fmt.Printf("%s queryMSQL======>%s\n", build_time_str, sqlStr) } if len(conn) > 0 { tx := conn[0] row := tx.QueryRowx(sqlStr) return c.scanRowToModel(row, obj) } else { row := c.db.QueryRowx(sqlStr) return c.scanRowToModel(row, obj) } } // GetJdbcModelByMap 根据参数map查询单个模型 func (c *DBClient) GetJdbcModelByMap(params map[string]interface{}, clazz interface{}, conn ...*sqlx.Tx) error { // 获取表名 tableName := utils.GetTableName(clazz) // 获取结构体字段列表 fields, err := c.getStructDBFields(clazz) if err != nil { println(err.Error()) return err } if len(fields) == 0 { return errors.New("no db fields found in struct") } // 构建字段列表字符串 fieldsStr := strings.Join(fields, ", ") // 构建WHERE条件 whereSQL, err := utils.BuildWhereCondition(params) if err != nil { println(err.Error()) return err } sqlStr := fmt.Sprintf("SELECT %s FROM %s%s", fieldsStr, tableName, whereSQL) if c.log { build_time_str := time.Now().Format(time.DateTime) fmt.Printf("%s queryMMSQL======>%s\n", build_time_str, sqlStr) } if len(conn) > 0 { tx := conn[0] row := tx.QueryRowx(sqlStr) return c.scanRowToModel(row, clazz) } else { row := c.db.QueryRowx(sqlStr) return c.scanRowToModel(row, clazz) } } // GetJdbcModelById 根据ID查询单个模型 func (c *DBClient) GetJdbcModelById(obj interface{}, conn ...*sqlx.Tx) error { // 获取表名 tableName := utils.GetTableName(obj) // 获取结构体字段列表 fields, err := c.getStructDBFields(obj) if err != nil { println(err.Error()) return err } if len(fields) == 0 { return errors.New("no db fields found in struct") } // 构建字段列表字符串 fieldsStr := strings.Join(fields, ", ") // 获取ID字段名(假设为"id") idField := "id" // 尝试从结构体中获取ID字段 v := reflect.ValueOf(obj) if v.Kind() == reflect.Ptr { v = v.Elem() } t := v.Type() for i := 0; i < t.NumField(); i++ { field := t.Field(i) dbTag := field.Tag.Get("db") jsonTag := field.Tag.Get("json") fieldName := strings.ToLower(field.Name) // 尝试找到ID字段 if dbTag == "id" || jsonTag == "id" || fieldName == "id" { if dbTag != "" && dbTag != "-" { idField = dbTag } break } } // 获取ID值 var idValue interface{} idFieldFound := false for i := 0; i < v.NumField(); i++ { field := t.Field(i) fieldValue := v.Field(i) is_format:=formatSqlValue(field.Name,fieldValue) if is_format { continue } dbTag := field.Tag.Get("db") jsonTag := field.Tag.Get("json") fieldName := strings.ToLower(field.Name) if dbTag == "id" || jsonTag == "id" || fieldName == "id" { idValue = fieldValue.Interface() idFieldFound = true continue } } if !idFieldFound || isEmptyValue(reflect.ValueOf(idValue)) { return errors.New("id field not found or is empty") } sqlStr := fmt.Sprintf("SELECT %s FROM %s WHERE %s = ?", fieldsStr, tableName, idField) if c.log { build_time_str := time.Now().Format(time.DateTime) fmt.Printf("%s queryIDSQL======>%s %s\n", build_time_str, sqlStr, utils.FormatToString(idValue)) } if len(conn) > 0 { tx := conn[0] row := tx.QueryRowx(sqlStr, idValue) return c.scanRowToModel(row, obj) } else { row := c.db.QueryRowx(sqlStr, idValue) return c.scanRowToModel(row, obj) } } func (c *DBClient) JdbcInsert(model interface{}, conn ...*sqlx.Tx) error { // 1. 校验model必须是指针(否则无法赋值自增ID) val := reflect.ValueOf(model) if val.Kind() != reflect.Ptr || val.IsNil() { return fmt.Errorf("model必须是非空指针类型") } modelVal := val.Elem() // 解引用指针,获取实际结构体值 // 2. 生成插入SQL(保留原有逻辑) uuid := utils.GenerateUUID() sqlStr, err := utils.FormatInsertSql(model, uuid) if c.log { build_time_str := time.Now().Format(time.DateTime) fmt.Printf("%s insertSQL======>%s\n", build_time_str, sqlStr) } if err != nil { return fmt.Errorf("生成插入SQL失败: %w", err) } // 3. 执行INSERT并获取自增ID var lastInsertID int64 if len(conn) > 0 { // 事务场景 tx := conn[0] result, err := tx.Exec(sqlStr) if err != nil { return fmt.Errorf("事务执行INSERT失败: %w", err) } // 检查受影响行数 rowsAffected, err := result.RowsAffected() if err != nil { // 某些数据库驱动或特定查询可能不支持RowsAffected // 但这通常发生在SELECT等语句上,INSERT/UPDATE/DELETE通常支持 return fmt.Errorf("警告:无法获取受影响行数(可能不影响业务): %w", err) } // 对于INSERT,通常期望至少插入1行 if rowsAffected == 0 { return fmt.Errorf("操作未生效(受影响行数为0),请检查数据或约束。SQL: %s", sqlStr) } lastInsertID, err = result.LastInsertId() if err != nil { return fmt.Errorf("获取事务自增ID失败: %w", err) } } else { // 非事务场景 result, err := c.db.Exec(sqlStr) if err != nil { return fmt.Errorf("执行INSERT失败: %w", err) } lastInsertID, err = result.LastInsertId() if err != nil { fmt.Println("获取自增ID失败: %w", err) return nil } } // 4. 反射赋值自增ID到model的ID字段 if err := setAutoIncrementID(modelVal, lastInsertID, uuid); err != nil { // 仅打印警告,不中断流程(避免非自增表场景报错) fmt.Printf("自增ID赋值失败(非自增表可忽略): %v\n", err) } return nil } // setAutoIncrementID 反射给model赋值自增ID // modelVal: 结构体的reflect.Value(已解引用指针) // lastInsertID: 数据库返回的自增ID func setAutoIncrementID(modelVal reflect.Value, lastInsertID int64, uuid string) error { // 遍历结构体字段,找到自增ID字段(db:"id") for i := 0; i < modelVal.NumField(); i++ { field := modelVal.Type().Field(i) // 字段元信息 fieldVal := modelVal.Field(i) // 字段值 // 解析db标签,判断是否是ID字段(支持如 db:"id,primarykey" 这类带额外参数的标签) dbTag := field.Tag.Get("db") if dbTag == "" { continue } tagParts := strings.Split(dbTag, ",") if tagParts[0] != "id" { continue } // 处理指针类型 if fieldVal.Kind() == reflect.Ptr { // 指针为空,需要创建新的实例 if fieldVal.IsNil() { // 根据指针指向的类型创建新值 elemType := fieldVal.Type().Elem() newVal := reflect.New(elemType) fieldVal.Set(newVal) } // 获取指针指向的值 elem := fieldVal.Elem() // 根据指针指向的实际类型赋值 return setValueByKind(elem, lastInsertID, field.Name, uuid) } // 非指针类型,检查是否可设置 if !fieldVal.CanSet() { continue } // 根据字段类型赋值自增ID return setValueByKind(fieldVal, lastInsertID, field.Name, uuid) } return fmt.Errorf("未找到可赋值的自增ID字段(需包含 db:\"id\" 标签且为整数类型)") } // setValueByKind 根据不同的类型设置值 func setValueByKind(fieldVal reflect.Value, lastInsertID int64, fieldName string, uuid string) error { // 根据字段类型赋值自增ID,并校验范围 switch fieldVal.Kind() { case reflect.Int, reflect.Int64: fieldVal.SetInt(lastInsertID) case reflect.Uint, reflect.Uint64: fieldVal.SetUint(uint64(lastInsertID)) case reflect.Int8: if lastInsertID < math.MinInt8 || lastInsertID > math.MaxInt8 { return fmt.Errorf("自增ID %d 超出int8字段 %s 范围(%d~%d)", lastInsertID, fieldName, math.MinInt8, math.MaxInt8) } fieldVal.SetInt(lastInsertID) case reflect.Int16: if lastInsertID < math.MinInt16 || lastInsertID > math.MaxInt16 { return fmt.Errorf("自增ID %d 超出int16字段 %s 范围(%d~%d)", lastInsertID, fieldName, math.MinInt16, math.MaxInt16) } fieldVal.SetInt(lastInsertID) case reflect.Int32: if lastInsertID < math.MinInt32 || lastInsertID > math.MaxInt32 { return fmt.Errorf("自增ID %d 超出int32字段 %s 范围(%d~%d)", lastInsertID, fieldName, math.MinInt32, math.MaxInt32) } fieldVal.SetInt(lastInsertID) case reflect.Uint8: if uint64(lastInsertID) > math.MaxUint8 { return fmt.Errorf("自增ID %d 超出uint8字段 %s 范围(0~%d)", lastInsertID, fieldName, math.MaxUint8) } fieldVal.SetUint(uint64(lastInsertID)) case reflect.Uint16: if uint64(lastInsertID) > math.MaxUint16 { return fmt.Errorf("自增ID %d 超出uint16字段 %s 范围(0~%d)", lastInsertID, fieldName, math.MaxUint16) } fieldVal.SetUint(uint64(lastInsertID)) case reflect.Uint32: if uint64(lastInsertID) > math.MaxUint32 { return fmt.Errorf("自增ID %d 超出uint32字段 %s 范围(0~%d)", lastInsertID, fieldName, math.MaxUint32) } fieldVal.SetUint(uint64(lastInsertID)) case reflect.String: fieldVal.SetString(string(uuid)) default: return fmt.Errorf("字段 %s 类型 %s 不支持自增ID赋值", fieldName, fieldVal.Kind()) } return nil } // JdbcUpdate 更新数据 func (c *DBClient) JdbcUpdate(model interface{}, whereMap map[string]interface{}, conn ...*sqlx.Tx) error { sqlStr, err := utils.FormatUpdateSql(model, whereMap) if c.log { build_time_str := time.Now().Format(time.DateTime) fmt.Printf("%s updateSQL======>%s\n", build_time_str, sqlStr) } if err != nil { println(err.Error()) return err } if len(conn) > 0 { tx := conn[0] _, err := tx.Exec(sqlStr) if err != nil { return fmt.Errorf("事务执行UPDATE失败: %w", err) } return nil } else { _, err := c.db.Exec(sqlStr) if err != nil { return fmt.Errorf("执行UPDATE失败: %w", err) } return nil } } // JdbcUpdateById 根据ID更新数据 func (c *DBClient) JdbcUpdateById(model interface{}, conn ...*sqlx.Tx) error { sqlStr, err := utils.FormatUpdateByIdSql(model) if c.log { build_time_str := time.Now().Format(time.DateTime) fmt.Printf("%s updateSQL======>%s\n", build_time_str, sqlStr) } if err != nil { println(err.Error()) return err } if len(conn) > 0 { tx := conn[0] _, err := tx.Exec(sqlStr) return err } else { _, err := c.db.Exec(sqlStr) return err } } // JdbcRemoveById 根据ID删除数据 func (c *DBClient) JdbcRemoveById(model interface{}, conn ...*sqlx.Tx) error { sqlStr, err := utils.FormatRemoveByIdSql(model) if c.log { build_time_str := time.Now().Format(time.DateTime) fmt.Printf("%s removeSQL======>%s\n", build_time_str, sqlStr) } if err != nil { return err } if len(conn) > 0 { tx := conn[0] _, err := tx.Exec(sqlStr) return err } else { _, err := c.db.Exec(sqlStr) return err } } // JdbcRemove 根据条件删除数据 func (c *DBClient) JdbcRemove(model interface{}, conn ...*sqlx.Tx) error { sqlStr, err := utils.FormatRemoveSql(model) if c.log { build_time_str := time.Now().Format(time.DateTime) fmt.Printf("%s removeSQL======>%s\n", build_time_str, sqlStr) } if err != nil { println(err.Error()) return err } if len(conn) > 0 { tx := conn[0] _, err := tx.Exec(sqlStr) return err } else { _, err := c.db.Exec(sqlStr) return err } } // GetJdbcCount 统计数量(根据对象) func (c *DBClient) GetJdbcCount(obj interface{}, conn ...*sqlx.Tx) (int64, error) { sqlStr, err := utils.FormatSelectCountSql(obj) if c.log { build_time_str := time.Now().Format(time.DateTime) fmt.Printf("%s countSQL======>%s\n", build_time_str, sqlStr) } if err != nil { println(err.Error()) return 0, err } var count int64 if len(conn) > 0 { tx := conn[0] row := tx.QueryRowx(sqlStr) err = row.Scan(&count) } else { row := c.db.QueryRowx(sqlStr) err = row.Scan(&count) } if err != nil { println(err.Error()) return 0, err } return count, nil } // GetJdbcCountByMap 统计数量(根据参数map) func (c *DBClient) GetJdbcCountByMap(params map[string]interface{}, clazz interface{}, conn ...*sqlx.Tx) (int64, error) { sqlStr, err := utils.FormatSelectCountSqlByMap(clazz, params) if c.log { build_time_str := time.Now().Format(time.DateTime) fmt.Printf("%s countSQL======>%s\n", build_time_str, sqlStr) } if err != nil { println(err.Error()) return 0, err } var count int64 if len(conn) > 0 { tx := conn[0] row := tx.QueryRowx(sqlStr) err = row.Scan(&count) } else { row := c.db.QueryRowx(sqlStr) err = row.Scan(&count) } if err != nil { println(err.Error()) return 0, err } return count, nil } func (c *DBClient) GetMinioFile(obj interface{}, conn ...*sqlx.Tx) ([]models.MinioFile, error) { tableName := utils.GetTableName(obj) id, err := utils.GetIdValue(obj) if err != nil { return []models.MinioFile{}, err } file := new(models.MinioFile) file.RefId = &id file.RefType = &tableName result, err := c.GetJdbcListByObject(file) if err != nil { build_time_str := time.Now().Format(time.DateTime) fmt.Printf("%s SQL执行失败: %v\n", build_time_str, err) return []models.MinioFile{}, fmt.Errorf("SQL执行失败: %v", err) } list := utils.ConvertInterface[[]models.MinioFile](result) return list, nil } // 辅助方法 // scanRowsToList 将查询结果扫描到结构体列表 func (c *DBClient) scanRowsToList(rows *sqlx.Rows, clazz interface{}) (interface{}, error) { // 获取类型信息 var elemType reflect.Type // 处理指针类型 rt := reflect.TypeOf(clazz) if rt.Kind() == reflect.Ptr { rt = rt.Elem() } // 如果是reflect.Type类型 if rt.Kind() == reflect.Struct { elemType = rt } else { // 尝试从接口获取类型 elemType = reflect.TypeOf(clazz) if elemType.Kind() == reflect.Ptr { elemType = elemType.Elem() } } // 创建切片 sliceType := reflect.SliceOf(elemType) resultSlice := reflect.New(sliceType).Elem() for rows.Next() { elem := reflect.New(elemType).Interface() err := rows.StructScan(elem) if err != nil { return nil, err } elemValue := reflect.ValueOf(elem).Elem() for i := 0; i < elemValue.NumField(); i++ { field := elemValue.Field(i) fieldType := elemType.Field(i) // 检查字段名和类型 fieldName := fieldType.Name is_format:=formatSqlValue(fieldName,field) if is_format { continue } } resultSlice = reflect.Append(resultSlice, reflect.ValueOf(elem).Elem()) } return resultSlice.Interface(), nil } // scanRowToModel 将单行查询结果扫描到结构体 func (c *DBClient) scanRowToModel(row *sqlx.Row, clazz interface{}) error { err := row.StructScan(clazz) if err != nil { if errors.Is(err, sql.ErrNoRows) { if c.log { build_time_str := time.Now().Format(time.DateTime) fmt.Printf("%s scanRowToModel======>%s\n", build_time_str, "sql: no rows in result set") } return nil } return err } // 获取结构体值 elemValue := reflect.ValueOf(clazz) if elemValue.Kind() != reflect.Ptr { return fmt.Errorf("clazz must be a pointer") } elemValue = elemValue.Elem() if elemValue.Kind() != reflect.Struct { return fmt.Errorf("clazz must point to a struct") } elemType := elemValue.Type() // 遍历结构体字段 for i := 0; i < elemValue.NumField(); i++ { field := elemValue.Field(i) fieldType := elemType.Field(i) // 检查字段名和类型 fieldName := fieldType.Name is_format:=formatSqlValue(fieldName,field) if is_format { continue } } return nil } func formatSqlValue(fieldName string,fieldValue reflect.Value) bool { // 检查字段名和类型 is_format := true if strings.HasSuffix(fieldName, "Time") && fieldValue.Type() == reflect.TypeOf((*string)(nil)) { if fieldValue.IsValid() && !fieldValue.IsNil() { fieldValue_t := utils.FormatToString(fieldValue.Interface()) t, err := time.Parse(time.RFC3339, fieldValue_t) if err != nil { build_time_str := time.Now().Format(time.DateTime) _, file, line, _ := runtime.Caller(0) fmt.Printf("%s err %s %d======> %v\n", build_time_str, file, line, err) return is_format } strPtr := new(string) t_str := t.Format(time.DateTime) strPtr = &t_str fieldValue.Set(reflect.ValueOf(strPtr)) return is_format } } else if strings.HasSuffix(fieldName, "Date") && fieldValue.Type() == reflect.TypeOf((*string)(nil)) { if fieldValue.IsValid() && !fieldValue.IsNil() { fieldValue_t := utils.FormatToString(fieldValue.Interface()) if len(fieldValue_t) > 10 { t_str := fieldValue_t[:10] strPtr := new(string) strPtr = &t_str fieldValue.Set(reflect.ValueOf(strPtr)) } return is_format } } return false } func (c *DBClient) ScanRowToModel(row *sqlx.Row, clazz interface{}) error { return c.scanRowToModel(row, clazz) } func (c *DBClient) ScanRowToList(rows *sqlx.Rows, clazz interface{}) (interface{}, error) { return c.scanRowsToList(rows, clazz) } // objectToMap 将对象转换为map[string]interface{} func (c *DBClient) objectToMap(obj interface{}) (map[string]interface{}, error) { result := make(map[string]interface{}) // 获取对象类型和值 objType := reflect.TypeOf(obj) objValue := reflect.ValueOf(obj) // 如果是指针,获取指向的值 if objType.Kind() == reflect.Ptr { objType = objType.Elem() objValue = objValue.Elem() } // 检查是否是结构体 if objType.Kind() != reflect.Struct { return nil, errors.New("参数必须是结构体或结构体指针") } // 遍历结构体字段 for i := 0; i < objType.NumField(); i++ { field := objType.Field(i) fieldValue := objValue.Field(i) // 跳过不可导出的字段 if !fieldValue.CanInterface() { continue } // 检查字段值是否为空(零值) if isEmptyValue(fieldValue) { continue } // 获取db标签作为字段名 dbTag := field.Tag.Get("db") if dbTag == "" || dbTag == "-" { continue } // 添加字段到map result[dbTag] = fieldValue.Interface() } return result, nil } // getStructDBFields 获取结构体的db标签字段列表 func (c *DBClient) getStructDBFields(obj interface{}) ([]string, error) { var fields []string // 获取对象类型 objType := reflect.TypeOf(obj) if objType.Kind() == reflect.Ptr { objType = objType.Elem() } // 检查是否是结构体 if objType.Kind() != reflect.Struct { return nil, errors.New("参数必须是结构体或结构体指针") } // 遍历结构体字段 for i := 0; i < objType.NumField(); i++ { field := objType.Field(i) // 获取db标签 dbTag := field.Tag.Get("db") if dbTag != "" && dbTag != "-" { // 使用反引号包裹字段名,防止关键字冲突 fields = append(fields, fmt.Sprintf("`%s`", dbTag)) } } if len(fields) == 0 { // 如果没有db标签,尝试使用字段名 for i := 0; i < objType.NumField(); i++ { field := objType.Field(i) // 只导出可导出的字段(首字母大写) if field.PkgPath == "" { fieldName := strings.ToLower(field.Name) fields = append(fields, fmt.Sprintf("`%s`", fieldName)) } } } return fields, nil } // isEmptyValue 检查值是否为空(零值) func isEmptyValue(v reflect.Value) bool { switch v.Kind() { case reflect.String: return v.String() == "" case reflect.Bool: return false // 布尔类型没有"空"的概念 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: return v.Int() == 0 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: return v.Uint() == 0 case reflect.Float32, reflect.Float64: return v.Float() == 0 case reflect.Ptr, reflect.Interface: return v.IsNil() case reflect.Slice, reflect.Map, reflect.Array: return v.Len() == 0 default: // 对于其他类型,尝试检查IsZero return v.IsZero() } }