营业额统计
service层
- 在需要处理空值、与数据库交互或使用集合时,
Integer
、Double是更好的选择。
java
// 导入string工具类
import org.apache.commons.lang.StringUtils;
@Service // 标记该类为Spring的服务组件
@Slf4j // 引入日志功能
public class ReportServiceImpl implements ReportService {
@Override
public TurnoverReportVO getTurnoverStatistics(LocalDate begin, LocalDate end) {
// 该方法用于获取从begin到end之间的时间区间
List<LocalDate> datelist = new ArrayList<>(); // 创建一个列表以存储日期
datelist.add(begin); // 将开始日期添加到日期列表中
// 循环直到开始日期等于结束日期
while (!begin.equals(end)) { // 注意,最后一天end也存到集合里了
// 自动增加一天直到符合的日期
begin = begin.plusDays(1); // 将开始日期增加一天
datelist.add(begin); // 将新的开始日期添加到日期列表中
}
// 存储每个日期的营业额
List<Double> turnoverList = new ArrayList<>(); // 创建一个列表以存储营业额
for (LocalDate date : datelist) { // 遍历每个日期,将LocalDate 转为LocalDateTime
LocalDateTime beginTime = LocalDateTime.of(date, LocalTime.MIN); // 获取当天的最小时间(00:00)
LocalDateTime endTime = LocalDateTime.of(date, LocalTime.MAX); // 获取当天的最大时间(23:59:59.999999999)
// 创建一个Map以存储查询条件
Map<String, Object> map = new HashMap<>();
map.put("begin", beginTime); // 将开始时间放入Map中
map.put("end", endTime); // 将结束时间放入Map中
map.put("status", Orders.COMPLETED); // 将订单状态放入Map中
// 调用数据访问层的方法,获取指定时间段内的营业额
Double turnover = orderMapper.sumByMap(map); // 获取营业额
turnover = turnover == null ? 0.0 : turnover; // 处理null
turnoverList.add(turnover); // 将营业额添加到营业额列表中
}
// 构建并返回TurnoverReportVO对象
return TurnoverReportVO
.builder() // 创建构建器
.dateList(StringUtils.join(datelist, ",")) // 将日期列表转换为以逗号分隔的字符串
.turnoverList(StringUtils.join(turnoverList, ",")) // 将营业额列表转换为以逗号分隔的字符串
.build(); // 构建对象并返回
}
}
mapper层
XML
<select id="sumByMap" resultType="java.lang.Double">
select sum(amount) from orders
<where>
<if test="begin != null">
and order_time > #{begin}
</if>
<if test="end != null">
and order_time < #{end}
</if>
<if test="status != null">
and status = #{status}
</if>
</where>
</select>
用户统计
controller层
java
@GetMapping("/userStatistics")
@ApiOperation("用户统计")
public Result<UserReportVO> userStatistics(
@DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate begin,
@DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate end) {
log.info("用户数据统计:{},{}", begin, end);
return Result.success(reportService.getUserStatistics(begin, end));
}
service层
java
@Override
public UserReportVO getUserStatistics(LocalDate begin, LocalDate end) {
// 收集begin和end之间的每天的日期
// 创建一个列表来存储日期
List<LocalDate> dateList = new ArrayList<>();
// 将开始日期添加到列表中
dateList.add(begin);
// 使用循环将开始日期逐天增加,直到等于结束日期
while (!begin.equals(end)) {
// 将开始日期增加一天
begin = begin.plusDays(1);
// 将增加后的日期添加到列表中
dateList.add(begin);
}
// 保存每天的新用户数
// 创建一个列表来存储每天的新用户数
List<Integer> newUserList = new ArrayList<>();
// 保存每天的总用户数
// 创建一个列表来存储每天的总用户数
List<Integer> totalUserList = new ArrayList<>();
// 遍历日期列表
for (LocalDate date : dateList) {
// 获取当前日期的开始时间(00:00:00)
LocalDateTime beginTime = LocalDateTime.of(date, LocalTime.MIN);
// 获取当前日期的结束时间(23:59:59)
LocalDateTime endTime = LocalDateTime.of(date, LocalTime.MAX);
// 创建一个Map来存储查询条件
Map map = new HashMap();
// 将结束时间作为查询条件添加到Map中
map.put("end", endTime);
// 查询当前日期的总用户数
Integer totalUser = userMapper.countByMap(map);
// 将开始时间也作为查询条件添加到Map中
map.put("begin", beginTime);
// 查询当前日期的新用户数
Integer newUser = userMapper.countByMap(map);
// 将查询到的总用户数添加到列表中
totalUserList.add(totalUser);
// 将查询到的新用户数添加到列表中
newUserList.add(newUser);
}
// 返回结果
// 使用UserReportVO的构建器创建一个UserReportVO对象
return UserReportVO.builder()
// 将日期列表转换为逗号分隔的字符串,并设置到UserReportVO对象中
.dateList(StringUtils.join(dateList,","))
// 将总用户数列表转换为逗号分隔的字符串,并设置到UserReportVO对象中
.totalUserList(StringUtils.join(totalUserList,","))
// 将新用户数列表转换为逗号分隔的字符串,并设置到UserReportVO对象中
.newUserList(StringUtils.join(newUserList,","))
// 构建并返回UserReportVO对象
.build();
}
Mapper层(动态sql实现,可以使得service层调用同一个方法)
XML
<select id="countByMap" resultType="java.lang.Integer">
select count(id) from user
<where>
<if test="begin != null">
and create_time > #{begin}
</if>
<if test="end != null">
and create_time < #{end}
</if>
</where>
</select>
销量排名统计top10
service层
java
@Override
public SalesTop10ReportVO getSalesTop10Statistics(LocalDate begin, LocalDate end) {
// 将LocalDate转换为LocalDateTime,分别设置为当天的开始和结束时间
LocalDateTime beginTime = LocalDateTime.of(begin, LocalTime.MIN);
LocalDateTime endTime = LocalDateTime.of(end, LocalTime.MAX);
// 调用orderMapper.getSalesTop10方法获取销量排名前10的商品信息
List<GoodsSalesDTO> salesTop10 = orderMapper.getSalesTop10(beginTime, endTime);
// 使用流操作获取所有商品的名称,并收集到列表中
List<String> names = salesTop10.stream().map(GoodsSalesDTO::getName).collect(Collectors.toList());
// 将商品名称列表转换为逗号分隔的字符串
String nameList = StringUtils.join(names, ","); // 注意:separator参数应为",",而不是separator:","
// 使用流操作获取所有商品的销量,并收集到列表中
List<Integer> numbers = salesTop10.stream().map(GoodsSalesDTO::getNumber).collect(Collectors.toList());
// 将销量列表转换为逗号分隔的字符串
String numberList = StringUtils.join(numbers, ","); // 同上,应为","
// 使用构建器模式封装返回结果
return SalesTop10ReportVO.builder()
.nameList(nameList) // 设置商品名称列表
.numberList(numberList) // 设置销量列表
.build(); // 构建并返回SalesTop10ReportVO对象
}
mapper层(关于获取top10排名的sql)
XML
<select id="getSalesTop10" resultType="com.sky.dto.GoodsSalesDTO">
select od.name, sum(od.number) number
from order_detail od, orders o
where od.order_id = o.id and o.status = 5
<if test="begin != null">
and o.order_time > #{begin}
</if>
<if test="end != null">
and o.order_time < #{end}
</if>
group by od.name
order by number desc
limit 0, 10
</select>
ApachePOI
介绍
Apache POI 是一个处理 Microsoft Office 各种文件格式的开源项目。简单来说,我们可以使用 POI 在 Java 程序中对 Microsoft Office 各种文件进行读写操作。
一般情况下,POI 都是用于操作 Excel 文件。
坐标导入
XML
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>3.16</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>3.16</version>
</dependency>
案例引入:读取文件和写入文件
实现步骤:
- 设计Excel模板文件(不要手动编程去实现)
- 查询近30天的运营数据
- 将查询到的运营数据写入模板文件
- 通过输出来将Excel文件下载到客户端浏览器
代码开发:
java
@GetMapping("/export")
@ApiOperation("导出运营数据结果")
// 传入HttpServletResponse ,是负责设置响应携带的文件
public void export(HttpServletResponse response){
reportService.exportBusinessData(response);
}
java
/**
* 导出运营数据报表
* @param response HTTP响应对象,用于输出Excel文件
*/
public void exportBusinessData(HttpServletResponse response) {
// 1. 查询数据库,获取营业数据---查询最近30天的运营数据
LocalDate dateBegin = LocalDate.now().minusDays(30); // 获取30天前的日期
LocalDate dateEnd = LocalDate.now().minusDays(1); // 获取昨天的日期
// 查询概览数据
BusinessDataVO businessDataVO = workspaceService.getBusinessData(
LocalDateTime.of(dateBegin, LocalTime.MIN),
LocalDateTime.of(dateEnd, LocalTime.MAX)
);
// 2. 通过POI将数据写入到Excel文件中
InputStream in = this.getClass().getClassLoader().getResourceAsStream("template/运营数据报表模板.xlsx"); // 加载Excel模板
// 加载资源文件,并以输入流的形式返回
try {
// 基于模板文件创建一个新的Excel文件
XSSFWorkbook excel = new XSSFWorkbook(in);
// 获取表格文件的Sheet页
XSSFSheet sheet = excel.getSheet("Sheet1");
// 填充数据--时间
sheet.getRow(1).getCell(1).setCellValue("时间:" + dateBegin + "至" + dateEnd); // 设置时间范围
// 获得第4行
XSSFRow row = sheet.getRow(3);
row.getCell(2).setCellValue(businessDataVO.getTurnover()); // 填充营业额
row.getCell(4).setCellValue(businessDataVO.getOrderCompletionRate()); // 填充订单完成率
row.getCell(6).setCellValue(businessDataVO.getNewUsers()); // 填充新增用户数
// 获得第5行
row = sheet.getRow(4);
row.getCell(2).setCellValue(businessDataVO.getValidOrderCount()); // 填充有效订单数
row.getCell(4).setCellValue(businessDataVO.getUnitPrice()); // 填充单价
// 填充明细数据
for (int i = 0; i < 30; i++) { // 遍历最近30天
LocalDate date = dateBegin.plusDays(i); // 获取当前遍历的日期
// 查询某一天的营业数据
BusinessDataVO businessData = workspaceService.getBusinessData(
LocalDateTime.of(date, LocalTime.MIN),
LocalDateTime.of(date, LocalTime.MAX)
);
// 获得某一行
row = sheet.getRow(7 + i); // 从第8行开始填充数据
row.getCell(1).setCellValue(date.toString()); // 填充日期
row.getCell(2).setCellValue(businessData.getTurnover()); // 填充营业额
row.getCell(3).setCellValue(businessData.getValidOrderCount()); // 填充有效订单数
row.getCell(4).setCellValue(businessData.getOrderCompletionRate()); // 填充订单完成率
row.getCell(5).setCellValue(businessData.getUnitPrice()); // 填充单价
row.getCell(6).setCellValue(businessData.getNewUsers()); // 填充新增用户数
}
// 3. 通过输出流将Excel文件通过响应发送给浏览器端
ServletOutputStream out = response.getOutputStream(); // 获取输出流
excel.write(out); // 将Excel内容写入输出流
// 关闭资源
out.close(); // 关闭输出流
excel.close(); // 关闭Excel文件
} catch (IOException e) {
e.printStackTrace(); // 捕获并打印异常
}
}