1. 注册及申请

注册及申请自己的顾客编码及校验码
地址
在这里插入图片描述

2. 下载sdk及引入

地址
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

        <dependency>
            <groupId>com.sf</groupId>
            <artifactId>SF-CSIM-EXPRESS-SDK</artifactId>
            <version>2.1.7</version>
            <scope>system</scope>
            <systemPath>${project.basedir}/lib/SF-CSIM-EXPRESS-SDK-V2.1.7.jar</systemPath>
        </dependency>

3.代码

3.1 实体类

吐槽一下 都提供sdk了 也不给提供参数类,这里只创建几个关键的,没用到了比如报关什么都没建立

package com.shimao.iibs.common.sf.domain;

import com.baomidou.mybatisplus.annotation.*;
import com.shimao.iibs.common.sf.ExpredssTypeEnum;
import lombok.Data;
import lombok.experimental.Accessors;

import javax.validation.constraints.*;
import java.math.BigDecimal;
import java.util.Date;
import java.util.List;

@Data
//@FieldDefaults(level = lombok.AccessLevel.PRIVATE)
@TableName(value = "sf_order")
@Accessors(chain = true)
public class Order {

    // ==================== 必填字段 ====================

    /**
     * id
     */
    @TableId(value = "id", type = IdType.AUTO)
    private Long id;

    /**
     * 客户订单号(必填)
     */
    @NotBlank(message = "订单号不能为空")
    @Size(max = 64, message = "订单号长度不能超过64")
    @TableField(value = "order_id")
    private String orderId;

    /**
     * 运单号
     */
    @TableField(value = "waybill_no")
    private String waybillNo;

    /**
     * 付款方式,支持以下值: 1:寄方付 2:收方付 3:第三方付
     * 字典 sf_pay_method
     */
    @Min(value = 1, message = "必须为1-3")
    @Max(value = 3, message = "必须为1-3")
    @TableField(value = "pay_method")
    private Integer payMethod = 1;

    /**
     * 收寄双方信息列表(必填)
     */
    @NotEmpty(message = "联系人信息不能为空")
    @TableField(exist = false)
    private List<ContactInfo> contactInfoList;

    /**
     * 托寄物信息(必填)
     */
    @NotEmpty(message = "托寄物信息不能为空")
    @TableField(exist = false)
    private List<CargoDetail> cargoDetails;

    /**
     * 快件产品类别代码
     * 字典 sf_expredss_type
     */
    @NotNull(message = "快件产品类别代码不能为空")
    @TableField(value = "express_type_id")
    private Integer expressTypeId = ExpredssTypeEnum.T4_1.getCode();

    /**
     * 快件产品类别名称
     */
    @NotNull(message = "快件产品类别名称")
    @TableField(value = "express_type_name")
    private Integer expressTypeName;

    /**
     * 响应报文的语言(必填,默认zh-CN)
     */
    @NotBlank(message = "语言不能为空")
    @Size(max = 10, message = "语言长度不能超过10")
    @Pattern(regexp = "zh-CN|zh-TW|zh-HK|zh-MO|en", message = "不支持的语种类型")
    @TableField(exist = false)
    private String language = "zh-CN";

    /**
     * 是否返回路由标签(必填,默认1)
     */
    @NotNull(message = "是否返回路由标签不能为空")
    @Min(value = 0, message = "必须为0或1")
    @Max(value = 1, message = "必须为0或1")
    @TableField(exist = false)
    private Integer isReturnRoutelabel = 1;


    /**
     * 顺丰月结卡号(月结支付时必填)
     */
    @Size(max = 20, message = "月结卡号长度不能超过20")
    @TableField(value = "monthly_Card")
    private String monthlyCard;

    /**
     * 订单货物总重量(子母件/郑州空港海关必填)
     */
    @Digits(integer = 17, fraction = 5, message = "总重量格式不正确")
    @DecimalMin(value = "0.001", inclusive = false, message = "总重量必须大于0")
    @TableField(exist = false)
    private BigDecimal totalWeight = new BigDecimal(0.5);

    /**
     * 上门取件开始时间
     * 要求上门取件开始时间, 格式: YYYY-MM-DD HH24:MM:SS, 示例: 2012-7-30 09:30:00 ,
     * 若该字段没有赋值,默认开始时间为当前时间,(可配合上门取件截止时间pickupAppointEndTime扩展字段备注进行下发,
     * 若没有给截止时间则系统默认1小时的截止时间)
     */
    @TableField(value = "send_start_tm")
    private Date sendStartTm;

    /**
     * 状态
     * 字典 sf_order_status
     */
    @TableField(value = "status")
    private String status;

    /**
     * 备注
     */
    @Size(max = 100, message = "长度不能超过100")
    @TableField(value = "remark")
    private String remark;

    /**
     * 是否通过手持终端 通知顺丰收派 员上门收件,支持以下值: 1:要求 0:不要求 (默认0)
     */
    @Min(value = 0, message = "必须为0或1")
    @Max(value = 1, message = "必须为0或1")
    @TableField(value = "is_docall")
    private Integer isDocall = 1;

    /**
     * 寄件人id
     */
    @TableField(value = "send_contact_id")
    private  String  sendContactId;

    /**
     * 收件人id
     */
    @TableField(value = "receive_contact_id")
    private  String  receiveContactId;

    /**
     * 邮寄内容
     */
    @TableField(value = "cargo_item")
    private  String  cargoItem;

    /**
     * 总费用
     */
    @TableField(exist = false)
    private BigDecimal totalWaybill;

    /**
     * 请求报文
     */
    @TableField(value = "params")
    private String params;

    /**
     * 结果报文
     */
    @TableField(value = "result")
    private String result;

    /**`
     * 创建者
     */
    @TableField(value = "create_by")
    private String createBy;

    /**
     * 创建用户
     */
    @TableField(exist = false)
    private String createName;

    /**
     * 创建时间
     */
    @TableField(value = "create_time", fill = FieldFill.INSERT)
    private Date createTime;


    // ==================== 取消订单用 ====================
    /**
     * 客户订单操作标识: 1:确认 (丰桥下订单接口默认自动确认,不需客户重复确认,该操作用在其它非自动确认的场景) 2:取消
     */
    @TableField(exist = false)
    private Integer dealType = 1;
    // ==================== 取消订单用 ====================



    // ==================== 查订单用 ====================
    /**
     * 查询类型:1正向单 2退货单
     */
    @Size(max = 2, message = "查询类型:1正向单 2退货单")
    @TableField(exist = false)
    private String searchType = "1";

    // ==================== 查订单用 ====================


    // ==================== 清单运费 ====================
    /**
     * 费用清单
     */
    @TableField(exist = false)
    private List<Waybill> waybillList;
    // ==================== 清单运费 ====================



    // ==================== 路由查询 ====================
    /**
     * 查询号类别:
     * 1:根据顺丰运单号查询,trackingNumber将被当作顺丰运单号处理
     * 2:根据客户订单号查询, trackingNumber将被当作客户订单号处理
     */
    @TableField(exist = false)
    private Integer trackingType = 2;

    /**
     * 查询号:
     * 1、如果trackingType=1,则此值为顺丰运单号
     * 2、如果trackingType=2,则此值为客户订单号
     */
    @TableField(exist = false)
    private List<String> trackingNumber;

    /**
     * 路由查询结果
     */
    @TableField(exist = false)
    private List<Routes> routesList;
    // ==================== 路由查询 ====================


    /**
     * 包裹数(默认1)
     */
    @Min(value = 1, message = "必须大于0")
    @TableField(exist = false)
    private Integer parcelQty = 1;

    /**
     * 是否返回二维码(默认0)
     */
    @Min(value = 0, message = "必须为0或1")
    @Max(value = 1, message = "必须为0或1")
    @TableField(exist = false)
    private Integer isReturnQRCode = 0;

    /**
     * 是否返回签回单路由标签(默认0)
     */
    @Min(value = 0, message = "必须为0或1")
    @Max(value = 1, message = "必须为0或1")
    @TableField(exist = false)
    private Integer isReturnSignBackRouteLabel = 0;

    /**
     * 是否使用统一面单号(默认0)
     */
    @Min(value = 0, message = "必须为0或1")
    @Max(value = 1, message = "必须为0或1")
    @TableField(exist = false)
    private Integer isUnifiedWaybillNo = 0;

    /**
     * 是否生成运单号(默认1)
     */
    @Min(value = 0, message = "必须为0或1")
    @Max(value = 1, message = "必须为0或1")
    @TableField(exist = false)
    private Integer isGenWaybillNo = 1;


    /**
     * 头程运单号(郑州空港海关必填)
     */
    //private String inProcessWaybillNo;

    /**
     * 订单货物总长
     */
    //private BigDecimal totalLength;

    /**
     * 订单货物总宽
     */
    //private BigDecimal totalWidth;

    /**
     * 订单货物总高
     */
    //private BigDecimal totalHeight;

    /**
     * 订单货物总体积
     */
    //private BigDecimal totalVolume;

    /**
     * 商品总净重
     */
    //private BigDecimal totalNetWeight;


}

package com.shimao.iibs.common.sf.domain;

import lombok.Data;

/**
 * 公共响应参数
 */
@Data
public class ApiResultData {
    /**
     * 请求是否成功(必填)
     * true-请求成功,false-请求失败
     */
    private Boolean success;

    /**
     * 错误编码(必填)
     * S0000表示成功
     */
    private String errorCode;

    /**
     * 错误描述(必填)
     */
    private String errorMsg;

    /**
     * 顺丰运单号
     */
    private String waybillNo;

    /**
     * 请求信息
     */
    private String params;

    /**
     * 返回的详细数据(必填)
     * 使用泛型适应不同数据类型
     */
    private String msgData;




}

package com.shimao.iibs.common.sf.domain;

import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import lombok.experimental.Accessors;

import javax.validation.constraints.*;
import java.io.Serializable;
import java.math.BigDecimal;

/**
 * 顺丰订单货物明细 仅下单使用 不存库
 */
@Data
@Accessors(chain = true)
public class CargoDetail implements Serializable {



    /**
     * 货物名称(必填,电子运单必填)
     */
    @NotBlank(message = "货物名称不能为空")
    @Size(max = 128, message = "货物名称长度不能超过128")
    private String name;

    /**
     * 货物数量(跨境件报关必填)
     */
    @Min(value = 1, message = "货物数量必须大于0")
    @Max(value = 99999, message = "货物数量不能超过99999")
    private Integer count;

    /**
     * 货物单位重量(跨境件报关必填)
     */
    @Digits(integer = 16, fraction = 3, message = "重量格式不正确")
    @DecimalMin(value = "0.001", message = "重量必须大于0")
    private BigDecimal weight;

    /**
     * 货物单位(跨境件报关必填)
     */
    @Size(max = 30, message = "货物单位长度不能超过30")
    private String unit;

    /**
     * 货物单价(跨境件报关必填)
     */
    //@Digits(integer = 17, fraction = 3, message = "金额格式不正确")
    //@DecimalMin(value = "0.001", message = "金额必须大于0")
    //private BigDecimal amount;

    /**
     * 货物单价的币别(跨境件报关必填)
     */
    //@Size(max = 5, message = "币别长度不能超过5")
    //private String currency;

    /**
     * 原产地国别(跨境件报关必填)
     */
    //@Size(max = 5, message = "原产地国别长度不能超过5")
    //private String sourceArea;

}

package com.shimao.iibs.common.sf.domain;

import com.baomidou.mybatisplus.annotation.*;
import lombok.Data;
import lombok.experimental.Accessors;

import javax.validation.constraints.*;
import java.util.Date;

/**
 * 收发人信息
 */
@Data
@Accessors(chain = true)
@TableName(value = "sf_contactInfo")
public class ContactInfo {

    /**
     * id
     */
    @TableId(value = "id", type = IdType.AUTO)
    private Long id;

    /**
     * sf_order表主键
     */
    @TableField(value = "marter_id")
    private Long marterId;

    /**
     * 客户订单号(必填)
     */
    @NotBlank(message = "订单号不能为空")
    @Size(max = 64, message = "订单号长度不能超过64")
    @TableField(value = "order_id")
    private String orderId;

    /**
     * 运单号
     */
    @TableField(value = "waybill_no")
    private String waybillNo;

    /**
     * 地址类型:1-寄件方信息,2-到件方信息(必填)
     */
    @NotNull(message = "地址类型不能为空")
    @Min(value = 1, message = "地址类型必须为1或2")
    @Max(value = 2, message = "地址类型必须为1或2")
    @TableField(value = "contact_type")
    private Integer contactType;


    /**
     * 联系人(条件必填)
     */
    @TableField(value = "contact")
    private String contact;

    /**
     * 公司名称(条件必填)
     */
    @TableField(value = "company")
    private String company;

    /**
     * 手机(条件必填:tel和mobile必填其中一个)
     */
    @TableField(value = "mobile")
    private String mobile;

    /**
     * 电话(条件必填:tel和mobile必填其中一个)
     */
    //private String tel;

    /**
     * 国家或地区代码 例如:内地件CN 香港852(必填)
     */
    @NotBlank(message = "国家代码不能为空")
    @Size(max = 30, message = "国家代码长度不能超过30")
    @TableField(value = "country")
    private String country = "CN";

    /**
     * 所在省级行政区名称(非必填)
     */
    @Size(max = 30, message = "省份长度不能超过30")
    @TableField(value = "province")
    private String province;

    /**
     * 所在地级行政区名称(非必填)
     */
    @Size(max = 100, message = "城市长度不能超过100")
    @TableField(value = "city")
    private String city;

    /**
     * 所在县/区级行政区名称(非必填)
     */
    @Size(max = 30, message = "区县长度不能超过30")
    @TableField(value = "county")
    private String county;

    /**
     * 详细地址(必填)
     * 详细地址,若有四级行政区划,如镇/街道等信息可拼接至此字段,格式样例:镇/街道+详细地址。
     * 若province/city 字段的值不传,此字段必须包含省市信息,避免影响原寄地代码识别,
     * 如:广东省深圳市福田区新洲十一街万基商务大厦10楼;此字段地址必须详细,否则会影响目的地中转识别
     */
    @NotBlank(message = "详细地址不能为空")
    @Size(max = 200, message = "地址长度不能超过200")
    @TableField(value = "address")
    private String address;


    /**
     * 备注
     */
    @Size(max = 100, message = "长度不能超过100")
    @TableField(value = "remark")
    private String remark;

    /**`
     * 创建者
     */
    @TableField(value = "create_by")
    private String createBy;

    /**
     * 创建用户
     */
    @TableField(exist = false)
    private String createName;

    /**
     * 创建时间
     */
    @TableField(value = "create_time", fill = FieldFill.INSERT)
    private Date createTime;

    /**
     * 邮编(条件必填:跨境件必填,中国内地、港澳台互寄除外)
     */
    //@Size(max = 25, message = "邮编长度不能超过25")
    //private String postCode;

    /**
     * 证件类型(非必填)
     */
    //@Size(max = 200, message = "证件类型长度不能超过200")
    //private String certType;

    /**
     * 证件号码(非必填)
     */
    //@Size(max = 1000, message = "证件号码长度不能超过1000")
    //private String certNo;

    /**
     * 邮箱地址(非必填)
     */
    //@Email(message = "邮箱格式不正确")
    //@Size(max = 200, message = "邮箱长度不能超过200")
    //private String email;

    /**
     * 税号(非必填)
     */
    //@Size(max = 100, message = "税号长度不能超过100")
    //private String taxNo;

    /**
     * 联系人属性(非必填)
     */
    //@Pattern(regexp = "01|02", message = "联系人属性必须是01或02")
    //@Size(max = 100, message = "联系人属性长度不能超过100")
    //private String contactRemark;


}

package com.shimao.iibs.common.sf.domain;

import com.baomidou.mybatisplus.annotation.*;
import lombok.Data;
import lombok.experimental.Accessors;

import java.io.Serializable;
import java.util.Date;

/**
 * 路由信息
 */
@Data
@Accessors(chain = true)
@TableName(value = "sf_routes")
public class Routes implements Serializable {

    /**
     * id
     */
    @TableId(value = "id", type = IdType.AUTO)
    private Long id;

    /**
     * sf_order表主键
     */
    @TableField(value = "marter_id")
    private Long marterId;

    /**
     * 订单id
     */
    @TableField(value = "order_id")
    private String orderId;

    /**
     * 运单号
     */
    @TableField(value = "waybill_no")
    private String waybillNo;

    /**
     * 路由节点时间
     * 格式:YYYY-MM-DD HH24:MM:SS
     */
    @TableField(value = "accept_time")
    private Date acceptTime;

    /**
     * 路由节点描述(必填)
     */
    @TableField(value = "remark")
    private String remark;

    /**
     * 操作码(必填)
     */
    @TableField(value = "op_code")
    private String opCode;

    /**
     * 路由节点地点
     */
    @TableField(value = "accept_address")
    private String acceptAddress;

    /**
     * 一级状态编码
     */
    @TableField(value = "first_status_code")
    private String firstStatusCode;

    /**
     * 一级状态名称
     */
    @TableField(value = "first_status_name")
    private String firstStatusName;

    /**
     * 二级状态编码(必填)
     */
    @TableField(value = "secondary_status_code")
    private String secondaryStatusCode;

    /**
     * 二级状态名称(必填)
     */
    @TableField(value = "secondary_status_name")
    private String secondaryStatusName;

    /**`
     * 创建者
     */
    @TableField(value = "create_by", fill = FieldFill.INSERT)
    private String createBy;

    /**
     * 创建用户
     */
    @TableField(exist = false)
    private String createName;

    /**
     * 创建时间
     */
    @TableField(value = "create_time", fill = FieldFill.INSERT)
    private Date createTime;


}

package com.shimao.iibs.common.sf.domain;


import com.baomidou.mybatisplus.annotation.*;
import lombok.Data;

import java.io.Serializable;
import java.math.BigDecimal;
import java.util.Date;

/**
 * 费用清单
 */
@Data
@TableName(value = "sf_waybill")
public class Waybill implements Serializable {

    /**
     * 主键
     */
    @TableId(value = "id", type = IdType.AUTO)
    private Long id;

    /**
     * sf_order表主键
     */
    @TableField(value = "marter_id")
    private Long marterId;


    /**
     * 订单id
     */
    @TableField(value = "order_id")
    private String orderId;

    /**
     * 运单号
     */
    @TableField(value = "waybill_no")
    private String waybillNo;

    /**
     * 查费用类型
     */
    @TableField(value = "waybill_type")
    private String waybillType;

    /**
     * 查费用名称
     */
    @TableField(value = "waybill_name")
    private String waybillName;

    /**
     * 费用金额
     */
    @TableField(value = "waybill_value")
    private BigDecimal waybillValue;

    /**
     * 付款类型:1、寄付;2、到付;3、第三方付
     * 字典 sf_payment_type
     */
    @TableField(value = "payment_type_code")
    private String paymentTypeCode;

    /**
     * 结算类型:1为现结;2为月结
     */
    @TableField(value = "settlement_type_code")
    private String settlementTypeCode;

    /**
     * 月结账号
     */
    @TableField(value = "customer_acct_code")
    private String customerAcctCode;

    /**`
     * 创建者
     */
    @TableField(value = "create_by", fill = FieldFill.INSERT)
    private String createBy;

    /**
     * 创建用户
     */
    @TableField(exist = false)
    private String createName;

    /**
     * 创建时间
     */
    @TableField(value = "create_time", fill = FieldFill.INSERT)
    private Date createTime;

}

3.2 工具类

package com.shimao.iibs.common.sf;


/**
 * 快递类型枚举
 * sf_expredss_type
 */

public enum ExpredssTypeEnum {
    T4_1(1, "T4", "顺丰特快"),
    T6_2(2, "T6", "顺丰标快"),
    T104_6(6, "T104", "顺丰即日"),
    T14_10(10, "T14", "国际小包"),
    T9_23(23, "T9", "顺丰国际特惠(文件)"),
    T9_24(24, "T9", "顺丰国际特惠(包裹)"),
    T7_26(26, "T7", "国际大件"),
    T7_29(29, "T7", "国际电商专递-标准"),
    T4_30(30, "T4", "三号便利箱(特快)"),
    T4_31(31, "T4", "便利封/袋(特快)"),
    T4_32(32, "T4", "二号便利箱(特快)"),
    T4_33(33, "T4", "岛内件(80CM)"),
    T23_35(35, "T23", "物资配送"),
    T4_39(39, "T4", "岛内件(110CM)"),
    T4_40(40, "T4", "岛内件(140CM)"),
    T4_41(41, "T4", "岛内件(170CM)"),
    T4_42(42, "T4", "岛内件(210CM)"),
    T4_43(43, "T4", "台湾岛内件-批(80CM)"),
    T4_44(44, "T4", "台湾岛内件-批(110CM)"),
    T4_45(45, "T4", "台湾岛内件-批(140CM)"),
    T4_46(46, "T4", "台湾岛内件-批(170CM)"),
    T4_47(47, "T4", "台湾岛内件-批(210CM)"),
    T4_48(48, "T4", "台湾岛内件店取(80CM)"),
    T4_49(49, "T4", "台湾岛内件店取(110CM)"),
    T4_50(50, "T4", "千点取60"),
    T4_51(51, "T4", "千点取80"),
    T4_52(52, "T4", "千点取100"),
    T4_53(53, "T4", "电商盒子F1"),
    T4_54(54, "T4", "电商盒子F2"),
    T4_55(55, "T4", "电商盒子F3"),
    T4_56(56, "T4", "电商盒子F4"),
    T4_57(57, "T4", "电商盒子F5"),
    T4_58(58, "T4", "电商盒子F6"),
    SP202_59(59, "SP202", "E顺递"),
    T4_60(60, "T4", "顺丰特快(文件)"),
    T4_61(61, "T4", "C1类包裹"),
    T4_62(62, "T4", "C2类包裹"),
    T4_63(63, "T4", "C3类包裹"),
    T4_64(64, "T4", "C4类包裹"),
    T4_65(65, "T4", "C5类包裹"),
    T4_66(66, "T4", "特快D类"),
    T4_73(73, "T4", "F5超值箱"),
    T4_99(99, "T4", "顺丰国际标快(文件)"),
    T4_100(100, "T4", "顺丰国际标快(包裹)"),
    T4_104(104, "T4", "岛内件(80CM,1kg以内)"),
    T9_106(106, "T9", "国际运输-门到门"),
    T36_111(111, "T36", "顺丰干配"),
    T6_113(113, "T6", "便利封/袋(标快)"),
    T6_114(114, "T6", "二号便利箱(标快)"),
    T6_115(115, "T6", "三号便利箱(标快)"),
    T4_116(116, "T4", "国际标快-BD2"),
    T4_117(117, "T4", "国际标快-BD3"),
    T4_118(118, "T4", "国际标快-BD4"),
    T4_119(119, "T4", "国际标快-BD5"),
    T4_120(120, "T4", "国际标快-BD6"),
    T4_121(121, "T4", "国际标快-BDE"),
    T4_126(126, "T4", "掌柜-大格"),
    T4_127(127, "T4", "掌柜-中格"),
    T4_128(128, "T4", "掌柜-小格"),
    T4_129(129, "T4", "掌柜-柜到柜(单程)"),
    T4_130(130, "T4", "掌柜-柜到柜(双程)"),
    T9_132(132, "T9", "顺丰国际特惠(FBA)"),
    T4_136(136, "T4", "国际集运"),
    T104_144(144, "T104", "当日配-门(80CM/1KG以内)"),
    T104_145(145, "T104", "当日配-门(80CM)"),
    T104_146(146, "T104", "当日配-门(110CM)"),
    T104_147(147, "T104", "当日配-门(140CM)"),
    T104_148(148, "T104", "当日配-门(170CM)"),
    T104_149(149, "T104", "当日配-门(210CM)"),
    T6_150(150, "T6", "标快D类"),
    T12_153(153, "T12", "整车直达"),
    T9_160(160, "T9", "国际运输-港到港"),
    T4_178(178, "T4", "一号便利箱(特快)"),
    T6_179(179, "T6", "一号便利箱(标快)"),
    T4_180(180, "T4", "岛內件-专车普运"),
    T4_184(184, "T4", "顺丰国际标快+(文件)"),
    T4_186(186, "T4", "顺丰国际标快+(包裹)"),
    T15_201(201, "T15", "冷运标快"),
    T4_202(202, "T4", "顺丰微小件"),
    SP619_207(207, "SP619", "限时次日"),
    T39_215(215, "T39", "大票直送"),
    T7_218(218, "T7", "国际电商专递-CD"),
    T15_221(221, "T15", "香港冷运到家(≤60厘米)"),
    T15_222(222, "T15", "香港冷运到家(61-80厘米)"),
    T15_223(223, "T15", "香港冷运到家(81-100厘米)"),
    T15_224(224, "T15", "香港冷运到家(101-120厘米)"),
    T15_225(225, "T15", "香港冷运到家(121-150厘米)"),
    T6_231(231, "T6", "陆运包裹"),
    T66_235(235, "T66", "预售当天达"),
    T68_236(236, "T68", "电商退货"),
    T7_241(241, "T7", "国际电商专递-快速"),
    T4_244(244, "T4", "店到店"),
    T4_245(245, "T4", "店到门"),
    T4_246(246, "T4", "门到店"),
    T68_247(247, "T68", "电商标快"),
    T4_249(249, "T4", "丰礼遇"),
    T123_252(252, "T123", "即时城配"),
    T122_253(253, "T122", "前置当天达"),
    T28_255(255, "T28", "顺丰卡航"),
    T28_256(256, "T28", "顺丰卡航(D类)"),
    T4_257(257, "T4", "医药温控配送"),
    T4_258(258, "T4", "退换自寄"),
    T104_259(259, "T104", "极速配"),
    T68_261(261, "T68", "O2O店配"),
    T6_262(262, "T6", "前置标快"),
    T11_263(263, "T11", "顺丰半日达"),
    T67_265(265, "T67", "预售电标"),
    T5_266(266, "T5", "顺丰空配(新)"),
    T4_267(267, "T4", "失物送递"),
    T4_268(268, "T4", "行李送递"),
    T4_269(269, "T4", "酒类配送"),
    T4_270(270, "T4", "行李托运-上门"),
    T4_271(271, "T4", "行李托运"),
    T4_272(272, "T4", "行李送递-上门 (九龙)"),
    SP7_273(273, "SP7", "温控配送自取"),
    SP7_274(274, "SP7", "温控配送上门"),
    SP7_275(275, "SP7", "酒类温控自取"),
    SP7_276(276, "SP7", "酒类温控上门"),
    T73_277(277, "T73", "跨境FBA空运"),
    T74_278(278, "T74", "跨境FBA海运"),
    T75_283(283, "T75", "填舱标快"),
    T76_285(285, "T76", "填舱电标"),
    T41_293(293, "T41", "特快包裹(新)"),
    T98_297(297, "T98", "样本安心递"),
    T99_299(299, "T99", "标快零担"),
    T105_303(303, "T105", "专享即日"),
    T43_308(308, "T43", "国际特快(文件)"),
    T43_310(310, "T43", "国际特快(包裹)"),
    T78_314(314, "T78", "中国内地集运"),
    T44_316(316, "T44", "前置次日达"),
    T69_318(318, "T69", "航空港到港"),
    T79_323(323, "T79", "电商微小件"),
    T682_325(325, "T682", "温控包裹"),
    T281_329(329, "T281", "填舱大件"),
    T124_331(331, "T124", "区域城配"),
    T125_355(355, "T125", "计划城配");

    private final int code;
    private final String typeCode;
    private final String description;

    ExpredssTypeEnum(int code, String typeCode, String description) {
        this.code = code;
        this.typeCode = typeCode;
        this.description = description;
    }

    public int getCode() {
        return code;
    }

    public String getTypeCode() {
        return typeCode;
    }

    public String getDescription() {
        return description;
    }

    /**
     * 根据code获取枚举
     */
    public static ExpredssTypeEnum getByCode(int code) {
        for (ExpredssTypeEnum type : values()) {
            if (type.code == code) {
                return type;
            }
        }
        return null;
    }

    /**
     * 根据typeCode获取枚举
     */
    public static ExpredssTypeEnum getByTypeCode(String typeCode) {
        for (ExpredssTypeEnum type : values()) {
            if (type.typeCode.equals(typeCode)) {
                return type;
            }
        }
        return null;
    }
}

package com.shimao.iibs.common.sf;

import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.shimao.iibs.common.sf.domain.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.math.BigDecimal;
import java.util.*;

/**
 * 顺丰报文格式转换
 */
public class SFDataFormat {
    private static final Logger log = LoggerFactory.getLogger("sf-api-callBack");

    public static ApiResultData createOrderFormat(String str) {
        //订单信息
        String resultDataStr = JSONUtil.parseObj(str).get("apiResultData") + "";
        ApiResultData appResultData = JSONUtil.toBean(resultDataStr, ApiResultData.class);
        JSONObject apiResultData = JSONUtil.parseObj(JSONUtil.parseObj(str).get("apiResultData"));

        if (apiResultData.getBool("success")) {
            //单号信息
            String waybillNo = JSONUtil.getByPath(apiResultData, "$.msgData.routeLabelInfo[0].routeLabelData.waybillNo") + "";
            appResultData.setWaybillNo(waybillNo);
            log.info("顺丰单号:" + waybillNo);
        }

        log.info("顺丰结果:" + appResultData);
        return appResultData;
    }

    public static ApiResultData queryWaybillFormat(String str, Order order) {
        //订单信息
        String resultDataStr = JSONUtil.parseObj(str).get("apiResultData") + "";
        ApiResultData appResultData = JSONUtil.toBean(resultDataStr, ApiResultData.class);
        JSONObject apiResultData = JSONUtil.parseObj(JSONUtil.parseObj(str).get("apiResultData"));

        if (apiResultData.getBool("success")) {
            JSONObject json = JSONUtil.parseObj(str);//层级获取
            JSONObject apiResultJson = json.getJSONObject("apiResultData");
            JSONObject msgDataJson = apiResultJson.getJSONObject("msgData");
            JSONArray waybillFeeList = msgDataJson.getJSONArray("waybillFeeList");
            JSONObject waybillInfo = msgDataJson.getJSONObject("waybillInfo");

            List<Waybill> waybills = new ArrayList<>();
            for (int i = 0; i < waybillFeeList.size(); i++) {
                JSONObject waybillFee = waybillFeeList.getJSONObject(i);
                Waybill waybill = new Waybill();
                waybill.setOrderId(order.getOrderId());
                waybill.setWaybillNo(waybillInfo.getStr("waybillNo"));//运单号
                waybill.setWaybillType(waybillFee.getStr("type"));//查费用类型
                waybill.setWaybillName(waybillFee.getStr("name"));//查费用名称
                waybill.setWaybillValue(new BigDecimal(waybillFee.getStr("value")));//费用金额
                waybill.setPaymentTypeCode(waybillFee.getStr("paymentTypeCode"));//付款类型:1、寄付;2、到付;3、第三方付
                waybill.setSettlementTypeCode(waybillFee.getStr("settlementTypeCode"));//结算类型:1为现结;2为月结
                waybill.setCustomerAcctCode(waybillFee.getStr("customerAcctCode"));//月结账号
                waybills.add(waybill);
            }

            order.setWaybillList(waybills);
        }


        log.info("顺丰清单运费查询结果:" + order);
        return appResultData;
    }

