顺丰接口接入-主要处理下单接口上电子面单上传问题

目录

概述

最近接到一个需求,需要和顺丰接口对接。由于是第一次对接,就需要把所有的流程全部走一遍,从 注册关联API 以及代码测试电子面单审核上线,下面就分开来说明把。本来是想着偷懒来着,作为专业的程序员,能Ctrl + C 加上 Ctrl + V 的,绝对不会有多余的动作,但是发现这个能找到的文章都上年纪了,不适合当下了。

大致流程图

文章代码

传送连接,点这里吧,代码是放在了 Github 上面,方便于大伙查看

顺丰速运接入

接入肯定是需要看官方的文档的,点击这里看官方的详细接入指引,官网上面说的还是比较详细的,另外还有一个2分钟的视频说明还算是贴心的了。我这边就简单的梳理下,大伙按照官网的来就好。

第一步:注册

登录LaaS开放平台
如果您已有开放平台账号,可直接使用账号密码登录。如果您已有月结管家/速打平台/数据灯塔账号,可选择对应登录方式直接登录。如果您是顺丰内部员工,可选择顺丰工号登录方式完成域账号登录。
如果您是首次与顺丰合作,可通过注册平台账号后登录

顺丰注册

第二步:认证
进入“控制台”,在控制台首页点击【立即认证】,根据实际情况选择“个人认证”或“企业认证”。这里我就不赘述了,大家看下官网就好,我是用的个人认证的,先测试通过再说。点击这里看官方的详细接入指引

第三步:创建应用

在“控制台-业务中心”选择“业务对接-开发者对接”,点击【新建应用】按钮创建应用。每个应用对应您需要接入顺丰服务的单个系统,平台将为每个应用分配独立的对接账号(顾客编码)及密钥(校验码)。

开发者对接

创建应用
创建应用
创建成功
创建成功
关联API
关联所需要的API
这里是我自己关联的API
个人关联的
这个云打印面单转PDF的接口这里先有个印象,后面回用到
基础通用的API
到这里,我们的第一部分认证以及关联就算是搞完了,后面我们就开始上代码了。

SDK下载与说明

丰桥API-SDK下载
点击这里看官方连接,很重要,由于不知道什么时候我这里的文档也过时,看下官方的最保险。
下载 SDK 工具
在这里插入图片描述

下载
下载完成之后,我们看下对应的包
调用测试类
CallExpressServiceTools 是使用 sdk-java 的入口,下载的zip包内json文件夹对应的是丰桥服务接口对应的报文,如下订单使用的报文是\json\EPSJson\EPS.1.COM_RECE_EPS_ORDER.json,请求对应的接口使用对应的请求报文(可以将请求报文的文件放置在 java 工程的目录内,方便测试调用。

下载的zip包 java-demo 目录还有个java版的测试类(TestCallExpressNewAPIService.java),可以在java工程中新建个测试目录如com.sf.test,完整的测试接口调用环境如下截图:
在这里插入图片描述
完整的客户端调用代码如下:

package com.sf.csim.express.test;


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;

public class TestCallExpressNewAPIService {
	
private static final String CLIENT_CODE = "";  //此处替换为您在丰桥平台获取的顾客编码
private static final String CHECK_WORD = "";//此处替换为您在丰桥平台获取的校验码

//沙箱环境的地址
private static final String CALL_URL_BOX = "https://sfapi-sbox.sf-express.com/std/service";
//生产环境的地址
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 
		   详情见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 = 	
		
		
		 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);  // 顾客编码
        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));
        
        String result = HttpClientUtil.post(CALL_URL_BOX, params);
        System.out.println("===调用地址 ==="+CALL_URL_BOX);
        System.out.println("===顾客编码 ==="+CLIENT_CODE);
        System.out.println("===返回结果:" +result);
     
	}	

}

代码测试

工程搭建

在项目工程中引入顺丰的SDK
工程结构
Pom 文件

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

对应的调用代码示例

package com.demo.express.sf.utils;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
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 org.apache.commons.io.IOUtils;

import java.io.*;
import java.net.URL;
import java.net.URLConnection;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;


