Java之各平台快递对接

韵达快递、安能快递、百世快递、中国邮政快递、EMS、德邦快递、极兔快递、顺丰快递、申通快递、众邮快递、圆通快递、中通快递
 
Express接口类 

public interface Express {
    /**
     * 快递编码
     *
     * @return String
     */
    String expressCode();

    /**
     * 根据快递编码相关信息查询快递信息
     *
     * @param request 请求参数
     * @return ExpressSearchResponse
     * @throws NoSuchAlgorithmException
     */
    ExpressSearchResponse logisticsSearch(ExpressSearchRequest request) throws NoSuchAlgorithmException;
}

SelectExpress类

import org.springframework.boot.CommandLineRunner;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.HashMap;
import java.util.Map;

@Service
public class SelectExpress implements CommandLineRunner {
    @Resource
    private ApplicationContext applicationContext;

    private Map<String, Express> expressMap = new HashMap<>();

    /**
     * 根据名字返回相应的实现类
     *
     * @param code 快递公司编码
     * @return 实现类
     */
    public Express get(String code) {
        return expressMap.get(code);
    }

    @Override
    public void run(String... args) throws Exception {
        applicationContext.getBeansOfType(Express.class).values()
                .forEach(express -> expressMap.put(express.expressCode(), express));
    }
}

ExpressSearchRequest请求类

import io.swagger.annotations.ApiModelProperty;
import lombok.Data;

import java.io.Serializable;

@Data
public class ExpressSearchRequest implements Serializable {
    private static final long serialVersionUID = -880253965590928905L;
    @ApiModelProperty(value = "真实物流单号")
    private String logisticsNo;
    @ApiModelProperty(value = "物流公司名称", hidden = true)
    private String expressName;
    @ApiModelProperty(value = "物流公司编码", hidden = true)
    private String expressCode;
    @ApiModelProperty(value = "订单编码", hidden = true)
    private String orderNo;
    @ApiModelProperty(value = "收件人姓名", hidden = true)
    private String receiverName;
    @ApiModelProperty(value = "收件人手机号", hidden = true)
    private String receiverMobile;
    @ApiModelProperty(value = "收人地址:省份名称", hidden = true)
    private String provinceName;
    @ApiModelProperty(value = "收人地址:地市名称", hidden = true)
    private String cityName;
    @ApiModelProperty(value = "收人地址:区县名称", hidden = true)
    private String districtName;
    @ApiModelProperty(value = "收件人详细地址", hidden = true)
    private String detailAddress;
}

 ExpressSearchResponse返回类

import io.swagger.annotations.ApiModelProperty;
import lombok.Data;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;

@Data
public class ExpressSearchResponse implements Serializable {
    private static final long serialVersionUID = 8570085965157271803L;
    @ApiModelProperty("快递公司名称")
    private String logisticsName = "";
    @ApiModelProperty("快递单号")
    private String logisticsNo = "";
    @ApiModelProperty("描述")
    List<ExpressDescDTO> descList = new ArrayList<>();
}

ExpressDescDTO返回类子类 

import io.swagger.annotations.ApiModelProperty;
import lombok.Data;

import java.io.Serializable;

@Data
public class ExpressDescDTO implements Serializable {
    private static final long serialVersionUID = 2774275564551643616L;
    @ApiModelProperty("轨迹描述")
    private String desc = "";
    @ApiModelProperty("日期")
    private String date = "";
}

 ResponseController返回结果封装类

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.jumi.microservice.warehouse.entity.dto.ExpressDescDTO;
import com.jumi.microservice.warehouse.entity.dto.ExpressSearchRequest;
import com.jumi.microservice.warehouse.entity.dto.ExpressSearchResponse;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

public class ResponseController {

    /**
     * 校验返回结果
     *
     * @param jsonArray json数组
     * @param request   请求参数
     * @return ExpressSearchResponse
     */
    public ExpressSearchResponse checkResult(JSONArray jsonArray, ExpressSearchRequest request) {
        ExpressSearchResponse expressSearchResponse = new ExpressSearchResponse();
        expressSearchResponse.setLogisticsName(request.getExpressName());
        expressSearchResponse.setLogisticsNo(request.getLogisticsNo());
        if (jsonArray == null || jsonArray.isEmpty()) {
            expressSearchResponse.setDescList(new ArrayList<>());
        }
        return expressSearchResponse;
    }

    /**
     * 组装返回实体类
     *
     * @param expressSearchResponse 返回信息
     * @param jsonArr               json数组
     * @param descKey               描述
     * @param dateKey               时间
     * @return 组装返回实体类
     */
    public ExpressSearchResponse controller(ExpressSearchResponse expressSearchResponse, JSONArray jsonArr,
                                            String descKey, String dateKey) {
        if (jsonArr == null || jsonArr.isEmpty()) {
            return expressSearchResponse;
        }
        List<ExpressDescDTO> list = new ArrayList<>();
        for (Object j : jsonArr) {
            JSONObject json = JSONObject.parseObject(j.toString());
            ExpressDescDTO expressDescDTO = new ExpressDescDTO();
            if (json.getString(descKey) == null || json.getString(dateKey) == null) {
                return expressSearchResponse;
            }
            expressDescDTO.setDesc(json.getString(descKey));
            expressDescDTO.setDate(json.getString(dateKey));
            list.add(expressDescDTO);
        }
        list = list.stream().sorted(Comparator.comparing(ExpressDescDTO::getDate).reversed()).collect(Collectors.toList());
        expressSearchResponse.setDescList(list);
        return expressSearchResponse;
    }

    /**
     * 组装返回实体类
     *
     * @param expressSearchResponse 返回信息
     * @param jsonArr               json数组
     * @param descKey               描述
     * @param dateKey               时间
     * @return 组装返回实体类
     */
    public ExpressSearchResponse controllerZto(ExpressSearchResponse expressSearchResponse, JSONArray jsonArr,
                                               String descKey, String dateKey) {
        if (jsonArr == null || jsonArr.isEmpty()) {
            return expressSearchResponse;
        }
        List<ExpressDescDTO> list = new ArrayList<>();
        for (Object j : jsonArr) {
            JSONObject json = JSONObject.parseObject(j.toString());
            ExpressDescDTO expressDescDTO = new ExpressDescDTO();
            if (json.getString(descKey) == null || json.getString(dateKey) == null) {
                return expressSearchResponse;
            }
            expressDescDTO.setDesc(json.getString(descKey));
            expressDescDTO.setDate(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date(Long.parseLong(json.getString(dateKey)))));
            list.add(expressDescDTO);
        }
        list = list.stream().sorted(Comparator.comparing(ExpressDescDTO::getDate).reversed()).collect(Collectors.toList());
        expressSearchResponse.setDescList(list);
        return expressSearchResponse;
    }
}

通用查询快递方法 

    /**
     * 查询快递
     *
     * @param sn   快递单号
     * @param name 快递公司名称
     * @param code 快递公司编码
     * @return 结果
     */
    public ExpressSearchResponse queryExpress(String sn, String name, String code) {

        ExpressSearchResponse response;
        if (StringUtils.isBlank(sn)) {
            return new ExpressSearchResponse();
        }
        Express express = selectExpress.get(code);
        ExpressSearchRequest request = new ExpressSearchRequest();
        request.setExpressName(name);
        request.setLogisticsNo(sn);
        request.setExpressCode(code);
        return express.logisticsSearch(request);
    }

 HttpClientUtils工具类 

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.util.Map;
import java.util.Set;

@Component
public class HttpClientUtils {
    /**
     * http get
     *
     * @param url   可带参数的 url 链接
     * @param heads http 头信息
     */
    public String get(String url, Map<String, String> heads) {
        org.apache.http.client.HttpClient httpClient = HttpClients.createDefault();
        HttpResponse httpResponse = null;
        String result = "";
        HttpGet httpGet = new HttpGet(url);
        if (heads != null) {
            Set<String> keySet = heads.keySet();
            for (String s : keySet) {
                httpGet.addHeader(s, heads.get(s));
            }
        }
        try {
            httpResponse = httpClient.execute(httpGet);
            HttpEntity httpEntity = httpResponse.getEntity();
            if (httpEntity != null) {
                result = EntityUtils.toString(httpEntity, "utf-8");
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return result;
    }

    /**
     * http post
     */
    public String post(String url, String data, Map<String, String> heads) {
        org.apache.http.client.HttpClient httpClient = HttpClients.createDefault();
        HttpResponse httpResponse = null;
        String result = "";
        HttpPost httpPost = new HttpPost(url);
        if (heads != null) {
            Set<String> keySet = heads.keySet();
            for (String s : keySet) {
                httpPost.addHeader(s, heads.get(s));
            }
        }
        try {
            StringEntity s = new StringEntity(data, "utf-8");
            httpPost.setEntity(s);
            httpResponse = httpClient.execute(httpPost);
            HttpEntity httpEntity = httpResponse.getEntity();
            if (httpEntity != null) {
                result = EntityUtils.toString(httpEntity, "utf-8");
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return result;
    }
}

 MD5工具类

import com.google.common.collect.Maps;
import org.springframework.stereotype.Component;

import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.util.Map;
import java.util.concurrent.locks.ReentrantLock;


@Component
public class MD5 {
    private static int DIGITS_SIZE = 16;
    private static char[] digits = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};

    private static Map<Character, Integer> rDigits = Maps.newHashMapWithExpectedSize(16);

    static {
        for (int i = 0; i < digits.length; ++i) {
            rDigits.put(digits[i], i);
        }
    }

    private static MD5 me = new MD5();
    private MessageDigest mHasher;
    private ReentrantLock opLock = new ReentrantLock();

    private MD5() {
        try {
            mHasher = MessageDigest.getInstance("md5");
        } catch (Exception e) {
            throw new RuntimeException(e);
        }

    }

    public static MD5 getInstance() {
        return me;
    }

    public String getMD5String(String content) {
        return bytes2string(hash(content));
    }

    public String getMD5String(byte[] content) {
        return bytes2string(hash(content));
    }

    public byte[] getMD5Bytes(byte[] content) {
        return hash(content);
    }

    /**
     * 对字符串进行md5
     *
     * @param str
     * @return md5 byte[16]
     */
    public byte[] hash(String str) {
        opLock.lock();
        try {
            byte[] bt = mHasher.digest(str.getBytes(StandardCharsets.UTF_8));
            if (null == bt || bt.length != DIGITS_SIZE) {
                throw new IllegalArgumentException("md5 need");
            }
            return bt;
        } finally {
            opLock.unlock();
        }
    }

    /**
     * 对二进制数据进行md5
     *
     * @param data
     * @return md5 byte[16]
     */
    public byte[] hash(byte[] data) {
        opLock.lock();
        try {
            byte[] bt = mHasher.digest(data);
            if (null == bt || bt.length != DIGITS_SIZE) {
                throw new IllegalArgumentException("md5 need");
            }
            return bt;
        } finally {
            opLock.unlock();
        }
    }

    /**
     * 将一个字节数组转化为可见的字符串
     *
     * @param bt
     * @return
     */
    public String bytes2string(byte[] bt) {
        int l = bt.length;
        char[] out = new char[l << 1];
        for (int i = 0, j = 0; i < l; i++) {
            out[j++] = digits[(0xF0 & bt[i]) >>> 4];
            out[j++] = digits[0x0F & bt[i]];
        }
        return new String(out);
    }
}

MD5加密工具类

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import java.security.MessageDigest;

@Component
public class Md5Utils {
    private static final Logger log = LoggerFactory.getLogger(Md5Utils.class);

    private static byte[] md5(String s) {
        MessageDigest algorithm;
        try {
            algorithm = MessageDigest.getInstance("MD5");
            algorithm.reset();
            algorithm.update(s.getBytes("UTF-8"));
            byte[] messageDigest = algorithm.digest();
            return messageDigest;
        } catch (Exception e) {
            log.error("MD5 Error...", e);
        }
        return null;
    }

    private static final String toHex(byte hash[]) {
        if (hash == null) {
            return null;
        }
        StringBuffer buf = new StringBuffer(hash.length * 2);
        int i;
        for (i = 0; i < hash.length; i++) {
            if ((hash[i] & 0xff) < 0x10) {
                buf.append("0");
            }
            buf.append(Long.toString(hash[i] & 0xff, 16));
        }
        return buf.toString();
    }

    public static String hash(String s) {
        try {
            return new String(toHex(md5(s)).getBytes("UTF-8"), "UTF-8");
        } catch (Exception e) {
            log.error("not supported charset...{}", e);
            return s;
        }
    }
}

pom.xml——>引入顺丰、申通、众邮快递SDK。引入谷歌工具包:调用com.google.common.collect.Maps。

        <dependency>
                <groupId>com.express</groupId>
            <artifactId>lop-zhongyou-api-sdk</artifactId>
            <version>2.0.0</version>
            <scope>compile</scope>
        </dependency>
        <dependency>
            <groupId>com.express</groupId>
            <artifactId>sf-csim-express-sdk</artifactId>
            <version>2.0.0</version>
            <scope>compile</scope>
        </dependency>
        <dependency>
            <groupId>com.express</groupId>
            <artifactId>sto-link-sdk</artifactId>
            <version>2.0.0</version>
            <scope>compile</scope>
        </dependency>
        <dependency>
            <groupId>com.google.guava</groupId>
            <artifactId>guava</artifactId>
            <version>22.0</version>
         </dependency>

 韵达快递——>接收OrderInfo类

import lombok.Data;

@Data
public class OrderInfo {
    private String orderid;
    private String mailno;
    private UserInfo sender;
    private UserInfo receiver;
}

 韵达快递——>接收子类UserInfo类 

import lombok.Data;

@Data
public class UserInfo {
    private String name;
    private String province;
    private String city;
    private String county;
    private String address;
    private String phone;
    private String mobile;
}

例1:YdExpress——>韵达快递

import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import OrderInfo;
import UserInfo;
import ExpressSearchRequest;
import ExpressSearchResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * 韵达
 */
@Service
public class YdExpress extends ResponseController implements Express {
    private static final Logger log = LoggerFactory.getLogger(YdExpress.class);
    private static final String TRACK_SERVER_URL = "https://openapi.yundaex.com/openapi/outer/logictis/subscribe";
    private static final String SERVER_URL = "https://openapi.yundaex.com/openapi/outer/logictis/query";
    private static final String APP_KEY = "123456";
    private static final String APP_SECRET = "e10adc3949ba59abbe56e057f20f883e";
    @Resource
    private RedisTemplate redisTemplate;
    private static final String LOGISTICS_TRACK = "logistics::track:{}";

    @Override
    public String expressCode() {
        return "YD";
    }

    @Override
    public ExpressSearchResponse logisticsSearch(ExpressSearchRequest request) {
        log.info("韵达快递查询参数[{}]", JSON.toJSONString(request));
        JSONArray jsonArray = new JSONArray();
        String logisticsTrack = StrUtil.format(LOGISTICS_TRACK, request.getLogisticsNo());
        boolean isTrack = false;
        try {
            if (!redisTemplate.hasKey(logisticsTrack)) {
                //物流轨迹订阅
                String orderid = request.getOrderNo();
                String mailno = request.getLogisticsNo();

                String senderName = request.getReceiverName();
                String senderProvince = request.getProvinceName();
                String senderCity = request.getCityName();
                String senderCounty = request.getDistrictName();
                String senderAddress = request.getDetailAddress();
                String senderPhone = request.getReceiverMobile();
                String senderMobile = request.getReceiverMobile();

                String receiverName = request.getReceiverName();
                String receiverProvince = request.getProvinceName();
                String receiverCity = request.getCityName();
                String receiverCounty = request.getDistrictName();
                String receiverAddress = request.getDetailAddress();
                String receiverPhone = request.getReceiverMobile();
                String receiverMobile = request.getReceiverMobile();

                List<OrderInfo> orderInfoList = new ArrayList<>();
                OrderInfo orderInfo = new OrderInfo();
                orderInfo.setOrderid(orderid);
                orderInfo.setMailno(mailno);
                //发货人信息
                UserInfo userInfoSender = new UserInfo();
                userInfoSender.setName(senderName);
                userInfoSender.setProvince(senderProvince);
                userInfoSender.setCity(senderCity);
                userInfoSender.setCounty(senderCounty);
                userInfoSender.setAddress(senderAddress);
                userInfoSender.setPhone(senderPhone);
                userInfoSender.setMobile(senderMobile);
                orderInfo.setSender(userInfoSender);
                //接收人信息
                UserInfo userInfoReceiver = new UserInfo();
                userInfoReceiver.setName(receiverName);
                userInfoReceiver.setProvince(receiverProvince);
                userInfoReceiver.setCity(receiverCity);
                userInfoReceiver.setCounty(receiverCounty);
                userInfoReceiver.setAddress(receiverAddress);
                userInfoReceiver.setPhone(receiverPhone);
                userInfoReceiver.setMobile(receiverMobile);
                orderInfo.setReceiver(userInfoReceiver);
                orderInfoList.add(orderInfo);
                String orders = "{\"orders\":" + JSONObject.toJSONString(orderInfoList) + "}";
                String resTrack = doPostJson(TRACK_SERVER_URL, orders);
                JSONObject jsonObjTrack = JSON.parseObject(resTrack);
                if (jsonObjTrack.getBoolean("result")) {
                    redisTemplate.expire(logisticsTrack, 60, TimeUnit.DAYS);
                    isTrack = true;
                }
            }
            if (isTrack) {
                String sourceContent = "{\"mailno\":\"" + request.getLogisticsNo() + "\"}";
                String res = doPostJson(SERVER_URL, sourceContent);
                log.info("请求返回结果[{}]", res);
                JSONObject jsonObj = JSON.parseObject(res);
                if (jsonObj.containsKey("data")) {
                    JSONObject json = jsonObj.getJSONObject("data");
                    if (json.containsKey("steps")) {
                        jsonArray = json.getJSONArray("steps");
                    }
                }
            }
        } catch (Exception e) {
            log.error("韵达快递查询出错[{}]", e.getMessage());
        }
        ExpressSearchResponse expressSearchResponse = checkResult(jsonArray, request);
        log.info("请求返回[{}]", JSON.toJSONString(controller(expressSearchResponse, jsonArray, "description", "time")));
        return controller(expressSearchResponse, jsonArray, "description", "time");
    }

    /**
     * 发送HTTP请求
     *
     * @param apiUrl     请求URL
     * @param jsonParams 请求参数
     * @return String
     */
    private static String doPostJson(String apiUrl, String jsonParams) {
        StringBuffer sbResult = new StringBuffer();
        try {
            URL url = new URL(apiUrl);
            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
            conn.setDoOutput(true);
            conn.setDoInput(true);
            conn.setUseCaches(false);
            conn.setRequestMethod("POST");
            conn.setRequestProperty("Connection", "Keep-Alive");
            conn.setRequestProperty("Charset", "UTF-8");
            byte[] data = jsonParams.getBytes(StandardCharsets.UTF_8);
            conn.setRequestProperty("Content-Length", String.valueOf(data.length));
            conn.setRequestProperty("Content-Type", "application/json");
            conn.setRequestProperty("app-key", YdExpress.APP_KEY);
            conn.setRequestProperty("req-time", String.valueOf(System.currentTimeMillis()));
            conn.setRequestProperty("sign", MD5(jsonParams + "_" + YdExpress.APP_SECRET));
            conn.connect();
            OutputStream out = new DataOutputStream(conn.getOutputStream());
            out.write(data);
            out.flush();
            out.close();
            if (200 == conn.getResponseCode()) {
                InputStream inputStream = conn.getInputStream();
                try {
                    String readLine = null;
                    BufferedReader responseReader = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8));

                    while ((readLine = responseReader.readLine()) != null) {
                        sbResult.append(readLine).append("\n");
                    }

                    responseReader.close();
                } catch (Exception var12) {
                    var12.printStackTrace();
                }
            }
        } catch (Exception var13) {
            var13.printStackTrace();
        }
        return sbResult.toString();
    }

    /**
     * Md5加密算法
     *
     * @param str
     * @return
     * @throws Exception
     */
    private static String MD5(String str) throws Exception {
        MessageDigest md = MessageDigest.getInstance("MD5");
        md.update(str.getBytes(StandardCharsets.UTF_8));
        byte[] result = md.digest();
        StringBuffer sb = new StringBuffer(32);
        for (int i = 0; i < result.length; ++i) {
            int val = result[i] & 255;
            if (val <= 15) {
                sb.append("0");
            }
            sb.append(Integer.toHexString(val));
        }
        return sb.toString().toLowerCase();
    }
}

例2:AneExpress——>安能快递

import cn.hutool.core.codec.Base64;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.http.HttpRequest;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import ExpressSearchRequest;
import ExpressSearchResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import java.security.NoSuchAlgorithmException;

/**
 * 安能
 **/
@Service
public class AneExpress extends ResponseController implements Express {
    private static final Logger log = LoggerFactory.getLogger(AneExpress.class);
    private static String URL = "http://opc.ane56.com/aneop/services/logisticsQuery/new/query";
    private static String APPKEY = "e10adc3949ba59abbe56e057f20f883e";
    private static String CODE = "ANENG";