    public static ApiResultData queryRoutesFormat(String str, Order order) {
        //订单信息
        String resultDataStr = JSONUtil.parseObj(str).get("apiResultData") + "";
        ApiResultData appResultData = JSONUtil.toBean(resultDataStr, ApiResultData.class);
        JSONObject apiResultData = JSONUtil.parseObj(JSONUtil.parseObj(str).get("apiResultData"));
        if (apiResultData.getBool("success")) {
            JSONObject json = JSONUtil.parseObj(str);//层级获取
            JSONObject apiResultJson = json.getJSONObject("apiResultData");
            JSONObject msgDataJson = apiResultJson.getJSONObject("msgData");

            //JSONObject routeResps = msgDataJson.getJSONObject("routeResps");
            JSONArray routeRespsList = msgDataJson.getJSONArray("routeResps");
            //JSONArray routesList = routeRespsList.getJSONArray("routes");

            System.out.println("routeRespsList" + routeRespsList);

            List<Routes> routes = new ArrayList<>();
            for (int i = 0; i < routeRespsList.size(); i++) {
                JSONObject routeResps = routeRespsList.getJSONObject(i);

                JSONArray routesList = routeResps.getJSONArray("routes");
                for (int x = 0; x < routesList.size(); x++) {
                    JSONObject routeJson = routesList.getJSONObject(x);
                    Routes route = new Routes()
                            .setOrderId(order.getOrderId())
                            .setWaybillNo(routeJson.getStr("mailNo"))//运单号
                            .setAcceptTime(routeJson.getDate("acceptTime"))//路由节点时间
                            .setAcceptAddress(routeJson.getStr("acceptAddress"))//路由节点地址
                            .setOpCode(routeJson.getStr("opCode"))//操作码
                            .setSecondaryStatusCode(routeJson.getStr("secondaryStatusCode"))//二级状态码
                            .setSecondaryStatusName(routeJson.getStr("secondaryStatusName"))//二级状态名称
                            .setFirstStatusCode(routeJson.getStr("firstStatusCode"))//一级状态码
                            .setFirstStatusName(routeJson.getStr("firstStatusName"))//一级状态名称
                            .setRemark(order.getRemark())
                            .setCreateTime(new Date());
                    routes.add(route);
                }

            }

            order.setRoutesList( routes);
        }

        log.info("顺丰清单运费查询结果:" + order);
        return appResultData;
    }


    public static void main(String[] args) {

        String jsonString = "{\"apiErrorMsg\":\"\",\"apiResponseID\":\"000198A0E95AAF3FE48701968B22EF3F\",\"apiResultCode\":\"A1000\",\"apiResultData\":\"{\\\"success\\\":true,\\\"errorCode\\\":\\\"S0000\\\",\\\"errorMsg\\\":null,\\\"msgData\\\":{\\\"orderId\\\":\\\"0000001\\\",\\\"originCode\\\":\\\"755\\\",\\\"destCode\\\":\\\"010\\\",\\\"filterResult\\\":2,\\\"remark\\\":\\\"\\\",\\\"url\\\":null,\\\"paymentLink\\\":null,\\\"isUpstairs\\\":null,\\\"isSpecialWarehouseService\\\":null,\\\"mappingMark\\\":null,\\\"agentMailno\\\":null,\\\"returnExtraInfoList\\\":null,\\\"waybillNoInfoList\\\":[{\\\"waybillType\\\":1,\\\"waybillNo\\\":\\\"SF7444498114972\\\",\\\"boxNo\\\":null,\\\"length\\\":null,\\\"width\\\":null,\\\"height\\\":null,\\\"weight\\\":null,\\\"volume\\\":null}],\\\"routeLabelInfo\\\":[{\\\"code\\\":\\\"1000\\\",\\\"routeLabelData\\\":{\\\"waybillNo\\\":\\\"SF7444498114972\\\",\\\"sourceTransferCode\\\":\\\"755W\\\",\\\"sourceCityCode\\\":\\\"755\\\",\\\"sourceDeptCode\\\":\\\"755\\\",\\\"sourceTeamCode\\\":\\\"\\\",\\\"destCityCode\\\":\\\"010\\\",\\\"destDeptCode\\\":\\\"010\\\",\\\"destDeptCodeMapping\\\":\\\"\\\",\\\"destTeamCode\\\":\\\"\\\",\\\"destTeamCodeMapping\\\":\\\"\\\",\\\"destTransferCode\\\":\\\"010W\\\",\\\"destRouteLabel\\\":\\\"010W-010\\\",\\\"proName\\\":\\\"\\\",\\\"cargoTypeCode\\\":\\\"C201\\\",\\\"limitTypeCode\\\":\\\"T4\\\",\\\"expressTypeCode\\\":\\\"B1\\\",\\\"codingMapping\\\":\\\"WU\\\",\\\"codingMappingOut\\\":\\\"\\\",\\\"xbFlag\\\":\\\"0\\\",\\\"printFlag\\\":\\\"000000000\\\",\\\"twoDimensionCode\\\":\\\"MMM={'k1':'010W','k2':'010','k3':'','k4':'T4','k5':'SF7444498114972','k6':'','k7':'86e53682'}\\\",\\\"proCode\\\":\\\"特快\\\",\\\"printIcon\\\":\\\"00000000\\\",\\\"abFlag\\\":\\\"\\\",\\\"destPortCode\\\":\\\"\\\",\\\"destCountry\\\":\\\"\\\",\\\"destPostCode\\\":\\\"\\\",\\\"goodsValueTotal\\\":\\\"\\\",\\\"currencySymbol\\\":\\\"\\\",\\\"cusBatch\\\":\\\"\\\",\\\"goodsNumber\\\":\\\"\\\",\\\"errMsg\\\":\\\"\\\",\\\"checkCode\\\":\\\"86e53682\\\",\\\"proIcon\\\":\\\"\\\",\\\"fileIcon\\\":\\\"\\\",\\\"fbaIcon\\\":\\\"\\\",\\\"icsmIcon\\\":\\\"\\\",\\\"destGisDeptCode\\\":\\\"010\\\",\\\"newIcon\\\":null,\\\"sendAreaCode\\\":null,\\\"destinationStationCode\\\":null,\\\"sxLabelDestCode\\\":null,\\\"sxDestTransferCode\\\":null,\\\"sxCompany\\\":null,\\\"newAbFlag\\\":null,\\\"destAddrKeyWord\\\":\\\"\\\",\\\"rongType\\\":null,\\\"waybillIconList\\\":null},\\\"message\\\":\\\"SF7444498114972:\\\"}],\\\"contactInfoList\\\":null,\\\"sendStartTm\\\":null,\\\"customerRights\\\":null,\\\"expressTypeId\\\":null}}\"}\n";
        createOrderFormat(jsonString);

    }


}

package com.shimao.iibs.common.sf;

import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;

/**
 * 顺丰加密通用接口工具类
 */
public class SFMd5EncodeUtil {

