Apache ECharts介紹:
Apache ECharts 是一款基于 Javascript 的數據可視化圖表庫,提供直觀,生動,可交互,可個性化定制的數據可視化圖表。
官網地址:https://echarts.apache.org/zh/index.html
Apache ECharts入門程序:
進入官網,按照官方給的步驟:
<!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>
?
營業額統計:
業務規則及接口設計:
- 營業額指訂單狀態為已完成的訂單金額合計
- 基于可視化報表的折線圖展示營業額數據,X軸為日期,Y軸為營業額
- 根據時間選擇區間,展示每天的營業額數據
?
?前端想展示數據,也要設計接口從后端獲取數據。
返回數據這一塊,因為是前端來展示數據,所以我們提供的數據是要依照前端的規則。
?具體代碼實現:
Controll層:
@Autowiredprivate ReportService reportService;/*** 營業額統計* @param begin* @param end* @return*/@GetMapping("/turnoverStatistics")@ApiOperation("營業額統計")public Result<TurnoverReportVO> turnoverStatistics(@DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate begin,@DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate end){log.info("營業額統計");TurnoverReportVO turnoverReportVO = reportService.turnoverStatistics(begin,end);return Result.success(turnoverReportVO);}
這里有個小細節,就是查詢統計營業額,前端傳的參數是日期的起始時間和結束時間,
格式是yyyy-MM-dd這種形式,所以,我們也要用這種形式來進行接收。
@DateTimeFormat(pattern = "yyyy-MM-dd"),就用到了這個方法。
?Service層:
package com.sky.service.impl;import com.sky.entity.Orders;
import com.sky.mapper.OrderMapper;
import com.sky.service.ReportService;
import com.sky.vo.TurnoverReportVO;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;import javax.validation.constraints.Min;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;@Service
public class ReportServiceImpl implements ReportService {@Autowiredprivate OrderMapper orderMapper;@Overridepublic TurnoverReportVO turnoverStatistics(LocalDate begin, LocalDate end) {//封裝TurnoverReportVO的dateList對象List<LocalDate> datelist = new ArrayList<>();datelist.add(begin);while(!begin.equals(end)){//將日期加到list集合中begin = begin.plusDays(1);datelist.add(begin);}String datejoin = StringUtils.join(datelist, ",");//封裝TurnoverReportVO的turnoverList對象List<Double> turnoverlist = new ArrayList<>();for (LocalDate localDate : datelist) {//查詢date日期對應的營業額數據,營業額是指:狀態為“已完成”的訂單金額合計LocalDateTime beginTime = LocalDateTime.of(localDate, LocalTime.MIN);LocalDateTime endTime = LocalDateTime.of(localDate,LocalTime.MAX);//select sum(amount) from orders where order_time > ? and order_time < ? and status = 5Map map = new HashMap();map.put("begin",beginTime);map.put("end",endTime);map.put("status", Orders.COMPLETED);Double turnover = orderMapper.TurnoverOfSum(map);turnover = turnover==null?0.0:turnover;turnoverlist.add(turnover);}for (Double v : turnoverlist) {System.out.println("今日份營業額:"+ v);}//封裝TurnoverReportVO對象TurnoverReportVO turnoverReportVO = new TurnoverReportVO();turnoverReportVO.setDateList(datejoin);turnoverReportVO.setTurnoverList(StringUtils.join(turnoverlist,","));return turnoverReportVO;}
}
思路:
我們觀察TurnoverReportVO對象里面有兩個值,dateList,turnoverList
一個是日期列表,一個是營業額列表。
我們觀察前端頁面也能看成
橫坐標:是日期? ?縱坐標:是營業額。
?所以我們Service層的思路就很簡單了
1:封裝dateList對象
創建一個LocalDate的列表,然后通過LocalDate提供的庫函數plusDay,將日期由begin一直加到end,并且TurnoverReportVO對象中的dateList對象是一個String,所以我們再調用String.utils的方法對這個列表進行逗號分割。
2:封裝turnoverList對象
我們已經有了每一天的日期了,我們需要每一天的營業額(當然這里也不一定是每一天的,我們前端界面是可以選擇的,有可能是一周,也有可能是一個月)。
這個turnoverList對象的封裝就需要查詢數據庫了
select sum(amout) from orders where?order_time > ? and order_time < ? and status = 5
我們創建一個map對象里面有beginTime,endTime,status,然后傳到mapper層,查詢數據中的數據。
3:最后再封裝TurnoverReportVO對象返回。
Mapper層及注解:
/*** 動態查詢營業額* @param map* @return*/Double TurnoverOfSum(Map map);
<select id="TurnoverOfSum" resultType="java.lang.Double">select sum(amount) from sky_take_out.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>
用戶統計:
業務規則及接口設計:
業務規則:
- 基于可視化報表的折線圖展示用戶數據,X軸為日期,Y軸為用戶數
- 根據時間選擇區間,展示每天的用戶總量和新增用戶量數據
?
用戶統計和上面的不同點就是我們的返回值有三個列表:
- dateList
- newUserList
- totalUserList
?具體代碼實現:
整體的思路和上面的營業額統計差不多
Controll層:
/*** 用戶數量統計* @param begin* @param end* @return*/@GetMapping("/userStatistics")@ApiOperation("用戶數量統計")public Result<UserReportVO> userStatistics(@DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate begin,@DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate end){log.info("用戶數量統計");UserReportVO userReportVO = reportService.userStatistics(begin,end);return Result.success(userReportVO);}
Service層:
/*** 用戶數量統計* @param begin* @param end* @return*/@Overridepublic UserReportVO userStatistics(LocalDate begin, LocalDate end) {//封裝UserReportVO的dateList對象List<LocalDate> dateList = new ArrayList<>();while (!begin.equals(end)){dateList.add(begin);begin = begin.plusDays(1);}String datejoin = StringUtils.join(dateList, ",");//封裝UserReportVO的totalUserList對象//select count(id) from user where create_time < endTime//封裝UserReportVO的newUserList對象//select count(id) from user where create_time > beginTime and create_time < endTimeList<Integer> totalUserList = new ArrayList<>();List<Integer> newUserList = new ArrayList<>();for (LocalDate date : dateList) {LocalDateTime beginTime = LocalDateTime.of(date,LocalTime.MIN);LocalDateTime endTime = LocalDateTime.of(date,LocalTime.MAX);Map map = new HashMap();map.put("end",endTime);Integer totalUser = userMapper.UserofSum(map);map.put("begin",beginTime);Integer newUser = userMapper.UserofSum(map);totalUserList.add(totalUser);newUserList.add(newUser);}String totaluserjoin = StringUtils.join(totalUserList, ",");String newluserjoin = StringUtils.join(newUserList, ",");UserReportVO userReportVO = new UserReportVO();userReportVO.setDateList(datejoin);userReportVO.setTotalUserList(totaluserjoin);userReportVO.setNewUserList(newluserjoin);return userReportVO;}
這里Service層的業務就是封裝三個列表
要想封裝這個用戶,我們需要去調userMapper
我們想要知道總共的用戶的sql是:
//select count(id) from user where create_time < endTime
截至到這個end時間時候的用戶數量。
而新增用戶的sql是:
//select count(id) from user where create_time > beginTime and create_time < endTime
我們要給這個新增確定一個日期范圍。?
userMapper及注解:
Integer UserofSum(Map map);
<select id="UserofSum" resultType="java.lang.Integer">select count(id) from sky_take_out.user<where><if test="begin != null">and create_time > #{begin}</if><if test="end != null">and create_time < #{end}</if></where></select>
?訂單統計:
業務規則及接口設計:
業務規則:
- 有效訂單指狀態為 “已完成” 的訂單
- 基于可視化報表的折線圖展示訂單數據,X軸為日期,Y軸為訂單數量
- 根據時間選擇區間,展示每天的訂單總數和有效訂單數
- 展示所選時間區間內的有效訂單數、總訂單數、訂單完成率,訂單完成率 = 有效訂單數 / 總訂單數 * 100%
具體的代碼實現:?
Controll層:
/*** 訂單統計* @param begin* @param end* @return*/@GetMapping("/ordersStatistics")@ApiOperation("訂單統計")public Result<OrderReportVO> orderStatistics(@DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate begin,@DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate end){log.info("訂單統計");OrderReportVO orderReportVO = reportService.ordersStatistics(begin,end);return Result.success(orderReportVO);}
Service層:
/*** 訂單統計* @param begin* @param end* @return*/@Overridepublic OrderReportVO ordersStatistics(LocalDate begin, LocalDate end) {//封裝OrderReportVO的dateList對象List<LocalDate> dateList = new ArrayList<>();while (!begin.equals(end)){dateList.add(begin);begin = begin.plusDays(1);}String datejoin = StringUtils.join(dateList, ",");//封裝OrderReportVO的orderCountList對象//封裝OrderReportVO的validOrderCountList對象List<Integer> orderCountList = new ArrayList<>();List<Integer> validOrderCountList = new ArrayList<>();for (LocalDate date : dateList) {LocalDateTime beginTime = LocalDateTime.of(date,LocalTime.MIN);LocalDateTime endTime = LocalDateTime.of(date,LocalTime.MAX);Map map = new HashMap();map.put("begin",beginTime);map.put("end",endTime);Integer totalorders = orderMapper.OrdersofSum(map);map.put("status",Orders.COMPLETED);Integer validorders = orderMapper.OrdersofSum(map);orderCountList.add(totalorders);validOrderCountList.add(validorders);}String totaljoin = StringUtils.join(orderCountList, ",");String validjoin = StringUtils.join(validOrderCountList,",");//計算時間區間內的訂單總數量Integer totalOrderCount = orderCountList.stream().reduce(Integer::sum).get();//計算時間區間內的有效訂單數量Integer validOrderCount = validOrderCountList.stream().reduce(Integer::sum).get();//計算訂單完成率Double orderCompletionRate = 0.0;if(totalOrderCount!=0){orderCompletionRate = validOrderCount.doubleValue()/totalOrderCount.doubleValue();}OrderReportVO orderReportVO = new OrderReportVO();orderReportVO.setDateList(datejoin);orderReportVO.setOrderCountList(totaljoin);orderReportVO.setValidOrderCountList(validjoin);orderReportVO.setTotalOrderCount(totalOrderCount);orderReportVO.setValidOrderCount(validOrderCount);orderReportVO.setOrderCompletionRate(orderCompletionRate);return orderReportVO;}
Mapper層及注解:
/*** 訂單統計* @param map* @return*/Integer OrdersofSum(Map map);
<select id="OrdersofSum" resultType="java.lang.Integer">select count(id) from sky_take_out.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>
銷量排名統計(TOP10):
業務規則及接口設計:

業務規則:
- 根據時間選擇區間,展示銷量前10的商品(包括菜品和套餐)
- 基于可視化報表的柱狀圖降序展示商品銷量
- 此處的銷量為商品銷售的份數
具體的代碼實現:
?Controll層:
/*** TOP10銷量統計* @param begin* @param end* @return*/@GetMapping("/top10")@ApiOperation("TOP10銷量統計")public Result<SalesTop10ReportVO> Top10Statostics(@DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate begin,@DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate end){log.info("TOP10銷量統計");SalesTop10ReportVO salesTop10ReportVO = reportService.Top10Statostics(begin,end);return Result.success(salesTop10ReportVO);}
Service層:
/*** TOP10銷量統計* @param begin* @param end* @return*/@Overridepublic SalesTop10ReportVO Top10Statostics(LocalDate begin, LocalDate end) {LocalDateTime beginTime = LocalDateTime.of(begin,LocalTime.MIN);LocalDateTime endTime = LocalDateTime.of(end,LocalTime.MAX);System.out.println("開始時間是:"+beginTime);System.out.println("結束時間是:"+endTime);List<GoodsSalesDTO> goodsSalesDTOList = orderMapper.GetTop10(beginTime,endTime);List<String> names = goodsSalesDTOList.stream().map(GoodsSalesDTO::getName).collect(Collectors.toList());String nameList = StringUtils.join(names, ",");List<Integer> numbers = goodsSalesDTOList.stream().map(GoodsSalesDTO::getNumber).collect(Collectors.toList());String numberList = StringUtils.join(numbers, ",");SalesTop10ReportVO salesTop10ReportVO = new SalesTop10ReportVO();salesTop10ReportVO.setNameList(nameList);salesTop10ReportVO.setNumberList(numberList);return salesTop10ReportVO;}
這題的從sql語句開始分析比較簡單
select od.name,sum(od.number) number from order_detail od,orders o
where od.order_id = o.id and o.status = 5 and o.order_time < 2024-05-04 and o.order_time > 2024-05-10
group by od.name
order by number desc
limit 0,10
根據傳入的時間范圍來獲取數據。
Mapper層及注解:
/*** TOP10銷量統計* @param beginTime* @param endTime* @return*/List<GoodsSalesDTO> GetTop10(LocalDateTime beginTime, LocalDateTime endTime);
<select id="GetTop10" resultType="com.sky.dto.GoodsSalesDTO">select od.name,sum(od.number) numberfrom sky_take_out.order_detail od,sky_take_out.orders owhere od.order_id = o.id and o.status = 5<if test="beginTime != null">and o.order_time > #{beginTime}</if><if test="endTime != null">and o.order_Time < #{endTime}</if>group by od.nameorder by number desclimit 0,10</select>