2C的一些项目中有些数据还是需要统计出来给用户来看的,项目中我们随着业务的不断增多项目逐渐臃肿不堪,而根据不同的业务逻辑去做统计的一些定时任务,也就成了重灾区,不同的业务给前端一坨Vo对象,再让去前端一个一个去对来对去,自己又是也就蒙圈了。
接口类:
@GetMapping("info")
public ResponseTO<MerchantSummaryVo, DefaultResponseErrorType> info(
@Valid @NotBlank(message = CommonConstants.INMNO_HEADER
+ "不能为空") @RequestHeader(CommonConstants.INMNO_HEADER) String inMno) {
try {
return ok(merchantSummaryBiz.home(inMno));
} catch (SystemException e) {
log.error("{}经营数据概览异常: {}", inMno, e.getMessage());
return error(DefaultResponseErrorType.ERROR, e.getMessage());
} catch (Exception e) {
log.error("{}经营数据概览异常: ", inMno, e);
return error(DefaultResponseErrorType.ERROR, ResultErrorMessage.COMMON_ERR.getMessage());
}
}
内部实现类(这只是一个业务逻辑):
MerchantSummaryVo merchantSummaryVo = new MerchantSummaryVo();
*//** 1.累积数据 *//*
MileMerchantSummary merchantSummary = summaryService.findByInMno(inMno);
if (ObjectUtils.isEmpty(merchantSummary)) {
return merchantSummaryVo;
}
// 总营业额
merchantSummaryVo.setAmountTotal(AmountConvertUtils.twoScale(merchantSummary.getAmountTotalRecharge()).toPlainString());
// 充值收入
merchantSummaryVo.setRechargeAmountTotal(
AmountConvertUtils.twoScale(merchantSummary.getRechargeAmountTotal()).toPlainString());
// 非充值收入
merchantSummaryVo.setUnRechargeAmountTotal(
AmountConvertUtils.twoScale(merchantSummary.getUnRechargeAmountTotal()).toPlainString());
// 充值会员消费人数
merchantSummaryVo.setRechargeNumTotal(merchantSummary.getRechargeNumTotal());
// 非充值会员消费人数
merchantSummaryVo.setUnRechargeNumTotal(merchantSummary.getUnRechargeNumTotal());
// 所有动态数据都是近7天
MileMerchantStatisticInfo statisticInfo = statisticInfoService.findByInMnoAndType(inMno,
CommonCodeStrEnum.STATISTIC_TYPE_R7.getCode());
// 上7天
MileMerchantStatisticInfo statisticInfoLast = statisticInfoService.findByInMnoAndType(inMno,
CommonCodeStrEnum.STATISTIC_TYPE_L7.getCode());
*//** 2.客流分析 *//*
merchantSummaryVo.setConsumerFlowVo(this.consumerFlow(statisticInfo, statisticInfoLast, null));
*//** 3.充值会员消费看板 *//*
merchantSummaryVo.setRechargeVo(this.recharge(statisticInfo, statisticInfoLast));
*//** 4.推广数据分析 *//*
merchantSummaryVo.setSpreadVo(this.spread(merchantSummary, Boolean.FALSE));
*//** 5.店铺交易概览 *//*
merchantSummaryVo.setStoreVo(this.store(statisticInfo, statisticInfoLast, null));
// 近30天
statisticInfo = statisticInfoService.findByInMnoAndType(inMno, CommonCodeStrEnum.STATISTIC_TYPE_R30.getCode());
return merchantSummaryVo;
是不是特别臃肿,当我们还需要一个别的需求的时候,我们还需要的再往这个方法中不停的添加逻辑,导致这个方法的很长。有人说到了:封装方法不就好了?? 那么我就会问你了。当你封装了一堆方法,别人怎么围护你写的代码,再来新的业务时候还需要重写掰扯原先的计算逻辑,再去修改代码,效率很低,不符合封闭开放的原则。
所以我们要对他进行改造,我们经常用到的Web框架是Spring,而Spring的容器管理很强大,强大到你无法象想。
代码如下:
首先我们顶一个抽象策略类
这个用来抽象不同的业务所需要执行的方法(也就是策略设计模式中所谓的不同的算法簇)。
而第二个方法,只是对这个方法的一种定义,让我们的程序可以方便的找到自己应该执行的方法(算法簇)。
/* @Classname IActivityHandleStrategy
* @Description 抽象活动统计策略类
* @Date 2021/5/26 17:12
* @Created by ZhuBo
*/
public interface IActivityHandleStrategy {
/**
* 执行拦截器
* @param inMno
* @return
*/
MerchantSummaryVo handleReceipt(String inMno);
/**
* 经营数据类型
* @return
*/
String getTypeId();
}
看到代码中的Resource注解了么?我们还记得他的作用是什么?如果不记得同学要百度一下。这里先卖个关子。(自己动手去百度才会认真看。我这里就不解释了)
这个工厂类使用Spring从而动态的获取到对应的实体类,返回的对象
/**
* @Classname HandleStrategyFactory
* @Description 统计经营数据工厂类,生成统计实体
* @Date 2021/5/26 17:43
* @Created by 朱博
*/
@Component
public class ActivityHandleStrategyFactory {
@Resource
private List<IActivityHandleStrategy> iActivityHandleStrategies;
@Autowired
private MileDiscountCardMerchantService mileDiscountCardMerchantService;
@Autowired
private MileMerchantActivityService mileMerchantActivityService;
/**
* 获取具体的统计实体
* @param inMno
* @return IActivityHandleStrategy
*/
public IActivityHandleStrategy getReceiptHandleStrategy(String inMno) {
//Zhubo todo 这里需要优化
int discountNum = mileDiscountCardMerchantService.existsDiscountActivity(inMno);
int rechargeNum = mileMerchantActivityService.countByInMno(inMno);
String type;
if (discountNum > 0 && rechargeNum > 0) {
type = StatisticsConstants.ALL_CARD;//全量统计
} else if (discountNum > 0) {
type = StatisticsConstants.DISCOUNT_CARD;//折扣会员卡统计
} else if (rechargeNum > 0) {
type = StatisticsConstants.RECHARGE_CARD;//储值会员统计
} else {
type = StatisticsConstants.NORMAL;//默认会员统计
}
Optional<IActivityHandleStrategy> first =
iActivityHandleStrategies.stream().filter(service -> service.getTypeId().equals(type)).findFirst();
return first.get();
}
}
接下来我们没一个自己定义的策略类,都要去实现之前的策略抽象类,实现其中的具体的handleReceipt() 这个方法,这样我们就工厂类对其创造的对象从而执行具体的是实现。
通过这样的改造,我们实现了简单工厂模式+策略设计模式的实现,当我们产品小姐姐再一次提出新需求的时候,就不用再改原来的统计代码了,也是我们所说的对代码的侵入性不高,对于原有逻辑不具有影响性。
package com.suixingpay.mile.front.common.impl;
import com.google.common.collect.Lists;
import com.suixingpay.mile.constants.enums.CommonCodeStrEnum;
import com.suixingpay.mile.dao.entity.MileMerchantDayStatisticInfo;
import com.suixingpay.mile.dao.entity.MileMerchantStatisticInfo;
import com.suixingpay.mile.dao.entity.MileMerchantSummary;
import com.suixingpay.mile.front.common.abstarct.IActivityHandleStrategy;
import com.suixingpay.mile.front.service.*;
import com.suixingpay.mile.front.vo.*;
import com.suixingpay.mile.util.AmountConvertUtils;
import com.suixingpay.takin.util.collection.ListUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.time.temporal.TemporalAdjusters;
import java.util.List;
import java.util.Optional;
import java.util.stream.Stream;
/**
* @Classname IAlleHandleStrategyImpl
* @Description 全量数据统计
* @Date 2021/5/26 18:31
* @Created by 朱博
*/
@Component
public class IAllHandleStrategyImpl implements IActivityHandleStrategy {
/******************对应的代码逻辑**********************/
public final String ALL_CARD="ALL_CARD";
@Override
public String getTypeId() {
return ALL_CARD;
}
@Autowired
private MileMerchantSummaryService summaryService;
@Autowired
private MileMerchantStatisticInfoService statisticInfoService;
@Autowired
private MileMerchantDayStatisticInfoService dayStatisticInfoService;
@Autowired
private MileTradeRecordService tradeRecordService;
@Override
public MerchantSummaryVo handleReceipt(String inMno) {
MerchantSummaryVo merchantSummaryVo = new MerchantSummaryVo();
merchantSummaryVo.setDataType(ALL_CARD);
MileMerchantSummary merchantSummary = summaryService.findByInMno(inMno);
if (ObjectUtils.isEmpty(merchantSummary)) {
merchantSummaryVo.setDataType(ALL_CARD);
return merchantSummaryVo;
}
// 总营业额
merchantSummaryVo.setAmountTotal(AmountConvertUtils.twoScale(merchantSummary.getAmountTotal()).toPlainString());
// 累计充值金额
merchantSummaryVo.setRechargeAmountTotal(
AmountConvertUtils.twoScale(merchantSummary.getRechargeAmountTotal()).toPlainString());
// 普通交易金额
merchantSummaryVo.setUnRechargeAmountTotal(
AmountConvertUtils.twoScale(merchantSummary.getUnRechargeAmountTotal()).toPlainString());
// 打折卡消费金额
merchantSummaryVo.setDiscountAmountTotal(AmountConvertUtils.twoScale(merchantSummary.getDiscountCardAmountTotal()).toPlainString());
// 充值会员消费人数
merchantSummaryVo.setRechargeNumTotal(merchantSummary.getRechargeNumTotal());
// 折扣会员消费人数
merchantSummaryVo.setDiscountCardNumTotal(merchantSummary.getDiscountCardNumTotal());
// 非折扣会员消费人数(普通会员消费人数)
merchantSummaryVo.setUnRechargeNumTotal(merchantSummary.getUnRechargeNumTotal());
// 普通会员人数
merchantSummaryVo.setNormalNum(merchantSummary.getNormalNum());
// 储值会员人数
merchantSummaryVo.setRechargeNum(merchantSummary.getRechrageNum());
// 折扣会员人数
merchantSummaryVo.setDiscountNum(merchantSummary.getDiscountNum());
// 所有动态数据都是近7天
MileMerchantStatisticInfo statisticInfo = statisticInfoService.findByInMnoAndType(inMno,
CommonCodeStrEnum.STATISTIC_TYPE_R7.getCode());
// 上7天
MileMerchantStatisticInfo statisticInfoLast = statisticInfoService.findByInMnoAndType(inMno,
CommonCodeStrEnum.STATISTIC_TYPE_L7.getCode());
/** 2.客流分析(充值) */
merchantSummaryVo.setConsumerFlowVo(this.consumerFlow(statisticInfo, statisticInfoLast, null));
/** 4.充值会员消费看板 */
merchantSummaryVo.setRechargeVo(this.recharge(statisticInfo, statisticInfoLast));
/** 5.折扣会员消费看板 */
merchantSummaryVo.setDiscountVo(this.disocunt(statisticInfo, statisticInfoLast));
/** 6.推广数据分析(充值) */
merchantSummaryVo.setSpreadVo(this.spread(merchantSummary, Boolean.FALSE));
/** 7.推广数据分析(折扣卡) */
merchantSummaryVo.setSpreadDiscountVo(this.spreadOfDiscountCard(merchantSummary,Boolean.FALSE));
/** 8.店铺交易概览 */
merchantSummaryVo.setStoreVo(this.storeOfDiscountCard(statisticInfo, statisticInfoLast, null));
// 近30天
statisticInfo = statisticInfoService.findByInMnoAndType(inMno, CommonCodeStrEnum.STATISTIC_TYPE_R30.getCode());
MileMerchantStatisticInfo statisticInfoBy30 = statisticInfoService.findByInMnoAndType(inMno,
CommonCodeStrEnum.STATISTIC_TYPE_R30.getCode());
/** 10.近30天人均消费频次充值 */
merchantSummaryVo.setCapitaComsumeVo(this.capitaComsume(statisticInfoBy30));
/** 11.近30天客单价充值 */
merchantSummaryVo.setUnitPriceVo(this.unitPrice(statisticInfoBy30));
/** 12.近30天人均消费频次折扣 */
merchantSummaryVo.setCapitaComsumeDiscountVo(this.capitaComsumeOfDisocount(statisticInfo));
// 总营业额
merchantSummaryVo.setAmountTotal(AmountConvertUtils.twoScale(merchantSummary.getAmountTotal()).toPlainString());
return merchantSummaryVo;
}
/**
* 客流分析(储值+折扣)
*
* @param statisticInfo 近N天数据
* @param statisticInfoLast 上N天数据
* @param dayStatisticInfoList 每日数据
* @return
*/
public MerchantSummaryConsumerFlowVo consumerFlow(MileMerchantStatisticInfo statisticInfo,
MileMerchantStatisticInfo statisticInfoLast, List<MileMerchantDayStatisticInfo> dayStatisticInfoList) {
// 充值会员消费人数
int rechargeConsumeNumTotal = statisticInfo.getRechargeConsumeNum();
// 新增会员人数
int newRechargeNumTotal = statisticInfo.getNewRechargeNum();
// 非充值会员消费人数
int unRechargeConsumeNumTotal = statisticInfo.getUnRechargeConsumeNum();
// 新增普通会员人数
int newUnRechargeNumTotal = statisticInfo.getNewUnRechargeNum();
// 各数据坐标系数
List<MerchantSummaryCoordinateVo> rechargeConsumeNumCoordinateVos = Lists.newArrayList();
List<MerchantSummaryCoordinateVo> unRechargeConsumeNumCoordinateVos = Lists.newArrayList();
List<MerchantSummaryCoordinateVo> newRechargeNumCoordinateVos = Lists.newArrayList();
List<MerchantSummaryCoordinateVo> newUnRechargeNumCoordinateVos = Lists.newArrayList();
if (ListUtils.isNotEmpty(dayStatisticInfoList)) {
dayStatisticInfoList.stream().forEach(item -> {
// 横轴日期处理
String statisticDate = this.statisticDate(item);
rechargeConsumeNumCoordinateVos.add(MerchantSummaryCoordinateVo.builder().horizontalAxis(statisticDate)
.verticalAxis(String.valueOf(item.getRechargeConsumeNum())).build());
unRechargeConsumeNumCoordinateVos
.add(MerchantSummaryCoordinateVo.builder().horizontalAxis(statisticDate)
.verticalAxis(String.valueOf(item.getUnRechargeConsumeNum())).build());
newRechargeNumCoordinateVos.add(MerchantSummaryCoordinateVo.builder().horizontalAxis(statisticDate)
.verticalAxis(String.valueOf(item.getNewRechargeNum())).build());
newUnRechargeNumCoordinateVos.add(MerchantSummaryCoordinateVo.builder().horizontalAxis(statisticDate)
.verticalAxis(String.valueOf(item.getNewUnRechargeNum())).build());
});
}
// 上周期
// 充值会员消费人数
int rechargeConsumeNumTotalLast = statisticInfoLast.getRechargeConsumeNum();
// 新增会员人数
int newRechargeNumTotalLast = statisticInfoLast.getNewRechargeNum();
// 非充值会员消费人数
int unRechargeConsumeNumTotalLast = statisticInfoLast.getUnRechargeConsumeNum();
// 新增普通会员人数
int newUnRechargeNumTotalLast = statisticInfoLast.getNewUnRechargeNum();
MerchantSummaryConsumerFlowVo consumerFlowVo = new MerchantSummaryConsumerFlowVo();
// 充值会员消费人数同比
consumerFlowVo
.setRechargeConsumeNumRatio(this.computeData(rechargeConsumeNumTotal, rechargeConsumeNumTotalLast));
// 非充值会员消费人数同比
consumerFlowVo.setUnRechargeConsumeNumRatio(
this.computeData(unRechargeConsumeNumTotal, unRechargeConsumeNumTotalLast));
// 新增会员人数同比
consumerFlowVo.setNewRechargeNumRadio(this.computeData(newRechargeNumTotal, newRechargeNumTotalLast));
// 普通会员人数同比
consumerFlowVo.setNewUnRechargeNumRadio(this.computeData(newUnRechargeNumTotal, newUnRechargeNumTotalLast));
consumerFlowVo.setRechargeConsumeNumTotal(rechargeConsumeNumTotal);
consumerFlowVo.setUnRechargeConsumeNumTotal(unRechargeConsumeNumTotal);
consumerFlowVo.setNewRechargeNumTotal(newRechargeNumTotal);
consumerFlowVo.setNewUnRechargeNumTotal(newUnRechargeNumTotal);
consumerFlowVo.setRechargeConsumeNumCoordinateVos(rechargeConsumeNumCoordinateVos);
consumerFlowVo.setUnRechargeConsumeNumCoordinateVos(unRechargeConsumeNumCoordinateVos);
consumerFlowVo.setNewRechargeNumCoordinateVos(newRechargeNumCoordinateVos);
consumerFlowVo.setNewUnRechargeNumCoordinateVos(newUnRechargeNumCoordinateVos);
//*************************************************** 折扣 ************************************************//
// 本周期
// 折扣消费人数
int discountConsumeNum = statisticInfo.getDiscountConsumeNum();
// 普通消费人数
int unDiscountConsumeNum = statisticInfo.getUnRechargeConsumeNum();
// 新增折扣卡消费人数
int newDiscountConsumeNum = statisticInfo.getNewDiscountNum();
// 新增普通会员人数
int newUnDiscountConsumeNum = statisticInfo.getNewUnRechargeNum();
// 各数据坐标系数
List<MerchantSummaryCoordinateVo> unRechargeNumCoordinateVos = Lists.newArrayList();
List<MerchantSummaryCoordinateVo> discountConsumeNumCoordinateVos = Lists.newArrayList();
List<MerchantSummaryCoordinateVo> newDiscountNumCoordinateVos = Lists.newArrayList();
List<MerchantSummaryCoordinateVo> newUnRechargeVos = Lists.newArrayList();
if (ListUtils.isNotEmpty(dayStatisticInfoList)) {
dayStatisticInfoList.stream().forEach(item -> {
// 横轴日期处理
String statisticDate = this.statisticDate(item);
unRechargeNumCoordinateVos.add(MerchantSummaryCoordinateVo.builder().horizontalAxis(statisticDate)
.verticalAxis(String.valueOf(item.getUnRechargeConsumeNum())).build());
discountConsumeNumCoordinateVos.add(MerchantSummaryCoordinateVo.builder().horizontalAxis(statisticDate)
.verticalAxis(String.valueOf(item.getDiscountConsumeNum())).build());
newDiscountNumCoordinateVos.add(MerchantSummaryCoordinateVo.builder().horizontalAxis(statisticDate)
.verticalAxis(String.valueOf(item.getNewDiscountNum())).build());
newUnRechargeVos.add(MerchantSummaryCoordinateVo.builder().horizontalAxis(statisticDate)
.verticalAxis(String.valueOf(item.getNewUnRechargeNum())).build());
});
}
// 上周期
// 折扣消费会员人数
int discountConsumeNumLast = statisticInfoLast.getDiscountConsumeNum();
// 普通消费人数
int unDiscountConsumeNumLast = statisticInfoLast.getUnRechargeConsumeNum();
// 新增折扣消费人数
int newDiscountNumTotalLast = statisticInfoLast.getNewDiscountNum();
// 新增普通会员人数
int newUnDiscountConsumeNumLast = statisticInfoLast.getNewUnRechargeNum();
// 折扣会员人数同比
consumerFlowVo.setDiscountConsumeNumRatio(this.computeData(discountConsumeNum,discountConsumeNumLast));
// 普通会员人数同比
consumerFlowVo.setUnRechargeConsumeNumRatio(this.computeData(unDiscountConsumeNum,unDiscountConsumeNumLast));
// 新增会员人数同比
consumerFlowVo.setNewDiscountNumRadio(this.computeData(newDiscountConsumeNum, newDiscountNumTotalLast));
// 新增普通人数同比
consumerFlowVo.setNewUnRechargeNumRadio(this.computeData(newUnDiscountConsumeNum, newUnDiscountConsumeNumLast));
consumerFlowVo.setDiscountConsumeNumTotal(discountConsumeNum);
consumerFlowVo.setUnRechargeConsumeNumTotal(unDiscountConsumeNum);
consumerFlowVo.setNewDiscountNumTotal(newDiscountConsumeNum);
consumerFlowVo.setNewUnRechargeNumTotal(newUnDiscountConsumeNum);
consumerFlowVo.setUnRechargeConsumeNumCoordinateVos(unRechargeNumCoordinateVos);
consumerFlowVo.setDiscountConsumeNumCoordinateVos(discountConsumeNumCoordinateVos);
consumerFlowVo.setNewUnRechargeNumCoordinateVos(newUnRechargeVos);
consumerFlowVo.setNewDiscountNumCoordinateVos(newDiscountNumCoordinateVos);
return consumerFlowVo;
}
/******************对应的代码逻辑**********************/
}
/**
* 计算百分比
*
* @param recent 除数
* @param last 被除数
* @return 比例
*/
private int computeData(int recent, int last) {
if (0 == last) {
if (0 != recent) {
return 100;
}
return 0;
}
return new BigDecimal(recent).divide(new BigDecimal(last), 2, RoundingMode.DOWN).subtract(new BigDecimal(1))
.multiply(new BigDecimal(100)).intValue();
}
/**
* 横轴日期转换
*
* @param dayStatisticInfo 每日基础数据
* @return
*/
private String statisticDate(MileMerchantDayStatisticInfo dayStatisticInfo) {
if (!ObjectUtils.isEmpty(dayStatisticInfo.getStatisticDate())) {
return dayStatisticInfo.getStatisticDate().format(DateTimeFormatter.ofPattern("MM/dd"));
}
return StringUtils.EMPTY;
}
/**
* 根据天数查询每日数据
*
* @param inMno
* @param days 天数
* @return
*/
private List<MileMerchantDayStatisticInfo> conditionDayStatistic(String inMno, int days) {
List<MileMerchantDayStatisticInfo> result = Lists.newArrayList();
// 近7天每日数据
LocalDate now = LocalDate.now();
LocalDate lastDay = now.minusDays(days);
List<MileMerchantDayStatisticInfo> dayStatisticInfos = dayStatisticInfoService.findByInMnoAndDate(inMno,
lastDay.format(DateTimeFormatter.ISO_LOCAL_DATE), now.format(DateTimeFormatter.ISO_LOCAL_DATE));
if (dayStatisticInfos.size() != days) {
for (int i = days; i > 0; i--) {
LocalDate date = now.minusDays(i);
this.dayStatisticInfo(result, dayStatisticInfos, date);
}
} else {
result.addAll(dayStatisticInfos);
}
return result;
}
/**
* 根据月份查询每日数据
*
* @param inMno
* @param month
* @return
*/
private List<MileMerchantDayStatisticInfo> monthForDayStatisticInfo(String inMno, LocalDate month) {
List<MileMerchantDayStatisticInfo> result = Lists.newArrayList();
// 当前月首日
LocalDate first = month.with(TemporalAdjusters.firstDayOfMonth());
// 下个月首日
LocalDate last = first.plusMonths(1);
long distance = ChronoUnit.DAYS.between(first, last);
if (distance < 1) {
return result;
}
List<MileMerchantDayStatisticInfo> dayStatisticInfos = dayStatisticInfoService.findByInMnoAndDate(inMno,
first.format(DateTimeFormatter.ISO_LOCAL_DATE), last.format(DateTimeFormatter.ISO_LOCAL_DATE));
Stream.iterate(first, d -> d.plusDays(1)).limit(distance)
.forEach(f -> this.dayStatisticInfo(result, dayStatisticInfos, f));
return result;
}
/**
* 获取指定天的开始时间
*
* @param spaceDay
* @return
*/
private String obtainSpecifiedDayBeginTime(int spaceDay) {
return LocalDateTime.of(LocalDate.now().minusDays(spaceDay), LocalTime.MIN)
.format(DateTimeFormatter.ofPattern(DateUtils.DATE_FORMAT_DATETIME));
}
/**
* 获取指定天的结束时间
*
* @param spaceDay
* @return
*/
private String obtainSpecifiedDayEndTime(int spaceDay) {
return LocalDateTime.of(LocalDate.now().minusDays(spaceDay), LocalTime.MAX)
.format(DateTimeFormatter.ofPattern(DateUtils.DATE_FORMAT_DATETIME));
}
/**
* 获取指定月的开始时间
*
* @param day
* @return
*/
private String obtainSpecifiedMonthBeginTime(int day) {
return LocalDateTime.now().minusDays(day).with(TemporalAdjusters.firstDayOfMonth()).withHour(0)
.withMinute(0).withSecond(0).format(DateTimeFormatter.ofPattern(DateUtils.DATE_FORMAT_DATETIME));
}
/**
* 获取指定月的结束时间
*
* @param day
* @return
*/
private String obtainSpecifiedMonthEndTime(int day) {
return LocalDateTime.now().minusDays(day).with(TemporalAdjusters.lastDayOfMonth()).withHour(23)
.withMinute(59).withSecond(59).format(DateTimeFormatter.ofPattern(DateUtils.DATE_FORMAT_DATETIME));
}
/**
* 获取指定天指定月的结束时间
*
* @param day
* @param month
* @return
*/
private String obtainSpecifiedMonthFilterEndTime(int day, int month) {
return LocalDateTime.now().minusMonths(month).minusDays(day).with(TemporalAdjusters.lastDayOfMonth()).withHour(23)
.withMinute(59).withSecond(59).format(DateTimeFormatter.ofPattern(DateUtils.DATE_FORMAT_DATETIME));
}