【快递100功能开发】系统模块集成快递订阅推送服务(二)——定时扫描快递单号,批量订阅

配置 account.properties

resources目录下新建account.properties文件

该文件,是快递100接口扫描账号信息的文件,具体代码可以查看 PropertiesReader
在这里插入图片描述
account.properties文件内容如下:

#快递100的基础账号信息,可以在这里获取
# https://poll.kuaidi100.com/manager/page/myinfo/enterprise
key = RI9X9Ah9cXAWq69X9A066
customer = 9FAF61DDB3F5DC91DDBE61DDB80C11DDBCE
secret = eec334c30bc349c3c9b60c311c3431c36
userid = 6136983402942534171f54d56386799389
#回调地址(写上真实的回调地址)
url = http://localhost:8080/express/data/callback
#开通行政区域解析功能以及物流轨迹增加物流状态值
resultv2 = 1
#是否记录快递100接口返回结果,建议记录日志或者入库,方便后期有问题双方排查(true:启用 false: 关闭 )
log.return.record = false

修改主启动

主启动类上增加注解@EnableScheduling,开启对定时任务的支持

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.scheduling.annotation.EnableScheduling;

@EnableScheduling
@EnableDiscoveryClient
@SpringBootApplication
public class ExpressApplication {
    public static void main(String[] args) {
        SpringApplication.run(ExpressApplication.class, args);
    }
}

创建定时任务

SysExpressController.java

/**
 * @author layman
 * @description: 快递100接口
 * @date 2021/11/22
 */
@RestController
@RequestMapping("/express/data")
public class SysExpressController{


    @Autowired
    private ISysExpressService expressService;

    /**
     * 该接口为自动订阅接口
     * 每隔15分钟扫描sys_express表中,距今一个月,状态为未签收,订阅状态为未成功的快递单
     * 然后批量向快递100注册推送服务
     */
    @Scheduled(cron = "0 0/15 * * * ?")
    public void autoSubscribe() throws Exception {
        System.out.println("每隔15分钟执行一次:" + new Date());
        // 获取距今一个月内,所有未签收,且未订阅推送的快递单
        List<SysExpress> allExpress = expressService.selectNotCheckAndNotSign();

        if(allExpress != null && allExpress.size() > 0){
            // 订阅快递信息推送服务
            expressService.subscribe(allExpress);
        }
    }

    /**
     * 快递100回调接口
     * @param request
     */
    @PostMapping("/callback")
    public SubscribeResp callBack(HttpServletRequest request) throws Exception {
        return expressService.handleCallBack(request);
    }

SysExpressServiceImpl 实现类

/**
 * @author layman
 * @description: 快递100接口服务类
 * @date 2021/11/23
 */
@Service
public class SysExpressServiceImpl implements ISysExpressService {


    protected final Logger logger = LoggerFactory.getLogger(this.getClass());

    @Autowired
    private SysExpressInfoMapper expressInfoMapper;

    @Autowired
    private SysExpressMapper expressMapper;

    @Autowired
    private SysExpressDataMapper expressDataMapper;

    // 授权key
    private String key = PropertiesReader.get("key");
    private String customer = PropertiesReader.get("customer");
    // 接口回调地址
    private String callbackUrl = PropertiesReader.get("url");
    // 开启行政区域解析
    private String resultv2 = PropertiesReader.get("resultv2");

    /**
     * 订阅快递信息推送服务
     * @param allExpress 快递单集合
     */
    @Override
    @Transactional
    public void subscribe(List<SysExpress> allExpress) throws Exception {

        //附加参数信息(回调地址,签名,是否开启行政区域解析等)
        SubscribeParameters parameter = getSubscribeParameters();

        // 设置参数(设置key)
        SubscribeParam param = getSubscribeParam(parameter);

        // 设置请求参数
        SubscribeReq request = getSubscribeReq();

        // 设置请求接口
        IBaseClient subscribe = new Subscribe();

        for (SysExpress express : allExpress) {
            param.setCompany(express.getCompanyCode());
            param.setNumber(express.getExpressNum());

            request.setParam(ChangeToJson(param));

            // 订阅推送服务
            HttpResult httpResult = subscribe.execute(request);

            SubscribeResp response = new Gson().fromJson(httpResult.getBody(), SubscribeResp.class);

            String returnCode = response.getReturnCode();
            if("501".equals(returnCode)){
                // 重复订阅的请求,不改变订阅成功的状态,只保存报文(以防误操作)
                express.setSubStatus(200L);
            }else{
                express.setSubStatus(Long.valueOf(returnCode));
            }
            express.setSubParam(request.getParam());
            express.setSubResult(httpResult.getBody());

            expressMapper.updateSysExpress(express);
        }
    }

    /**
     * 处理快递100推送请求并响应
     *
     * @param request 快递100的推送请求
     * @return 响应
     */
    @Override
    @Transactional
    public SubscribeResp handleCallBack(HttpServletRequest request) throws Exception {
        // 获取参数
        String param = request.getParameter("param");
        String sign = request.getParameter("sign");

        // 解析报文
        SubscribePushParamResp backResp = new Gson().fromJson(param, SubscribePushParamResp.class);
        handleResponse(param,backResp);
        
        return getSubscribeResp();
    }