    /**
     * MD5加密
     * @param str 报文
     * @param timeStamp 时间戳
     * @param key 平台获取的校验码
     * @return 加密后的密文
     */
    public static String getMD5(String str,String timeStamp,String key) throws UnsupportedEncodingException {
        String toVerifyText = URLEncoder.encode(str+ timeStamp + key, "UTF8");
        MessageDigest md5 = null;
        try {
            md5 = MessageDigest.getInstance("MD5");
        } catch (NoSuchAlgorithmException e) {
            throw new RuntimeException(e);
        }
        md5.update(toVerifyText.getBytes(StandardCharsets.UTF_8));
        byte[] md = md5.digest();

        //通过BASE64生成数字签名
        String msgDigest = Base64.getEncoder().encodeToString(md);
        if(msgDigest != null){
            return msgDigest;
        }
        return null;
    }
}

可以直接main方法执行,记得换成你的顾客编码及效验码
package com.shimao.iibs.common.sf;

import cn.hutool.json.JSONUtil;
import com.sf.csim.express.service.HttpClientUtil;
import com.sf.csim.express.service.code.ExpressServiceCodeEnum;
import com.shimao.iibs.common.core.domain.R;
import com.shimao.iibs.common.sf.domain.*;

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

import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;


/**
 * 顺丰接口工具类
 */
public class SFUtils {
    private static final Logger log = LoggerFactory.getLogger("sf-api");

    private static final String CLIENT_CODE ="SMKJFRW1ERL2";  //顾客编码
    private static final String CHECK_WORD = "MEvLbOPOCrEfbSXM2L2lcyf5kgQ2OBdZ";//校验码
    private static final String CALL_URL_BOX = "https://sfapi-sbox.sf-express.com/std/service";//沙箱环境的地址 -Test
    //private static final String CALL_URL_BOX = "https://sfapi.sf-express.com/std/service";//生产环境的地址 -PROD
    private static final String MONTHLY_CARD = "7551234567";//月结卡号


    //  ExpressServiceCodeEnum.EXP_RECE_CREATE_ORDER; //下订单   1
    //  ExpressServiceCodeEnum.EXP_RECE_SEARCH_ORDER_RESP; //查订单 1
    //  ExpressServiceCodeEnum.EXP_RECE_UPDATE_ORDER;//订单取消 1
    // 	ExpressServiceCodeEnum.EXP_RECE_FILTER_ORDER_BSP;//订单筛选
    //  ExpressServiceCodeEnum.EXP_RECE_SEARCH_ROUTES;//查路由 1
    //	ExpressServiceCodeEnum.EXP_RECE_GET_SUB_MAILNO;//子单号
    //	ExpressServiceCodeEnum.EXP_RECE_QUERY_SFWAYBILL;//查运费 1
    //	ExpressServiceCodeEnum.EXP_RECE_REGISTER_ROUTE;//注册路由
    //	ExpressServiceCodeEnum.EXP_RECE_CREATE_REVERSE_ORDER;//退货下单
    //	ExpressServiceCodeEnum.EXP_RECE_CANCEL_REVERSE_ORDER;//退货消单
    //	ExpressServiceCodeEnum.EXP_RECE_WANTED_INTERCEPT;//截单转寄
    // 	ExpressServiceCodeEnum.EXP_RECE_QUERY_DELIVERTM;//时效标准及价格查询
    //  ExpressServiceCodeEnum.COM_RECE_CLOUD_PRINT_WAYBILLS;//面单打印
    //  ExpressServiceCodeEnum.EXP_RECE_UPLOAD_ROUTE;//路由上传
    //  ExpressServiceCodeEnum.EXP_RECE_SEARCH_PROMITM;//预计派送时间查询
    //  ExpressServiceCodeEnum.EXP_EXCE_CHECK_PICKUP_TIME;//揽件服务时间查询
    //  ExpressServiceCodeEnum.EXP_RECE_VALIDATE_WAYBILLNO;//运单号合法性校验


    /**
     * 创建顺丰订单
     */
    public static R createOrder(Order order) throws UnsupportedEncodingException {
        order.setMonthlyCard(MONTHLY_CARD);//月卡
        String jsonStr = JSONUtil.toJsonStr(order);
        Map<String, String> params = new HashMap<>();
        //获取当前时间戳
        String timeStamp = String.valueOf(System.currentTimeMillis());
        params.put("partnerID", CLIENT_CODE);
        params.put("requestID", order.getOrderId());
        params.put("serviceCode", ExpressServiceCodeEnum.EXP_RECE_CREATE_ORDER.getCode());// 接口服务码
        params.put("timestamp", timeStamp);
        params.put("msgData", jsonStr);
        String md5 = SFMd5EncodeUtil.getMD5(jsonStr, timeStamp, CHECK_WORD);
        params.put("msgDigest", md5);
        log.info("====顺丰下单请求:" + params);
        order.setParams(params.toString());
        try {
            String result = HttpClientUtil.post(CALL_URL_BOX, params);

            log.info("====顺丰下单接口报文:" + result);
            ApiResultData resultData = SFDataFormat.createOrderFormat(result);
            if (resultData.getSuccess()) {
                log.info("====顺丰下单成功");
                return R.ok(null, "顺丰下单成功");
            }
        } catch (UnsupportedEncodingException e) {
            throw new RuntimeException(e);
        }
        return R.fail("顺丰快递下单失败");
    }

    /**
     * 查询顺丰订单
     * 因Internet环境下,网络不是绝对可靠,用户系统下订单到顺丰后,不一定可以收到顺丰系统返回的数据,
     * 此接口用于在未收到返回数据时,查询订单创建接口客户订单当前的处理情况。
     */
    public static R queryOrder(Order order) throws UnsupportedEncodingException {
        String jsonStr = JSONUtil.toJsonStr(order);
        Map<String, String> params = new HashMap<>();
        //获取当前时间戳
        String timeStamp = String.valueOf(System.currentTimeMillis());
        params.put("partnerID", CLIENT_CODE);
        params.put("requestID", order.getOrderId());
        params.put("serviceCode", ExpressServiceCodeEnum.EXP_RECE_SEARCH_ORDER_RESP.getCode());// 接口服务码
        params.put("timestamp", timeStamp);
        params.put("msgData", jsonStr);
        String md5 = SFMd5EncodeUtil.getMD5(jsonStr, timeStamp, CHECK_WORD);
        params.put("msgDigest", md5);
        log.info("====顺丰查询订单请求:" + params);
        order.setParams(params.toString());
        try {
            String result = HttpClientUtil.post(CALL_URL_BOX, params);
            order.setResult(result);
            log.info("====顺丰查询订单接口报文:" + result);
            ApiResultData resultData = SFDataFormat.createOrderFormat(result);
            if (resultData.getSuccess()) {
                log.info("====顺丰查询订单成功");
                return R.ok(null, "顺丰查询订单成功");
            }
        } catch (UnsupportedEncodingException e) {
            throw new RuntimeException(e);
        }
        return R.fail("顺丰查询订单失败");
    }

    /**
     * 订单确认/取消接口
     * (1)客户在确定将货物交付给顺丰托运后,将运单上的一些重要信息,如快件重量通过此接口发送给顺丰。
     * (2)客户在发货前取消订单。
     */
    public static R updateOrder(Order order) throws UnsupportedEncodingException {
        order.setDealType(2);//客户订单操作标识: 1:确认  2:取消
        String jsonStr = JSONUtil.toJsonStr(order);
        Map<String, String> params = new HashMap<>();
        //获取当前时间戳
        String timeStamp = String.valueOf(System.currentTimeMillis());
        params.put("partnerID", CLIENT_CODE);
        params.put("requestID", order.getOrderId());
        params.put("serviceCode", ExpressServiceCodeEnum.EXP_RECE_UPDATE_ORDER.getCode());// 接口服务码
        params.put("timestamp", timeStamp);
        params.put("msgData", jsonStr);
        String md5 = SFMd5EncodeUtil.getMD5(jsonStr, timeStamp, CHECK_WORD);
        params.put("msgDigest", md5);
        log.info("====顺丰订单取消请求:" + params);
        order.setParams(params.toString());
        try {
            String result = HttpClientUtil.post(CALL_URL_BOX, params);
            order.setResult(result);
            log.info("====顺丰订单取消接口报文:" + result);
            ApiResultData resultData = SFDataFormat.createOrderFormat(result);
            if (resultData.getSuccess()) {
                log.info("====顺丰订单取消成功");
                return R.ok(null, "顺丰订单取消成功");
            }
        } catch (UnsupportedEncodingException e) {
            throw new RuntimeException(e);
        }
        return R.fail("顺丰订单取消失败");
    }


