目录
课程内容
-
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-03
private String dateList;
//营业额,以逗号分隔,例如:406.0,1520.0,75.0
private String turnoverList;
}
2.2.2 Controller层
根据接口定义创建ReportController:
注意在controller写请求方法参数时,如果只有两三个参数可以不封装直接写在方法参数中,如果传入的参数比较多,可以封装到一个DTO中。但是前提是这些参数必须是普通参数,如果是要求json格式的参数,就算只有一个参数也必须要封装。

注意这里的参数是LocalDate,必须要加@DateTimeFormat注解来规定日期格式,如果参数是封装到DTO中的,也要添加此注解。
@Api(tags = "数据统计相关接口")
@RestController
@RequestMapping("/admin/report")
@Slf4j
public class ReportController {
@Autowired
private 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 {
@Autowired
private OrdersMapper ordersMapper;
/**
* 营业额统计
* @param begin
* @param end
* @return
*/
@Override
public 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.准备营业额列表数据 turnoverList
List<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:00
map.put("endTime", LocalDateTime.of(date, LocalTime.MAX)); //2024-05-14 23:59:59.999999
Double 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-03
private String dateList;
//用户总量,以逗号分隔,例如:200,210,220
private String totalUserList;
//新增用户,以逗号分隔,例如:20,21,10
private 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
*/
@Override
public 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<>();
//循环遍历查询每日的新增用户数--user
dateList.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:00
map.put("endTime", LocalDateTime.of(date, LocalTime.MAX)); //2024-05-14 23:59:59.999999
Integer 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:00
Integer 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-03
private String dateList;
//每日订单数,以逗号分隔,例如:260,210,215
private String orderCountList;
//每日有效订单数,以逗号分隔,例如:20,21,10
private 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
*/
@Override
public OrderReportVO orderStatistics(LocalDate begin, LocalDate end) {
//1.获取日期列表数据 dateList
List<LocalDate> dateList = getDateList(begin, end);
//获取每日订单列表数据 orderCountList
List<Integer> orderCountList = new ArrayList<>();
//每日有效订单列表数 validOrderCountList
List<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 订单状态 = 4
map.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.计算完成率 orderCompletionRate
Double 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,200
private 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
*/
@Override
public 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 number
from orders o,
order_detail od
where o.id = od.order_id
and status = 5
and order_time between #{beginTime} and #{endTime}
group by od.name
order by number desc limit 10;
</select>
5.3 功能测试
可以通过如下方式进行测试:
-
接口文档测试
-
前后端联调
重启服务,直接采用前后端联调测试。
查看近30日销量排名Top10统计
若查询的某一段时间没有销量数据,则显示不出效果。

进入开发者模式,查看返回数据


2179

被折叠的 条评论
为什么被折叠?