    @Override
    public String expressCode() {
        return "ANE";
    }

    @Override
    public ExpressSearchResponse logisticsSearch(ExpressSearchRequest request) throws NoSuchAlgorithmException {
        log.info("安能快递查询参数[{}]", JSON.toJSONString(request));
        JSONArray jsonArray = new JSONArray();
        try {
            JSONObject jsonObject = new JSONObject();
            JSONObject params = new JSONObject();
            params.put("ewbNo", request.getLogisticsNo());
            jsonObject.put("params", params.toJSONString());
            String digest = Base64.encode(SecureUtil.md5("{\"ewbNo\":\"" + request.getLogisticsNo() + "\"}" + CODE + APPKEY));
            jsonObject.put("digest", digest);
            jsonObject.put("code", CODE);
            String timestamp = Long.toString(System.currentTimeMillis());
            jsonObject.put("timestamp", timestamp);
            String res = HttpRequest.post(URL).header("Content-type", "application/json").body(jsonObject.toJSONString()).execute().body();
            log.info("请求返回结果[{}]", res);
            JSONObject resObject = JSONObject.parseObject(res);
            jsonArray = resObject.getJSONObject("resultInfo").getJSONArray("traces");
        } catch (Exception e) {
            log.error("安能快递查询出错[{}]", e.getMessage());
        }
        ExpressSearchResponse expressSearchResponse = checkResult(jsonArray, request);
        log.info("请求返回[{}]", JSON.toJSONString(controller(expressSearchResponse, jsonArray, "desc", "operateTime")));
        return controller(expressSearchResponse, jsonArray, "desc", "operateTime");
    }
}

例3:BestExpress——>百世快递

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import ExpressSearchRequest;
import ExpressSearchResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.HashMap;
import java.util.Map;

/**
 * 百世
 */
@Service
public class BestExpress extends ResponseController implements Express {

