通过定时器推送入园人数
最近有个需求,需要对接某景区大数据,推送入园游客数。
解决思路就是在每天的22点推送一次当天的入园人数,然后获取大数据的入园人数。
首先先在controller层写接口,作为推送记录测试。
Controller层代码
@RestController
@Api(tags = "智游天府码(政务云)对接 接口服务")
@RequestMapping("/tourism/platform")
@Slf4j
public class TourismPlatformController {
@Autowired
private TourismPlatformOutPersonCountJobExecutor tourismPlatformOutPersonCountJobExecutor;
@PostMapping("/log")
@ApiOperation(value = "推送记录测试",notes = "推送记录测试")
@IgnoreUserToken
public RespVO<Object> getTodayInPersonCount() throws Exception{
String param = "";
ReturnT<String> result = this.tourismPlatformOutPersonCountJobExecutor.execute(param);
return RespVO.onSuc(result);
}
}
以上代码中,所使用到的注解解释如下:
@RestController:@ResponseBody和@Controller两个注解的合体。标注在类上,表示:这个Controller类的所有方法返回的数据直接写给浏览器。
@Api: 用在类上,说明该类的作用。可以标记一个 Controller 类作为 Swagger 文档资源。
@Request Mapping : 在 Spring MVC 应用程序中,注解RequestDispatcher (在 Front Controller 之下) 这个 servlet 负责将进入的 HTTP 请求路由到控制器的处理方法。
在对 Spring MVC 进行的配置的时候, 你需要指定请求与处理方法之间的映射关系。 要配置 Web 请求的映射,就需要你用上 @RequestMapping 注解。
@RequestMapping 注解可以在控制器类的级别和/或其中的方法的级别上使用。 在类的级别上的注解会将一个特定请求或者请求模式映射到一个控制器之上。之后你还可以另外添加方法级别的注解来进一步指定到处理方法的映射关系。
@Autowired: 当 Spring 容器启动时,AutowiredAnnotationBeanPostProcessor 将扫描 Spring 容器中所有 Bean,当发现 Bean 中拥有 @Autowired 注释时就找到和其匹配(默认按类型匹配)的 Bean,并注入到对应的地方中去。
@PostMapping: 开发过程IDEA提示如将@RequestMapping(value="/abc" , method = “RequestMethod.POST”)替换成@PostMapping。现对@PostMapping的实现。@PostMapping是一个复合注解,Spring framework 4.3引入了@RequestMapping注释的变体,以更好地表示带注释的方法的语义,作为@RequestMapping(method = RequestMethod.POST)的快捷方式。也就是可以简化成@PostMapping(value="/abc" )即可,主要是方便识记。
接着写定时器业务代码
定时器代码
@JobHandler(value = "tourismPlatformOutPersonCountJobExecutor")
@Component
@Slf4j
public class TourismPlatformOutPersonCountJobExecutor extends IJobHandler{
@Value("${provincial.tourism.platform.privateKey}")
private String privateKey;
@Value("${provincial.tourism.platform.resourceCode}")
private String resourceCode;
@Value("${provincial.tourism.platform.resourceType}")
private String resourceType;
@Value("${provincial.tourism.platform.url}")
private String url;
//TickCheckPersonInOutCountDO inOutCountDO = new TickCheckPersonInOutCountDO();
// private String sign = privateKey + resourceType + resourceCode + DateUtil.format(new Date(),"yyyy-MM-dd HH:mm") + inOutCountDO.getInPersonCount().toString();
@Autowired
private ITickCheckTicketLogRpcService tickCheckTicketLogRpcService;
@Override
public ReturnT<String> execute(String param) throws Exception {
log.info("智游天府码(政务云)-当天实时累计游客量推送数据定时器【开始】================>");
/**获取业务数据*/
InOutCountVO inPersonCount;
Map<String, JSONObject> pushResult = null;
if(StrUtil.isBlank(param)){
inPersonCount = this.getPushBusinessData(new Date());
} else{
Date paramDate = null;
try {
paramDate = DateUtil.parse(param, "yyyy-MM-dd");
}catch (Exception e){
throw new Exception("参数格式不正确,正确格式为:yyyy-MM-dd,例如2019-11-25");
}
inPersonCount = this.getPushBusinessData(paramDate);
}
log.info("开始推送数据----->");
//数据转换
JSONObject body = this.transformVOToJson(inPersonCount);
//推送业务数据
pushResult = this.pushBusinessInfo(body);
log.info("<-----推送数据结束");
/**保存上送记录*/
// ProvincialTourismPushLogDO pushLogDO = this.provincialTourismPushLogManager.getTodayInPersonCountPushLog();
// if(pushLogDO == null){
// ProvincialTourismPushLogDO provincialTourismPushLogDO = new ProvincialTourismPushLogDO();
// provincialTourismPushLogDO.setStatus(TrueOrFalseEnum.TRUE.getCode());
// provincialTourismPushLogDO.setPushType(PushTypeEnum.TODAY_IN_PERSON_COUNT.getCode());
// provincialTourismPushLogDO.setPushDateTime(DateUtil.parseDateTime(DateUtil.format(new Date(),"yyyy-MM-dd HH:mm:ss")));
// provincialTourismPushLogDO.setPushDateLog(DateUtil.parseDate(DateUtil.format(new Date(),"yyyy-MM-dd")));
// this.provincialTourismPushLogManager.save(provincialTourismPushLogDO);
// }else {
// pushLogDO.setStatus(TrueOrFalseEnum.TRUE.getCode());
// pushLogDO.setPushType(PushTypeEnum.TODAY_IN_PERSON_COUNT.getCode());
// pushLogDO.setPushDateTime(DateUtil.parseDateTime(DateUtil.format(new Date(),"yyyy-MM-dd HH:mm:ss")));
// pushLogDO.setPushDateLog(DateUtil.parseDate(DateUtil.format(new Date(),"yyyy-MM-dd")));
// this.provincialTourismPushLogManager.updateById(pushLogDO);
// }
/** 返回值处理 */
ReturnT<String> result = new ReturnT<>();
result.setContent("推送内容:" + pushResult);
log.info("推送内容:" + pushResult);
result.setMsg(pushResult.toString());
log.info("<================推送数据定时器【结束】");
result.setCode(ReturnT.SUCCESS_CODE);
return result;
}
/**
* 获取业务数据
* @param date
* @return*/
private InOutCountVO getPushBusinessData(Date date) {
DateTime beginDate = DateUtil.truncate(date, DateField.HOUR_OF_DAY);
DateTime endDate = DateUtil.ceiling(date, DateField.HOUR_OF_DAY);
InOutCountVO personInOutCountDO = new InOutCountVO();
InOutCountVO inPersonCount = tickCheckTicketLogRpcService.getInPersonCount(beginDate, endDate);
if(inPersonCount == null){
personInOutCountDO.setInCount(0);
//personInOutCountDO.setInOutDate(DateUtil.parseDate(DateUtils.formatDate(new Date(),"yyyy-MM-dd HH:mm")));
//personInOutCountDO.set(0);
}
Integer inPersonSum = 0;
List<InOutCountVO> inOutCountVOS = Collections.singletonList(tickCheckTicketLogRpcService.getInPersonCount(beginDate, endDate));
for(InOutCountVO tickCheckPersonInOutCountDO : inOutCountVOS){
inPersonSum = inPersonSum+tickCheckPersonInOutCountDO.getInCount();
}
personInOutCountDO.setInCount(inPersonSum);
log.info("需要推送的入园人数有:" + inPersonSum);
return personInOutCountDO;
}
/**
* 数据转换(VO转为接口所要推送的json结构数据)
* @return String
*/
private JSONObject transformVOToJson(InOutCountVO inOutCountDO){
JSONObject jsonObject = new JSONObject();
jsonObject.put("resourceType",resourceType);
jsonObject.put("resourceCode",resourceCode);
jsonObject.put("total",inOutCountDO.getInCount().toString());
jsonObject.put("date",DateUtil.format(new Date(),"yyyy-MM-dd HH:mm"));
jsonObject.put("sign",privateKey + resourceType + resourceCode + DateUtil.format(new Date(),"yyyy-MM-dd HH:mm") + inOutCountDO.getInCount().toString());
return jsonObject;
}
/**
* 推送业务数据
* @param body
* @return
*/
private Map<String, JSONObject> pushBusinessInfo(JSONObject body) {
JSONObject pushResult = null;
try {
log.info("上报body内容:" + body);
pushResult = this.dayInCountTotal(body);
log.info("上送body后返回值:" + pushResult.get("code"));
if("200".equals(pushResult.get("code"))){
pushResult.put("status", "success");
}
}catch (Exception e) {
log.info("上送异常,异常code-:" + pushResult.get("msg")+ ",原因为-" + pushResult.get("code"));
// //保存失败记录
// ProvincialTourismPushLogDO pushLogDO = new ProvincialTourismPushLogDO();
// pushLogDO.setPushDateLog(DateUtil.parse(DateUtil.format(new Date(),"yyyy-MM-dd")));
// pushLogDO.setPushDateTime(DateUtil.parse(DateUtil.format(new Date(),"yyyy-MM-dd HH:mm:ss")));
// pushLogDO.setPushType(PushTypeEnum.TODAY_IN_PERSON_COUNT.getCode());
// pushLogDO.setStatus(TrueOrFalseEnum.FALSE.getCode());
// this.provincialTourismPushLogManager.save(pushLogDO);
pushResult = new JSONObject();
pushResult.put("message", pushResult.get("msg"));
pushResult.put("status", "error");
e.printStackTrace();
}
/**相应结果处理*/
Map<String, JSONObject> result = new HashMap<>();
result.put("params", body);
result.put("result", pushResult);
return result;
}
/**
*
* @param jsonBody
* @param
* @return
* @throws
*/
private JSONObject dayInCountTotal(JSONObject jsonBody ){
/**推送数据*/
HttpResponse response = HttpRequest.post(url)
.body(String.valueOf(jsonBody))
//.header("sign",sign)
.timeout(2000)
.execute();
System.out.println(response.getStatus());
JSONObject resultRecord = JSONObject.parseObject(response.body());
// log.info("日累计游客量返回值为:" + resultRecord.toString());
return resultRecord;
}
}
很好理解,通过log日志记录推送情况->获取业务数据->数据转换->推送业务数据->返回值处理
其中,获取业务数据需要单独写一个类方法进行处理,数据转换也需要单独写一个类方法处理,同样的推送业务数据也需要一个单独的类方法。
值得注意的是,数据转换中,需要传入请求参数,请求参数需要根据对应的接口文档来写。
我这里需要用的请求参数有五个,resourceType,resourceCode,total,date,sign。
其中,resourceType、resourceCode已经配置在yml配置文件中,通过@Value注解进行取值。total需要通过InOutCountVO出入园统计输出参数VO类获取。date用DateUtil.format(new Date(),“yyyy-MM-dd HH:mm”)获取。sign需要根据接口文档进行获取对应的值。
最后,推送数据获取请求的时候,我这里通过HttpResponse response = HttpRequest.post(url)方法请求url,其中url为接口文档提供。
ITickCheckTicketLogRpcService服务层接口代码
public interface ITickCheckTicketLogRpcService {
/**
* 按时间段统计出入园数据
* @param beginDateTime 开始时间
* @param endDateTime 结束时间
* 开始时间的日期作为查询日期
* @return
*/
InOutCountVO getInPersonCount(Date beginDateTime,Date endDateTime);
紧接着写服务层接口对应的实现类代码
@Service
public class TickCheckTicketLogRpcServiceImpl implements ITickCheckTicketLogRpcService {
@Autowired
private ITickCheckTicketLogManager tickCheckTicketLogManager;
@Override
public InOutCountVO getInPersonCount(Date beginDateTime,Date endDateTime) {
//第一种写法:
//Date startDate = DateUtil.beginOfDay(date);
//Date endDate = DateUtil.endOfDay(date);
//QueryWrapper<TickCheckPersonInOutCountDO> wrapper = new QueryWrapper<TickCheckPersonInOutCountDO>();
//wrapper.between("in_out_date", startDate,endDate);
//return super.list(wrapper);
//第二种写法:
String beginTime=DateUtil.formatTime(beginDateTime);
String endTime=DateUtil.formatTime(endDateTime);
return tickCheckTicketLogManager.getInPersonCount(DateUtil.beginOfDay(beginDateTime),beginTime,endTime);
}
}
以上基本代码就写完了,接下来就开始写操作数据库的manager数据操作层代码
manager数据操作代码
public interface ITickCheckTicketLogManager extends IService<TickCheckTicketLogDO> {
InOutCountVO getInPersonCount(Date Date, String beginTime, String endTime);
}
对应的impl代码
@Service
public class TickCheckTicketLogManagerImpl extends ServiceImpl<TickCheckTicketLogDao, TickCheckTicketLogDO> implements ITickCheckTicketLogManager {
@Override
public InOutCountVO getInPersonCount(Date date, String beginTime, String endTime) {
return this.baseMapper.getInPersonCount(date,beginTime,endTime);
}
}
Dao层代码
@Mapper
public interface TickCheckTicketLogDao extends BaseMapper<TickCheckTicketLogDO> {
InOutCountVO getInPersonCount(@Param("date")Date date,@Param("beginTime")String beginTime,@Param("endTime")String endTime);
}
然后最后一步就是通过xml文件从数据库获取汇总数据:
SELECT
inoutlog.*,
inoutlog.inCount - inoutlog.outCount AS presentCount
FROM
(
SELECT
IFNULL(inlog.inCount, 0) AS inCount,
IFNULL(outLog.outCount, 0) AS outCount
FROM
(
SELECT
SUM(check_person) AS inCount
FROM
jt_check_ticket_log
WHERE
check_date = #{date}
and check_time BETWEEN #{beginTime} and #{endTime}
) inlog
JOIN (
SELECT
SUM(check_person) AS outCount
FROM
jt_check_person_leave_log
WHERE
check_date = #{date}
and check_time BETWEEN #{beginTime} and #{endTime}
) outLog
) inoutlog
结果如下: