今日開發(fā)收到了一個(gè)“簡(jiǎn)單”的需求:
“這項(xiàng)任務(wù)需要限制被指派者在7日內(nèi)完成茧跋。”
“嗯卓囚,果然簡(jiǎn)單瘾杭!”
“哦,客戶說(shuō)是7個(gè)工作日哪亿,應(yīng)該好弄吧粥烁?”
“好,工作日……啥S蕖讨阻?工作日……讓朕三思一下……”
站在坑里的我心里跑過(guò)……各種方法。
其實(shí)按照正常情況下篡殷,在工作日創(chuàng)建任務(wù)并指派钝吮,然后限期在7個(gè)工作日后則必然就是9天后(加上周末兩天嗎,看咱這數(shù)學(xué)_)板辽。所以主要麻煩點(diǎn)在于“假期調(diào)休”奇瘦!就是要解決幾個(gè)問(wèn)題:
- 假期調(diào)休數(shù)據(jù)來(lái)源
- 假期數(shù)據(jù)的獲取及記錄
- 當(dāng)前日期后指定工作日后的日期計(jì)算
假期調(diào)休數(shù)據(jù)來(lái)源
先考慮過(guò)手動(dòng)編輯,但是確實(shí)有些麻煩劲弦,網(wǎng)上搜索后決定使用【聚合數(shù)據(jù)的萬(wàn)年歷接口】耳标,可以免費(fèi)使用。
Tips:先要注冊(cè)用戶并申請(qǐng)使用接口獲取Key邑跪,這里省略此步次坡。
這里選擇使用【獲取近期假期】(http://v.juhe.cn/calendar/month)這個(gè)接口呼猪,因?yàn)樗祷氐膬?nèi)容更加詳細(xì),包括了假期中調(diào)休的日子砸琅。
Tips:聚合數(shù)據(jù)的請(qǐng)求接口參數(shù)的日期格式為yyyy-M宋距,返回?cái)?shù)據(jù)中的日期格式為yyyy-M-d;而項(xiàng)目中保存時(shí)需要的是yyyy-MM-dd明棍,要注意比對(duì)和轉(zhuǎn)換乡革。
假期數(shù)據(jù)的獲取及記錄
有了數(shù)據(jù)就可以開始開工了!
Tips:項(xiàng)目實(shí)際上是個(gè)定時(shí)任務(wù)后臺(tái)程序摊腋,工程采用了SpringBoot框架+MyBatis數(shù)據(jù)框架+Quartz任務(wù)調(diào)度框架沸版。MyBatis配置和Quartz動(dòng)態(tài)任務(wù)配置這些我后面其他系列的文章會(huì)有所涉及,這里就不說(shuō)了兴蒸。
創(chuàng)建數(shù)據(jù)表
字段名 | 格式 | 說(shuō)明 |
---|---|---|
date_tag | VARCHAR(11) | 日期標(biāo)識(shí)视粮,格式為yyyy-MM-dd |
name | VARCHAR(64) | 假期名稱 |
year | INT(5) | 所屬年份 |
date | DATE | 具體日期 |
配置訪問(wèn)地址
在application.properties(SpringBoot框架)中增加自定義配置項(xiàng):
#第三方接口
#聚合數(shù)據(jù)
other.juhe.url.holidayMonth=http://v.juhe.cn/calendar/month?key=我的Key&year-month=
添加數(shù)據(jù)層操作(mapper)
添加數(shù)據(jù)表的操作,包括了添加橙凳、刪除和獲取假期數(shù)量等操作:
/**
* 對(duì)假期字典表進(jìn)行處理
* Created by maqiang on 2017/6/7.
*/
public interface HolidayMapper
{
/**
* 獲取指定日期間的假期數(shù)量
* @param startDate
* @param endDate
* @return
*/
@Select("select count(date_tag) from c_holiday where date<=#{endDate} and date>=#{startDate}")
Integer count(@Param("startDate") String startDate,@Param("endDate") String endDate);
/**
* 添加或更新一條假期記錄
*
* @param holiday
*/
@Insert("insert into c_holiday("+
"date_tag,"+
"name,"+
"year,"+
"date"+
")VALUES("+
"#{holiday.date_tag},"+
"#{holiday.name},"+
"#{holiday.year},"+
"#{holiday.date}"+
")")
void insert(@Param("holiday") Map<String,Object> holiday);
/**
* 刪除指定日期的假期記錄
*
* @return
*/
@Delete("delete from c_holiday where date_tag like concat(#{dateTag},'%')")
void delete(@Param("dateTag") String dateTag);
/**
* 刪除指定日期之前的全部記錄
*
* @return
*/
@Delete("delete from c_holiday where date<#{date}")
void clearBefore(@Param("date") String date);
}
Tips:這里使用了MyBatis的注解方式配置蕾殴;未使用Bean,使用Map傳遞數(shù)據(jù)岛啸。
添加年度假期更新服務(wù)處理
在系統(tǒng)啟動(dòng)時(shí)對(duì)假期數(shù)據(jù)進(jìn)行初始化钓觉,如果現(xiàn)在為12月,則連明年的假日數(shù)據(jù)一起初始化坚踩。并增加定時(shí)任務(wù)每月1日定時(shí)調(diào)用此更新服務(wù)處理荡灾,具體流程如下:
Tips:每月更新便于及時(shí)獲取到假期的變化,并在12月就可以更新明年的假期數(shù)據(jù)瞬铸。
Tips:訪問(wèn)第三方接口使用的是apache的httpasyncclient框架批幌。這個(gè)項(xiàng)目我使用的是SpringBoot+Gradle配置,因此加入支持配置為:
//httpClient compile('org.apache.httpcomponents:httpclient:4.5.3') compile('org.apache.httpcomponents:httpasyncclient:4.1.3')
使用@value
注解引入配置連接地址
/**
* 萬(wàn)年歷接口
*/
@Value("${other.juhe.url.holidayMonth}")
private String urlHolidayMonth;
方法:從第三方接口異步獲取月份假期詳情
/**
* 請(qǐng)求第三方接口獲取月份法定假期詳情
*
* @param month
* @return
*/
public List<Map<String,Object>> loadMonthHoliday(String month) throws Exception
{
//發(fā)送異步請(qǐng)求
AsyncClientHttpRequestFactory asyncFactory=new HttpComponentsAsyncClientHttpRequestFactory();
URI uri=new URI(urlHolidayMonth+month);
AsyncClientHttpRequest asynReq=asyncFactory.createAsyncRequest(uri,HttpMethod.GET);
ListenableFuture<ClientHttpResponse> future=asynReq.executeAsync();
ClientHttpResponse response=future.get();
//獲取結(jié)果
InputStream inputStream=response.getBody();
BufferedReader reader=new BufferedReader(new InputStreamReader(inputStream,"UTF-8"));
String strRead=null;
StringBuffer sb=new StringBuffer();
while((strRead=reader.readLine())!=null)
{
sb.append(strRead);
}
String result=sb.toString();
//轉(zhuǎn)成JSON
ObjectMapper objectMapper=new ObjectMapper();
Map<String,Object> json=objectMapper.readValue(result,Map.class);
//解析出結(jié)果是否正確以及data內(nèi)容
Integer code=Integer.parseInt(json.get("error_code")+"");
String reason=json.get("reason")+"";
if(code!=0) throw new Exception(reason);
String holiday=((Map)((Map)json.get("result")).get("data")).get("holiday")+"";
return objectMapper.readValue(holiday,List.class);
}
Tips:注意聚合數(shù)據(jù)返回的holiday字段是個(gè)Json格式的字符串嗓节,要做一下轉(zhuǎn)換荧缘。
方法:生成一年的周末數(shù)據(jù)
/**
* 生成一年的全部假期列表
*
* @return
*/
public Map<String,Map<String,Object>> loadYearWeekly(final String year) throws ParseException
{
//獲取起始日期
final SimpleDateFormat format=new SimpleDateFormat("yyyy-MM-dd");
String startDateString=year+"-01-01";
String endDateString=year+"-12-31";
Date startDate=format.parse(startDateString);
//比較年份起始日和當(dāng)前日期
Date today=new Date();
startDate=(today.getTime()>startDate.getTime())?today:startDate;
//遍歷全年每天,記錄全部周末
Calendar calendar=Calendar.getInstance();
//結(jié)束日為最后一天加一天
calendar.setTime(format.parse(endDateString));
calendar.add(Calendar.DATE,1);
endDateString=format.format(calendar.getTime());
//設(shè)置開始日期
calendar.setTime(startDate);
String curDateString=format.format(startDate);
Date curDate=null;
Map<String,Map<String,Object>> result=new LinkedHashMap<>();
while(!curDateString.equals(endDateString))
{
//當(dāng)前日
curDate=calendar.getTime();
//當(dāng)前日如果為周末拦宣,則記錄結(jié)果
if(calendar.get(Calendar.DAY_OF_WEEK)==Calendar.SATURDAY
|| calendar.get(Calendar.DAY_OF_WEEK)==Calendar.SUNDAY)
{
final Date finalCurDate=curDate;
result.put(format.format(finalCurDate),new LinkedHashMap()
{{
put("date_tag",format.format(finalCurDate));
put("name","周末");
put("year",year);
put("date",finalCurDate);
}});
}
//前進(jìn)一天
calendar.add(Calendar.DATE,1);
curDateString=format.format(calendar.getTime());
}
return result;
}
方法:獲取一年的全部假期數(shù)據(jù)截粗,并從周末數(shù)據(jù)中扣除調(diào)休數(shù)據(jù)
/**
* 通過(guò)第三方接口,生成指定年份全部法定假期鸵隧;并扣除調(diào)休的周末日期
*
* @param year
* @return
* @throws Exception
*/
public Map<String,Map<String,Object>> loadYearHoliday(String year,Map<String,Map<String,Object>> holidayList)
throws Exception
{
//獲取起始日期
final SimpleDateFormat monthFormat=new SimpleDateFormat("yyyy-M");
final SimpleDateFormat readFormat=new SimpleDateFormat("yyyy-M-d");
final SimpleDateFormat writeFormat=new SimpleDateFormat("yyyy-MM-dd");
String startDateString=year+"-1";
String endDateString=year+"-12";
Date startDate=monthFormat.parse(startDateString);
//比較年份起始日和當(dāng)前日期
Date today=new Date();
startDate=(today.getTime()>startDate.getTime())?today:startDate;
//遍歷全年每月桐愉,解析并記錄全部法定假期
Calendar calendar=Calendar.getInstance();
//結(jié)束日為最后一個(gè)月加一個(gè)月
calendar.setTime(monthFormat.parse(endDateString));
calendar.add(Calendar.MONTH,1);
endDateString=monthFormat.format(calendar.getTime());
//設(shè)置開始日期
calendar.setTime(startDate);
String curDateString=monthFormat.format(startDate);
while(!curDateString.equals(endDateString))
{
//獲取當(dāng)前月的法定假日
List<Map<String,Object>> holiday=null;
try
{
holiday=loadMonthHoliday(curDateString);
}
catch(Exception ex)
{
logger.error(ex.getMessage(),ex);
holiday=null;
}
//解析和遍歷結(jié)果
if(holiday!=null)
{
for(Map<String,Object> content : holiday)
{
String name=content.get("name")+"";
for(Map<String,Object> dateMap : ((List<Map<String,Object>>)content.get("list")))
{
int status=Integer.parseInt(dateMap.get("status")+"");
String dateString=dateMap.get("date")+"";
dateString=writeFormat.format(readFormat.parse(dateString));
//增加假期
if(status==1)
{
Map data=new LinkedHashMap();
data.put("date_tag",dateString);
data.put("name",name);
data.put("year",year);
data.put("date",writeFormat.parse(dateString));
holidayList.put(dateString,data);
}
//扣除調(diào)休
if(status==2)
{
holidayList.remove(dateString);
}
}
}
}
//前進(jìn)一個(gè)月
calendar.add(Calendar.MONTH,1);
curDateString=monthFormat.format(calendar.getTime());
}
return holidayList;
}
方法:初始化一年的全部假期
/**
* 載入全年的的假期
*
* @param year
*/
public void loadYearAllHoliday(String year) throws Exception
{
logger.info("Start holiday init!");
Map<String,Map<String,Object>> holidayMap=new LinkedHashMap<>();
//載入當(dāng)前一年的周末
holidayMap.putAll(loadYearWeekly(year));
logger.info("Load all week holiday("+year+"),size:"+holidayMap.size());
//獲取當(dāng)前一年的全部法定假日,并清除調(diào)休
holidayMap=loadYearHoliday(year,holidayMap);
logger.info("Load all holiday("+year+"),size:"+holidayMap.size());
//將全部假期結(jié)果寫入數(shù)據(jù)庫(kù)
clearAndInsert(year,holidayMap);
logger.info("Insert holiday success");
}
/**
* 批量插入假期記錄
*
* @param holidayMap
*/
public void clearAndInsert(String deletePattern,Map<String,Map<String,Object>> holidayMap)
{
//插入前清除數(shù)據(jù)
if(StringUtils.nonEmptyString(deletePattern))
{
holidayMapper.delete(deletePattern);
}
//插入數(shù)據(jù)
for(Map<String,Object> holiday : holidayMap.values())
{
holidayMapper.insert(holiday);
}
}
最后是啟動(dòng)時(shí)數(shù)據(jù)初始化和定時(shí)任務(wù)調(diào)用的處理
/**
* 初始化:獲取今年假期數(shù)據(jù)掰派,初始化假期字典表
* 再根據(jù)系統(tǒng)參數(shù)配置的工作日天數(shù)从诲,計(jì)算出實(shí)際工作日+假期的天數(shù)并記錄
*/
@PostConstruct
public void init() throws Exception
{
//載入今年的假期
SimpleDateFormat format=new SimpleDateFormat("yyyy");
String year=format.format(new Date());
loadYearAllHoliday(year);
//如果當(dāng)前為12月,則明年的假期一起載入
SimpleDateFormat monthFormat=new SimpleDateFormat("MM");
String month=monthFormat.format(new Date());
if("12".equals(month))
{
Calendar calendar=Calendar.getInstance();
calendar.add(Calendar.YEAR,1);
year=format.format(calendar.getTime());
loadYearAllHoliday(year);
}
...
}
Tips:這里代碼并未寫全靡羡,結(jié)尾會(huì)有代碼純凈版系洛。
這樣俊性,假期數(shù)據(jù)就全部載入并記錄到數(shù)據(jù)庫(kù)中,下面就要執(zhí)行計(jì)算了描扯。
當(dāng)前日期后指定工作日后的日期計(jì)算
這里首先考慮實(shí)際上每日的7個(gè)工作日后在當(dāng)天是肯定不會(huì)變的定页,所以不需要在每次創(chuàng)建任務(wù)時(shí)就跑全部流程計(jì)算日期。而是在每日凌晨時(shí)執(zhí)行定時(shí)任務(wù)計(jì)算好7個(gè)工作日實(shí)際間隔的日數(shù)并保存在Redis中绽诚,這樣當(dāng)天創(chuàng)建的任務(wù)可以直接取出間隔計(jì)算限期就好了典徊。
Tips:同時(shí)在系統(tǒng)啟動(dòng)初始化也需計(jì)算此間隔,并記錄在Redis中恩够。
工作日的算法如下:
在今日日期到配置指定的工作日數(shù)量之間卒落,統(tǒng)計(jì)數(shù)據(jù)庫(kù)中這段時(shí)間內(nèi)的假期數(shù)量,如果為0則當(dāng)前指定工作日數(shù)即為實(shí)際天數(shù)蜂桶;如果不為0儡毕,則實(shí)際天數(shù)為當(dāng)前值增加假期數(shù);然后再次統(tǒng)計(jì)增加的這段天數(shù)中的假期數(shù)量扑媚,再次處理腰湾;以此類推,直到統(tǒng)計(jì)假期數(shù)為0疆股。
計(jì)算方法流程如下:
其實(shí)代碼看著要更簡(jiǎn)單些:
/**
* 獲取指定的工作日的實(shí)際天數(shù)
*
* @param workDay
* @return
*/
public Integer calculateRealDay(Date startDate,Integer workDay)
{
SimpleDateFormat format=new SimpleDateFormat("yyyy-MM-dd");
Calendar calendar=Calendar.getInstance();
calendar.setTime(startDate);
//循環(huán)查詢假期數(shù)并增加
Date curStartDate=startDate;
calendar.add(Calendar.DATE,workDay.intValue());
int holidayCount=-1;
while(holidayCount!=0)
{
//查詢假期表
holidayCount=holidayMapper.count(
format.format(curStartDate),
format.format(calendar.getTime()));
if(holidayCount>0)
{
//增加結(jié)果數(shù)
workDay=workDay.intValue()+holidayCount;
//轉(zhuǎn)移開始日期和結(jié)束日期
calendar.add(Calendar.DATE,1);
curStartDate=calendar.getTime();
calendar.add(Calendar.DATE,holidayCount-1);
}
}
return workDay;
}
至此费坊,這個(gè)“簡(jiǎn)單任務(wù)”終于完成了。
代碼純凈版
application.properties
#第三方接口
#聚合數(shù)據(jù)
other.juhe.url.holidayMonth=http://v.juhe.cn/calendar/month?key=我的Key&year-month=
HolidayMapper.java
import org.apache.ibatis.annotations.Delete;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import java.util.Map;
/**
* 對(duì)假期字典表進(jìn)行處理
* Created by maqiang on 2017/6/7.
*/
public interface HolidayMapper
{
/**
* 獲取指定日期間的假期數(shù)量
* @param startDate
* @param endDate
* @return
*/
@Select("select count(date_tag) from c_holiday where date<=#{endDate} and date>=#{startDate}")
Integer count(@Param("startDate") String startDate,@Param("endDate") String endDate);
/**
* 添加或更新一條假期記錄
*
* @param holiday
*/
@Insert("insert into c_holiday("+
"date_tag,"+
"name,"+
"year,"+
"date"+
")VALUES("+
"#{holiday.date_tag},"+
"#{holiday.name},"+
"#{holiday.year},"+
"#{holiday.date}"+
")")
void insert(@Param("holiday") Map<String,Object> holiday);
/**
* 刪除指定日期的假期記錄
*
* @return
*/
@Delete("delete from c_holiday where date_tag like concat(#{dateTag},'%')")
void delete(@Param("dateTag") String dateTag);
/**
* 刪除指定日期之前的全部記錄
*
* @return
*/
@Delete("delete from c_holiday where date<#{date}")
void clearBefore(@Param("date") String date);
}
HolidayService.java
import com.fasterxml.jackson.databind.ObjectMapper;
import com.mchange.v2.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpMethod;
import org.springframework.http.client.AsyncClientHttpRequest;
import org.springframework.http.client.AsyncClientHttpRequestFactory;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.http.client.HttpComponentsAsyncClientHttpRequestFactory;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.ui.ModelMap;
import org.springframework.util.concurrent.ListenableFuture;
import pb.analyzer.data.platform.HolidayMapper;
import javax.annotation.PostConstruct;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URI;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
/**
* 處理假期相關(guān)的業(yè)務(wù)
* Created by maqiang on 2017/6/7.
*/
@Transactional(rollbackFor=Exception.class)
@Service
public class HolidayService
{
//日志
private static final Logger logger=LoggerFactory.getLogger(HolidayService.class);
/**
* 假期字典表管理
*/
@Autowired
HolidayMapper holidayMapper;
/**
* Redis管理(平臺(tái)業(yè)務(wù))
*/
@Autowired
PlatformRedisService platformRedisService;
/**
* 萬(wàn)年歷接口
*/
@Value("${other.juhe.url.holidayMonth}")
private String urlHolidayMonth;
/**
* 初始化:獲取今年假期數(shù)據(jù)旬痹,初始化假期字典表
* 再根據(jù)系統(tǒng)參數(shù)配置的工作日天數(shù)附井,計(jì)算出實(shí)際工作日+假期的天數(shù)并記錄
*/
@PostConstruct
public void init() throws Exception
{
//載入今年的假期
SimpleDateFormat format=new SimpleDateFormat("yyyy");
String year=format.format(new Date());
loadYearAllHoliday(year);
//如果當(dāng)前為12月,則明年的假期一起載入
SimpleDateFormat monthFormat=new SimpleDateFormat("MM");
String month=monthFormat.format(new Date());
if("12".equals(month))
{
Calendar calendar=Calendar.getInstance();
calendar.add(Calendar.YEAR,1);
year=format.format(calendar.getTime());
loadYearAllHoliday(year);
}
//更新系統(tǒng)配置天數(shù)對(duì)應(yīng)的今日的真實(shí)工作日數(shù)
updateRealDay();
logger.info("Holiday init success!");
}
/**
* 載入全年的的假期
*
* @param year
*/
public void loadYearAllHoliday(String year) throws Exception
{
logger.info("Start holiday init!");
Map<String,Map<String,Object>> holidayMap=new LinkedHashMap<>();
//載入當(dāng)前一年的周末
holidayMap.putAll(loadYearWeekly(year));
logger.info("Load all week holiday("+year+"),size:"+holidayMap.size());
//獲取當(dāng)前一年的全部法定假日唱凯,并清除調(diào)休
holidayMap=loadYearHoliday(year,holidayMap);
logger.info("Load all holiday("+year+"),size:"+holidayMap.size());
//將全部假期結(jié)果寫入數(shù)據(jù)庫(kù)
clearAndInsert(year,holidayMap);
logger.info("Insert holiday success");
}
/**
* 生成一年的全部假期列表
*
* @return
*/
public Map<String,Map<String,Object>> loadYearWeekly(final String year) throws ParseException
{
//獲取起始日期
final SimpleDateFormat format=new SimpleDateFormat("yyyy-MM-dd");
String startDateString=year+"-01-01";
String endDateString=year+"-12-31";
Date startDate=format.parse(startDateString);
//比較年份起始日和當(dāng)前日期
Date today=new Date();
startDate=(today.getTime()>startDate.getTime())?today:startDate;
//遍歷全年每天羡忘,記錄全部周末
Calendar calendar=Calendar.getInstance();
//結(jié)束日為最后一天加一天
calendar.setTime(format.parse(endDateString));
calendar.add(Calendar.DATE,1);
endDateString=format.format(calendar.getTime());
//設(shè)置開始日期
calendar.setTime(startDate);
String curDateString=format.format(startDate);
Date curDate=null;
Map<String,Map<String,Object>> result=new LinkedHashMap<>();
while(!curDateString.equals(endDateString))
{
//當(dāng)前日
curDate=calendar.getTime();
//當(dāng)前日如果為周末谎痢,則記錄結(jié)果
if(calendar.get(Calendar.DAY_OF_WEEK)==Calendar.SATURDAY
|| calendar.get(Calendar.DAY_OF_WEEK)==Calendar.SUNDAY)
{
final Date finalCurDate=curDate;
result.put(format.format(finalCurDate),new LinkedHashMap()
{{
put("date_tag",format.format(finalCurDate));
put("name","周末");
put("year",year);
put("date",finalCurDate);
}});
}
//前進(jìn)一天
calendar.add(Calendar.DATE,1);
curDateString=format.format(calendar.getTime());
}
return result;
}
/**
* 通過(guò)第三方接口磕昼,生成指定年份全部法定假期;并扣除調(diào)休的周末日期
*
* @param year
* @return
* @throws Exception
*/
public Map<String,Map<String,Object>> loadYearHoliday(String year,Map<String,Map<String,Object>> holidayList)
throws Exception
{
//獲取起始日期
final SimpleDateFormat monthFormat=new SimpleDateFormat("yyyy-M");
final SimpleDateFormat readFormat=new SimpleDateFormat("yyyy-M-d");
final SimpleDateFormat writeFormat=new SimpleDateFormat("yyyy-MM-dd");
String startDateString=year+"-1";
String endDateString=year+"-12";
Date startDate=monthFormat.parse(startDateString);
//比較年份起始日和當(dāng)前日期
Date today=new Date();
startDate=(today.getTime()>startDate.getTime())?today:startDate;
//遍歷全年每月节猿,解析并記錄全部法定假期
Calendar calendar=Calendar.getInstance();
//結(jié)束日為最后一個(gè)月加一個(gè)月
calendar.setTime(monthFormat.parse(endDateString));
calendar.add(Calendar.MONTH,1);
endDateString=monthFormat.format(calendar.getTime());
//設(shè)置開始日期
calendar.setTime(startDate);
String curDateString=monthFormat.format(startDate);
while(!curDateString.equals(endDateString))
{
//獲取當(dāng)前月的法定假日
List<Map<String,Object>> holiday=null;
try
{
holiday=loadMonthHoliday(curDateString);
}
catch(Exception ex)
{
logger.error(ex.getMessage(),ex);
holiday=null;
}
//解析和遍歷結(jié)果
if(holiday!=null)
{
for(Map<String,Object> content : holiday)
{
String name=content.get("name")+"";
for(Map<String,Object> dateMap : ((List<Map<String,Object>>)content.get("list")))
{
int status=Integer.parseInt(dateMap.get("status")+"");
String dateString=dateMap.get("date")+"";
dateString=writeFormat.format(readFormat.parse(dateString));
//增加假期
if(status==1)
{
Map data=new LinkedHashMap();
data.put("date_tag",dateString);
data.put("name",name);
data.put("year",year);
data.put("date",writeFormat.parse(dateString));
holidayList.put(dateString,data);
}
//扣除調(diào)休
if(status==2)
{
holidayList.remove(dateString);
}
}
}
}
//前進(jìn)一個(gè)月
calendar.add(Calendar.MONTH,1);
curDateString=monthFormat.format(calendar.getTime());
}
return holidayList;
}
/**
* 請(qǐng)求第三方接口獲取月份法定假期詳情
*
* @param month
* @return
*/
public List<Map<String,Object>> loadMonthHoliday(String month) throws Exception
{
//發(fā)送異步請(qǐng)求
AsyncClientHttpRequestFactory asyncFactory=new HttpComponentsAsyncClientHttpRequestFactory();
URI uri=new URI(urlHolidayMonth+month);
AsyncClientHttpRequest asynReq=asyncFactory.createAsyncRequest(uri,HttpMethod.GET);
ListenableFuture<ClientHttpResponse> future=asynReq.executeAsync();
ClientHttpResponse response=future.get();
//獲取結(jié)果
InputStream inputStream=response.getBody();
BufferedReader reader=new BufferedReader(new InputStreamReader(inputStream,"UTF-8"));
String strRead=null;
StringBuffer sb=new StringBuffer();
while((strRead=reader.readLine())!=null)
{
sb.append(strRead);
}
String result=sb.toString();
//轉(zhuǎn)成JSON
ObjectMapper objectMapper=new ObjectMapper();
Map<String,Object> json=objectMapper.readValue(result,Map.class);
//解析出結(jié)果是否正確以及data內(nèi)容
Integer code=Integer.parseInt(json.get("error_code")+"");
String reason=json.get("reason")+"";
if(code!=0) throw new Exception(reason);
String holiday=((Map)((Map)json.get("result")).get("data")).get("holiday")+"";
return objectMapper.readValue(holiday,List.class);
}
/**
* 批量插入假期記錄
*
* @param holidayMap
*/
public void clearAndInsert(String deletePattern,Map<String,Map<String,Object>> holidayMap)
{
//插入前清除數(shù)據(jù)
if(StringUtils.nonEmptyString(deletePattern))
{
holidayMapper.delete(deletePattern);
}
//插入數(shù)據(jù)
for(Map<String,Object> holiday : holidayMap.values())
{
holidayMapper.insert(holiday);
}
}
/**
* 清除今天之前的假期記錄
*/
public void clearBefore()
{
SimpleDateFormat format=new SimpleDateFormat("yyyy-MM-dd");
holidayMapper.clearBefore(format.format(new Date()));
}
/**
* 更新系統(tǒng)配置天數(shù)對(duì)應(yīng)的今日的真實(shí)工作日數(shù)
*/
public void updateRealDay() throws IOException
{
//Redis更新的內(nèi)容自己寫吧
...
}
/**
* 獲取指定的工作日的實(shí)際天數(shù)
*
* @param workDay
* @return
*/
public Integer calculateRealDay(Date startDate,Integer workDay)
{
SimpleDateFormat format=new SimpleDateFormat("yyyy-MM-dd");
Calendar calendar=Calendar.getInstance();
calendar.setTime(startDate);
//循環(huán)查詢假期數(shù)并增加
Date curStartDate=startDate;
calendar.add(Calendar.DATE,workDay.intValue());
int holidayCount=-1;
while(holidayCount!=0)
{
//查詢假期表
holidayCount=holidayMapper.count(
format.format(curStartDate),
format.format(calendar.getTime()));
if(holidayCount>0)
{
//增加結(jié)果數(shù)
workDay=workDay.intValue()+holidayCount;
//轉(zhuǎn)移開始日期和結(jié)束日期
calendar.add(Calendar.DATE,1);
curStartDate=calendar.getTime();
calendar.add(Calendar.DATE,holidayCount-1);
}
}
return workDay;
}
}