    private static final Logger log = LoggerFactory.getLogger(BestExpress.class);
    private static String url = "http://edi-q9.ns.800best.com/kd/api/process";
    private static String partnerKey = "49ba59abbe56";
    private static String partnerID = "12345";
    private static String serviceType = "KD_TRACE_QUERY";
    @Resource
    HttpClientUtils httpClientUtils;

    @Override
    public String expressCode() {
        return "HTKY";
    }

    @Override
    public ExpressSearchResponse logisticsSearch(ExpressSearchRequest request) {
        log.info("百世快递查询参数[{}]", JSON.toJSONString(request));
        JSONArray jsonArr = null;
        ExpressSearchResponse expressSearchResponse = null;
        try {
            //拼接请求头
            Map<String, String> headers = new HashMap<>(4);
            headers.put("accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");
            headers.put("connection", "keep-alive");
            headers.put("user-agent", "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:34.0) Gecko/20100101 Firefox/34.0");
            headers.put("Content-Type", "application/x-www-form-urlencoded;charset=UTF-8");
            //组建数据格式
            String bizData = "{\"mailNos\": {\"mailNo\": [\"" + request.getLogisticsNo() + "\"]}}";
            String sign = Md5Utils.hash(bizData + partnerKey);
            String requestData = "partnerID=" + partnerID + "&serviceType=" + serviceType + "&bizData=" + bizData + "&sign=" + sign;
            //发送请求并接受返回
            String res = httpClientUtils.post(url, requestData, headers);
            log.info("请求返回结果[{}]", res);
            JSONObject json = JSONObject.parseObject(res);
            jsonArr = json.getJSONArray("traceLogs");
            //处理返回结果
            jsonArr = jsonArr.getJSONObject(0).getJSONObject("traces").getJSONArray("trace");
        } catch (Exception e) {
            log.error("百世快递查询出错[{}]", e.getMessage());
        }
        expressSearchResponse = checkResult(jsonArr, request);
        log.info("请求返回[{}]", JSON.toJSONString(controller(expressSearchResponse, jsonArr, "remark", "acceptTime")));
        return controller(expressSearchResponse, jsonArr, "remark", "acceptTime");
    }
}

例4:中国邮政快递——>ChinaPostExpress【线下联系邮政快递人员开通账号信息】

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import ExpressSearchRequest;
import ExpressSearchResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.HashMap;
import java.util.Map;

/**
 * 中国邮政
 */
@Service
public class ChinaPostExpress extends ResponseController implements Express {
    private static final Logger log = LoggerFactory.getLogger(ChinaPostExpress.class);
    @Resource
    HttpClientUtils httpClientUtils;

    @Override
    public String expressCode() {
        return "YZPY";
    }

    @Override
    public ExpressSearchResponse logisticsSearch(ExpressSearchRequest request) {
        log.info("邮政快递包裹查询参数[{}]", JSON.toJSONString(request));
        JSONArray jsonArray = null;
        try {
            String url = "http://211.156.193.140:8000/cotrackapi/api/track/mail/";
            //拼接请求头
            Map<String, String> headers = new HashMap<>(2);
            headers.put("Version", "ems_track_cn_1.0");
            headers.put("authenticate", "E10ADC3949BA59ABBE56E057F20F883E");
            //组建数据格式
            url = url + request.getLogisticsNo();
            //发送请求并接受返回
            String res = httpClientUtils.get(url, headers);
            //处理返回结果
            log.info("请求返回结果[{}]", res);
            JSONObject json = JSONObject.parseObject(res);
            jsonArray = json.getJSONArray("traces");
        } catch (Exception e) {
            log.error("邮政快递包裹查询出错[{}]", e.getMessage());
        }
        ExpressSearchResponse expressSearchResponse = checkResult(jsonArray, request);
        log.info("请求返回[{}]", JSON.toJSONString(controller(expressSearchResponse, jsonArray, "remark", "acceptTime")));
        return controller(expressSearchResponse, jsonArray, "remark", "acceptTime");
    }
}

例5:EMS——>EmsExpress【线下联系邮政快递人员开通账号信息】

import ExpressSearchRequest;
import ExpressSearchResponse;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;

/**
 * EMS
 */
@Service
public class EmsExpress extends ResponseController implements Express {
    @Resource
    ChinaPostExpress chinaPostExpress;

    @Override
    public String expressCode() {
        return "EMS";
    }

    @Override
    public ExpressSearchResponse logisticsSearch(ExpressSearchRequest request) {
        return chinaPostExpress.logisticsSearch(request);
    }
}

例6:德邦快递——>DepponExpress

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import ExpressSearchRequest;
import ExpressSearchResponse;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.digest.DigestUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.HashMap;
import java.util.Map;

/**
 * 德邦
 */
@Service
public class DepponExpress extends ResponseController implements Express {

    private static final Logger log = LoggerFactory.getLogger(DepponExpress.class);
    private static String url = "http://dpapi.deppon.com/dop-interface-sync/standard-query/newTraceQuery.action";
    private static String companyCode = "ABCDEFGHIJKLM";
    private static String appKey = "e10adc3949ba59abbe56e057f20f883e";
    @Resource
    HttpClientUtils httpClientUtils;

    @Override
    public String expressCode() {
        return "DBL";
    }

    @Override
    public ExpressSearchResponse logisticsSearch(ExpressSearchRequest request) {
        JSONArray jsonArray = null;
        log.info("德邦快递查询参数[{}]", JSON.toJSONString(request));
        try {
            //拼接请求头
            Map<String, String> headers = new HashMap<>(1);
            headers.put("Content-Type", "application/x-www-form-urlencoded;charset=utf-8");
            //组建数据格式
            String timestamp = String.valueOf(System.currentTimeMillis());
            String params = "{\"mailNo\":\"" + request.getLogisticsNo() + "\"}";
            String digest = Base64.encodeBase64String(DigestUtils.md5Hex(params + appKey + timestamp).getBytes());
            String requestData = "params=" + params + "&digest=" + digest + "&timestamp=" + timestamp + "&companyCode=" + companyCode;
            //发送请求并接受返回
            String res = httpClientUtils.post(url, requestData, headers);
            //处理返回结果
            log.info("请求返回结果[{}]", res);
            JSONObject json = JSONObject.parseObject(res);
            jsonArray = json.getJSONObject("responseParam").getJSONArray("trace_list");
        } catch (Exception e) {
            log.error("德邦快递查询出错[{}]", e.getMessage());
        }
        ExpressSearchResponse expressSearchResponse = checkResult(jsonArray, request);
        log.info("请求返回[{}]", JSON.toJSONString(controller(expressSearchResponse, jsonArray, "description", "time")));
        return controller(expressSearchResponse, jsonArray, "description", "time");
    }
}

例7:极兔快递——>JtExpress 

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import ExpressSearchRequest;
import ExpressSearchResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.digest.DigestUtils;

import javax.annotation.Resource;
import java.util.HashMap;
import java.util.Map;

/**
 * 极兔
 */
@Service
public class JtExpress extends ResponseController implements Express {
    private static final Logger log = LoggerFactory.getLogger(JtExpress.class);
    private static final String API_ACCOUNT = "178337126125932605";
    private static final String PRIVATE_KEY = "0258d71b55fc45e3ad7a7f38bf4b201a";
    private static final String SERVICE_URL = "https://openapi.jtexpress.com.cn/webopenplatformapi/api/logistics/trace";
    @Resource
    HttpClientUtils httpClientUtils;

    @Override
    public String expressCode() {
        return "JTSD";
    }

    @Override
    public ExpressSearchResponse logisticsSearch(ExpressSearchRequest request) {
        log.info("极兔查询参数[{}]", JSON.toJSONString(request));
        JSONArray jsonArray = new JSONArray();
        try {
            //查询参数
            String bizContent = "{\"billCodes\":\"" + request.getLogisticsNo() + "\"}";
            //拼接请求头
            Map<String, String> headers = new HashMap<>();
            headers.put("Content-Type", "application/x-www-form-urlencoded;charset=utf-8");
            headers.put("apiAccount", API_ACCOUNT);
            headers.put("digest", digestForHead(bizContent));
            headers.put("timestamp", String.valueOf(System.currentTimeMillis()));
            String requestData = "bizContent=" + bizContent;
            Map<String, String> jsonMap = new HashMap<>();
            jsonMap.put("header", JSON.toJSONString(headers));
            jsonMap.put("body", requestData);
            log.info("请求参数digest[{}]", digestForHead(bizContent));
            log.info("请求参数headers[{}]", JSON.toJSONString(headers));
            log.info("请求参数body[{}]", requestData);
            log.info("请求jsonMap[{}]", JSON.toJSONString(jsonMap));
            //发送请求并接受返回
            String res = httpClientUtils.post(SERVICE_URL, requestData, headers);
            //处理返回结果
            log.info("请求返回结果[{}]", res);
            JSONObject json = JSONObject.parseObject(res);
            jsonArray = json.getJSONArray("data").getJSONObject(0).getJSONArray("details");
        } catch (Exception e) {
            log.error("极兔快递查询出错[{}]", e.getMessage());
        }
        ExpressSearchResponse expressSearchResponse = checkResult(jsonArray, request);
        log.info("请求返回[{}]", JSON.toJSONString(controller(expressSearchResponse, jsonArray, "desc", "scanTime")));
        return controller(expressSearchResponse, jsonArray, "desc", "scanTime");
    }

    private static String digestForHead(String json) {
        String signStr = json + JtExpress.PRIVATE_KEY;
        byte[] encode = (new Base64()).encode(DigestUtils.md5(signStr));
        return new String(encode);
    }
}

 例8:顺丰快递——>SfExpress 【引用顺丰SDK】

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import ExpressSearchRequest;
import ExpressSearchResponse;
import com.sf.csim.express.service.CallExpressServiceTools;
import com.sf.csim.express.service.HttpClientUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import java.util.HashMap;
import java.util.Map;
import java.util.UUID;


/**
 * 顺丰
 */
@Service
public class SfExpress extends ResponseController implements Express {
    private static final Logger log = LoggerFactory.getLogger(SfExpress.class);
    /**
     * 顾客编码
     */
    private static final String CLIENT_CODE = "ABCDEFGHIJKL";
    /**
     * 丰桥平台生产校验码
     */
    private static final String CHECK_WORD = "E10ADC3949BA59ABBE56E057F20F883E";
    /**
     * 接口服务代码
     */
    private static final String SERVICE_CODE = "EXP_RECE_SEARCH_ROUTES";
    /**
     * 生产环境的地址
     */
    private static final String CALL_URL_PROD = "https://sfapi.sf-express.com/std/service";

    @Override
    public String expressCode() {
        return "SF";
    }

    @Override
    public ExpressSearchResponse logisticsSearch(ExpressSearchRequest request) {
        log.info("顺丰查询参数[{}]", JSON.toJSONString(request));
        JSONArray jsonArray = new JSONArray();
        try {
            Map<String, String> params = new HashMap<>();
            String msgData = "{" +
                    "    \"language\": 0," +
                    "    \"trackingType\": 1," +
                    "    \"trackingNumber\": [\"" + request.getLogisticsNo() + "\"]," +
                    "    \"methodType\": 1," +
                    "    \"checkPhoneNo\": \"" + request.getReceiverMobile().substring(7) + "\"" +
                    "}";
            String timeStamp = String.valueOf(System.currentTimeMillis());
            params.put("partnerID", CLIENT_CODE);
            params.put("requestID", UUID.randomUUID().toString().replace("-", ""));
            params.put("serviceCode", SERVICE_CODE);
            params.put("timestamp", timeStamp);
            params.put("msgData", msgData);
            params.put("msgDigest", CallExpressServiceTools.getMsgDigest(msgData, timeStamp, CHECK_WORD));
            System.out.println(params);
            String res = HttpClientUtil.post(CALL_URL_PROD, params);
            log.info("请求返回结果[{}]", res);
            JSONObject jsonObj = JSON.parseObject(res);
            if (jsonObj.containsKey("apiResultData")) {
                JSONObject json = jsonObj.getJSONObject("apiResultData");
                if (json.containsKey("msgData")) {
                    json = json.getJSONObject("msgData").getJSONArray("routeResps").getJSONObject(0);
                    if (json.containsKey("routes")) {
                        jsonArray = json.getJSONArray("routes");
                    }
                }
            }
        } catch (Exception e) {
            log.error("顺丰查询出错[{}]", e.getMessage());
        }
        ExpressSearchResponse expressSearchResponse = checkResult(jsonArray, request);
        log.info("请求返回[{}]", JSON.toJSONString(controller(expressSearchResponse, jsonArray, "remark", "acceptTime")));
        return controller(expressSearchResponse, jsonArray, "remark", "acceptTime");
    }

}

  例9:申通快递——>StoExpress 【引用申通SDK】

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import ExpressSearchRequest;
import ExpressSearchResponse;
import com.sto.link.request.LinkRequest;
import com.sto.link.util.LinkUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;

/**
 * 申通
 */
@Service
public class StoExpress extends ResponseController implements Express {
    private static final Logger log = LoggerFactory.getLogger(StoExpress.class);
    private static String url = "https://cloudinter-linkgatewayonline.sto.cn/gateway/link.do";
    private static String api_name = "STO_TRACE_QUERY_COMMON";
    private static String from_appkey = "ABCDEFGHIJKLMNO";
    private static String from_code = "ABCDEFGHIJKLMNO";
    private static String to_appkey = "sto_trace_query";
    private static String to_code = "sto_trace_query";
    private static String secretKey = "E10ADC3949BA59ABBE56E057F20F883E";

