根据自己的业务去修改,本文提供参考思路
首先:需求是要求指定年份每一天的价格,没有则补全并赋值日期之前最近的一次价格
有一个主表(主表中有id和价格)
子表中有主表的id和价格
主表价格更改,就需要向字表中添加一条数据
如下表:
解决方案1:设置定时任务,在每晚的12点去主表查询价格,然后向子表添加一条记录,如果当天已经存在记录就不在添加
问题:如果一天更改两次价格,子表中将会存在两个记录?
这个问题是这样解决的,更改的时候去逻辑删除子表中的这一天的记录,再去添加,保证,一天只有一条数据,逻辑删除的意义在于客户需要所有的记录可以都拿的出来
这样也是一个实现的思路,查询折线图的时候,直接获取未被逻辑删除的就是每一天的数据,
但我是另一种方式
解决方案二:
思路如下:
1.先去子表查询 指定年份的价格
2.得到指定年份的每一天存到一个集合中
3.遍历查询的指定年份的价格集合 拿到创建时间 和价格
(我这里查询是ASE升序,保证日期先后,比如11月9号和11月13号都有记录,则查询的集合中9号在13号之前)
4.在查询的指定年份的价格集合中遍历得到年份的每一天 ,拿到每一天
5. 判断这一天是否在 价格的日期与下一个日期之间,获取(get(i)和get(i+1))
(比如:11月9号和11月13号有记录,然后每一天回去比较是否在这两个日期区域,在的话就赋值11月9号的价格)
6.如果不在则跳出这轮循环,进行下一轮 continue
按年查询升序
public ReportResultVo getPrice(Long id, int years) {
ReportResultVo reportResultVo = new ReportResultVo();
ArrayList<String> xData = new ArrayList<>();
ArrayList<Long> yData = new ArrayList<>();
// 1.指定年份中的历史价格(子表数据)
List<GasSourcePrice> gasSourcePrices = gasSourcePriceMapper.selectGasSourcePriceByGasSourceId(id, years);
List<String> daysByYears = getDaysByYear(years);
for (int x = 0; x < gasSourcePrices.size(); x++) {
//next为下一条数据
int next = 0;
if (x + 1 < gasSourcePrices.size()) {
next = x + 1;
} else {
next = x;
}
GasSourcePrice gasSourcePrice = gasSourcePrices.get(x);
Date date1 = gasSourcePrice.getCreateTime();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
String format1 = sdf.format(date1);
Date beginTime = strToDate(format1);
GasSourcePrice gasSourcePriceNext = gasSourcePrices.get(next);
Date date2 = gasSourcePriceNext.getCreateTime();
String format2 = sdf.format(date2);
Date endTime = strToDate(format2);
for (int i = 0; i < daysByYears.size(); i++) {
log.info(daysByYears.get(i));
Date date = strToDate(daysByYears.get(i));
if (belongCalendar(date, beginTime, endTime)) {
xData.add(sdf.format(date));
yData.add(gasSourcePrice.getPrice().longValue());
} else {
continue;
}
}
}
reportResultVo.setXData(xData);
reportResultVo.setYData(yData);
return reportResultVo;
}
其中用到的方法:
1.判断时间是否在时间段内
/**
* 判断指定日期是否在两个日期内
*
* @param nowTime
* @param beginTime
* @param endTime
* @return
*/
public static boolean belongCalendar(Date nowTime, Date beginTime, Date endTime) {
Calendar date = Calendar.getInstance();
date.setTime(nowTime);
Calendar begin = Calendar.getInstance();
begin.setTime(beginTime);
Calendar end = Calendar.getInstance();
end.setTime(endTime);
if (date.after(begin) && date.before(end)) {
return true;
} else if (nowTime.compareTo(beginTime) == 0 ) {
return true;
} else {
return false;
}
}
2.生成指定年份的每一天
/**
* 生成指定年的每一天
* @param year
* @return
*/
public static List<String> getDaysByYear(int year){
Calendar c=Calendar.getInstance();
List<String> dates=new ArrayList<String>();
for(int i=0;i<12;i++){
c.set(year,i,1);
int lastDay=c.getActualMaximum(Calendar.DATE);
for(int j=1;j<=lastDay;j++){
String month="";
String day="";
if(i<9) month="-0"+(i+1);
else month="-"+(i+1);
if(j<10) day="-0"+j;
else day="-"+j;
String date=year+month+day;
dates.add(date);
}
}
return dates;
}
3.字符串转日期格式
// 字符串 转 日期
public static Date strToDate(String str) {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
Date date = null;
try {
date = sdf.parse(str);
} catch (ParseException e) {
}
return date;
}
效果如下
出现了新的问题
如果遇到上一年有记录,但这一年的记录是11月9号的,那就会存在一个问题,
返回的数据只是这一年11月9号之后的,之前并没有数据,所以需要改进
解决方案:
查询到这一年记录后判断这一年是否有记录
没有则查询这一年第一天之前数据库最近的一条记录,并将给一年赋值
查询的sql语句如下:
select * from 表
where date_format(时间字段,'%y%m%d') < date_format(#{指定日期},'%y%m%d')
ORDER BY create_time DESC LIMIT 1
其中指定日期就是指定年份的第一天(可以通过如下方法获取,传年,传月,返回第一天)
/**
* 获取该月的第一天
*
* @param year 年
* @param month 月
* @return
*/
public static Date getFirstDay(int year, int month) {
Calendar c = Calendar.getInstance();
c.set(Calendar.YEAR, year);
// 设置月份,因为月份从0开始,所以用month - 1
c.set(Calendar.MONTH, month - 1);
c.set(Calendar.DAY_OF_MONTH, 1);
Date time = c.getTime();
SimpleDateFormat slf = new SimpleDateFormat("yyyy-MM-dd");
String format = slf.format(time);
try {
return slf.parse(format);
} catch (ParseException e) {
e.printStackTrace();
}
return null;
}
这是这一年都没有记录的情况
下面是这一年中有记录
分两步,文章最开始已经将存在日期之后的数据赋值了为第二步
在之前添加第一步:
拿到指定年份中的历史数据之后 获取第一条数据
因为sql是ASC升序的,所以获取的第一条就是这一年的第一条数据,
根据这一年的第一条数据的日期去查询这之前数据库最近的一条记录
给这一年存在日期之前的数据赋值
这样就解决了
查询的sql还是上面那条,哪里的指定日期改为这里第一条数据的日期就可以了
成品如下:
public ReportResultVo getPrice(Long id, int years) {
//每一天
List<String> daysByYears = DateUtils.getDaysByYear(years);
ReportResultVo reportResultVo = new ReportResultVo();
ArrayList<String> xData = new ArrayList<>();
ArrayList<Long> yData = new ArrayList<>();
// 指定年份中的历史价格
List<GasSourcePrice> gasSourcePrices = gasSourcePriceMapper.selectGasSourcePriceByGasSourceId(id, years);
if (gasSourcePrices.size() > 0) {
//查询该年份之前的最近一条记录,赋值给该年份第一条记录之前的日期
//获取该年份第一条数据
GasSourcePrice gasSourcePriceOne = gasSourcePrices.get(0);
//查询该年份之前最近的一条记录
GasSourcePrice gasSourcePrice = gasSourcePriceMapper.selectGasSourcePriceByDate(id, gasSourcePriceOne.getCreateTime().toString());
if (StringUtils.isNotNull(gasSourcePrice)) {
Date date1 = gasSourcePrice.getCreateTime();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
String format1 = sdf.format(date1);
Date beginTime = DateUtils.strToDate(format1);
Date date2 = gasSourcePriceOne.getCreateTime();
String format2 = sdf.format(date2);
Date endTime = DateUtils.strToDate(format2);
for (int i = 0; i < daysByYears.size(); i++) {
Date date = DateUtils.strToDate(daysByYears.get(i));
if (DateUtils.belongCalendar(date, beginTime, endTime)) {
if (!xData.contains(sdf.format(date))) {
xData.add(sdf.format(date));
}
yData.add(gasSourcePrice.getPrice().longValue());
} else {
continue;
}
}
}
//赋值给该年份查询到第一条和最后一条之间的日期
for (int x = 0; x < gasSourcePrices.size(); x++) {
int next = 0;
if (x + 1 < gasSourcePrices.size()) {
next = x + 1;
} else {
next = x;
}
GasSourcePrice gas = gasSourcePrices.get(x);
Date date1 = gas.getCreateTime();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
String format1 = sdf.format(date1);
Date beginTime = DateUtils.strToDate(format1);
GasSourcePrice gasSourcePriceNext = gasSourcePrices.get(next);
Date date2 = gasSourcePriceNext.getCreateTime();
String format2 = sdf.format(date2);
Date endTime = DateUtils.strToDate(format2);
for (int i = 0; i < daysByYears.size(); i++) {
log.info(daysByYears.get(i));
Date date = DateUtils.strToDate(daysByYears.get(i));
if (DateUtils.belongCalendar(date, beginTime, endTime)) {
if (!xData.contains(sdf.format(date))) {
xData.add(sdf.format(date));
}
yData.add(gas.getPrice().longValue());
} else {
continue;
}
}
}
} else if (gasSourcePrices.size() == 0) {
//这一年没有记录 查之前的记录 并赋值给这一年
Date day = DateUtils.getFirstDay(years, 1);
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
String format1 = sdf.format(day);
//查询该年份之前最近的一条记录
GasSourcePrice gasSourcePrice = gasSourcePriceMapper.selectGasSourcePriceByDate(id, format1);
if (StringUtils.isNotNull(gasSourcePrice)) {
for (int i = 0; i < daysByYears.size(); i++) {
log.info(daysByYears.get(i));
yData.add(gasSourcePrice.getPrice().longValue());
}
}
xData.addAll(daysByYears);
}
reportResultVo.setXData(xData);
reportResultVo.setYData(yData);
return reportResultVo;
}
本以为结束了,又有新的问题,查询的数据如果是今年的应该查询的今天,而我所查询出来的只截止到最后一天
使用到的方法getLastDay,根据年月获取这个月第一天,最后一天
/**
* 获取该月的第一天
*
* @param year 年
* @param month 月
* @return
*/
public static Date getFirstDay(int year, int month) {
Calendar c = Calendar.getInstance();
c.set(Calendar.YEAR, year);
// 设置月份,因为月份从0开始,所以用month - 1
c.set(Calendar.MONTH, month - 1);
c.set(Calendar.DAY_OF_MONTH, 1);
Date time = c.getTime();
SimpleDateFormat slf = new SimpleDateFormat("yyyy-MM-dd");
String format = slf.format(time);
try {
return slf.parse(format);
} catch (ParseException e) {
e.printStackTrace();
}
return null;
}
/**
* 获取该月的最后一天
*/
public static Date getLastDay ( int year, int month){
Calendar c = Calendar.getInstance();
c.set(Calendar.YEAR, year);
// 设置月份,因为月份从0开始,所以用month - 1
c.set(Calendar.MONTH, month - 1);
// 获取当前时间下,该月的最大日期的数字
int lastDay = c.getActualMaximum(Calendar.DAY_OF_MONTH);
// 将获取的最大日期数设置为Calendar实例的日期数
c.set(Calendar.DAY_OF_MONTH, lastDay);
Date time = c.getTime();
SimpleDateFormat slf = new SimpleDateFormat("yyyy-MM-dd");
String format = slf.format(time);
try {
return slf.parse(format);
} catch (ParseException e) {
e.printStackTrace();
}
return null;
}
最终版的代码如下:
public ReportResultVo getPrice(Long id, int years) {
//每一天
List<String> daysByYears = DateUtils.getDaysByYear(years);
//返回结果
ReportResultVo reportResultVo = new ReportResultVo();
ArrayList<String> xData = new ArrayList<>();
ArrayList<Long> yData = new ArrayList<>();
// 指定年份中的历史价格
List<GasSourcePrice> gasSourcePrices = gasSourcePriceMapper.selectGasSourcePriceByGasSourceId(id, years);
if (gasSourcePrices.size() > 0) {
//判断是否是今年
if (DateUtils.isNowYear(years)){
//是今年则补全最后一条记录至今的数据
GasSourcePrice gasSourcePrice = new GasSourcePrice();
BeanUtils.copyProperties(gasSourcePrices.get(gasSourcePrices.size()-1),gasSourcePrice);
gasSourcePrice.setCreateTime(DateUtils.getNowDate());
gasSourcePrices.add(gasSourcePrice);
}else {
//不是今年,补全到年的最后一天
GasSourcePrice gasSourcePrice = new GasSourcePrice();
BeanUtils.copyProperties(gasSourcePrices.get(gasSourcePrices.size()-1),gasSourcePrice);
gasSourcePrice.setCreateTime(DateUtils.getLastDay(years,12));
gasSourcePrices.add(gasSourcePrice);
}
//查询该年份之前的最近一条记录,赋值给该年份第一条记录之前的日期
//获取该年份第一条数据
GasSourcePrice gasSourcePriceOne = gasSourcePrices.get(0);
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
String dateOne = simpleDateFormat.format(gasSourcePriceOne.getCreateTime());
//查询该年份之前最近的一条记录
GasSourcePrice gasSourcePrice = gasSourcePriceMapper.selectGasSourcePriceByDate(id,dateOne);
if (StringUtils.isNotNull(gasSourcePrice)) {
Date date1 = gasSourcePrice.getCreateTime();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
String format1 = sdf.format(date1);
Date beginTime = DateUtils.strToDate(format1);
Date date2 = gasSourcePriceOne.getCreateTime();
String format2 = sdf.format(date2);
Date endTime = DateUtils.strToDate(format2);
for (int i = 0; i < daysByYears.size(); i++) {
Date date = DateUtils.strToDate(daysByYears.get(i));
if (DateUtils.belongCalendar(date, beginTime, endTime)) {
if (!xData.contains(sdf.format(date))) {
xData.add(sdf.format(date));
}
yData.add(gasSourcePrice.getPrice().longValue());
} else {
continue;
}
}
}
//赋值给该年份查询到第一条和最后一条之间的日期
for (int x = 0; x < gasSourcePrices.size(); x++) {
int next = 0;
if (x + 1 < gasSourcePrices.size()) {
next = x + 1;
} else {
next = x;
}
GasSourcePrice gas = gasSourcePrices.get(x);
Date date1 = gas.getCreateTime();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
String format1 = sdf.format(date1);
Date beginTime = DateUtils.strToDate(format1);
GasSourcePrice gasSourcePriceNext = gasSourcePrices.get(next);
Date date2 = gasSourcePriceNext.getCreateTime();
String format2 = sdf.format(date2);
Date endTime = DateUtils.strToDate(format2);
for (int i = 0; i < daysByYears.size(); i++) {
log.info(daysByYears.get(i));
Date date = DateUtils.strToDate(daysByYears.get(i));
if (DateUtils.belongCalendar(date, beginTime, endTime)) {
if (!xData.contains(sdf.format(date))) {
xData.add(sdf.format(date));
}
yData.add(gas.getPrice().longValue());
} else {
continue;
}
}
}
} else if (gasSourcePrices.size() == 0) {
//这一年没有记录 查之前的记录 并赋值给这一年
Date day = DateUtils.getFirstDay(years, 1);
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
String format1 = sdf.format(day);
//查询该年份之前最近的一条记录
GasSourcePrice gasSourcePrice = gasSourcePriceMapper.selectGasSourcePriceByDate(id, format1);
if (StringUtils.isNotNull(gasSourcePrice)) {
for (int i = 0; i < daysByYears.size(); i++) {
log.info(daysByYears.get(i));
yData.add(gasSourcePrice.getPrice().longValue());
if (daysByYears.get(i).equals(DateUtils.getDate())){
break;
}
}
}
xData.addAll(daysByYears);
}
reportResultVo.setXData(xData);
reportResultVo.setYData(yData);
return reportResultVo;
}