🎉工作中遇到这样一个需求场景:实现一个统计查询,要求可以根据用户在前端界面筛选的字段进行动态地分组统计。也就是说,后端在实现分组查询的时候,Group By 的字段是不确定的,可能是一个字段、多个字段或者不进行分组查询,这都是由用户在前端决定的。
💡这里给出的实现方案:
- 前端界面收集用户需要分组统计的字段,然后将这些字段名组成一个字符串,字段名之间由逗号分隔,传递给后端。
- 后端拿到分组字段名字符串再根据逗号分隔符进行处理,拼装成一个分组字段名列表。
- 最后,利用 Mybatis 框架的动态 SQL 语句,实现动态分组字段的统计查询。
控制类XxxStatisticsController
实现代码如下:
@RestController
@RequestMapping("/statistics")
public class XxxStatisticsController {@Autowiredprivate 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 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">SELECTxxx,xxx,xxx,title,xxx,xxx,count(*) AS xxx_numFROM 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 DESCLIMIT 30</select>
</mapper>