    @Override
    public String expressCode() {
        return "STO";
    }

    @Override
    public ExpressSearchResponse logisticsSearch(ExpressSearchRequest request) {
        log.info("申通快递查询参数[{}]", JSON.toJSONString(request));
        JSONArray jsonArray = new JSONArray();
        try {
            LinkRequest data = new LinkRequest();
            data.setFromAppkey(from_appkey);
            data.setFromCode(from_code);
            data.setToAppkey(to_appkey);
            data.setToCode(to_code);
            data.setApiName(api_name);
            JSONObject jsonObject = new JSONObject();
            List<String> ll = new ArrayList<>();
            ll.add(request.getLogisticsNo());
            jsonObject.put("waybillNoList", ll);
            data.setContent(jsonObject.toJSONString());
            String res = LinkUtils.request(data, url, secretKey);
            log.info("请求返回结果[{}]", res);
            jsonArray = JSONObject.parseObject(res).getJSONObject("data").getJSONArray(request.getLogisticsNo());
        } catch (Exception e) {
            log.error("申通快递查询出错[{}]", e.getMessage());
        }
        ExpressSearchResponse expressSearchResponse = checkResult(jsonArray, request);
        log.info("请求返回[{}]", JSON.toJSONString(controller(expressSearchResponse, jsonArray, "memo", "opTime")));
        return controller(expressSearchResponse, jsonArray, "memo", "opTime");
    }
}

 例9:众邮快递——>ZyExpress 【引用众邮SDK】

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.jdwl.open.api.sdk.DefaultJdClient;
import com.jdwl.open.api.sdk.JdClient;
import com.jdwl.open.api.sdk.JdException;
import com.jdwl.open.api.sdk.domain.zhongyouex.OrderTraceApi.CommonParam;
import com.jdwl.open.api.sdk.request.zhongyouex.OrderFindTraceInfoByWaybillCodeLopRequest;
import com.jdwl.open.api.sdk.response.zhongyouex.OrderFindTraceInfoByWaybillCodeResponse;
import ExpressSearchRequest;
import ExpressSearchResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

/**
 * 众邮
 */
@Service
public class ZyExpress extends ResponseController implements Express {
    private static final Logger log = LoggerFactory.getLogger(ZyExpress.class);
    private static String serverUrl = "https://api.zhongyouex.com/routerjson";
    private static String accessToken = "E10ADC3949BA59ABBE56E057F20F883E";
    private static String appKey = "E10ADC3949BA59ABBE56E057F20F883E";
    private static String appSecret = "E10ADC3949BA59ABBE56E057F20F883E";
    private static String appCode = "EXPRESS_100";
    private static String source = "1234";
    private static String userCode = "zhangsan123";

    @Override
    public String expressCode() {
        return "ZY";
    }

    @Override
    public ExpressSearchResponse logisticsSearch(ExpressSearchRequest request) {
        log.info("众邮快递查询参数[{}]", JSON.toJSONString(request));
        JSONArray jsonArray = new JSONArray();
        try {
            JdClient client = new DefaultJdClient(serverUrl, accessToken, appKey, appSecret);
            OrderFindTraceInfoByWaybillCodeLopRequest lopRequest = new OrderFindTraceInfoByWaybillCodeLopRequest();
            lopRequest.setWaybillCode(request.getLogisticsNo());
            CommonParam commonParam = new CommonParam();
            commonParam.setAppCode(appCode);
            commonParam.setSource(source);
            commonParam.setUserCode(userCode);
            lopRequest.setCommonParam(commonParam);
            OrderFindTraceInfoByWaybillCodeResponse response = client.execute(lopRequest);
            log.info("请求返回结果[{}]", response.getMsg());
            JSONObject jsonObject = JSONObject.parseObject(response.getMsg());
            jsonArray = jsonObject.getJSONObject("response").getJSONObject("content").getJSONArray("data");
        } catch (JdException e) {
            log.error("众邮快递查询出错[{}]", e.getErrMsg());
        }
        ExpressSearchResponse expressSearchResponse = checkResult(jsonArray, request);
        log.info("请求返回[{}]", JSON.toJSONString(controller(expressSearchResponse, jsonArray, "content", "operateTime")));
        return controller(expressSearchResponse, jsonArray, "content", "operateTime");
    }
}

 例10:圆通快递——>YtoExpress

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import ExpressSearchRequest;
import ExpressSearchResponse;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.net.URLEncoder;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * 圆通
 */
@Service
public class YtoExpress extends ResponseController implements Express {
    private static final Logger log = LoggerFactory.getLogger(YtoExpress.class);
    private static String url = "http://openapi.yto.net.cn/service/waybill_query/v1/X1FKbA";
    private static String user_id = "YTOTEST";
    private static String app_key = "sF1Jzn";
    private static String secret_key = "1QLlIZ";
    private static String v = "1.01";
    private static String method = "yto.Marketing.WaybillTrace";
    @Resource
    HttpClientUtils httpClientUtils;

    @Override
    public String expressCode() {
        return "YTO";
    }

    @Override
    public ExpressSearchResponse logisticsSearch(ExpressSearchRequest request) {
        log.info("圆通快递查询参数[{}]", JSON.toJSONString(request));
        JSONArray jsonArray = new JSONArray();
        try {
            JSONObject jsonObject = new JSONObject();
            jsonObject.put("Number", request.getLogisticsNo());
            String timestamp = DateFormatUtils.format(new Date(), "yyyy-mm-dd HH:mm:ss");
            String sign = secret_key + "app_key" + app_key + "formatJSONmethod" + method + "timestamp"
                    + timestamp + "user_id" + user_id + "v" + v;
            sign = MD5.getInstance().getMD5String(sign).toUpperCase();
            String params = "sign=" + sign + "&app_key=" + app_key + "&format=JSON&method=" + method + "&timestamp="
                    + timestamp + "&user_id=" + user_id + "&v=" + v + "&param=" + URLEncoder.encode(jsonObject.toJSONString(), "UTF-8");
            Map<String, String> headers = new HashMap<>(1);
            headers.put("Content-Type", "application/x-www-form-urlencoded");
            String res = httpClientUtils.post(url, params, headers);
            log.info("请求返回结果[{}]", res);
            jsonArray = JSONObject.parseArray(res);
        } catch (Exception e) {
            log.error("圆通快递查询出错[{}]", e.getMessage());
        }
        ExpressSearchResponse expressSearchResponse = checkResult(jsonArray, request);
        log.info("请求返回[{}]", JSON.toJSONString(controller(expressSearchResponse, jsonArray, "processInfo", "upload_Time")));
        return controller(expressSearchResponse, jsonArray, "processInfo", "upload_Time");
    }
}

 例11:中通快递——>ZtoExpress【旧版】

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import ExpressSearchRequest;
import ExpressSearchResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.util.Base64Utils;

import javax.annotation.Resource;
import java.net.URLEncoder;
import java.security.NoSuchAlgorithmException;
import java.util.HashMap;
import java.util.Map;

/**
 * 中通
 */
@Component
public class ZtoExpress extends ResponseController implements Express {
    private static final Logger log = LoggerFactory.getLogger(ZtoExpress.class);
    private static String url = "https://japi.zto.com/traceInterfaceNewTraces";
    private static String companyId = "e10adc3949ba59abbe56e057f20f883e";
    private static String key = "abcdefghijkl";
    private static String msg_type = "NEW_TRACES";
    @Resource
    HttpClientUtils httpClientUtils;

