涉及接口 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());
...
...
...
}