对接顺丰开放平台查询物流路由信息


最近项目中需要用到查询快递信息的功能,像各个快递公司查询快递一样,显示时间节点和地点,即路由信息(轨迹)。最简单省事的方法自然是云市场买接口次数,但本着能白嫖就白嫖的原则,自然是要使用免费的。

一、准备工作

  1. 进入顺丰开放平台注册账号并登录。

  2. 进入控制台——开发者对接——认证(第一次使用需要认证,个人认证的话只需要身份证即可)

  3. 认证完成后进入控制台——开发者对接——新建应用,新建后点击关联API,选择路由查询接口
    在这里插入图片描述

  4. 保存顾客编码沙箱校验码生产校验码,后续会使用,若忘了保存可在开发者对接中点击应用详情查看

二、测试

  1. 进入沙箱工具——API测试工具,选择沙箱环境,输入沙箱校验码,选择API名称(即刚刚关联的路由API)在这里插入图片描述

  2. 提交测试

  3. 滚动屏幕,下面有API请求结果,出现以下结果,说明测试成功
    在这里插入图片描述

  4. 回到顶部,点击接口文档,找到路由查询接口接口-速运类API

  5. 根据这些参数,我们来组装POST请求,可以使用SDK也可不使用

非SDK方式

通过HuTool工具类发送请求,其中的ExpressConstants是自己建的常量类,里面定义了顺丰的顾客编码、校验码之类的。若是只是在自己的项目中使用顺丰,则没必要另外建了,直接用字符串即可。
若不使用HuTool工具类也可,根据以下代码自行修改
沙箱环境地址和生产环境地址在API-SDK的开发文档

//沙箱环境的地址
private static final String CALL_URL_BOX = "https://sfapi-sbox.sfexpress.com/std/service";
//生产环境的地址
private static final String CALL_URL_PROD = "https://sfapi.sfexpress.com/std/service";

引入HuTool工具类

<!--hutool工具类-->
<dependency>
    <groupId>cn.hutool</groupId>
    <artifactId>hutool-all</artifactId>
    <version>5.8.11</version>
</dependency>

编写实现类

import cn.hutool.core.lang.UUID;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson2.JSONObject;
import com.erp.admin.service.ExpresService;
import com.erp.common.constant.ExpressConstants;
import com.erp.common.core.domain.AjaxResult;
import com.erp.common.exception.ServiceException;
import com.erp.common.utils.DateUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.binary.Base64;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.security.GeneralSecurityException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

@Slf4j
@Service
public class ExpresServiceImpl implements ExpresService {
    /**
     * 查询物流路由信息
     * @param expressNum 运单号
     * @param phoneNumber 手机号后四位
     * @return
     * @throws IOException
     * @throws GeneralSecurityException
     */
    @Override
    public AjaxResult queryRoutes(String expressNum,String phoneNumber) throws IOException, GeneralSecurityException {
        if (expressNum == null || expressNum.isEmpty() || phoneNumber== null || phoneNumber.isEmpty()){
            throw new ServiceException("运单号/手机号不能为空!");
        }
        String result;
        //顺丰运单号正则
        String sfRegex = ExpressConstants.SF_CODE_RULE;
        //设置正则不区分大小写
        Pattern sfPattern = Pattern.compile(sfRegex, Pattern.CASE_INSENSITIVE);
        Matcher sfMatcher = sfPattern.matcher(expressNum);
        if(sfMatcher.matches()){
            result = querySFExpress(expressNum, phoneNumber);
            //返回参数中,routes为空,则运单号不正确
            Map routeRespsMap = (Map) JSONObject.parseObject(result).getJSONArray("routeResps").get(0);
            List<Map> routesList = (List<Map>)routeRespsMap.get("routes");
            if (routesList == null || routesList.isEmpty()){
                throw new ServiceException("运单号或手机号不正确!");
            }
            //按照时间逆序排列  顺丰返回的是按时间顺序排列的,而一般显示路由信息是逆序排列
            routesList.sort(Comparator.comparing(route -> String.valueOf(route.getOrDefault("acceptTime", 0).toString()), Comparator.reverseOrder()));
            return AjaxResult.success("SF",routesList);
        }else {
            throw new ServiceException("运单号或手机号不正确!");
        }
    }

