需求:可以分別按日,周,月進行統計交易總額。后台接收參數為type,string。其中type為查詢類型,string接收的為“yyyy-mm-dd”格式的字符串。按周統計的話是計算一周的交易總額,按月的話是計算一個月的交易總額;按周或者按月都是通過傳過來的字符串去解析周數或月份。默認查詢:日前推30天,周前推12周,月前推12個月。
注意:1,周計數策略統一為iso標准策略計算;每周一為一周的第一天,第一個自然周最少要4天;
相關參考鏈接:
https://blog.csdn.net/wysnxzm/article/details/89095495
https://blog.csdn.net/sayWhat_sayHello/article/details/80589304 ;
https://blog.csdn.net/lifuxiangcaohui/article/details/50953018
2,數據的補全策略,通過事先運算出該時間范圍內的所有應展示的統計數據與實際mysql中查詢出來的數據進行對比,如果不存在響應map中則添加一條值為0的記錄。
參考代碼:
1 public OpenAPiJsonResult shopTradeTrend(AppSession session, GetTradeTrendRequest request) throws Exception { 2 WeekFields weekFields = WeekFields.of(DayOfWeek.MONDAY, 4); 3 // 查詢條件 4 String queryData = request.getQueryDate(); 5 Integer queryType = request.getType(); 6 7 List<String> responseDate = Lists.newArrayList(); 8 if (Objects.isNull(queryType) && StringUtils.isBlank(queryData)) { 9 // 默認按日,展示當前日期前推30天的數據 10 request.setType(0); 11 request.setStartDate(LocalDate.now().minusDays(29).toString()); 12 request.setEndDate(LocalDate.now().plusDays(1).toString()); 13 responseDate = DateUtil.findDates(LocalDate.now().minusDays(30).toString(), LocalDate.now().toString()); 14 } else if (Objects.nonNull(queryType)) { 15 if (queryType == 0) { 16 // 按日,默認查30天 17 if (StringUtils.isBlank(queryData)) { 18 request.setStartDate(LocalDate.now().minusDays(29).toString()); 19 request.setEndDate(LocalDate.now().plusDays(1).toString()); 20 responseDate = DateUtil.findDates(LocalDate.now().minusDays(30).toString(), LocalDate.now().toString()); 21 } else { 22 LocalDate queryDate = DateUtil.stringToLocalDate(queryData); 23 request.setStartDate(queryDate.minusDays(29).toString()); 24 request.setEndDate(queryDate.plusDays(1).toString()); 25 responseDate = DateUtil.findDates(queryDate.minusDays(30).toString(), queryDate.toString()); 26 } 27 } else if (queryType == 1) { 28 // 按周,默認查當前周前推12周的數據 29 if (StringUtils.isBlank(queryData)) { 30 int nowWeekNo = LocalDate.now().get(weekFields.weekOfYear()); 31 String weekStartDate = DateUtil.getWeekDays(LocalDate.now().getYear(), nowWeekNo, -11); 32 request.setStartDate(weekStartDate); 33 request.setEndDate(LocalDate.now().plusDays(1).toString()); 34 responseDate = new ArrayList<>(Objects.requireNonNull(DateUtil.getWeekBetween(weekStartDate, LocalDate.now().toString()))); 35 } else { 36 LocalDate date = DateUtil.stringToLocalDate(queryData); 37 int nowWeekNo = date.get(weekFields.weekOfWeekBasedYear()); 38 request.setStartDate(DateUtil.getWeekDays(date.get(weekFields.weekBasedYear()), nowWeekNo, -11)); 39 request.setEndDate(DateUtil.getDateByYearAndWeekNo(date.get(weekFields.weekBasedYear()), nowWeekNo).plusDays(1).toString()); 40 responseDate = new ArrayList<>(Objects.requireNonNull(DateUtil.getWeekBetween(DateUtil.getWeekDays(date.get(weekFields.weekBasedYear()), nowWeekNo, -11), DateUtil.getDateByYearAndWeekNo(date.get(weekFields.weekBasedYear()), nowWeekNo).toString()))); 41 } 42 } else { 43 // 按月,默認查12個月 44 if (StringUtils.isBlank(queryData)) { 45 String startMonth = DateUtil.dateMinusMonth(LocalDate.now().getYear() + "" + LocalDate.now().getMonthValue(), -11); 46 request.setStartDate(startMonth.substring(0, 4) + "-" + startMonth.substring(4, 6) + "-01"); 47 request.setEndDate(LocalDate.now().plusDays(1).toString()); 48 49 responseDate = DateUtil.getMonthBetween(startMonth.substring(0, 4) + "-" + startMonth.substring(4, 6), LocalDate.now().getYear() + "-" + LocalDate.now().getMonthValue()); 50 } else { 51 LocalDate date = DateUtil.stringToLocalDate(queryData); 52 String startMonth = DateUtil.dateMinusMonth(date.getYear() + "" + date.getMonthValue(), -11); 53 request.setStartDate(startMonth.substring(0, 4) + "-" + startMonth.substring(4, 6) + "-01"); 54 String endDate = DateUtil.getLastDay(date.getYear() + "-" + date.getMonthValue() + "-01"); 55 request.setEndDate(DateUtil.stringToLocalDate(endDate).plusDays(1).toString()); 56 responseDate = DateUtil.getMonthBetween(startMonth.substring(0, 4) + "-" + startMonth.substring(4, 6), date.getYear() + "-" + date.getMonthValue()); 57 } 58 } 59 } 60 List<TradeTrendResponse> responseList = orderService.selectCountTradeTrend(session.getOrgId(), session.getStoreId(), request.getType(), request.getStartDate(), request.getEndDate()); 61 62 // 因為mysql month,week,day函數返回的數據在1-9內的都不帶0,需要拼裝成規范月,周,日數據 63 List<String> convertData = Stream.of("1", "2", "3", "4", "5", "6", "7", "8", "9").collect(toList()); 64 if (Objects.isNull(request.getType()) || request.getType() == 0) { 65 List<String> hasData = Lists.newArrayList(); 66 TreeMap<LocalDate, Double> responseMap = Maps.newTreeMap(); 67 // 按日 68 responseList.forEach(x -> { 69 if (convertData.contains(x.getMonthNo())) { 70 x.setMonthNo("0" + x.getMonthNo()); 71 } 72 if (convertData.contains(x.getDayNo())) { 73 x.setDayNo("0" + x.getDayNo()); 74 } 75 String str = x.getYearNo() + "-" + x.getMonthNo() + "-" + x.getDayNo(); 76 responseMap.put(DateUtil.stringToLocalDate(str), x.getAmount()); 77 hasData.add(str); 78 }); 79 responseDate.removeAll(hasData); 80 responseDate.forEach(noData -> { 81 responseMap.put(DateUtil.stringToLocalDate(noData), 0.00); 82 }); 83 return OpenAPiJsonResult.success(responseMap); 84 } else if (request.getType() == 1) { 85 // 按周 86 List<String> hasData = Lists.newArrayList(); 87 TreeMap<String, Double> map = Maps.newTreeMap(); 88 responseList.forEach(x -> { 89 map.put(x.getWeekNo().substring(0, 4) + "第" + x.getWeekNo().substring(4, 6) + "周", x.getAmount()); 90 hasData.add(x.getWeekNo()); 91 }); 92 responseDate.removeAll(hasData); 93 responseDate.forEach(noData -> { 94 map.put(noData.substring(0, 4) + "第" + noData.substring(4, 6) + "周", 0.00); 95 }); 96 if (map.size() > 12) { 97 map.remove(map.firstKey()); 98 } 99 return OpenAPiJsonResult.success(map); 100 } else { 101 // 按月 102 List<String> hasData = Lists.newArrayList(); 103 TreeMap<String, Double> map = Maps.newTreeMap(); 104 responseList.forEach(x -> { 105 if (convertData.contains(x.getMonthNo())) { 106 x.setMonthNo("0" + x.getMonthNo()); 107 } 108 String str = x.getYearNo() + "-" + x.getMonthNo(); 109 map.put(str + "月", x.getAmount()); 110 hasData.add(str); 111 }); 112 responseDate.removeAll(hasData); 113 responseDate.forEach(noData -> { 114 map.put(noData + "月", 0.00); 115 }); 116 return OpenAPiJsonResult.success(map); 117 } 118 }
1 /** 2 * 根據當前周號,計算n周前或后的周一日期 3 * 4 * @param year 5 * @param week 6 * @param targetNum 7 * @return 8 */ 9 public static String getWeekDays(int year, int week, int targetNum) { 10 // 計算目標周數 11 if (week + targetNum > 52) { 12 year++; 13 } else if (week + targetNum <= 0) { 14 year--; 15 week += targetNum + 52; 16 } else { 17 week += targetNum; 18 } 19 20 SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); 21 Calendar cal = Calendar.getInstance(); 22 23 // 設置每周的開始日期 24 cal.setFirstDayOfWeek(Calendar.MONDAY); 25 26 cal.set(Calendar.YEAR, year); 27 cal.set(Calendar.WEEK_OF_YEAR, week); 28 cal.set(Calendar.DAY_OF_WEEK, cal.getFirstDayOfWeek()); 29 30 // 該周周一 31 String beginDate = sdf.format(cal.getTime()); 32 33 cal.add(Calendar.DAY_OF_WEEK, 6); 34 // 該周周日 35 String endDate = sdf.format(cal.getTime()); 36 37 return beginDate; 38 } 39 40 /** 41 * 根據年,周號,獲取該周周日 42 * 43 * @return 44 */ 45 public static LocalDate getDateByYearAndWeekNo(int year, int week) { 46 WeekFields weekFields2 = WeekFields.of(DayOfWeek.MONDAY, 4); 47 LocalDate sunday = LocalDate.now() 48 .withYear(year) 49 .with(weekFields2.weekOfYear(), week) 50 .with(weekFields2.dayOfWeek(), 7L); 51 52 return sunday; 53 } 54 55 /** 56 * 日期加、減幾月 57 * 58 * @param str 59 * @param amount 正數加,負數減 60 * @return 61 * @throws Exception 62 */ 63 public static String dateMinusMonth(String str, int amount) throws Exception { 64 SimpleDateFormat sdf = new SimpleDateFormat("yyyyMM"); 65 Date dt = sdf.parse(str);//將字符串生成Date 66 Calendar rightNow = Calendar.getInstance(); 67 rightNow.setTime(dt);//使用給定的 Date 設置此 Calendar 的時間。 68 rightNow.add(Calendar.MONTH, amount);// 日期減1個月 69 Date dt1 = rightNow.getTime();//返回一個表示此 Calendar 時間值的 Date 對象。 70 String reStr = sdf.format(dt1);//將給定的 Date 格式化為日期/時間字符串,並將結果添加到給定的 StringBuffer。 71 return reStr; 72 } 73 74 /** 75 * 獲取某個月最后一天 76 * 77 * @param datadate 78 * @return 79 * @throws Exception 80 */ 81 public static String getLastDay(String datadate) throws Exception { 82 Date date = null; 83 String day_last = null; 84 SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd"); 85 date = format.parse(datadate); 86 87 //創建日歷 88 Calendar calendar = Calendar.getInstance(); 89 calendar.setTime(date); 90 calendar.add(Calendar.MONTH, 1); //加一個月 91 calendar.set(Calendar.DATE, 1);//設置為該月第一天 92 calendar.add(Calendar.DATE, -1);//再減一天即為上個月最后一天 93 day_last = format.format(calendar.getTime()); 94 return day_last; 95 } 96 97 /** 98 * 獲取時間段內,所有天 99 * 100 * @param dBegin 101 * @param dEnd 102 * @return 103 * @throws ParseException 104 */ 105 public static List<String> findDates(String dBegin, String dEnd) throws ParseException { 106 //日期工具類准備 107 DateFormat format = new SimpleDateFormat("yyyy-MM-dd"); 108 //設置開始時間 109 Calendar calBegin = Calendar.getInstance(); 110 calBegin.setTime(format.parse(dBegin)); 111 //設置結束時間 112 Calendar calEnd = Calendar.getInstance(); 113 calEnd.setTime(format.parse(dEnd)); 114 //裝返回的日期集合容器 115 List<String> datelist = new ArrayList<String>(); 116 // 每次循環給calBegin日期加一天,直到calBegin.getTime()時間等於dEnd 117 while (format.parse(dEnd).after(calBegin.getTime())) { 118 // 根據日歷的規則,為給定的日歷字段添加或減去指定的時間量 119 calBegin.add(Calendar.DAY_OF_MONTH, 1); 120 datelist.add(format.format(calBegin.getTime())); 121 } 122 return datelist; 123 } 124 125 /** 126 * 獲取一段時間內,所有月份 127 * 128 * @param minDate 129 * @param maxDate 130 * @return 131 * @throws ParseException 132 */ 133 public static List<String> getMonthBetween(String minDate, String maxDate) throws ParseException { 134 ArrayList<String> result = new ArrayList<String>(); 135 SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM");//格式化為年月 136 137 Calendar min = Calendar.getInstance(); 138 Calendar max = Calendar.getInstance(); 139 140 min.setTime(sdf.parse(minDate)); 141 min.set(min.get(Calendar.YEAR), min.get(Calendar.MONTH), 1); 142 143 max.setTime(sdf.parse(maxDate)); 144 max.set(max.get(Calendar.YEAR), max.get(Calendar.MONTH), 2); 145 146 Calendar curr = min; 147 while (curr.before(max)) { 148 result.add(sdf.format(curr.getTime())); 149 curr.add(Calendar.MONTH, 1); 150 } 151 152 return result; 153 } 154 155 /** 156 * 獲取時間段內所有的周,注意:需要指定周計數策略 157 * 158 * @param startStr 159 * @param endStr 160 * @return 161 */ 162 @SuppressWarnings("all") 163 public static Set<String> getWeekBetween(String startStr, String endStr) { 164 WeekFields weekFields = WeekFields.of(DayOfWeek.MONDAY, 4); 165 LocalDate start = DateUtil.stringToLocalDate(startStr); 166 LocalDate end = DateUtil.stringToLocalDate(endStr); 167 int startY = start.get(weekFields.weekBasedYear()); 168 int startW = start.get(weekFields.weekOfWeekBasedYear()); 169 int endY = end.get(weekFields.weekBasedYear()); 170 int endW = end.get(weekFields.weekOfWeekBasedYear()); 171 List<Integer> convertData = Stream.of(1, 2, 3, 4, 5, 6, 7, 8, 9).collect(toList()); 172 Set<String> response = Sets.newTreeSet(); 173 if (endY - startY == 0) {// 同一年 174 for (int i = startW; i <= endW; i++) { 175 if (convertData.contains(i)) { 176 response.add(endY + "0" + i); 177 } else { 178 response.add(endY + "" + i); 179 } 180 } 181 return response; 182 } else if (endY - startY == 1) { // 這里因業務只統計跨度為12周的數據,所以只考慮年差距在一年的情況 183 String lastDay = startY + "-12-31"; // 獲取起始年最大周數 184 int maxWeek = DateUtil.stringToLocalDate(lastDay).get(weekFields.weekOfYear()); 185 for (int i = startW; i <= maxWeek; i++) { 186 if (convertData.contains(i)) { 187 response.add(startY + "0" + i); 188 } else { 189 response.add(startY + "" + i); 190 } 191 } 192 for (int j = 1; j <= endW; j++) { 193 if (convertData.contains(j)) { 194 response.add(endY + "0" + j); 195 } else { 196 response.add(endY + "" + j); 197 } 198 } 199 return response; 200 } else {// 暫不考慮 201 return null; 202 } 203 }
1 <select id="selectCountTradeTrend" resultMap="CountPayTrend"> 2 select 3 <if test="queryType == 0"> 4 MONTH(pay_time) as month_no, 5 DAY(pay_time) as day_no, 6 </if> 7 <if test="queryType == 1"> 8 yearweek(pay_time,3) as week_no, 9 </if> 10 <if test="queryType == 2"> 11 MONTH(pay_time) as month_no, 12 </if> 13 YEAR(pay_time) as year_no, 14 SUM(practical_deal_price) as amount 15 from 16 <include refid="tableName"/> 17 <where> 18 org_id = #{orgId} 19 and store_id = #{storeId} 20 and is_del = 0 21 <if test="startDate != null and startDate != ''"> 22 and pay_time >= #{startDate} 23 </if> 24 <if test="endDate != null and endDate != ''"> 25 and pay_time <= #{endDate} 26 </if> 27 </where> 28 GROUP BY 29 <if test="queryType == 0"> 30 DAY(pay_time) 31 </if> 32 <if test="queryType == 1"> 33 yearweek(pay_time,3) 34 </if> 35 <if test="queryType == 2"> 36 MONTH(pay_time) 37 </if> 38 </select>