    @Override
    public String expressCode() {
        return "ZTO";
    }

    @Override
    public ExpressSearchResponse logisticsSearch(ExpressSearchRequest request) throws NoSuchAlgorithmException {
        JSONArray jsonArray = null;
        log.info("中通快递查询参数[{}]", JSON.toJSONString(request));
        try {
            //组建数据格式
            String strToDigest = "data=['" + request.getLogisticsNo() + "']&company_id=" + companyId + "&msg_type=" + msg_type + key;
            String dataDigest = Base64Utils.encodeToString(MD5.getInstance().hash(strToDigest));
            String requestData = "data=" + URLEncoder.encode("['" + request.getLogisticsNo() + "']", "UTF-8") +
                    "&company_id=" + companyId + "&msg_type=" + msg_type;
            //拼接请求头
            Map<String, String> headers = new HashMap<>(3);
            headers.put("Content-Type", "application/x-www-form-urlencoded; charset=utf-8");
            headers.put("x-companyId", companyId);
            headers.put("x-dataDigest", dataDigest);
            //发送请求并接受返回
            String res = httpClientUtils.post(url, requestData, headers);
            //处理返回结果
            log.info("请求返回结果[{}]", res);
            JSONObject json = JSONObject.parseObject(res);
            jsonArray = json.getJSONArray("data").getJSONObject(0).getJSONArray("traces");
        } catch (Exception e) {
            log.error("中通快递查询出错[{}]", e.getMessage());
        }
        ExpressSearchResponse expressSearchResponse = checkResult(jsonArray, request);
        log.info("请求返回[{}]", JSON.toJSONString(controller(expressSearchResponse, jsonArray, "desc", "scanDate")));
        return controller(expressSearchResponse, jsonArray, "desc", "scanDate");
    }
}

例12:中通快递——>ZtoExpress【新版】 

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;;
import ExpressSearchRequest;
import ExpressSearchResponse;
import zop.EncryptionType;
import zop.ZopClient;
import zop.ZopPublicRequest;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.security.NoSuchAlgorithmException;

/**
 * 中通
 */
@Component
public class ZtoExpress extends ResponseController implements Express {
    private static final Logger log = LoggerFactory.getLogger(ZtoExpress.class);
    private static String url = "https://japi.zto.com/zto.merchant.waybill.track.query";
    private static String appKey = "ea8a706c4c34a168abcde";
    private static String appSecret = "827ccb0eea8a706c4c34a16891f84e7b";

    @Override
    public String expressCode() {
        return "ZTO";
    }

    @Override
    public ExpressSearchResponse logisticsSearch(ExpressSearchRequest request) throws NoSuchAlgorithmException {
        JSONArray jsonArray = null;
        log.info("中通快递查询参数[{}]", JSON.toJSONString(request));
        ZopClient client = new ZopClient(appKey, appSecret);
        ZopPublicRequest zopPublicRequest = new ZopPublicRequest();
        String mobilePhone = request.getReceiverMobile().substring(request.getReceiverMobile().length() - 4);
        zopPublicRequest.setBody("{\"billCode\":\"" + request.getLogisticsNo() + "\",\"mobilePhone\":\"" + mobilePhone + "\"}");
        zopPublicRequest.setUrl(url);
        zopPublicRequest.setBase64(true);
        zopPublicRequest.setEncryptionType(EncryptionType.MD5);
        zopPublicRequest.setTimestamp(null);
        try {
            String res = client.execute(zopPublicRequest);
            //处理返回结果
            log.info("请求返回结果[{}]", res);
            JSONObject json = JSONObject.parseObject(res);
            jsonArray = json.getJSONArray("result");
            log.info("请求返回结果jsonArray[{}]", jsonArray);
        } catch (IOException e) {
            log.error("中通快递查询出错[{}]", e.getMessage());
        }
        ExpressSearchResponse expressSearchResponse = checkResult(jsonArray, request);
        log.info("中通快递返回数据[{}]", JSON.toJSONString(controllerZto(expressSearchResponse, jsonArray, "desc", "scanDate")));
        return controllerZto(expressSearchResponse, jsonArray, "desc", "scanDate");
    }
}

zop :中通快递新版所需公共资源包

 

zop 之 EncryptionType 枚举类

public enum EncryptionType {
    MD5,
    SHA256,
    HmacSHA256
}

 zop 之 HttpUtil 工具类

import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.Charset;
import java.util.Map;

public class HttpUtil {
    private static final int DEFAULT_TIMEOUT = 3000;

    public static String post(String interfaceUrl, Map<String, String> headers, String queryString) throws IOException {
        URL url = new URL(interfaceUrl);
        HttpURLConnection con = (HttpURLConnection) url.openConnection();
        con.setRequestMethod("POST");
        con.setRequestProperty("Content-Type", "application/x-www-form-urlencoded; charset=utf-8");
        con.setDoOutput(true);
        con.setConnectTimeout(DEFAULT_TIMEOUT);
        con.setReadTimeout(DEFAULT_TIMEOUT);
        for (Map.Entry<String, String> e : headers.entrySet()) {
            con.setRequestProperty(e.getKey(), e.getValue());
        }
        DataOutputStream out = null;
        BufferedReader in = null;
        try {
            out = new DataOutputStream(con.getOutputStream());
            out.write(queryString.getBytes(Charset.forName("UTF-8")));
            out.flush();
            in = new BufferedReader(
                    new InputStreamReader(con.getInputStream(), "UTF-8"));
            String inputLine;
            StringBuilder content = new StringBuilder();
            while ((inputLine = in.readLine()) != null) {
                content.append(inputLine);
            }
            return content.toString();
        } finally {
            if (out != null) {
                try {
                    out.close();
                } catch (Exception ignored) {
                }
            }
            if (in != null) {
                try {
                    in.close();
                } catch (Exception ignored) {
                }
            }
        }
    }

    public static String postJson(String interfaceUrl, Map<String, String> headers, String json) throws IOException {
        URL url = new URL(interfaceUrl);
        HttpURLConnection con = (HttpURLConnection) url.openConnection();
        con.setRequestMethod("POST");
        con.setRequestProperty("Content-Type", "application/json; charset=utf-8");
        con.setDoOutput(true);
        con.setConnectTimeout(DEFAULT_TIMEOUT);
        con.setReadTimeout(DEFAULT_TIMEOUT);
        for (Map.Entry<String, String> e : headers.entrySet()) {
            con.setRequestProperty(e.getKey(), e.getValue());
        }
        DataOutputStream out = null;
        BufferedReader in = null;
        try {
            out = new DataOutputStream(con.getOutputStream());
            out.write(json.getBytes(Charset.forName("UTF-8")));
            out.flush();
            in = new BufferedReader(
                    new InputStreamReader(con.getInputStream(), "UTF-8"));
            String inputLine;
            StringBuilder content = new StringBuilder();
            while ((inputLine = in.readLine()) != null) {
                content.append(inputLine);
            }
            return content.toString();
        } finally {
            if (out != null) {
                try {
                    out.close();
                } catch (Exception ignored) {
                }
            }
            if (in != null) {
                try {
                    in.close();
                } catch (Exception ignored) {
                }
            }
        }
    }
}