public class CallExpressApiService {

    private static final String CLIENT_CODE = "";  //此处替换为您在丰桥平台获取的顾客编码
    private static final String CHECK_WORD = "";//此处替换为您在丰桥平台获取的校验码


    //沙箱环境的地址 -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";


    /**
     * 调用参数
     * <pre>
     *     String msgData = "{" +
     *                 "    "cargoDetails":[" +
     *                 "        {          " +
     *                 "            "count":2.365," +
     *                 "             "unit":"个"," +
     *                 "             "weight":6.1," +
     *                 "             "amount":100.5111," +
     *                 "            "currency":"HKD"," +
     *                 "            "name":"护肤品1",           " +
     *                 "            "sourceArea":"CHN"          " +
     *                 "        }]," +
     *                 "    "contactInfoList":[" +
     *                 "        {" +
     *                 "            "address":"广东省深圳市南山区软件产业基地11栋"," +
     *                 "            "contact":"小曾"," +
     *                 "            "contactType":1," +
     *                 "            "country":"CN"," +
     *                 "            "postCode":"580058"," +
     *                 "            "tel":"4006789888"" +
     *                 "        }," +
     *                 "        {" +
     *                 "            "address":"广东省广州市白云区湖北大厦"," +
     *                 "            "company":"顺丰速运"," +
     *                 "            "contact":"小邱"," +
     *                 "            "contactType":2," +
     *                 "            "country":"CN"," +
     *                 "            "postCode":"580058"," +
     *                 "            "tel":"18688806057"" +
     *                 "        }]," +
     *                 "    "language":"zh_CN"," +
     *                 "    "orderId":"OrderNum20240612223"" +
     *                 "}";
     * </pre>
     * @param msgData
     * @return
     * @throws UnsupportedEncodingException
     */
    public static String createOrder(String msgData) throws UnsupportedEncodingException {
        IServiceCodeStandard standardService = ExpressServiceCodeEnum.EXP_RECE_CREATE_ORDER; //下订单

        CallExpressServiceTools tools = CallExpressServiceTools.getInstance();

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

        String timeStamp = String.valueOf(System.currentTimeMillis());

        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);
        String result = HttpClientUtil.post(CALL_URL_BOX, params);

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

        return result;
    }
}

这样子就可以测试了,几乎是按照官方的来的,还是比较简单。

下单接口文档
详细的接口文档地址 ,点击下面的 “下订单接口”
下单接口
说明下:我这个接口后面有个 “上线” 的操作,这个是因为我这边已经审核通过了,最开始这里是有一个测试操作的。

查询接口测试记录
查看测试接口记录

电子面单上传

在下单的接口处,我们会看到有这么一个地方,就是需要上传电子面单,这个东西我也是找了好久,最后发现这个其实是需要我们去调用面单打印的接口,由于我们是第一次调用,就需要去对接下这个接口
电子面单上传处理
配置云打印面单接口
这里我们需要在 基础通用API 关联 云打印面单转PDF接口,这里我是为了测试面单上传,就选择了 “同步” 方式,具体可以看下官方的说明,异步的话,需要自己给一个回调地址。
云打印面单
这里可以看到对应的模板名称
查看对应的模板名称

这个时候,我们就需要去关联云打印的接口了,基于上面的代码,我们增加两个函数:

  • printWayBills 云打印面单打印
  • 获取PDF接口
	/**
     * 调用参数
     * <pre>
     *  {
     *     "templateCode": "fm_150_standard_YJ3CB3FX",  这里是配置的那个打印模板
     *     "version":"2.0",
     *     "fileType":"pdf",
     *     "sync":true,
     *     "documents": [{
     *     "masterWaybillNo": "SF7444480501251"
     *     }]
     *  }
     */
 public static void printWayBills(String msgData) throws UnsupportedEncodingException {
        IServiceCodeStandard standardService = ExpressServiceCodeEnum.COM_RECE_CLOUD_PRINT_WAYBILLS; //云打印面单打印2.0接口

        CallExpressServiceTools tools = CallExpressServiceTools.getInstance();

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

        String timeStamp = String.valueOf(System.currentTimeMillis());

        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);
        String result = HttpClientUtil.post(CALL_URL_BOX, params);

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

