抱歉,您的浏览器无法访问本站
本页面需要浏览器支持(启用)JavaScript
了解详情 >

需求分析

作为一名后端在做Web后端业务开发时,都应该遵循以下规则

  • 降低代码耦合度
  • 尽量避免代码冗余

在使用RESTFUL API风格开发时,几乎所有方法为 GET列表或详情 接口

都不可避免的需要用到 分页查询筛选条件自定义排序 的功能

假如我们为每个接口去分别开发以上三种功能,将会耗费大量时间


问题分析

  • 相同的功能,代码相似度高
  • 当后端开发完成后,需要修改查询筛选条件时,前端无法及时反馈,需要等后端发布测试

解决方法

很多后端都会将 查询筛选条件自定义排序 做成参数查询

但是 查询筛选条件 则要一个个写接收请求参数并且去调用 where/orwhere/like/where in… 等方法去挨个处理

那要如何把选择权和控制权交给前端同事呢?
我们可以给所有接口获取列表的封装个方法

在这里使用的是 Gin+Gorm 的例子,其他框架也可以使用类似操作解决这样的问题


自定义分页

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
func Paging(c *gin.Context, db *gorm.DB) (db *gorm.DB, err error) {
limitStr := c.Request.FormValue("limit")
pageStr := c.Request.FormValue("page")
if limitStr == "" || pageStr == "" {
return db, nil
}
limit, err := strconv.Atoi(limitStr)
if err != nil {
return db, nil
}
page, err := strconv.Atoi(pageStr)
if err != nil {
return db, nil
}
db = db.Offset((page - 1) * limit).Limit(limit)
return db, nil
}

自定义排序

1
2
3
4
5
6
7
8
9
10
11
12
13
func Sort(c *gin.Context, db *gorm.DB) *gorm.DB {
orderBy := c.Request.FormValue("order_by")
if orderBy == "" {
return db
}
order := c.Request.FormValue("order")
if order != "" {
db = db.Order(orderBy + " " + order)
} else {
db = db.Order(orderBy + " DESC")
}
return db
}

自定义查询筛选条件

分页和自定义排序功能就不做解释了,做过web后端基本都了解了

按照field_查询操作符_字段名的格式前端请求的query参数中提取并添加查询条件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
// 按照field_查询操作符_字段名的格式前端请求的query参数中提取并添加查询条件
func ConditionSupport(c *gin.Context, db *gorm.DB) (*gorm.DB, error) {
query, err := url.ParseQuery(c.Request.URL.RawQuery)
if err != nil {
return nil, errors.New("请求参数不正确,请联系管理员进行处理")
}
// 找出所有带有field开头的,并且字符串长度大于9的query参数
for name, value := range query {
if !strings.HasPrfix(name, "field") || len(name) <= 9 {
return db,nil
}
// 给字段添加反引号,避免关键字等
fieldName := "`" + name[9:] + "`"
// 联表字段处理 例如 `user`.`id`
fieldName = strings.Replace(fieldName,".","`.`",-1)
//取出操作符
opt := name[6:8]
switch opt {
case "eq":
if len(value) == 1 {
db = db.Where(fieldName+"=?", value[0])
} else {
db = db.Where(fieldName+" IN (?)", value)
}
case "ne":
db = db.Where(fieldName+"<>?", value[0])
case "lt":
db = db.Where(fieldName+"<?", value[0])
case "le":
db = db.Where(fieldName+"<=?", value[0])
case "gt":
db = db.Where(fieldName+">?", value[0])
case "ge":
db = db.Where(fieldName+">=?", value[0])
case "lk":
db = db.Where(fieldName+" LIKE ?", "%"+value[0]+"%")
case "re":
db = db.Where(fieldName+" REGEXP ?", value[0])
default:
return nil, errors.New("不支持的条件查询操作")
}
}
return db, nil
}

结合三种方法一起使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
func Find(c *gin.Context, db *gorm.DB, result *interface{}) (int64, error) {
var count int64
err := c.Request.ParseForm()
if err != nil {
return 0, errors.New("参数不正确")
}
// 添加自定义查询条件
db, err = ConditionSupport(c, db)
if err != nil {
return 0, errors.New("查询条件有误")
}
// 添加分页支持
db, err = Paging(c, db)
if err != nil {
return 0, errors.New("分页参数不正确")
}
err = db.Count(&count).Error
if err != nil {
return 0, errors.New("数据库记录统计失败,请稍后再试")
}
// 添加自定义排序
err = Sort(c, db).Find(result).Error
return count, errors.New("数据库记录查询失败,请稍后再试")
}

最后我们只需要给每个需要 分页查询筛选条件自定义排序 的地方使用Find函数便可以将操作权交给前端了

评论