  zop 之 ZopClient 工具类

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.Map;

public class ZopClient {
    private final ZopProperties properties;

    public ZopClient(ZopProperties properties) {
        this.properties = properties;
    }

    public ZopClient(String appKey, String appSecret) {
        this.properties = new ZopProperties(appKey, appSecret);
    }

    public String execute(ZopPublicRequest request) throws IOException {
        String jsonBody = request.getBody();
        if (jsonBody == null) {
            Map<String, String> params = request.getParams();
            StringBuilder queryBuilder = new StringBuilder();
            StringBuilder strToDigestBuilder = new StringBuilder();
            for (Map.Entry<String, String> e : params.entrySet()) {
                strToDigestBuilder.append(e.getKey()).append("=").append(e.getValue()).append("&");
                queryBuilder.append(urlEncode(e.getKey())).append("=").append(urlEncode(e.getValue())).append("&");
            }
            String queryString = queryBuilder.substring(0, queryBuilder.length() - 1);
            String strToDigest = strToDigestBuilder.substring(0, strToDigestBuilder.length() - 1);
            strToDigest = strToDigest + properties.getKey();
            Map<String, String> headers = new HashMap<String, String>();
            headers.put("x-companyid", properties.getCompanyId());
            headers.put("x-datadigest", ZopDigestUtil.digest(strToDigest, request.getBase64(), request.getEncryptionType(), request.getTimestamp(), request.getSecretKey()));
            if (request.getTimestamp() != null) {
                headers.put("x-timestamp", String.valueOf(request.getTimestamp()));
            }
            return HttpUtil.post(request.getUrl(), headers, queryString);
        } else {
            Map<String, String> headers = new HashMap<>();
            String strToDigest = jsonBody + properties.getKey();
            headers.put("x-companyid", properties.getCompanyId());
            headers.put("x-datadigest", ZopDigestUtil.digest(strToDigest, request.getBase64(), request.getEncryptionType(), request.getTimestamp(), request.getSecretKey()));
            if (request.getTimestamp() != null) {
                headers.put("x-timestamp", String.valueOf(request.getTimestamp()));
            }
            return HttpUtil.postJson(request.getUrl(), headers, jsonBody);
        }
    }

    private String urlEncode(String str) {
        try {
            return URLEncoder.encode(str, "UTF-8");
        } catch (UnsupportedEncodingException e) {
            return str;
        }
    }
}

   zop 之 ZopDigestUtil 工具类

import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.binary.Hex;
import org.apache.commons.codec.digest.DigestUtils;

import javax.crypto.Mac;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;

public class ZopDigestUtil {
    private static final String HMAC_SHA_256 = "HmacSHA256";
    private static final Map<String, Mac> MAC_MAP = new ConcurrentHashMap<>();

    public static String digest(String str, Boolean isBase64, EncryptionType encryptionType, Long timestamp, String secretKey) {
        if (timestamp != null) {
            str = timestamp + str;
        }
        boolean base64 = isBase64 == null || isBase64;
        switch (encryptionType) {
            case SHA256:
                return base64 ? Base64.encodeBase64String(DigestUtils.sha256(str)) : DigestUtils.sha256Hex(str);
            case HmacSHA256:
                return base64 ? Base64.encodeBase64String(hmacSha256(secretKey, str)) : hmacSha256Str(secretKey, str);
            default:
                return base64 ? Base64.encodeBase64String(DigestUtils.md5(str)) : DigestUtils.md5Hex(str);
        }
    }

    public static String hmacSha256Str(String key, String body) {
        return Hex.encodeHexString(hmacSha256(key, body));
    }

    public static byte[] hmacSha256(String key, String body) {
        if (Objects.isNull(key)) {
            key = "";
        }
        Mac mac = MAC_MAP.get(key);
        if (mac == null) {
            try {
                mac = Mac.getInstance(HMAC_SHA_256);
                SecretKey secretKey = new SecretKeySpec(key.getBytes(StandardCharsets.UTF_8), HMAC_SHA_256);
                mac.init(secretKey);
                MAC_MAP.put(key, mac);
            } catch (NoSuchAlgorithmException | InvalidKeyException e) {
                throw new RuntimeException(e);
            }
        }
        return mac.doFinal(body.getBytes(StandardCharsets.UTF_8));
    }
}

   zop 之 ZopProperties 配置类

public class ZopProperties {
    private String companyId;
    private String key;

    public ZopProperties() {
    }

    public ZopProperties(String appKey, String appSecret) {
        this.companyId = appKey;
        this.key = appSecret;
    }

    public String getCompanyId() {
        return companyId;
    }

    public void setCompanyId(String companyId) {
        this.companyId = companyId;
    }

    public String getKey() {
        return key;
    }

    public void setKey(String key) {
        this.key = key;
    }
}

    zop 之 ZopPublicRequest 请求类

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;

import java.util.HashMap;
import java.util.Map;

public class ZopPublicRequest {

    private String url;

    private Map<String, String> params = new HashMap<String, String>();

    // 如果body有值,表示使用application/json的方式传值
    private String body;

    /**
     * 签名是否需要base64
     */
    private Boolean isBase64;

    /**
     * 加密方式,MD5或者SHA256
     */
    private EncryptionType encryptionType;

    /**
     * HmacSHA256加密key
     */
    private String secretKey;

    /**
     * 时间戳,如果接口文档未标识使用时间戳请不要传值,否则会导致签名错误
     */
    private Long timestamp;

    public ZopPublicRequest() {
    }

    public void setBody(String body) {
        this.body = body;
    }


    public String getBody() {
        return body;
    }

    public void addParam(String k, String v) {
        params.put(k, v);
    }

    public void setData(String data) {
        try {
            JSONObject jsonObject = JSON.parseObject(data);
            for (Map.Entry<String, Object> entry : jsonObject.entrySet()) {
                params.put(entry.getKey(), entry.getValue().toString());
            }
        } catch (Exception e) {
            throw new RuntimeException("JSON格式不对,请检查数据", e);
        }
    }

    public void setDataObj(Map<String, String> data) {
        params.putAll(data);
    }

    public void addParam(Map<String, String> p) {
        for (Map.Entry<String, String> entry : p.entrySet()) {
            params.put(entry.getKey(), entry.getValue());
        }
    }

    public String getUrl() {
        return url;
    }

    public void setUrl(String url) {
        this.url = url;
    }

    public Map<String, String> getParams() {
        return params;
    }

    public void setParams(Map<String, String> params) {
        this.params = params;
    }

    public Boolean getBase64() {
        return isBase64;
    }

    public void setBase64(Boolean base64) {
        isBase64 = base64;
    }

    public EncryptionType getEncryptionType() {
        return encryptionType;
    }

    public void setEncryptionType(EncryptionType encryptionType) {
        this.encryptionType = encryptionType;
    }

    public String getSecretKey() {
        return secretKey;
    }

    public void setSecretKey(String secretKey) {
        this.secretKey = secretKey;
    }

    public Long getTimestamp() {
        return timestamp;
    }

    public void setTimestamp(Long timestamp) {
        this.timestamp = timestamp;
    }
}
  • 9
    点赞
  • 48
    收藏
    觉得还不错? 一键收藏
  • 12
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值