需求:可以分别按日,周,月进行统计交易总额。后台接收参数为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的记录。
参考代码:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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 }
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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 }
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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>