    /**
     * 清单运费查询接口
     * 此功能主要是根据订单号或者运单号查询清单运费信息。
     * 默认校验月结信息,只能查询顾客编码下绑定成功的月结卡的订单
     */
    public static R queryWaybill(Order order) throws UnsupportedEncodingException {
        Map map = new HashMap();
        map.put("trackingType", "1");//1:表示按订单查询 2:表示按运单查询
        map.put("trackingNum", order.getOrderId());//订单号或运单号;
        String jsonStr = JSONUtil.toJsonStr(map);
        Map<String, String> params = new HashMap<>();
        //获取当前时间戳
        String timeStamp = String.valueOf(System.currentTimeMillis());
        params.put("partnerID", CLIENT_CODE);
        params.put("requestID", order.getOrderId());
        params.put("serviceCode", ExpressServiceCodeEnum.EXP_RECE_QUERY_SFWAYBILL.getCode());// 接口服务码
        params.put("timestamp", timeStamp);
        params.put("msgData", jsonStr);
        String md5 = SFMd5EncodeUtil.getMD5(jsonStr, timeStamp, CHECK_WORD);
        params.put("msgDigest", md5);
        order.setParams(params.toString());
        log.info("====顺丰清单运费查询请求:" + params);
        try {
            String result = HttpClientUtil.post(CALL_URL_BOX, params);
            log.info("====顺丰清单运费查询接口报文:" + result);
            ApiResultData resultData = SFDataFormat.queryWaybillFormat(result, order);
            if (resultData.getSuccess()) {
                log.info("====顺丰清单运费查询成功");
                return R.ok(null, "顺丰清单运费查询成功");
            }
        } catch (UnsupportedEncodingException e) {
            throw new RuntimeException(e);
        }
        return R.fail("顺丰清单运费查询失败");
    }


    /**
     * 路由查询接口
     * 客户可通过此接口查询顺丰运单路由,顺丰会在响应Json报文返回当时点要求的全部路由节点信息。
     * 说明:
     * ①可查询3个月内运单路由,路由响应空值代表无查询权限/无路由/超3个月。
     * ②响应报文为MOCK,不受全流程测试工具影响。
     * 此路由查询接口支持三类查询方式:
     * 1)根据顺丰运单号查询(限月结付款):所查询运单号付款使用的月结卡号,与调用接口时所用的partnerID(顾客编码)存在绑定关系,系统返回运单路由信息;反之routes路由响应空值。
     * 2)根据客户订单号查询:查询请求中提供partnerID(顾客编码)与订单号,验证partnerID(顾客编码)与所有请求订单号的归属关系,对于归属关系正确的订单号,找到对应的运单号,然后返回订单对应运单号的路由信息。适用于通过该partnerID(顾客编码)下单的客户。
     * 3)根据运单号+运单对应的收寄人任一方电话号码后4位(参数checkPhoneNo中传入)查询,系统校验信息匹配将返回对应运单路由信息。一次性查多个路由,checkPhoneNo传入多个电话号码后4位,用英文逗号隔开,作为一个字符串
     */
    public static R queryRoutes(Order order) throws UnsupportedEncodingException {
        order.setDealType(2);//客户订单操作标识: 1:确认  2:取消
        String jsonStr = JSONUtil.toJsonStr(order);
        Map<String, String> params = new HashMap<>();
        //获取当前时间戳
        String timeStamp = String.valueOf(System.currentTimeMillis());
        params.put("partnerID", CLIENT_CODE);
        params.put("requestID", timeStamp);
        params.put("serviceCode", ExpressServiceCodeEnum.EXP_RECE_SEARCH_ROUTES.getCode());// 接口服务码
        params.put("timestamp", timeStamp);
        params.put("msgData", jsonStr);
        String md5 = SFMd5EncodeUtil.getMD5(jsonStr, timeStamp, CHECK_WORD);
        params.put("msgDigest", md5);
        log.info("====顺丰路由查询接口请求:" + params);
        order.setParams(params.toString());
        try {
            String result = HttpClientUtil.post(CALL_URL_BOX, params);
            order.setResult(result);
            log.info("====顺丰路由查询接口报文:" + result);
            ApiResultData resultData = SFDataFormat.queryRoutesFormat(result, order);
            if (resultData.getSuccess()) {
                log.info("====顺丰路由查询成功");
                return R.ok(null, "顺丰路由查询成功");
            }
        } catch (UnsupportedEncodingException e) {
            throw new RuntimeException(e);
        }
        return R.fail("顺丰路由查询失败");
    }



    public static void main(String[] args) throws UnsupportedEncodingException {
        //下单
        //createOrder(initCreateOrder());

        //查询订单
        //queryOrder(initQueryOrder());

        //取消订单
        //updateOrder(initUpdateOrder());

        //清单运费
        //queryWaybill(initWaybillOrder());

        //路由查询
        //queryRoutes(initRoutesOrder());
    }

    static String ORDER_ID = "0000003";//订单号

    /**
     * 初始创建订单测试参数
     */
    static Order initCreateOrder(){
        // 设置订单信息
        Order order = new Order()
                .setOrderId(ORDER_ID)//客户订单号,重复使用订单号时返回第一次下单成功时的运单信息
                .setDealType(1) //1:确认 (丰桥下订单接口默认自动确认,不需客户重复确认,该操作用在其它非自动确认的场景) 2:取消
                .setParcelQty(1)//包裹数,一个包裹对应一个运单号;若包裹数大于1,则返回一个母运单号和N-1个子运单号
                .setExpressTypeId(ExpredssTypeEnum.T4_1.getCode())//快件产品类别
                .setIsReturnRoutelabel(1)//是否返回路由标签: 默认1, 1:返回路由标签, 0:不返回;
                .setIsDocall(1);//是否通过手持终端 通知顺丰收派 员上门收件,支持以下值: 1:要求 0:不要求

        // 设置货物信息
        List<CargoDetail> cargoDetails = new ArrayList<>();
        CargoDetail cargoDetail = new CargoDetail()
                .setName("护肤品1");//货物名称
                //.setCount(1)//货物数量 跨境件报关需要填写
                //.setUnit("件")//跨境件报关需要填写
                //.setWeight(new BigDecimal("3.5"));//订单货物单位重量,包含子母件, 单位千克,精确到小数点后3位 跨境件报关需要填写
        cargoDetails.add(cargoDetail);
        order.setCargoDetails(cargoDetails);

        // 设置收寄双方信息
        List<ContactInfo> contactInfoList = new ArrayList<>();
        ContactInfo senderInfo = new ContactInfo()
                .setContact("张三")//联系人
                .setContactType(1) // 地址类型: 1,寄件方信息 2,到件方信息
                .setAddress("广东省深圳市南山区科技园南区")
                .setCountry("CN")//国家代码
                .setProvince("广东省")//省份
                .setCity("深圳市")// 城市
                .setCounty("南山区")//区县
                .setMobile("13800138000");
        contactInfoList.add(senderInfo);

        ContactInfo receiverInfo = new ContactInfo()
                .setContact("李四")//联系人
                .setContactType(2) // 地址类型: 1,寄件方信息 2,到件方信息
                //.setCompany("顺丰速运")//公司名称
                //.setPostCode("518000")//邮编,跨境件必填
                .setAddress("北京市朝阳区望京街道")
                .setCountry("CN")//国家代码
                .setProvince("北京市")//省份
                .setCity("北京市")// 城市
                .setCounty("朝阳区")//区县
                .setMobile("13900139000");
        contactInfoList.add(receiverInfo);
        order.setContactInfoList(contactInfoList);
        return order;
    }