    /**
     * 业务处理
     */
    @Transactional
    public void handleResponse(String param,SubscribePushParamResp backResp) throws Exception {

        // 每次推送的报文,都要入库,方便出问题后排查
        String expressNum = backResp.getLastResult().getNu();
        SysExpressData expressData = new SysExpressData();
        expressData.setExpressNum(expressNum);
        expressData.setReceiveText(param);
        expressData.setStatus("0");
        expressDataMapper.insertSysExpressData(expressData);

        // 业务处理
        SysExpress express = expressMapper.selectSysExpressByNum(expressNum);

        //当message为“3天查询无记录”或“60天无变化时”status= abort,处理逻辑是重新订阅推送服务
        if("abort".equals(backResp.getStatus().trim())){
            express.setRemark("status= abort,重新订阅推送服务");
            List<SysExpress> expressList = new ArrayList<>();
            expressList.add(express);
            subscribe(expressList);
        }
        // shutdown说明快递被签收,推送服务中止
        if("shutdown".equals(backResp.getStatus().trim())){
            express.setStatus(3L);
            expressMapper.updateSysExpress(express);
        }
        // 获取data数据集,解析后存入数据库
        List<SubscribePushData> dataList = backResp.getLastResult().getData();
        List<SysExpressInfo> infoList = new ArrayList<>();
        for (SubscribePushData data : dataList) {
            SysExpressInfo info = new SysExpressInfo();
            info.setCompanyCode(backResp.getLastResult().getCom());
            info.setContext(data.getContext());
            info.setExpressNum(expressNum);
            info.setStatus(data.getStatus());
            info.setTime(DateUtils.parseDate(data.getFtime()));

            infoList.add(info);
        }
        if(infoList.size() > 0){
       		 // 入库操作前,先删除sys_express_info表中的数据,只保留最新数据。
            expressInfoMapper.deleteSysExpressInfoByNum(expressNum);
            expressInfoMapper.insertSysExpressBatch(infoList);
        }
    }
    public SubscribeParameters getSubscribeParameters(){
        SubscribeParameters parameter = new SubscribeParameters();
        // 设置回调地址,在account.properties中配置
        parameter.setCallbackurl(callbackUrl);
        //开通行政区域解析功能以及物流轨迹增加物流状态值
        parameter.setResultv2(resultv2);
        return parameter;
    }

    public SubscribeParam getSubscribeParam(SubscribeParameters parameter){
        SubscribeParam param = new SubscribeParam();
        param.setKey(key);
        param.setParameters(parameter);
        return param;
    }

    public SubscribeReq getSubscribeReq(){
        SubscribeReq request = new SubscribeReq();
        request.setSchema(ApiInfoConstant.SUBSCRIBE_SCHEMA);
        return request;
    }

    public SubscribeResp getSubscribeResp(){
        SubscribeResp response = new SubscribeResp();
        response.setResult(Boolean.TRUE);
        response.setReturnCode("200");
        response.setMessage("成功");
        return response;
    }

    public String ChangeToJson(Object src) {
       return new Gson().toJson(src);
    }
    /**
     * 查询所有未签收且未订阅成功的快递单号
     *
     * @return 快递单集合
     */
    @Override
    public List<SysExpress> selectNotCheckAndNotSign() {
        return expressMapper.selectNotCheckAndNotSign();
    }
}

expressMapper.selectNotCheckAndNotSign的SQL如下:

	<sql id="selectSysExpressVo">
        select express_id, express_num, company_code, status, sub_status, sub_param, sub_result, create_time, sub_time, remark from sys_express
    </sql>
    
	<select id="selectNotCheckAndNotSign" parameterType="SysExpress" resultMap="SysExpressResult">
        <include refid="selectSysExpressVo"/> where status = 400
            and sub_status != 200
            and create_time >= date_add(now(),interval -30 DAY)
    </select>

代码逻辑

  • 订阅服务
  1. 每隔15分钟,从sys_express扫描近一个月内,状态为未签收且订阅状态为未订阅的快递单集合
  2. 遍历该集合,向快递100批量订阅推送服务
  3. 将订阅推送的请求参数,返回参数,订阅状态,订阅时间更新到数据库,方便日后排查问题
  • 回调服务
  1. 开放8080端口,接收回调请求
  2. 快递100调用回调请求,传回的报文,首先进行入库操作(回调报文,接收时间)
  3. 解析报文,如果status=abort,则重新订阅推送,如果status=shutdown,则说明快递被签收
  4. 如果快递被签收,则更新sys_express表中的状态,下次不再扫描。
  5. 获取data数据集,解析后存入集合
  6. 如果集合中物流轨迹信息存在,则先删除轨迹表sys_express_info中对应快递单号的数据。
  7. 然后遍历集合,进行入库操作(保证数据库中的数据永远为最新数据)
  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值