根据上面 printWayBills 返回值,我们可以拿到对应的pdf文件地址,返回的数据如下:

 {"apiErrorMsg":"","apiResponseID":"00018E79F0AAEE3FE755F4D40823D73F","apiResultCode":"A1000","apiResultData":"{\"obj\":{\"clientCode\":\"YJ3CB3FX\",\"fileType\":\"pdf\",\"files\":[{\"areaNo\":1,\"documentSize\":0,\"pageCount\":0,\"pageNo\":1,\"seqNo\":1,\"token\":\"AUTH_tkv12_f146d1855480549d262b5c46ab0ab597ff20a97d9d0db45c16bedeb4fabd112b012deadd477ee524b1d690ce01baa3cdffbb125a6ccf69b73778dba2eb5157eb73eb03e946a2c01352db378fe2bdea7c95c535a186cf195dc290be8fb7d1e7064e80fa12c5e7757aff35d31ff59b7f55832b73ef3f6a4397c071ef11cba0f8623abd7a376adcd85a3c8e3e8c9b64f903a7d5c55353003625d76f23480fd915464d767f73ba97048cd4aef655f4d970ba\",\"url\":\"https://eos-scp-core-shenzhen-futian1-oss.sf-express.com:443/v1.2/AUTH_EOS-SCP-CORE/print-file-sbox/AAABjnnwq4I40xFIfoVMAJQtjYTrUht8_SF7444480501251_fm_150_standard_YJ3CB3FX_1_1.pdf\",\"waybillNo\":\"SF7444480501251\"}],\"templateCode\":\"fm_150_standard_YJ3CB3FX\"},\"requestId\":\"9c772eb846124800a15edcaf9e0cfea4\",\"success\":true}"}

调用代码,这里需要使用自己的请求参数,用我的是不行的哈

public static void getPDF(String result){
     JSONObject resultJson = JSON.parseObject(result).getJSONObject("apiResultData").getJSONObject("obj");
     JSONObject fileInfo = resultJson.getJSONArray("files").getJSONObject(0);

     try {
         URL noodleUrl = new URL(fileInfo.getString("url"));
         URLConnection connection = noodleUrl.openConnection(); //创建连接
         //设置请求头(下载文件时需要的token,设置在请求头的 X-Auth-token 字段,有效期 24h)
         connection.setRequestProperty("X-Auth-token", fileInfo.getString("token"));

         try ( InputStream in = connection.getInputStream()){
             File outputFile = new File("D:\\test\\"+resultJson.getString("templateCode")+".pdf");
             try (FileOutputStream outputStream = new FileOutputStream(outputFile)) {
                 IOUtils.copy(in, outputStream);
                 System.out.println("内容已成功写入到文件中。");
             }
         }

     } catch (IOException e) {
         throw new RuntimeException(e.getMessage());
     }
 }

然后在我本地就会有这个文件在,把这个文件转为png,在下单接口上传就好:
截图
最后审核通过的截图
已审核的截图

上线

API状态根据上线流程可分为:

待配置 :根据实际情况完成接口关键属性配置,对于不需要配置的接口,平台默认不显示此状态,直接切换为“测试中”。

测试中 :在沙箱环境自助联调接口。点击【测试】按钮可选择下载API-SDK或使用在线测试工具联调。点击【配置】按钮修改接口属 性,点击【查看】按钮查询已配置的接口属性。

待上线 :平台检测到API已具备切入生产环境条件(接口7天内测试成功3次以上,若为下单接口,需通过面单审核或配置免面单,具体参考面单部分说明)。点击【上线】按钮可完成接口上线。

已上线 :API已切入生产环境条件,可正常调用生产环境接口地址。

:新用户需对接使用云打印接口,上传云打印面单进行审核,审核通过后才能完成下单接口上线操作。

官方说明

  • 27
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Wayfreem

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

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

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

打赏作者

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

抵扣说明:

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

余额充值