    /**
     * 初始查询订单测试参数
     */
    static Order initQueryOrder(){
        // 设置订单信息
        Order order = new Order()
                .setOrderId(ORDER_ID)
                .setSearchType("1"); //查询类型:1正向单 2退货单
                //.setMainWaybillNo("")//顺丰下单接口返回的15或12位运单号,母单号 如:SF10116351372291
        return order;
    }

    /**
     * 初始取消订单测试参数
     */
    static Order initUpdateOrder(){
        // 设置订单信息
        Order order = new Order()
                .setOrderId(ORDER_ID)//客户订单号,重复使用订单号时返回第一次下单成功时的运单信息
                .setDealType(2); //1:确认 (丰桥下订单接口默认自动确认,不需客户重复确认,该操作用在其它非自动确认的场景) 2:取消
        return order;
    }

    /**
     * 初始清单运费测试参数
     */
    static Order initWaybillOrder(){
        // 设置订单信息
        Order order = new Order().setOrderId(ORDER_ID);
        return order;
    }

    /**
     * 初始路由查询测试参数
     */
    static Order initRoutesOrder(){
        // 订单号
        String orderNo = "SF7444498111484";
        List<String> orderList = new ArrayList<>();
        orderList.add(orderNo);
        // 设置订单信息
        Order order = new Order()
                .setTrackingType(1)//查询号类别: 1:根据顺丰运单号查询, 2:根据客户订单号查询
                .setTrackingNumber(orderList);//查询号 trackingType=1,则此值为顺丰运单号 如果trackingType=2,则此值为客户订单号
        return order;
    }
}

顺丰提供的 呵呵
package com.shimao.iibs.common.sf;


import java.io.UnsupportedEncodingException;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import com.sf.csim.express.service.CallExpressServiceTools;
import com.sf.csim.express.service.HttpClientUtil;
import com.sf.csim.express.service.IServiceCodeStandard;
import com.sf.csim.express.service.code.ExpressServiceCodeEnum;
import com.sf.csim.express.service.code.HZTServiceCodeEnum;

public class TestCallExpressNewAPIService {

    /**丰桥新沙箱测试顾客编码  Yg4Zf06w_sxZs3A5D
     校验码  3Xdk1jqeG1Xod9nUXus8Op7DNOkchTnw
     **/
    private static final String CLIENT_CODE = "SMKJFRW1ERL2";  //此处替换为您在丰桥平台获取的顾客编码
    private static final String CHECK_WORD = "MEvLbOPOCrEfbSXM2L2lcyf5kgQ2OBdZ";//此处替换为您在丰桥平台获取的校验码


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

    public static void main(String[] args) throws UnsupportedEncodingException {
        /**ExpressServiceCodeEnum     对应速运类-快递APIs
         POSTServiceCodeEnum        对应速运类-驿站APIs
         YJTServiceCodeEnum         对应解决方案-医寄通APIs
         EPSServiceCodeEnum         对应解决方案-快递管家APIs
         HZTServiceCodeEnum         对应解决方案-函证通APIs    2022-2-24 新增
         详情见code目录下枚举类,客户可自行修改引用的该类
         **/

        IServiceCodeStandard standardService = ExpressServiceCodeEnum.EXP_RECE_CREATE_ORDER; //下订单
        //	IServiceCodeStandard standardService = ExpressServiceCodeEnum.EXP_RECE_SEARCH_ORDER_RESP; //查订单
        //  IServiceCodeStandard standardService = ExpressServiceCodeEnum.EXP_RECE_UPDATE_ORDER;//订单取消
        // 	IServiceCodeStandard standardService = ExpressServiceCodeEnum.EXP_RECE_FILTER_ORDER_BSP;//订单筛选
        //  IServiceCodeStandard standardService = ExpressServiceCodeEnum.EXP_RECE_SEARCH_ROUTES;//查路由
        //	IServiceCodeStandard standardService = ExpressServiceCodeEnum.EXP_RECE_GET_SUB_MAILNO;//子单号
        //	IServiceCodeStandard standardService = ExpressServiceCodeEnum.EXP_RECE_QUERY_SFWAYBILL;//查运费
        //	IServiceCodeStandard standardService = ExpressServiceCodeEnum.EXP_RECE_REGISTER_ROUTE;//注册路由
        //	IServiceCodeStandard standardService = ExpressServiceCodeEnum.EXP_RECE_CREATE_REVERSE_ORDER;//退货下单
        //	IServiceCodeStandard standardService = ExpressServiceCodeEnum.EXP_RECE_CANCEL_REVERSE_ORDER;//退货消单
        //	IServiceCodeStandard standardService = ExpressServiceCodeEnum.EXP_RECE_WANTED_INTERCEPT;//截单转寄
        // 	IServiceCodeStandard standardService = ExpressServiceCodeEnum.EXP_RECE_QUERY_DELIVERTM;//时效标准及价格查询
        //  IServiceCodeStandard standardService = ExpressServiceCodeEnum.COM_RECE_CLOUD_PRINT_WAYBILLS;//面单打印
        //  IServiceCodeStandard standardService = ExpressServiceCodeEnum.EXP_RECE_UPLOAD_ROUTE;//路由上传
        //   IServiceCodeStandard standardService = ExpressServiceCodeEnum.EXP_RECE_SEARCH_PROMITM;//预计派送时间查询
        //  IServiceCodeStandard standardService = ExpressServiceCodeEnum.EXP_EXCE_CHECK_PICKUP_TIME;//揽件服务时间查询
        //  IServiceCodeStandard standardService = ExpressServiceCodeEnum.EXP_RECE_VALIDATE_WAYBILLNO;//运单号合法性校验


        CallExpressServiceTools tools=CallExpressServiceTools.getInstance();

        // set common header
        Map<String, String> params = new HashMap<String, String>();

        String timeStamp = String.valueOf(System.currentTimeMillis());
        String msgData =tools.packageMsgData(standardService);

        params.put("partnerID", CLIENT_CODE);  // 顾客编码 ,对应丰桥上获取的clientCode
        params.put("requestID", UUID.randomUUID().toString().replace("-", ""));
        params.put("serviceCode",standardService.getCode());// 接口服务码
        params.put("timestamp", timeStamp);
        params.put("msgData", msgData);
        params.put("msgDigest", tools.getMsgDigest(msgData,timeStamp,CHECK_WORD));

        // System.out.println(params.get("requestID"));
        long startTime = System.currentTimeMillis();

        //  System.out.println("====调用请求:" + params.get("msgData"));
        System.out.println("====调用实际请求:" + params);
        String result = HttpClientUtil.post(CALL_URL_BOX, params);

        System.out.println("====调用丰桥的接口服务代码:" + String.valueOf(standardService.getCode()) + " 接口耗时:"+ String.valueOf(System.currentTimeMillis()-startTime)+"====");
        System.out.println("===调用地址 ==="+CALL_URL_BOX);
        System.out.println("===顾客编码 ==="+CLIENT_CODE);
        System.out.println("===返回结果:" +result);

    }
}

Logo

电商企业物流数字化转型必备!快递鸟 API 接口,72 小时快速完成物流系统集成。全流程实战1V1指导,营造开放的API技术生态圈。

更多推荐