涉及接口 hotel.incr.order、hotel.order.detail
demo语言: Java
开发环境:
后端 jdk1.7以上、 tomcat8以上、spring + mybatis
非主线程异步轮询调用订单增量接口获取增量,根据增量修改订单表
增量任务类
定义task继承Thread类或实现Runnable接口,实现InitializingBean用以spring容器初始化该任务时可以调用相关方法
@Service public class IncrOrderTask extends Thread implements InitializingBean { @Autowired private IIncrOrderManagerDao incrOrderManagerDao; // 订单增量管理表访问Dao对象 @Autowired private IOrderDao orderDao; // 订单访问Dao对象 @Autowired private HotelIncrOrderApi incrOrderApi; // 订单增量api调用对象 @Autowired private HotelOrderDetailApi hotelOrderDetailApi; // 订单详情访问api对象 ... ... // 重写Thread的run public void run() { while (true) { readTask(); } } ... ... // 初始化bean之后,自动执行此方法,开始执行轮询任务 @Override public void afterPropertiesSet() throws Exception { this.start(); } }
任务实现1
具体增量轮询任务实现, 如果应用部署在单台机器,则只需在新线程进行拉取增量,更新数据。
@Transactional public void readTask() { try { updateOrder(managerDo); sleep(CommonService.INCR_ORDER_FREQUENCY); } catch (Exception e) { // 吃掉异常,避免影响正常业务 logger.error(e); } }
任务实现2
具体增量轮询任务实现, 如果应用部署在多台机器,为了保证增量在单线程拉取,则需要抢占执行
@Transactional public void readTask() { try { IncrOrderManagerDo managerDo = incrOrderManagerDao.getManagerInfo(); // 首先判断是否要抢占更新任务资源 // mac地址为空 或者 心跳时间为1970-01-01 或者 心跳时间超过设置的更新频率 // 间隔的四倍并且在5分钟以上 则认为原有的更新任务死掉了 需要抢占 if (StringUtils.isBlank(managerDo.getMacAddr()) || managerDo.getBeatTime().getTime() == -28800000 || ((new Date().getTime() - managerDo.getBeatTime() .getTime()) / CommonService.INCR_ORDER_FREQUENCY > 4 && (new Date().getTime() - managerDo .getBeatTime().getTime()) / 60000 > 5)) { // 此时需要抢占 Map<String, Object> params = new HashMap<String, Object>(); params.put("newMacAddr", CommonService.MAC_ADDR); params.put("beatTime", new Date()); params.put("oldMacAddr", managerDo.getMacAddr()); incrOrderManagerDao.updateMacAddr(params); } else { // 此时不需要抢占 如果mac地址是本机地址,那么执行更新任务,否则睡眠等待 if (managerDo.getMacAddr().equals(CommonService.MAC_ADDR)) { updateOrder(managerDo); sleep(CommonService.INCR_ORDER_FREQUENCY); } else { sleep(noTaskSleep); } } } catch (Exception e) { // 吃掉异常,避免影响正常业务 logger.error(e); } }
增量api
调用艺龙订单增量api接口
public class HotelOrderIncrApi { private static double version = 1.50; private static EnumLocal locale = EnumLocal.zh_CN; private static boolean isHttps = true; // 测试环境为false,使用http ... ... /** * 通过http工具类调用艺龙接口,将前端参数拼接为URL */ public OrderIncrResult getStateIncr(GetOrderIncrRequest condition, String userName, String appKey, String secretKey) { String url = ""; String responseData = ""; OrderIncrResult result = new OrderIncrResult(); try{ BaseRequest<GetOrderIncrRequest> req = new BaseRequest<GetOrderIncrRequest>(); req.Version = version; req.Local = locale; req.Request = condition; //请求参数转换为Json字符串 String str = JsonUtil.entity2Json(req); //产生签名 long epoch = System.currentTimeMillis()/1000; String sig = Tool.md5(epoch + Tool.md5(str + appKey) + secretKey); //产生请求链接 url = "http"+(this.isHttps ? "s": "")+ "://" + serverHost + "/rest?format=json&method=hotel.incr.order"; url += "&user="+ userName +"×tamp="; url += epoch; url += "&signature="; url += sig; url += "&data=" + Tool.encodeUri(str); //发送请求 responseData = HttpUtil.Send("GET", url, "", "application/json"); //返回值处理 result = JsonUtil.jsonToObject(responseData, OrderIncrResult.class); } catch (Exception e) { log.info("[HotelOrderIncrApi] 异常: " + e); log.info("发送的url: " + url); log.info("返回值: " + responseData); } return result; } ... ... }
更新订单信息
如果有增量,则先请求订单详情接口,根据订单详情更新本地订单信息
private void updateOrder(IncrOrderManagerDo managerDo) { // 先调用订单详情接口 IncrCondition condition = new IncrCondition(); condition.setLastId(managerDo.getLastId()); OrderIncrResult incrResult = null; try { incrResult = incrOrderApi.Invoke(condition); } catch (Exception e) { logger.error(e); } // 更新订单 if (incrResult != null && incrResult.getCode().equals("0") && incrResult.getResult() != null && incrResult.getResult().getOrders() != null && incrResult.getResult().getOrders().size() > 0) { List<Order> orderList = incrResult.getResult().getOrders(); for (int i = 0; i< orderList.size(); i++) { Order order = orderList.get(i); // 创建数据库对象 OrderDo orderDo = new OrderDo(); orderDo.setOrderId(order.getOrderId()); orderDo.setStatus(order.getStatus()); orderDo.setArrivalDate(order.getArrivalDate()); orderDo.setDepartureDate(order.getDepartureDate()); orderDo.setAffiliateConfirmationId(order.getAffiliateConfirmationId()); orderDo.setTotalPrice(order.getTotalPrice().doubleValue()); orderDo.setRoomNum(order.getNumberOfRooms()); orderDo.setPayStatus(order.getPayStatus()); ... ... ... }