java 对接顺丰快递进行寄件操作 (使用RestTemplate 请求)

相关资料

顺丰统一接入平台 :https://freight.sf-express.com/api/api.html#id=28

顺丰在线查询物流信息地址: https://www.sf-express.com/cn/sc/dynamic_function/waybill/#search/bill-number/SF1193907051991

SF1193907051991] 为快递号 -> 修改为自己的即可

在这里插入图片描述

一、顺丰api 接口请求核心类

在这里插入图片描述

1、顺丰请求工具类 SFUtil

package com.ws.ldy.others.kuaidi.sf.util;

import com.alibaba.fastjson.JSON;
import com.ws.ldy.config.error.ErrorException;
import com.ws.ldy.others.kuaidi.sf.entity.SFReturnData;
import com.ws.ldy.others.kuaidi.sf.entity.SFReturnError;
import com.ws.ldy.others.kuaidi.sf.entity.cancel.request.RequestCancel;
import com.ws.ldy.others.kuaidi.sf.entity.cancel.response.ResponseCancel;
import com.ws.ldy.others.kuaidi.sf.entity.send.request.RequestCreate;
import com.ws.ldy.others.kuaidi.sf.entity.send.response.ResponseCreate;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;
import sun.misc.BASE64Encoder;

import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

/**
 * 顺丰快递 Api 接口对接, 官网文档-零担下单: https://freight.sf-express.com/api/api.html#id=30
 * <P>
 * 请求头必须添加: "Content-type","application/x-www-form-urlencoded;charset=UTF-8”
 * </P>
 * @author wangsong
 * @mail [email protected]
 * @date 2020/9/9 0009 9:38
 * @version 1.0.0
 */
@SuppressWarnings("all")
@Component
@Slf4j
public class SFUtil {

    @Autowired
    private RestTemplate restTemplate;

    //测试地址
    private static final String TEST_URL = "https://sfapi.sit.sf-express.com:45273/std/service";
    private static final String TEST_PARTNER_ID = "fop_test";
    private static final String TEST_MD5_KEY = "2Z7YPBNG2CKKBV17";
    //正式地址 final
    private static final String SF_URL = "https://sfapi.sf-express.com/std/service";
    private static final String SF_PARTNER_ID = "fop_test";
    private static final String SF_MD5_KEY = "2Z7YPBNG2CKKBV17";


    /**
     * 顺丰寄件下单
     * @author wangsong
     * @author requestCreate 下单参数
     * @date 2020/9/15 0015 15:42
     * @return ResponseCreate
     * @version 1.0.0
     */
    public ResponseCreate fopReceLtlCreateOrder(RequestCreate requestCreate) {
        String mgsData = JSON.toJSONString(requestCreate);
        //
        SFReturnData sfReturnData = http("FOP_RECE_LTL_CREATE_ORDER", mgsData);
        //
        if (!"A1000".equals(sfReturnData.getApiResultCode())) {
            //失败
            log.info(sfReturnData.toString());
            throw new ErrorException(10099, sfReturnData.getApiErrorMsg());
        }
        String apiResultData = sfReturnData.getApiResultData();
        ResponseCreate responseCreate = JSON.parseObject(apiResultData, ResponseCreate.class);
        if (!responseCreate.isSuccess()) {
            //失败
            log.info(sfReturnData.toString());
            SFReturnError sfReturnError = JSON.parseObject(apiResultData, SFReturnError.class);
            throw new ErrorException(10099, sfReturnError.getErrorMessage());
        }
        return responseCreate;
    }


    /**
     * 顺丰取消订单
     * @author wangsong
     * @author cancel 下单参数
     * @date 2020/9/15 0015 15:42
     * @return 取消结果信息
     * @version 1.0.0
     */
    public ResponseCancel fopReceLtlCancelOrder(RequestCancel cancel) {
        //
        String mgsData = JSON.toJSONString(cancel);
        //
        SFReturnData sfReturnData = http("FOP_RECE_LTL_CANCEL_ORDER", mgsData);
        if (!"A1000".equals(sfReturnData.getApiResultCode())) {
            //失败
            log.info(sfReturnData.toString());
            throw new ErrorException(10099, sfReturnData.getApiErrorMsg());
        }
        String apiResultData = sfReturnData.getApiResultData();
        ResponseCancel responseCancel = JSON.parseObject(apiResultData, ResponseCancel.class);
        if (!responseCancel.getSuccess()) {
            log.info(sfReturnData.toString());
            SFReturnError sfReturnError = JSON.parseObject(apiResultData, SFReturnError.class);
            throw new ErrorException(10099, sfReturnError.getErrorMessage());
        }
        return responseCancel;
    }

    /**
     * 下单结果查询
     * @author wangsong
     * @author orderId 寄件商家的订单Id(非寄件单号)
     * @date 2020/9/15 0015 15:42
     * @return 同下单相同数据
     * @version 1.0.0
     */
    public ResponseCreate fopReceLtlGetOrderResult(String orderId) {
        //
        Map<String,String> param = new HashMap<>();
        param.put("orderId",orderId);
        String mgsData = JSON.toJSONString(param);
        //
        SFReturnData sfReturnData = http("FOP_RECE_LTL_GET_ORDER_RESULT", mgsData);
        //
        if (!"A1000".equals(sfReturnData.getApiResultCode())) {
            //失败
            log.info(sfReturnData.toString());
            throw new ErrorException(10099, sfReturnData.getApiErrorMsg());
        }
        String apiResultData = sfReturnData.getApiResultData();
        ResponseCreate responseCreate = JSON.parseObject(apiResultData, ResponseCreate.class);
        if (!responseCreate.isSuccess()) {
            //失败
            log.info(sfReturnData.toString());
            SFReturnError sfReturnError = JSON.parseObject(apiResultData, SFReturnError.class);
            throw new ErrorException(10099, sfReturnError.getErrorMessage());
        }
        return responseCreate;
    }

    /**
     *
     * @param serviceCode 请求接口
     * @param mgsData 请求参数: json 参数
     *   <P>
     * //  1*	下快运订单	FOP_RECE_LTL_CREATE_ORDER
     * //  2*	取消订单   	FOP_RECE_LTL_CANCEL_ORDER
     * //  3	筛单结果查询	FOP_RECE_LTL_SEARCH_ORDER
     * //  4	路由查询 	FOP_RECE_LTL_SEARCH_ROUTER
     * //  5	路由推送	    FOP_PUSH_LTL_ROUTER
     * //  6	清单费用推送	FOP_PUSH_LTL_FEE
     * //  7	清单费用查询	FOP_RECE_LTL_QUERY_FEE
     * //  8*	下单结果查询	FOP_RECE_LTL_GET_ORDER_RESULT
     * //  9	注册路由	    FOP_RECE_LTL_REGISTER_ROUTER
     *   </P>
     * @return SFReturnData
     */
    private SFReturnData http(String serviceCode, String mgsData) {
        String timestamp = System.currentTimeMillis() + "";
        // 发送快递参数处理
        MultiValueMap<String, Object> sendBody = new LinkedMultiValueMap<>();
        sendBody.add("partnerID", TEST_PARTNER_ID);                   // 合作伙伴编码(由顺丰分配)
        sendBody.add("requestID", UUID.randomUUID().toString());      // 请求唯一号UUID
        sendBody.add("serviceCode", serviceCode);                     // 接口服务代码取消订单
        sendBody.add("timestamp", timestamp);                         // 调用接口时间戳
        sendBody.add("msgDigest", genDigest(timestamp, mgsData, TEST_MD5_KEY));  // 数字签名
        sendBody.add("msgData", mgsData);                                        // 业务数据报文
        //设置请求头参数
        HttpHeaders headers = new HttpHeaders();
        headers.add("Content-type", "application/x-www-form-urlencoded;charset=UTF-8");
        //发送请求
        HttpEntity<MultiValueMap<String, Object>> formEntity = new HttpEntity<>(sendBody, headers);
        ResponseEntity<String> result = restTemplate.postForEntity(TEST_URL, formEntity, String.class);
        //
        SFReturnData sfReturnData = JSON.parseObject(result.getBody(), SFReturnData.class);
        return sfReturnData;
    }


    /**
     * 业务数据加密
     * @param timestamp
     * @param mgsData
     * @param md5key
     * @return
     * @throws Exception
     */
    private String genDigest(String timestamp, String mgsData, String md5key) {
        //将业务报文+时间戳+秘钥组合成需加密的字符串(注意顺序)
        String toVerifyText = mgsData + timestamp + md5key;
        //因业务报文中可能包含加号、空格等特殊字符,需要urlEnCode处理
        try {
            toVerifyText = URLEncoder.encode(toVerifyText, "UTF-8");
            //进行Md5加密
            MessageDigest md5 = MessageDigest.getInstance("MD5");
            md5.update(toVerifyText.getBytes("UTF-8"));
            byte[] md = md5.digest();
            //通过BASE64生成数字签名
            String msgDigest = new String(new BASE64Encoder().encode(md));
            return msgDigest;
        } catch (UnsupportedEncodingException | NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        return null;
    }
}

2、提供接口 SFService

/**
 * 顺丰快递
 * @author wangsong
 * @mail [email protected]
 * @date 2020/9/15 0015 17:22
 * @version 1.0.0
 */
public interface SFService {

    public String sendSF(RequestCreate en, String productName);

    public String cancelSF(String orderId);

    public ResponseCreate getOrderSF(String orderId);


}

3、接口实现 SFServiceImpl

package com.ws.ldy.others.kuaidi.sf.service.impl;

import com.ws.ldy.others.kuaidi.sf.entity.cancel.request.RequestCancel;
import com.ws.ldy.others.kuaidi.sf.entity.cancel.response.ResponseCancel;
import com.ws.ldy.others.kuaidi.sf.entity.send.request.CargoList;
import com.ws.ldy.others.kuaidi.sf.entity.send.request.RequestCreate;
import com.ws.ldy.others.kuaidi.sf.entity.send.response.ResponseCreate;
import com.ws.ldy.others.kuaidi.sf.service.SFService;
import com.ws.ldy.others.kuaidi.sf.util.SFUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;


/**
 * 顺丰
 * @author wangsong
 * @mail [email protected]
 * @date 2020/9/15 0015 17:24 
 * @version 1.0.0
 */
@Service
public class SFServiceImpl implements SFService {

    @Autowired
    private SFUtil sfUtil;

    /**
     * 顺丰下单 /返回单号
     * @author wangsong
     * @mail [email protected]
     * @date 2020/9/15 0015 19:36
     * @version 1.0.0
     */
    @Override
    public String sendSF(RequestCreate en, String productName) {

        // 付款方式(邮费): 1.寄方付 2.收方付 3.第三方付(默认收件方付)
        en.setPayMethod("2");
        // 货物明细
        CargoList cargoList = new CargoList();
        cargoList.setName(productName);
        en.setCargoList(cargoList);
        ResponseCreate responseCreate = sfUtil.fopReceLtlCreateOrder(en);
        return responseCreate == null ? null : responseCreate.getObj().getWaybillNo();
    }


    /**
     * 顺丰取消订单
     * @author wangsong
     * @mail [email protected]
     * @date 2020/9/15 0015 19:36
     * @version 1.0.0
     */
    @Override
    public String cancelSF(String orderId) {
        RequestCancel requestCancel = new RequestCancel();
        requestCancel.setOrderid(orderId);  //客户订单号
        requestCancel.setCancelType("1");  //传1取消后,orderId可重复利用
        ResponseCancel responseCancel = sfUtil.fopReceLtlCancelOrder(requestCancel);
        return responseCancel == null ? null : responseCancel.getObj();
    }


    /**
     * 顺丰查询订单
     * @author wangsong
     * @mail [email protected]
     * @date 2020/9/15 0015 19:36
     * @version 1.0.0
     */
    @Override
    public ResponseCreate getOrderSF(String orderId) {
        ResponseCreate responseCreate = sfUtil.fopReceLtlGetOrderResult(orderId);
        return responseCreate;
    }
}

4、提供测试接口

   @ApiOperation("发货测试")
    @RequestMapping(value = "/sendTest", method = RequestMethod.GET)
    public R<String> findTable(String orderId) {
        //
        RequestCreate en = new RequestCreate();
        en.setOrderid(orderId); // 订单Id
        en.setSendContact("王松");            // 寄件方联系人
        en.setSendMobile("17628689969");     // 寄件方电话
        en.setSendProvince("四川省");         // 寄件方所在省级行政区名称,必须是标准的省级行政区名称,如:北京、广东省、广西壮族自治区等;
        en.setSendCity("成都市");             // 寄件方所在地级行政区名称,必须是标准的城市称谓,   如:北京市、深圳市、大理白族自治州等;
        en.setSendCounty("青羊区");           // 寄件人所在县/区级行政区名称必须是标准的县/区称谓,   如:福田区,南涧彝族自治县、准格尔旗等。
        en.setSendAddress("新洲十一街万基商务大厦10楼。");    // 寄件人详细地址(请勿包含省市区),        如:新洲十一街万基商务大厦10楼。
        //
        en.setDeliveryContact("王松");     // 到件方联系人
        en.setDeliveryMobile("17628689969");
        en.setDeliveryProvince("四川省");  // 到件方所在省级行政区名称,必须是标准的省级行政区名称 如:北京、广东省、广西壮族自治区等;
        en.setDeliveryCity("成都市");      // 到件方所在地级行政区名称,必须是标准的城市称谓
        en.setDeliveryCounty("武侯区");    // 到件方所在县/区级行政区名称,必须是标准的县/区称谓, 如:福田区,南涧彝族自治县、准格尔旗等
        en.setDeliveryAddress("新洲十一街万基商务大厦11楼");// 到件方详细地址(请勿包含省市区),   如:新洲十一街万基商务大厦10楼。
        //
        return R.success(sfService.sendSF(en, "测试商品"));
    }


二、实体类封装

1、返回

1.1、正确统一返回 SFReturnError

package com.ws.ldy.others.kuaidi.sf.entity;


import com.ws.ldy.others.base.model.Convert;
import lombok.Data;
import lombok.ToString;

/**
  * 统一返回正确获取对应数据时错误
  * @author wangsong
  * @mail  [email protected]`在这里插入代码片`
  * @date  2020/9/15 0015 20:29
  * @version 1.0.0
  */
@Data
@ToString
public class SFReturnError extends Convert {

    private String errorCode;

    private String errorMessage;

    private Boolean success;
}

1.2、错误统一返回 SFReturnData

package com.ws.ldy.others.kuaidi.sf.entity;


import com.ws.ldy.others.base.model.Convert;
import lombok.Data;
import lombok.ToString;

/**
 * 顺丰请求的-统一返回数据格式
 */
@Data
@ToString
public class SFReturnData extends Convert {

    private String apiErrorMsg;
    private String apiResponseID;
    private String apiResultCode;
    private String apiResultData;

}

2、寄件请求

2.1、请求必填参数 RequestCreate

/**
 * Copyright 2020 bejson.com
 */
package com.ws.ldy.others.kuaidi.sf.entity.send.request;

import com.ws.ldy.others.base.model.Convert;
import lombok.Data;
import lombok.ToString;


/**
 * 顺丰寄件必填参数的请求参数(当前系统使用参数)
 * @author wangsong
 * @date 2020/9/15 0015 16:05
 * @return
 * @version 1.0.0
 */
@Data
@ToString
public class RequestCreate extends Convert {

    private String orderid;           // 订单Id
    // 寄件方
    private String sendContact;       // 寄件方联系人
    private String sendMobile;        // 寄件方电话
    private String sendProvince;      // 寄件方所在省级行政区名称,必须是标准的省级行政区名称,如:北京、广东省、广西壮族自治区等;
    private String sendCity;          // 寄件方所在地级行政区名称,必须是标准的城市称谓,   如:北京市、深圳市、大理白族自治州等;
    private String sendCounty;        // 寄件人所在县/区级行政区名称必须是标准的县/区称谓,   如:福田区,南涧彝族自治县、准格尔旗等。
    private String sendAddress;       // 寄件人详细地址(请勿包含省市区),        如:新洲十一街万基商务大厦10楼。
    // 到件方
    private String deliveryContact;   // 到件方联系人
    private String deliveryMobile;    // 到件方电话
    private String deliveryProvince;  // 到件方所在省级行政区名称,必须是标准的省级行政区名称 如:北京、广东省、广西壮族自治区等;
    private String deliveryCity;      // 到件方所在地级行政区名称,必须是标准的城市称谓
    private String deliveryCounty;    // 到件方所在县/区级行政区名称,必须是标准的县/区称谓, 如:福田区,南涧彝族自治县、准格尔旗等
    private String deliveryAddress;   // 到件方详细地址(请勿包含省市区),   如:新洲十一街万基商务大厦10楼。
    //
    private String payMethod;         // 付款方式(邮费): 1.寄方付   2.收方付     3.第三方付
    private CargoList cargoList;      // 货物明细,-非必填 参见Cargo
    private String remark;            // 下单备注
    private String pickUpMode;         // 取件方式 1. 客户自送 2 上门接货。默认为2上门接货。
    private String expectedPickUpTime;  //  希望上门取件时间。 格式:yyyy-MM-dd HH:mm:ss

}

2.2、请求必填- 子参数 CargoList

/**
  * 货物信息
  * @author wangsong
  * @mail  [email protected]
  * @date  2020/9/15 0015 20:13
  * @version 1.0.0
  */
@Data
@ToString
public class CargoList {

    private String name;
    private int count;
    private String unit;
    private int length;
    private int width;
    private double amount;
    private String currency;
    private String sourcearea;
    private String productrecordno;
    private String goodPrepardNo;
    private String taxNo;
    private String hsCode;
    private double volume;
    private int boxno;
    private int installcargotype;
    private int height;
    private int weight;
}

2.3、响应参数 ResponseCreate

/**
  * 顺丰快递统一响应成功 SFReturnData 下的 apiResultData 内数据
  * @author wangsong
  * @mail  [email protected]
  * @date  2020/9/15 0015 20:15
  * @version 1.0.0
  */
@Data
@ToString
public class ResponseCreate extends Convert {

    private Obj obj;
    private boolean success;
}

2.4、响应子参数 Obj

@Data
@ToString
public class Obj extends Convert {

    private String destCode;
    private String filterResult;
    private String orderId;
    private RlsInfo rlsInfo;
    private String waybillNo;  //顺丰订单号

}

2.5、响应子参数 RlsDetail

@Data
@ToString
public class RlsDetail extends Convert {

    private String abFlag;
    private String cargoTypeCode;
    private String codingMapping;
    private String codingMappingOut;
    private String deliveryMode;
    private String destCityCode;
    private String destDeptCode;
    private String destDeptCodeMapping;
    private String destRouteLabel;
    private String destTeamCode;
    private String destTeamCodeMapping;
    private String destTransferCode;
    private String destinationStationCode;
    private String errMsg;
    private String expressTypeCode;
    private String fopIcon;
    private String goodsNumber;
    private String limitTypeCode;
    private String newIcon;
    private String printFlag;
    private String printIcon;
    private String proCode;
    private String proName;
    private String routeArray;
    private String sendAreaCode;
    private String sourceCityCode;
    private String sourceDeptCode;
    private String sourceTeamCode;
    private String sourceTransferCode;
    private String sxCompany;
    private String twoDimensionCode;
    private String waybillNo;
    private String xbFlag;
}

2.6、响应子参数 RlsInfo

@Data
@ToString
public class RlsInfo extends Convert {

    private RlsDetail rlsDetail;

}

3、取消寄件

3.1、请求 RequestCancel

@Data
@ToString
public class RequestCancel extends Convert {

    private String orderid;             // 客户订单号
    private String cancelType;          // 传1取消后,orderId可重复利用

}

3.2、响应 ResponseCancel

/**
 * 顺丰快递统一响应成功 SFReturnData 下的 apiResultData 内数据
 * @author wangsong
 * @date 2020/9/15 0015 16:05
 * @return
 * @version 1.0.0
 */
@Data
@ToString
public class ResponseCancel extends Convert {

    private String errorCode;      // 错误代码
    private String errorMessage;   // 错误描述
    private Boolean success;       // 是否成功
    private String obj;            // 返回数据 //orderId	String(64)	R	客户订单号

}
  • 个人开源项目(通用后台管理系统)–> https://gitee.com/wslxm/spring-boot-plus2 , 喜欢的可以看看

  • 本文到此结束,如果觉得有用,动动小手点赞或关注一下呗,将不定时持续更新更多的内容…,感谢大家的观看!

猜你喜欢

转载自blog.csdn.net/qq_41463655/article/details/108631569
今日推荐