🎉工作中遇到这样一个需求场景:实现一个统计查询,要求可以根据用户在前端界面筛选的字段进行动态地分组统计。也就是说,后端在实现分组查询的时候,Group By 的字段是不确定的,可能是一个字段、多个字段或者不进行分组查询,这都是由用户在前端决定的。
💡这里给出的实现方案:
- 前端界面收集用户需要分组统计的字段,然后将这些字段名组成一个字符串,字段名之间由逗号分隔,传递给后端。
- 后端拿到分组字段名字符串再根据逗号分隔符进行处理,拼装成一个分组字段名列表。
- 最后,利用 Mybatis 框架的动态 SQL 语句,实现动态分组字段的统计查询。
控制类XxxStatisticsController
实现代码如下:
java
@RestController
@RequestMapping("/statistics")
public class XxxStatisticsController {
@Autowired
private XxxService xxxService;
@Operation(method = GET_METHOD, summary = "xxx动态分组统计直方图", parameters = {
@Parameter(name = "startDate", description = "开始日期,形如:2023-07-01"),
@Parameter(name = "endDate", description = "结束日期,形如:2023-07-10"),
@Parameter(name = "groupFields", description = "需要分组的字段名称,逗号分隔,形如"level,title""),
@Parameter(name = "title", description = "标题")
})
@Login
@GetMapping("/xxxStatistics")
public Result<Map<String, List<StatisticsDO>>> xxxStatistics(
@RequestParam String startTime,
@RequestParam String endTime,
@RequestParam(required = false) String groupFields,
@RequestParam(required = false) String title) {
QueryBuilder builder = QueryBuilder.page(0).pageSize(1);
// 此处省略若干代码
if (StringUtils.isNotBlank(groupFields)) {
List<String> groupFieldList = Arrays.asList(groupFields.split(Constants.COMMA_SPLIT));
builder.put("groupFieldList", groupFieldList);
}
return xxxService.xxxStatistics(builder.build());
}
}
xxx-statistics-info-mapper.xml
文件代码如下:
xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="XxxStatisticsInfoMapper">
<resultMap id="default" type="XxxStatisticsInfoDO">
<result column="id" property="id"/>
<result column="title" property="title"/>
<result column="xxx" property="xxx"/>
<result column="xxx" property="xxx"/>
<result column="xxx" property="xxx"/>
<result column="xxx" property="xxx"/>
<result column="xxx" property="xxx"/>
<result column="xxx" property="xxx"/>
<result column="create_time" property="createTime"/>
<result column="update_time" property="updateTime"/>
</resultMap>
<sql id="query">
<if test="startTime != null and startTime != ''">
AND alert_time >= #{startTime}
</if>
<if test="endTime != null and endTime != ''">
AND alert_time <= #{endTime}
</if>
</sql>
<sql id="queryByGroup">
<if test="groupFieldList != null and groupFieldList.size() > 0">
<!-- 这里根据前端传入的参数拼接动态的 GROUP BY 子句 -->
GROUP BY
<foreach item="field" collection="groupFieldList" separator=",">
${field}
</foreach>
</if>
</sql>
<select id="dynamicGroupStatistics" resultType="com.xxx.xxx.domain.DynamicGroupStatisticsDO">
SELECT
xxx,
xxx,
xxx,
title,
xxx,
xxx,
count(*) AS xxx_num
FROM xxx_statistics_info
<where>
<include refid="query"/>
<if test="title != null and title != ''">
AND title = #{title}
</if>
</where>
<include refid="queryByGroup"/>
ORDER BY xxx_num DESC
LIMIT 30
</select>
</mapper>