    /**
     * 查询顺丰物流路由信息
     */
    private String querySFExpress(String expressNum,String phoneNumber) throws NoSuchAlgorithmException {
        String timeStamp = DateUtils.parseDateToStr("yyyyMMddHHmmssSSS",new Date());
        JSONObject msgDataJson = new JSONObject();
        msgDataJson.put("language","0");
        msgDataJson.put("trackingType","1");
        msgDataJson.put("trackingNumber",expressNum);
        msgDataJson.put("methodType","1");
        msgDataJson.put("checkPhoneNo",phoneNumber);
        String msgData = JSONUtil.toJsonStr(msgDataJson);
        //md5加密摘要
        String encryptStr;
        try {
            encryptStr = URLEncoder.encode(msgData + timeStamp + ExpressConstants.SF_CHECK_WORD_PROD, "UTF-8");
        } catch (UnsupportedEncodingException e) {
            throw new RuntimeException(e);
        }
        MessageDigest md5 = MessageDigest.getInstance("MD5");
        md5.update(encryptStr.getBytes(StandardCharsets.UTF_8));
        String msgDigest = (new Base64()).encodeAsString(md5.digest());

        //创建Http POST请求对象
        HttpRequest get = HttpUtil.createPost(ExpressConstants.SF_CALL_URL_BOX);
        Map<String,String> headers = new HashMap<>();
        headers.put("appCode", ExpressConstants.SF_CLIENT_CODE);
        headers.put("timestamp", timeStamp);
        headers.put("Content-Type", "application/x-www-form-urlencoded;charset=utf-8");
        //设置请求头
        get.addHeaders(headers);
        //设置参数
        get.form("partnerID",ExpressConstants.SF_CLIENT_CODE)
                .form("requestID", UUID.randomUUID().toString().replace("-", ""))
                .form("serviceCode", "EXP_RECE_SEARCH_ROUTES")
                .form("timestamp", timeStamp)
                .form("msgData", msgData)
                .form("msgDigest",msgDigest);
        String body = get.execute().body();

        JSONObject msgDataResult = JSONObject.parseObject(body)
                .getJSONObject("apiResultData")
                .getJSONObject("msgData");
        return msgDataResult.toString();
    }
}

常量类

/**
 * 查询物流路由常量
 */
public class ExpressConstants
{
    /**顺丰顾客编码*/
    public static final String SF_CLIENT_CODE = "******";
    /**顺丰生产校验码*/
    public static final String SF_CHECK_WORD_PROD = "**********";
    /**顺丰沙箱校验码*/
    public static final String SF_CHECK_WORD_DEV = "***********";
    /**顺丰沙箱环境的地址 -PRO*/
    public static final String SF_CALL_URL_BOX = "*********************";
    /**顺丰生产环境的地址 -PRO*/
    public static final String SF_CALL_URL_PROD = "********************";
    /**顺丰运单号正则表达式*/
    public static final String SF_CODE_RULE = "^[A-Za-z0-9-]{4,35}$";
}

SDK方式

  1. 进入丰桥API-SDK(JAVA)使用说明
  2. 下载SDK
  3. 根据PDF文档编写代码在这里插入图片描述
  4. 主要问题是jar包不好引入,我是用的是idea,每次引入完之后刷新maven就需要重新引入,打包时也打不进去,网上方法找遍了,都不好使,只能手动将外部jar包引入本地仓库

三、上线

API需要先完成接口配置后才可以联调测试,API在沙箱环境7天内成功调用三次以上才可申请上线

在沙箱调用成功三次之后就可以点击开发者对接—查看API,点击后面的上线,即可完成上线。

四、Tips

  • 顺丰API可以查询任何人的快递信息,另外有调用次数,生产环境500000次/日,测试环境2000次/日
  • 手机号是收件人或寄件人的后四位,两个手机号都可以查到
  • 若公司有月结卡号的话,可以绑定月结卡号,这样就只需要物流单号就可以查询了,但必须是用月结下的单才可以。
    在这里插入图片描述
  • 26
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

仰望星空的打工人

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值