package com.chinacreator.process.job; import com.chinacreator.common.exception.BusinessException; import com.chinacreator.common.util.DESUtil; import com.chinacreator.common.util.MD5; import com.chinacreator.process.dao.BackBusiVipAsynDao; import com.chinacreator.process.dao.DictionaryDao; import com.chinacreator.process.util.HttpInvoke; import com.chinacreator.process.util.JsonUtil; import com.chinacreator.process.util.URLUtil; import org.apache.log4j.Logger; import org.quartz.DisallowConcurrentExecution; import org.quartz.PersistJobDataAfterExecution; import org.springframework.beans.factory.annotation.Autowired; import java.net.URLEncoder; import java.text.SimpleDateFormat; import java.util.*; import java.util.concurrent.*; /** * 后向送会员异步处理 * @author xu.zhou * @date 20200818 */ @PersistJobDataAfterExecution @DisallowConcurrentExecution public class BackBusiVipAsynJob { private static Logger logger = Logger.getLogger("backbusivipsyn"); @Autowired private BackBusiVipAsynDao asyndao; @Autowired private DictionaryDao dictionaryDao; public void doProcess() throws Exception { String trycount = dictionaryDao.getValue("vipasyntrycount");//后向产品赠送会员异步处理重试次数 if(trycount == null || "".equals(trycount)) trycount = "3"; logger.info(Thread.currentThread().getName()+"定时任务开始"); long beginTime = System.currentTimeMillis(); List list = asyndao.getVipAsynData(trycount); if(list != null && list.size() > 0){ //推送月份 String pushmonth = new SimpleDateFormat("yyyyMM").format(new Date()); CountDownLatch threadSignal = new CountDownLatch(list.size()); ExecutorService executorService = new ThreadPoolExecutor(12, 16, 10L, TimeUnit.MINUTES, new LinkedBlockingQueue(), new ThreadPoolExecutor.CallerRunsPolicy()); List dataList = paraseData(list); logger.info("数据库有效订购的用户数:"+dataList.size()); for(HashMap vipmap : dataList){ BackBusiVipSynService continueService = new BackBusiVipSynService(list.size(),threadSignal,vipmap,asyndao,dictionaryDao); executorService.execute(continueService); } executorService.shutdown(); try { executorService.awaitTermination(5L, TimeUnit.MINUTES); } catch (InterruptedException e) { e.printStackTrace(); } } logger.info(Thread.currentThread().getName()+"定时任务完成,耗时:"+(System.currentTimeMillis()-beginTime)/1000+" 秒"); } /** * 去除重复数据,防止赠送会员接口被并发限制 * @param dataList * @return */ private List paraseData(List dataList){ //去重复后的数据集 List reDataList = new ArrayList(); HashMap tmpMap = new HashMap(); for (HashMap dataMap : dataList) { if(tmpMap.containsKey(dataMap.get("USERID").toString()+dataMap.get("CPID")+dataMap.get("SPID"))){ logger.info("重复数据,"+dataMap.get("USERID")+dataMap.get("CPID")+dataMap.get("SPID")); }else{ reDataList.add(dataMap); List tmpList = new ArrayList(); tmpList.add(dataMap.get("SPID")); tmpMap.put(dataMap.get("USERID").toString()+dataMap.get("CPID")+dataMap.get("SPID"), tmpList); } } return reDataList; } } class BackBusiVipSynService implements Runnable { private static Logger log = Logger.getLogger("backbusivipsyn"); private int totalSize; private CountDownLatch threadSignal; private HashMap vipmap; private DictionaryDao dictionaryDao; private BackBusiVipAsynDao asyndao; public BackBusiVipSynService(int totalSize,CountDownLatch threadSignal,HashMap vipmap,BackBusiVipAsynDao asyndao,DictionaryDao dictionaryDao){ this.totalSize = totalSize; this.threadSignal = threadSignal; this.vipmap = vipmap; this.asyndao = asyndao; this.dictionaryDao = dictionaryDao; } @Override public void run() { long startime = System.currentTimeMillis(); Map logMap = new HashMap(); String id = vipmap.get("ID").toString(); logMap.put("vipmap", vipmap); String resultcode = "-1"; String errorinfo = ""; String vipsendcode = "3"; //赠送会员结果标识,默认为失败 try { //更新为正在赠送状态 asyndao.updVipSendStatus(id); HashMap remap = sendVip(); if("0".equals(remap.get("vipsendcode"))){ resultcode = "0"; vipsendcode = "0"; errorinfo = "赠送成功"; }else{ resultcode = remap.get("vipsendcode"); errorinfo = remap.get("vipsendinfo"); } } catch (Exception e) { if (e instanceof BusinessException) { errorinfo = ((BusinessException) e).getMessage(); resultcode = ((BusinessException) e).getCode(); }else{ e.printStackTrace(); resultcode = "8000"; errorinfo = "处理数据出现异常,"+e.getMessage(); } }finally { threadSignal.countDown(); String time = System.currentTimeMillis()-startime+""; try{ //更新赠送会员结果出现异常 asyndao.updVipSendStatus(id, vipsendcode, time); }catch(Exception e){ log.error(vipmap.get("USERID")+"更新赠送会员结果出现异常,"+e.getMessage()); } //回调 callBack(resultcode, errorinfo); //发送成功短信 inserSmstMq(resultcode); //写日志 logMap.put("resultcode", resultcode); logMap.put("errorinfo", errorinfo); logMap.put("time", time); logMap.put("count", totalSize+"/"+(totalSize - threadSignal.getCount())); log.info(JsonUtil.objectToJson(logMap)); } } /** * 推送办理成功的短信到队列 * @param orderInfo */ private void inserSmstMq(String resultcode){ try{ //赠送成功才发短信 if(!"0".equals(resultcode)) return; String userid = vipmap.get("USERID").toString(); if(userid == null || userid.length() != 11) return; String channel = vipmap.get("CHANNEL").toString(); String cpid = vipmap.get("CPID").toString(); String spid = vipmap.get("SPID").toString(); Map map = new HashMap(); map.put("userid", userid); map.put("cpid", cpid); map.put("spid", spid); map.put("result", "0"); map.put("channel", ""); map.put("style","0000"); map.put("times", ""); map.put("orderType", ""); map.put("type", "cssms"); map.put("busiType", "tran_succ"); //订购成功短信 if("TX20_twback_qc".equals(channel)){//女王卡领取会员发短信,同样的SPID短信内容不同 map.put("busiType", "qc_tran_succ"); } String mqReciveUrl = dictionaryDao.getValue("mqReciveUrl"); URLUtil.post(mqReciveUrl, JsonUtil.objectToJson(map)); //部分业务要发三条短信 if(!"TX20_twback_qc".equals(channel)){ map.put("busiType", "tran_succ2"); //订购成功短信 } URLUtil.post(mqReciveUrl, JsonUtil.objectToJson(map)); if(!"TX20_twback_qc".equals(channel)){ map.put("busiType", "tran_succ3"); //订购成功短信 } URLUtil.post(mqReciveUrl, JsonUtil.objectToJson(map)); }catch (Exception e){ e.printStackTrace(); log.info(vipmap.get("ID")+",发送成功短信失败"); } } /** * 调接口送会员 * @param orderInfo * @return * @throws Exception */ private HashMap sendVip() throws Exception{ HashMap remap = new HashMap(); String vipsendcode = "3"; //默认失败 String vipsendinfo = "赠送失败"; try { //http://114.255.201.228:86/activity/youkuHX String vipurl = this.dictionaryDao.getValue("backBusiVipUrl"); String timestamp = (System.currentTimeMillis() / 1000) + ""; String userid = vipmap.get("USERID").toString(); String orderid = vipmap.get("ORDERID").toString(); String channel = vipmap.get("CHANNEL").toString(); String cpid = vipmap.get("CPID").toString(); String spid = vipmap.get("SPID").toString(); String pwd = ""; List confList = asyndao.getBackBusiConf(cpid, spid); pwd = confList.get(0).get("PWD").toString(); if("0".equals(confList.get(0).get("HASFH"))){ //是复合产品 vipurl = this.dictionaryDao.getValue("backBusiGroupVipUrl"); } userid = DESUtil.encode(userid, pwd); //MD5(orderid+userid+goodscode+pwd+timestamp)转换为十六进制ASCII 码字符串,共32 个字符,全小写 userid= Des(手机号码,pwd) //MD5(orderid+userid+timestamp+pwd)转换为十六进制ASCII 码字符串,共32 个字符,全小写 String signature = MD5.MD5Encode(orderid + userid + timestamp + pwd); signature = signature.toLowerCase(); vipurl = vipurl + "?userid=" + URLEncoder.encode(userid, "utf-8")+ "&orderid="+ orderid + "&cpid=" + cpid + "&spid=" + spid + "×tamp=" + timestamp + "&signature=" + signature+ "&apptype=2"; log.info("vipurl: "+vipurl); //http://114.255.201.228:86/activity/eshop/vip?userid=iafPbU9aRLghY%2FEVMXFeag%3D%3D&orderid=201906231206498662914&goodscode=pointshop130×tamp=1561445765&signature=47fe0e3900b29ef88fd0889b7c0e4cc6&apptype=5 String result = URLUtil.get(vipurl,30*1000); //调赠送会员接口,超时时间设置为10秒 log.info("赠送会员重试结果=> userid: " +userid+", orderid: "+orderid+" , result: "+result); Map map = JsonUtil.jsonToMap(result); //resultcode = (String)map.get("resultcode"); // if("0".equals(map.get("resultcode"))){ // vipsendcode = "0"; // } vipsendcode = map.get("resultcode")+""; vipsendinfo = map.get("errorinfo")+""; } catch (Exception e) { e.printStackTrace(); log.error("userid: "+vipmap.get("USERID")+"赠送会员失败,"+e); if(e.getMessage() != null && e.getMessage().indexOf("TimeoutException") != -1){//超时异常 throw new BusinessException("9070","赠送会员超时", new String[0]); }else{ throw new BusinessException("9002","赠送会员未成功", new String[0]); } } remap.put("vipsendcode", vipsendcode); remap.put("vipsendinfo", vipsendinfo); return remap; } /** * 回调通知 * @param orderBean * @return 0成功,1未回调,2出现异常 */ private String callBack(String resultcode, String resultinfo){ String res = "1"; try { String trycountconf = dictionaryDao.getValue("vipasyntrycount"); String trycount = vipmap.get("RETRYCOUNT").toString(); String userid = vipmap.get("USERID").toString(); String orderid = vipmap.get("ORDERID").toString(); String channel = vipmap.get("CHANNEL").toString(); String id = vipmap.get("ID").toString(); //判断重试是否已是最大次数 if(!"0".equals(resultcode) && Integer.parseInt(trycount)+1 < Integer.parseInt(trycountconf)){ return null; } //当会员赠送失败时,反查一下会员赠送日志表,看是否真的赠送失败,防止调接口超时获取不到真实赠送结果 if(!"0".equals(resultcode)){ if(asyndao.getVipSendRes(orderid)){ resultcode = "0"; resultinfo = "OK"; } } HashMap channelInfo = asyndao.getChannelPwdByChannel(channel); String pwd = channelInfo.get("PASSWORD")+""; userid = DESUtil.encode(userid, pwd); userid = URLEncoder.encode(userid, "utf-8"); String vipRetryCallBackUrl = this.dictionaryDao.getValue("vipRetryCallBackUrl");//回调接口地址 vipRetryCallBackUrl += "?orderid="+orderid+"&resultcode="+resultcode+"&resultinfo="+URLEncoder.encode(resultinfo,"utf-8")+"&userid="+userid; log.info("===========回调地址:"+vipRetryCallBackUrl); String result = HttpInvoke.sendhttpsReq("GET", vipRetryCallBackUrl, "", null, 60*1000, "TLSv1.2"); //String result = URLUtil.get(vipRetryCallBackUrl,60*1000); //调赠送会员接口,超时时间设置为10秒 log.info("回调通知接口返回信息=>userid: " +userid+", orderid: "+orderid+", result: "+result); Map map = JsonUtil.jsonToMap(result); res = (String)map.get("result"); } catch (Exception e) { res = "2"; e.printStackTrace(); log.error("id=>"+vipmap.get("ID")+",回调接口出现异常,"+e.getMessage()); } return res; } }