苍穹外卖-Apache ECharts与数据统计
目录
1. Apache ECharts
1.1 介绍
1.2 入门案例
2. 营业额统计
2.1 需求分析和设计
2.1.1 产品原型
2.1.2 接口设计
2.2 代码开发
2.2.1 VO设计
2.2.2 Controller层
2.2.3 Service层接口
2.2.4 Service层实现类
2.2.5 Mapper层
2.3 功能测试
3. 用户统计
3.1 需求分析和设计
3.1.1 产品原型
3.1.2 接口设计
3.2 代码开发
3.2.1 VO设计
3.2.2 Controller层
3.2.3 Service层接口
3.2.4 Service层实现类
3.2.5 Mapper层
3.3 功能测试
4. 订单统计
4.1 需求分析和设计
4.1.1 产品原型
4.1.2 接口设计
4.2 代码开发
4.2.1 VO设计
4.2.2 Controller层
4.2.3 Service层接口
4.2.4 Service层实现类
4.2.5 Mapper层
4.3 功能测试
5. 销量排名Top10
5.1 需求分析和设计
5.1.1 产品原型
5.1.2 接口设计
5.2 代码开发
5.2.1 VO设计
5.2.2 Controller层
5.2.3 Service层接口
5.2.4 Service层实现类
5.2.5 Mapper层
5.3 功能测试
课程内容
-
Apache ECharts
-
营业额统计
-
用户统计
-
订单统计
-
销量排名Top10
学习目标
- 了解Apache Echarts的作用
- 能进行需求分析并实现营业额统计业务的代码开发
- 能进行需求分析并实现用户统计业务的代码开发
- 能进行需求分析并实现订单统计业务的代码开发
- 能进行需求分析并实现销量排名统计业务的代码开发
功能实现:数据统计
数据统计效果图:
1. Apache ECharts
1.1 介绍
Apache ECharts 是一款基于 Javascript 的数据可视化图表库,提供直观,生动,可交互,可个性化定制的数据可视化图表。 官网地址:https://echarts.apache.org/zh/index.html
常见效果展示:
1). 柱形图
2). 饼形图
3). 折线图
总结:不管是哪种形式的图形,最本质的东西实际上是数据,它其实是对数据的一种可视化展示。
1.2 入门案例
Apache Echarts官方提供的快速入门:https://echarts.apache.org/handbook/zh/get-started/
效果展示:
实现步骤:
1). 引入echarts.js 文件(当天资料已提供)
2). 为 ECharts 准备一个设置宽高的 DOM
3). 初始化echarts实例
4). 指定图表的配置项和数据
5). 使用指定的配置项和数据显示图表
代码开发:
<!DOCTYPE html>
<html><head><meta charset="utf-8" /><title>ECharts</title><!-- 引入刚刚下载的 ECharts 文件 --><script src="echarts.js"></script></head><body><!-- 为 ECharts 准备一个定义了宽高的 DOM --><div id="main" style="width: 600px;height:400px;"></div><script type="text/javascript">// 基于准备好的dom,初始化echarts实例var myChart = echarts.init(document.getElementById('main'));// 指定图表的配置项和数据var option = {title: {text: 'ECharts 入门示例'},tooltip: {},legend: {data: ['销量']},xAxis: {data: ['衬衫', '羊毛衫', '雪纺衫', '裤子', '高跟鞋', '袜子']},yAxis: {},series: [{name: '销量',type: 'bar',data: [5, 20, 36, 10, 10, 20]}]};// 使用刚指定的配置项和数据显示图表。myChart.setOption(option);</script></body>
</html>
总结:使用Echarts,重点在于研究当前图表所需的数据格式。通常是需要后端提供符合格式要求的动态数据,然后响应给前端来展示图表。
2. 营业额统计
2.1 需求分析和设计
2.1.1 产品原型
营业额统计是基于折线图来展现,并且按照天来展示的。实际上,就是某一个时间范围之内的每一天的营业额。同时,不管光标放在哪个点上,那么它就会把具体的数值展示出来。并且还需要注意日期并不是固定写死的,是由上边时间选择器来决定。比如选择是近7天、或者是近30日,或者是本周,就会把相应这个时间段之内的每一天日期通过横坐标展示。
原型图:
业务规则:
-
营业额指订单状态为已完成的订单金额合计
-
基于可视化报表的折线图展示营业额数据,X轴为日期,Y轴为营业额
-
根据时间选择区间,展示每天的营业额数据
2.1.2 接口设计
通过上述原型图,设计出对应的接口。
注意:具体返回数据一般由前端来决定,前端展示图表,具体折线图对应数据是什么格式,是有固定的要求的。 所以说,后端需要去适应前端,它需要什么格式的数据,我们就给它返回什么格式的数据。
2.2 代码开发
2.2.1 VO设计
根据接口定义设计对应的VO:
在sky-pojo模块,TurnoverReportVO.java已定义
package com.sky.vo;import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;import java.io.Serializable;@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class TurnoverReportVO implements Serializable {//日期,以逗号分隔,例如:2022-10-01,2022-10-02,2022-10-03private String dateList;//营业额,以逗号分隔,例如:406.0,1520.0,75.0private String turnoverList;}
2.2.2 Controller层
根据接口定义创建ReportController:
注意在controller写请求方法参数时,如果只有两三个参数可以不封装直接写在方法参数中,如果传入的参数比较多,可以封装到一个DTO中。但是前提是这些参数必须是普通参数,如果是要求json格式的参数,就算只有一个参数也必须要封装。
注意这里的参数是LocalDate,必须要加@DateTimeFormat注解来规定日期格式,如果参数是封装到DTO中的,也要添加此注解。
@Api(tags = "数据统计相关接口")
@RestController
@RequestMapping("/admin/report")
@Slf4j
public class ReportController {@Autowiredprivate ReportService reportService;/*** 营业额统计* @param begin* @param end* @return*/@ApiOperation("营业额统计")@GetMapping("/turnoverStatistics")public Result turnoverStatistics(@DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate begin,@DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate end) {log.info("营业额统计:{},{}",begin,end);TurnoverReportVO vo = reportService.turnoverStatistics(begin,end);return Result.success(vo);}
}
2.2.3 Service层接口
创建ReportService接口,声明getTurnover方法:
package com.sky.service;import com.sky.vo.TurnoverReportVO;import java.time.LocalDate;public interface ReportService {/*** 营业额统计* @param begin* @param end* @return*/TurnoverReportVO turnoverStatistics(LocalDate begin, LocalDate end);
}
2.2.4 Service层实现类
创建ReportServiceImpl实现类,实现getTurnover方法:
@Service
@Slf4j
public class ReportServiceImpl implements ReportService {@Autowiredprivate OrdersMapper ordersMapper;/*** 营业额统计* @param begin* @param end* @return*/@Overridepublic TurnoverReportVO turnoverStatistics(LocalDate begin, LocalDate end) {//1.准备日期列表数据 dateList ---> 近7日:[5-14,5-15,...5-20]List<LocalDate> dateList = new ArrayList<LocalDate>();//循环插入日期数据while (!begin.isAfter(end)){//注意:小心死循环dateList.add(begin);begin = begin.plusDays(1);}log.info("dateList = {}" , dateList);//2.准备营业额列表数据 turnoverListList<Double> turnoverList = new ArrayList<>();//营业额=订单状态为已完成的订单金额//查询order表,条件: 状态-已完成, 下单时间//要统计每一天的营业额,我们可以循环遍历dateList列表,得到每一天的日期,再进行条件查询dateList.forEach(date -> {//注意一定要用sum,不能用count,count统计出来的是一列有几条数据,sum统计出来的是所有订单金额之和//select sum(amount) from orders where status = 5 and order_time between '2025-10-09 00:00:00' and '2025-10-09 23:59:59.999999';Map map = new HashMap();map.put("status", Orders.COMPLETED);map.put("beginTime", LocalDateTime.of(date, LocalTime.MIN)); //2024-05-14 00:00:00map.put("endTime", LocalDateTime.of(date, LocalTime.MAX)); //2024-05-14 23:59:59.999999Double turnover = ordersMapper.sumByMap(map);//用来处理没有营业额的情况turnover = turnover == null ? 0.0 : turnover;turnoverList.add(turnover);});//3.构造TurnoverReportVO对象并返回return TurnoverReportVO.builder().dateList(StringUtils.join(dateList,",")) //[5-14,5-15,...5-20] --> "5-14,5-15,...5-20".turnoverList(StringUtils.join(turnoverList,",")).build();}
}
注意这里我们还要处理没有营业额的情况让他返回为0,不然前端会没有数据
StringUtils.join(dateList,",") 是 Apache Commons Lang 库中的工具方法,用于将集合中的元素按照指定分隔符连接成一个字符串。
🔧 方法参数说明
第一个参数: dateList - 要连接的集合对象(这里是 List<LocalDate>)
第二个参数: "," - 分隔符,用于分隔集合中的各个元素
在 turnoverStatistics 方法中,这个方法被用来:
将 dateList 转换为逗号分隔的字符串,用于前端展示日期范围
将 turnoverList 转换为逗号分隔的字符串,用于前端展示对应的营业额数据
- 为什么 begin 有这么多方法?
因为 begin 是 LocalDate 类的一个实例,而 LocalDate 类提供了很多实用的方法来操作和获取日期信息。这些方法使得对日期的操作变得非常方便和安全。
- 常见的 LocalDate 方法详解
以下是一些常用的 LocalDate 方法及其用途:
2.2.5 Mapper层
在OrderMapper接口声明sumByMap方法:
/*** 统计每日营业额* @param map* @return*/@Select("select sum(amount) from orders where status = #{status} and order_time between #{beginTime} and #{endTime}")Double sumByMap(Map map);
2.3 功能测试
可以通过如下方式进行测试:
-
接口文档测试
-
前后端联调测试
启动服务器,启动nginx,直接采用前后端联调测试。
进入数据统计模块
1). 查看近7日营业额统计
进入开发者模式,查看返回数据
2). 查看近30日营业额统计
进入开发者模式,查看返回数据
3. 用户统计
3.1 需求分析和设计
3.1.1 产品原型
所谓用户统计,实际上统计的是用户的数量。通过折线图来展示,上面这根蓝色线代表的是用户总量,下边这根绿色线代表的是新增用户数量,是具体到每一天。所以说用户统计主要统计两个数据,一个是总的用户数量,另外一个是新增用户数量。
原型图:
业务规则:
-
基于可视化报表的折线图展示用户数据,X轴为日期,Y轴为用户数
-
根据时间选择区间,展示每天的用户总量和新增用户量数据
3.1.2 接口设计
根据上述原型图设计接口。
3.2 代码开发
3.2.1 VO设计
根据用户统计接口的返回结果设计VO:
在sky-pojo模块,UserReportVO.java已定义
package com.sky.vo;import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class UserReportVO implements Serializable {//日期,以逗号分隔,例如:2022-10-01,2022-10-02,2022-10-03private String dateList;//用户总量,以逗号分隔,例如:200,210,220private String totalUserList;//新增用户,以逗号分隔,例如:20,21,10private String newUserList;}
3.2.2 Controller层
根据接口定义,在ReportController中创建userStatistics方法:
@ApiOperation("用户统计")@GetMapping("/userStatistics")public Result<UserReportVO> userStatistics(@DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate begin,@DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate end) {log.info("用户统计:{},{}",begin,end);UserReportVO vo = reportService.userStaticstics(begin,end);return Result.success(vo);}
3.2.3 Service层接口
在ReportService接口中声明getUserStatistics方法:
/*** 用户统计* @param begin* @param end* @return*/UserReportVO userStaticstics(LocalDate begin, LocalDate end);
3.2.4 Service层实现类
在ReportServiceImpl实现类中实现getUserStatistics方法:
/*** 用户统计* @param begin* @param end* @return*/@Overridepublic UserReportVO userStaticstics(LocalDate begin, LocalDate end) {//1.构造dateList数据List<LocalDate> dateList = getDateList(begin, end);//2.构造newUserList数据,新增用户列表List<Integer> newUserList = new ArrayList<>();//3.totalUserList数据,总用户列表List<Integer> totalUserList = new ArrayList<>();//循环遍历查询每日的新增用户数--userdateList.forEach(date -> {//select count(*) from user where create_time between #{} and #{}//select count(*) from user where create_time >= 当天开始时间 and create_time < 当天结束时间Map map = new HashMap<>();map.put("beginTime", LocalDateTime.of(date, LocalTime.MIN)); //2024-05-14 00:00:00map.put("endTime", LocalDateTime.of(date, LocalTime.MAX)); //2024-05-14 23:59:59.999999Integer newUser = userMapper.countByMap(map);newUserList.add(newUser);//循环遍历查询每日的总用户数--user//统计5-14日的注册用户数,就是要统计5-14日之前所有的用户数//select count(*) from user where create_time <= 当天结束时间map.put("beginTime", null); //2024-05-14 00:00:00Integer totalUser = userMapper.countByMap(map);totalUserList.add(totalUser);});//4.构造UserReportVO对象并返回return UserReportVO.builder().dateList(StringUtils.join(dateList,",")).newUserList(StringUtils.join(newUserList,",")).totalUserList(StringUtils.join(totalUserList,",")).build();}/*** 获取指定日期范围内的日期列表数据* @param begin* @param end* @return*/private List<LocalDate> getDateList(LocalDate begin, LocalDate end){List<LocalDate> dateList = new ArrayList<LocalDate>();//循环插入日期数据while (!begin.isAfter(end)) {dateList.add(begin);begin = begin.plusDays(1);}log.info("dateList = {}" , dateList);return dateList;}
这里面我们查询了每日的新增用户数和每日的总用户数,查询这两条数据的sql语句可以合为一条,利用动态sql语句查询。所以再循环遍历查询每日总用户数时,可以往map集合put新的beginTime赋值为null会覆盖原来的值,这里不再需要传入endTime了。
3.2.5 Mapper层
在UserMapper接口中声明countByMap方法:
/*** 根据条件统计用户数量* @param map* @return*///@Select("select count(*) from user where create_time between #{beginTime} and #{endTime}")Integer countByMap(Map map);
在UserMapper.xml文件中编写动态SQL:
<!-- 动态统计每日新增用户数量和总用户数量--><select id="countByMap" resultType="java.lang.Integer">select count(id) from user<where><if test="beginTime != null">create_time >= #{beginTime}</if><if test="endTime != null">and create_time <= #{endTime}</if>
<!-- <![CDATA[-->
<!-- and create_time <= #{endTime}-->
<!-- ]]>--></where></select>
但是我们用xml动态sql时,<=和>=会报错,需要转义字符
还有一种方式是CD,在这个大括号里可以随意写
3.3 功能测试
可以通过如下方式进行测试:
-
接口文档测试
-
前后端联调测试
进入数据统计模块
1). 查看近7日用户统计
进入开发者模式,查看返回数据
2). 查看近30日用户统计
进入开发者模式,查看返回数据
也可通过断点方式启动,查看每步执行情况。
4. 订单统计
4.1 需求分析和设计
4.1.1 产品原型
订单统计通过一个折现图来展现,折线图上有两根线,这根蓝色的线代表的是订单总数,而下边这根绿色的线代表的是有效订单数,指的就是状态是已完成的订单就属于有效订单,分别反映的是每一天的数据。上面还有3个数字,分别是订单总数、有效订单、订单完成率,它指的是整个时间区间之内总的数据。
原型图:
业务规则:
-
有效订单指状态为 “已完成” 的订单
-
基于可视化报表的折线图展示订单数据,X轴为日期,Y轴为订单数量
-
根据时间选择区间,展示每天的订单总数和有效订单数
-
展示所选时间区间内的有效订单数、总订单数、订单完成率,订单完成率 = 有效订单数 / 总订单数 * 100%
4.1.2 接口设计
根据上述原型图设计接口。
4.2 代码开发
4.2.1 VO设计
根据订单统计接口的返回结果设计VO:
在sky-pojo模块,OrderReportVO.java已定义
package com.sky.vo;import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class OrderReportVO implements Serializable {//日期,以逗号分隔,例如:2022-10-01,2022-10-02,2022-10-03private String dateList;//每日订单数,以逗号分隔,例如:260,210,215private String orderCountList;//每日有效订单数,以逗号分隔,例如:20,21,10private String validOrderCountList;//订单总数private Integer totalOrderCount;//有效订单数private Integer validOrderCount;//订单完成率private Double orderCompletionRate;}
4.2.2 Controller层
在ReportController中根据订单统计接口创建orderStatistics方法:
/*** 订单统计* @param begin* @param end* @return*/@ApiOperation("订单统计")@GetMapping("/ordersStatistics")public Result<OrderReportVO> orderStatistics(@DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate begin,@DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate end) {log.info("订单统计:{},{}",begin,end);OrderReportVO vo = reportService.orderStatistics(begin,end);return Result.success(vo);}
4.2.3 Service层接口
在ReportService接口中声明getOrderStatistics方法:
/*** 订单统计* @param begin* @param end* @return*/OrderReportVO orderStatistics(LocalDate begin, LocalDate end);
4.2.4 Service层实现类
在ReportServiceImpl实现类中实现getOrderStatistics方法:
/*** 订单统计* @param begin* @param end* @return*/@Overridepublic OrderReportVO orderStatistics(LocalDate begin, LocalDate end) {//1.获取日期列表数据 dateListList<LocalDate> dateList = getDateList(begin, end);//获取每日订单列表数据 orderCountListList<Integer> orderCountList = new ArrayList<>();//每日有效订单列表数 validOrderCountListList<Integer> validOrderCountList = new ArrayList<>();//初始化订单总数Integer totalOrderCount = 0;//初始化有效订单总数Integer validOrderCount = 0;//2.获取每日订单列表数据 orderCountList// 统计每日orders表数量,条件:下单时间 >= 当天开始时间 and 下单时间 < 当天结束时间// 循环遍历日期列表进行订单统计for (LocalDate date : dateList) {//2.获取每日订单列表数据 orderCountList// 统计每日orders表数量,条件:下单时间 >= 当天开始时间 and 下单时间 < 当天结束时间Map map = new HashMap();map.put("beginTime", LocalDateTime.of(date, LocalTime.MIN));map.put("endTime", LocalDateTime.of(date, LocalTime.MAX));Integer totalOrder = ordersMapper.countByMap(map);orderCountList.add(totalOrder);//3.每日有效订单列表数 validOrderCountList// 统计每日有效orders表数量,条件:状态=有效(已完成)、下单时间 >= 当天开始时间 and 下单时间 < 当天结束时间 and 订单状态 = 4map.put("status", Orders.COMPLETED);Integer validOrder = ordersMapper.countByMap(map);validOrderCountList.add(validOrder);//4.获取订单总数 totalOrderCount// select count(*) from where 下单时间 >= '2025-05-14 00:00:00' and 下单时间 <= '2025-05-20 23:59:59.999999'// 将每日的订单数累加就是总订单数
// totalOrderCount += totalOrder;//5.获取有效订单数 validOrderCount//将每日的有效订单数累加就是有效订单总数validOrderCount += validOrder;}//4.获取区间订单总数 totalOrderCount---写法二
// for (Integer orderCount : orderCountList) {
// totalOrderCount += orderCount;
// }//[10,20,30,40,50,10,10]
// totalOrderCount = orderCountList.stream().reduce(new BinaryOperator<Integer>() {
// @Override
// public Integer apply(Integer num1, Integer num2) { //累加器方法
// return num1 + num2;
// }
// }).get();//Integer::sum 是integer提供的求和的方法
// totalOrderCount = orderCountList.stream().reduce(Integer::sum).get();totalOrderCount = orderCountList.stream().reduce(0,Integer::sum);//6.计算完成率 orderCompletionRateDouble orderCompletionRate = 0.0;if (totalOrderCount != 0) {orderCompletionRate = validOrderCount.doubleValue() / totalOrderCount;}//7.封装OrderReportVO对象并返回return OrderReportVO.builder().dateList(StringUtils.join(dateList,",")).orderCountList(StringUtils.join(orderCountList,",")).validOrderCountList(StringUtils.join(validOrderCountList,",")).totalOrderCount(totalOrderCount).validOrderCount(validOrderCount).orderCompletionRate(orderCompletionRate).build();}
在ReportServiceImpl实现类中提供私有方法获取指定日期范围内的日期列表数getDateList:
/*** 获取指定日期范围内的日期列表数据* @param begin* @param end* @return*/private List<LocalDate> getDateList(LocalDate begin, LocalDate end){List<LocalDate> dateList = new ArrayList<LocalDate>();//循环插入日期数据while (!begin.isAfter(end)) {dateList.add(begin);begin = begin.plusDays(1);}log.info("dateList = {}" , dateList);return dateList;}
4.2.5 Mapper层
在OrderMapper接口中声明countByMap方法:
/*** 订单统计* @param map*/Integer countByMap(Map map);
在OrderMapper.xml文件中编写动态SQL:
<!-- 订单统计--><select id="countByMap" resultType="java.lang.Integer">select count(*) from orders<where><if test="status != null">and status = #{status}</if><if test="beginTime != null">and order_time >= #{beginTime}</if><if test="endTime != null">and order_time <= #{endTime}</if></where></select>
4.3 功能测试
可以通过如下方式进行测试:
-
接口文档测试
-
前后端联调
重启服务,直接采用前后端联调测试。
进入数据统计模块
1). 查看近7日订单统计
进入开发者模式,查看返回数据
2). 查看近30日订单统计
进入开发者模式,查看返回数据
5. 销量排名Top10
5.1 需求分析和设计
5.1.1 产品原型
所谓销量排名,销量指的是商品销售的数量。项目当中的商品主要包含两类:一个是套餐,一个是菜品,所以销量排名其实指的就是菜品和套餐销售的数量排名。通过柱形图来展示销量排名,这些销量是按照降序来排列,并且只需要统计销量排名前十的商品。
原型图:
业务规则:
-
根据时间选择区间,展示销量前10的商品(包括菜品和套餐)
-
基于可视化报表的柱状图降序展示商品销量
-
此处的销量为商品销售的份数
5.1.2 接口设计
根据上述原型图设计接口。
5.2 代码开发
5.2.1 VO设计
根据销量排名接口的返回结果设计VO:
在sky-pojo模块,SalesTop10ReportVO.java已定义
package com.sky.vo;import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class SalesTop10ReportVO implements Serializable {//商品名称列表,以逗号分隔,例如:鱼香肉丝,宫保鸡丁,水煮鱼private String nameList;//销量列表,以逗号分隔,例如:260,215,200private String numberList;}
在sky-pojo模块,GoodsSalesDTO.java已定义
package com.sky.dto;import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;import java.io.Serializable;@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class GoodsSalesDTO implements Serializable {//商品名称private String name;//销量private Integer number;
}
5.2.2 Controller层
在ReportController中根据销量排名接口创建top10方法:
/*** 销量top10* @param begin* @param end* @return*/@ApiOperation("销量top10")@GetMapping("/top10")public Result<SalesTop10ReportVO> top10(@DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate begin,@DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate end) {log.info("销量top10:{},{}",begin,end);SalesTop10ReportVO vo = reportService.top10(begin,end);return Result.success(vo);}
5.2.3 Service层接口
在ReportService接口中声明getSalesTop10方法:
/*** 销量top10* @param begin* @param end* @return*/SalesTop10ReportVO top10(LocalDate begin, LocalDate end);
5.2.4 Service层实现类
在ReportServiceImpl实现类中实现getSalesTop10方法:
/*** 销量排名top10* @param begin* @param end* @return*/@Overridepublic SalesTop10ReportVO top10(LocalDate begin, LocalDate end) {//1.构造nameList,商品名称列表List<String> nameList = new ArrayList<>();//2.构造numberList,商品销量(份数)列表List<Integer> numberList = new ArrayList<>();// 查询orders_detail + orders表,条件:订单状态-已完成,下单时间Map map = new HashMap();map.put("status", Orders.COMPLETED);map.put("beginTime", LocalDateTime.of(begin, LocalTime.MIN));map.put("endTime", LocalDateTime.of(end, LocalTime.MAX));List<GoodsSalesDTO> list = ordersMapper.sumTop10(map);for (GoodsSalesDTO dto : list) {nameList.add(dto.getName());numberList.add(dto.getNumber());}//3.封装SalesTop10ReportVO对象并返回return SalesTop10ReportVO.builder().nameList(StringUtils.join(nameList,",")).numberList(StringUtils.join(numberList,",")).build();}
5.2.5 Mapper层
在OrderMapper接口中声明getSalesTop10方法:
/*** 销量排名top10* @param map* @return*/@MapKey("name")List<GoodsSalesDTO> sumTop10(Map map);
如果返回值设置为Map类型,需要添加如下注解:
在OrderMapper.xml文件中编写动态SQL:
<!-- 查询销量Top10--><select id="sumTop10" resultType="com.sky.dto.GoodsSalesDTO">select od.name, sum(od.number) as numberfrom orders o,order_detail odwhere o.id = od.order_idand status = 5and order_time between #{beginTime} and #{endTime}group by od.nameorder by number desc limit 10;</select>
5.3 功能测试
可以通过如下方式进行测试:
-
接口文档测试
-
前后端联调
重启服务,直接采用前后端联调测试。
查看近30日销量排名Top10统计
若查询的某一段时间没有销量数据,则显示不出效果。
进入开发者模式,查看返回数据