Java连接顺丰开放平台

news2024/11/17 17:41:47

今天使用Java去访问顺丰的开放平台时,JSON转换一直不成功,最终发现是
在这里插入图片描述
可以看到这里是

"apiResultData": "{\"success\": .........

它是以 " 开头的!!!如果是对象的话,那么json是这样的:

"address": {
    "street": "123 Main St",
    "city": "Anytown",
    "state": "CA",
    "zip": "12345"
  }

对象是以 { 开头 !!!
然后我一天的bug都是因为,我的接收对象使用了

 private static class RouteQueryResponse {
        public String apiResponseID;
        public String apiErrorMsg;
        public String apiResultCode;
        public ApiResultData apiResultData;
}

这里的apiResultData应该是String类型

那么言归正传,这里是要讲Java连接顺丰开放平台,那么首先是需要认证,认证的话 顺丰认证 有两种方式,OAuth2 和 数字签名,这里我实践发现,第二种一直是服务不可用,所以这里只能用前一种。

看一下官网的请求示例
在这里插入图片描述
他发的请求是

https://sfapi-sbox.sf-express.com/oauth2/accessToken?partnerID=XXXXXXXX&grantType=password&secret=0705GuswG6BwiTTEbYMkIkZHxxxxxxxxx

所以我们只要拼接一下即可。
然后他响应成功是返回accessToken,我们直接存到缓存里即可,后面请求其他接口必须使用这个accessToken

public String SFToken(Object request) throws IOException {
        // TODO SF-获取签名-数字签名认证说明
        //目前是测试方式获得
        String url = "https://sfapi-sbox.sf-express.com/oauth2/accessToken?partnerID=" + partnerId + "&grantType=password&secret=" + verifyTestCode;
        HttpPost post = new HttpPost(url);
        post.setHeader("Content-type", "application/x-www-form-urlencoded;charset=UTF-8");
        String response = httpClient.execute(post);
        log.info("#sf-Token response, {}", JsonUtils.toStr(response));
        SFTokenResponseBody str = JsonUtils.fromStr(response, SFTokenResponseBody.class);
        //把accessToken放到cache中,2小时
        cacheManager.put(CommonCacheManager.CacheType.SF_ACCESS_TOKEN_V2, "accessTokenv2", str.getAccessToken(), 120 * 60);
        return str.getAccessToken();
    }
@Data
@AllArgsConstructor
public class SFTokenResponseBody {
    String accessToken;
    String refreshToken;

    public SFTokenResponseBody(){}
}

partnerIdverifyTestCode都是你注册顺丰时发给你的。
httpClient和JsonUtils均可使用其他的平替
放到cache中的那一句代码可以自己进行修改

这只是认证,然后拿到了accessToken,可以去请求其他接口。

这里先看一下通用的方法:

 public void setCommonParams(HttpPost httpPost, SFCommonReq req) throws UnsupportedEncodingException {
        httpPost.setHeader("Content-type", "application/x-www-form-urlencoded;charset=UTF-8");
        List<NameValuePair> params = new ArrayList<>();
        params.add(new BasicNameValuePair("accessToken", req.getAccessToken()));
        params.add(new BasicNameValuePair("partnerID", req.getPartnerID()));
        params.add(new BasicNameValuePair("requestID", req.getRequestID()));
        params.add(new BasicNameValuePair("serviceCode", req.getServiceCode()));
        params.add(new BasicNameValuePair("timestamp", req.getTimestamp()));
        params.add(new BasicNameValuePair("msgData", req.getMsgData()));
        UrlEncodedFormEntity entity = new UrlEncodedFormEntity(params, "UTF-8");
        httpPost.setEntity(entity);
    }

顺丰下订单

官网是
下订单
看到这里的
公共请求,我们需要创建一个这样的类,使用内部类即可。
然后响应的json也需要一个对象接收。
然后代码如下:


public SFOrderResponseBody orderV2(int orderId, int cityId, ExpressAddressDTO expressAddressDTO) throws IOException {
        // SF-下订单接口-速运类API
        SFCommonReq req = SFCommonReq.builder()
            .partnerID(partnerId)
            .requestID(UUID.randomUUID().toString())
            .serviceCode(serviceCode.makeOrder)
            .timestamp(String.valueOf(System.currentTimeMillis()))
            .accessToken(getOrGenerateToken()) //这里只是从缓存获取accessToken
            .build();
        HashMap<String, String> msgData = new HashMap<>();
        msgData.put("language", "zh-CN");
        LinkedList<CargoDetails> cargoDetails = new LinkedList<>();
        CargoDetails details = new CargoDetails();
        details.setName(expressAddressDTO.getName());
        cargoDetails.add(details);
        ContactInfo contactInfo = new ContactInfo();
        contactInfo.setAddress(expressAddressDTO.getAddress());
        contactInfo.setTel(expressAddressDTO.getPhone());
        contactInfo.setCity(districtService.findById(cityId).getName());
        contactInfo.setContact(expressAddressDTO.getName());
        //只能发到中国
        contactInfo.setCountry("CN");
        contactInfo.setCounty(expressAddressDTO.getDistrictName());
        contactInfo.setMobile(expressAddressDTO.getPhone());
        // "postCode":"580058",不用填
        //找到省
        contactInfo.setProvince(districtService.findByCode(districtService.findById(cityId).getCode()).getName());
        msgData.put("cargoDetails", String.valueOf(cargoDetails));
        msgData.put("contactInfoList", String.valueOf(Collections.singletonList(contactInfo)));
        msgData.put("orderId", String.valueOf(orderId));
        //顺丰特快
        msgData.put("expressTypeId", String.valueOf(1));
        //1:寄方付 2:收方付 3:第三方付
        msgData.put("payMethod", String.valueOf(2));
        msgData.put("isReturnRoutelabel", String.valueOf(1));
        req.setMsgData(JsonUtils.toStr(msgData));
        //沙箱URL
        HttpPost httpPost = new HttpPost("https://sfapi-sbox.sf-express.com/std/service");

        setCommonParams(httpPost, req);

        log.info("发送的请求是:" + httpPost);
        String s = httpClient.execute(httpPost);
        try {
            // 解析 JSON 格式的响应
            createOrderResponse cor = JsonUtils.fromStr(s, createOrderResponse.class);
            //特殊处理
            createOrderResponse.ApiResultData apiResultData = JsonUtils.fromStr(cor.getApiResultData(), createOrderResponse.ApiResultData.class);
            if (!"A1000".equals(cor.getApiResultCode())) {
                //请求失败
                log.error("请求失败,响应是:" + s);
                SFOrderResponseBody sfOrderResponseBody = new SFOrderResponseBody();
                sfOrderResponseBody.setRetry(true);
                sfOrderResponseBody.setOrderId(s);
                return sfOrderResponseBody;
            }
            //请求成功
            Boolean success = apiResultData.getSuccess();
            SFOrderResponseBody sfOrderResponseBody = new SFOrderResponseBody();
            if (success) {
                sfOrderResponseBody.setOrderId(apiResultData.getMsgData().getOrderId());
                sfOrderResponseBody.setRetry(false);
            } else {
                sfOrderResponseBody.setRetry(true);
            }
            return sfOrderResponseBody;

        } catch (Exception e) {
            e.printStackTrace();
            SFOrderResponseBody sfOrderResponseBody = new SFOrderResponseBody();
            sfOrderResponseBody.setRetry(true);
            sfOrderResponseBody.setOrderId("异常是" + e + ",响应是" + s);
            return sfOrderResponseBody;
        }
    }
    @Data
    @Builder
    @AllArgsConstructor
    @NoArgsConstructor
    private static class SFCommonReq {
        String partnerID;
        String requestID;
        String serviceCode;
        String timestamp;
        String accessToken;
        String msgData;
    }
    private static class serviceCode {
        //下单
        private static final String makeOrder = "EXP_RECE_CREATE_ORDER";
        //查询路径
        private static final String route = "EXP_RECE_SEARCH_ROUTES";
        //查询订单
        private static final String searchOrder = "EXP_RECE_SEARCH_ORDER_RESP";

        private static final String print = "COM_RECE_CLOUD_PRINT_WAYBILLS";

        private static final String cloudPrint = "COM_PUSH_CLOUD_PRINT_WAYBILLS";
    }
     @Data
    private static class CargoDetails {
        @NotNull
        private BigDecimal amount;
        @NotNull
        private BigDecimal count;
        @NotNull
        private String currency;
        private String goodPrepardNo;
        private String hsCode;
        @NotNull
        private String name;
        private String productRecordNo;
        @NotNull
        private String sourceArea;
        private String taxNo;
        @NotNull
        private String unit;
        @NotNull
        private BigDecimal weight;
    }
    public class ExpressAddressDTO implements Serializable {
    Integer districtId;
    String districtName;
    String phone;
    String address;
    String name;
}
 @Data
    private static class ContactInfo {
        private String address;
        private String city;
        private String contact;
        private Integer contactType;
        private String country;
        private String county;
        private String mobile;
        private String postCode;
        private String province;
        private String tel;

    }
     @Data   //这个就是接收的对象
    private static class createOrderResponse {
        public String apiErrorMsg;
        public String apiResponseID;
        public String apiResultCode;
        public String apiResultData;

        @Data
        private static class ApiResultData {
            public Boolean success;
            public String errorCode;
            public String errorMsg;
            public MsgData msgData;

            @Data
            private static class MsgData {
                public String orderId;
                public String originCode;
                public String destCode;
                public Integer filterResult;
                public String remark;
                public String url;
                public String paymentLink;
                public Boolean isUpstairs;
                public Boolean isSpecialWarehouseService;
                public String mappingMark;
                public String agentMailno;
                public Object returnExtraInfoList;
                public List<WaybillNoInfo> waybillNoInfoList;
                public List<RouteLabelInfo> routeLabelInfo;
                public Object contactInfoList;

                @Data
                private static class WaybillNoInfo {
                    public Integer waybillType;
                    public String waybillNo;
                }

                @Data
                private static class RouteLabelInfo {
                    public String code;
                    public RouteLabelData routeLabelData;
                    public String message;

                    @Data
                    private static class RouteLabelData {
                        public String waybillNo;
                        public String sourceTransferCode;
                        public String sourceCityCode;
                        public String sourceDeptCode;
                        public String sourceTeamCode;
                        public String destCityCode;
                        public String destDeptCode;
                        public String destDeptCodeMapping;
                        public String destTeamCode;
                        public String destTeamCodeMapping;
                        public String destTransferCode;
                        public String destRouteLabel;
                        public String proName;
                        public String cargoTypeCode;
                        public String limitTypeCode;
                        public String expressTypeCode;
                        public String codingMapping;
                        public String codingMappingOut;
                        public String xbFlag;
                        public String printFlag;
                        public String twoDimensionCode;
                        public String proCode;
                        public String printIcon;
                        public String abFlag;
                        public String destPortCode;
                        public String destCountry;
                        public String destPostCode;
                        public String goodsValueTotal;
                        public String currencySymbol;
                        public String cusBatch;
                        public String goodsNumber;
                        public String errMsg;
                        public String checkCode;
                        public String proIcon;
                        public String fileIcon;
                        public String fbaIcon;
                        public String icsmIcon;
                        public String destGisDeptCode;
                        public Object newIcon;
                    }
                }
            }
        }
    }

路由查询接口

和上面类似,也是创建json的接收类,然后设置一下请求,这里不放完整代码了,最后放整个类的代码

//沙箱环境
        String url = "https://sfapi-sbox.sf-express.com/std/service";
        HttpPost post = new HttpPost(url);
        SFCommonReq req = SFCommonReq.builder()
            .partnerID(partnerId)
            .requestID(UUID.randomUUID().toString())
            .serviceCode(serviceCode.route)
            .timestamp(String.valueOf(System.currentTimeMillis()))
            .accessToken(getOrGenerateToken())
            .build();
        HashMap<String, String> msgData = new HashMap<>();
        msgData.put("language", "zh-CN");
        msgData.put("trackingType", String.valueOf(1));
        msgData.put("trackingNumber", mailNo);
        req.setMsgData(JsonUtils.toStr(msgData));
        setCommonParams(post, req);
        log.info("发送的请求是:" + post);
        String s = httpClient.execute(post);
        try {
            // 解析 JSON 格式的响应
            RouteQueryResponse rqr = JsonUtils.fromStr(s, RouteQueryResponse.class);
            if (!"A1000".equals(rqr.getApiResultCode())) {
                //请求失败
                log.error("请求失败,响应是:" + s);
                SFResponse<SFRouteInfos> response = new SFResponse<>();
                response.setBody(null);
                SFResponseHead head = new SFResponseHead();
                head.setCode("500");
                head.setMessage("请求失败了,返回的响应是" + s);
                response.setHead(head);
                return response;
            }
            //请求成功
            //特殊处理
            RouteQueryResponse.ApiResultData apiResultData = JsonUtils.fromStr(rqr.getApiResultData(), RouteQueryResponse.ApiResultData.class);
            

订单结果查询接口

链接

//沙箱环境
            String url = "https://sfapi-sbox.sf-express.com/std/service";
            HttpPost post = new HttpPost(url);
            SFCommonReq req = SFCommonReq.builder()
                .partnerID(partnerId)
                .requestID(UUID.randomUUID().toString())
                .serviceCode(serviceCode.searchOrder)
                .timestamp(String.valueOf(System.currentTimeMillis()))
                .accessToken(getOrGenerateToken())
                .build();

            OrderSearchReqDto orderSearchReqDto = new OrderSearchReqDto();
            orderSearchReqDto.setOrderId(String.valueOf(orderId));
            orderSearchReqDto.setSearchType(String.valueOf(1));
            orderSearchReqDto.setLanguage("zh-CN");
            req.setMsgData(JsonUtils.toStr(orderSearchReqDto));
            setCommonParams(post, req);
            String s = httpClient.execute(post);
@Data
private static class OrderSearchReqDto {
        String orderId;
        //查询类型:1正向单 2退货单
        String searchType;
        //响应报文的语言, 缺省值为zh-CN
        String language;
    }

顺丰云打印

链接是 云打印

这里采用的是同步,也就是访问了,顺丰就返回文件url

String url = "https://sfapi-sbox.sf-express.com/std/service";
        HttpPost post = new HttpPost(url);
        SFCommonReq req = SFCommonReq.builder()
            .partnerID(partnerId)
            .requestID(UUID.randomUUID().toString())
            .serviceCode(serviceCode.print)
            .timestamp(String.valueOf(System.currentTimeMillis()))
            .accessToken(getOrGenerateToken())
            .build();
        PrintTemplate template = PrintTemplate.builder()
            .sync(true) //设置同步
            .templateCode(templateCode)
            .version("2.0").build();
        Document document = new Document();
        document.setMasterWaybillNo(String.valueOf(orderId));
        LinkedList<Document> documents = new LinkedList<>();
        template.setDocuments(documents);
        req.setMsgData(JsonUtils.toStr(template));
        setCommonParams(post, req);
        String s = httpClient.execute(post);
        

@Data
    @AllArgsConstructor
    @NoArgsConstructor
    @Builder
    private static class PrintTemplate {
        //关联云打印接口后,点击查看,可在接口详情页获取模板编码
        private String templateCode;
        //版本号,传固定值:2.0
        private String version;
        //pdf格式
        private String fileType;
        private List<Document> documents;
        //true: 同步,false: 异步,默认异步
        private Boolean sync;
        private ExtJson extJson;
    }
   @Data
    @AllArgsConstructor
    @NoArgsConstructor
    private static class Document {
        private String masterWaybillNo;
        private String branchWaybillNo;
        private String backWaybillNo;
        private String seq;
        private String sum;
        private Boolean isPrintLogo;
        private String remark;
        private String waybillNoCheckType;
        private String waybillNoCheckValue;
        private String customData;
    }

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/496689.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Zookeeper初识

序 Zookeeper是什么&#xff0c;Zookeeper有什么用&#xff1f;因为在研究Zookeeper源码之后&#xff0c;就要去研究Dubbo源码&#xff0c;而Dubbo必然用到了Zookeeper&#xff0c;而我在写这篇博客时&#xff0c;我也是一个Zookeeper小白&#xff0c;我也有7年开发经验了&…

将ROS1和ROS2安装到同一个ubuntu系统中,ROS2安装

1. 本文测试环境: ubuntu:20.04,虚拟机 ROS1:noetic ROS2:foxy 2. 先说结论 ROS1 与 ROS2 共存,需要考虑三个问题: 1) 不同Ubuntu版本,有不同版本的ROS1和ROS2推荐,尽量不要任性地乱装; 2)ROS1和ROS2安装过程中,是否会出现文件“删改”的问题?目前使用下来,并…

章节1:PHP反序列化渗透与防御

章节1&#xff1a;PHP反序列化渗透与防御 1.1-PHP类与对象 类Class 一个共享相同结构和行为的对象的集合。 对象Object 类的实例 1.2-PHP Magic函数 Magic Methods https://www.php.net/__sleep 函数作用 函数作用__construct当一个对象创建时被调用__destruct当一个对象…

Linux_红帽8学习笔记分享_10(SELinux管理与防火墙)

Linux_红帽8学习笔记分享_10(SELinux管理与防火墙) 文章目录 Linux_红帽8学习笔记分享_10(**SELinux管理与防火墙**)1.Linux系统的安全机制1.1 Filesystem1.2 Service1.3 Firewall1.4 SELinux 2.SElinux理论概述3.SElinux的配置文件3.1 SELINUX参数3.2 SELINUXTYPE参数 4.查看和…

网络安全行业职位解析:如何选择适合自己的职业发展路径?

前言 网络安全行业发展迅速&#xff0c;各种职位层出不穷&#xff0c;这给刚入门的小伙伴带来了很大的困惑&#xff1a;我应该选择哪个职位&#xff1f;如何才能在这个行业立足并获得高薪工作&#xff1f;如果你也有这些疑惑&#xff0c;那么恭喜你&#xff0c;来到了正确的地…

git push 上去的文件操作

先在git 创建一个仓库&#xff0c;仓库创建好后有一个快速上手的页面 注意第一个是你的登录账号和密码这个是账号和密码这个是你这个仓库的地址 接下来在你要上传的文件右键git bash here 进入 1. 先初始化进入 git init 2.再登录和输入你的密码登录好了&#xff0c;可以再初…

Java笔记_17(异常、File)

Java笔记_17 一、异常1.1、异常体系介绍1.2、编译时异常和运行时异常1.3、异常的作用1.4、异常的处理方式1.5、捕获异常的灵魂四问1.6、异常中的常见方法1.7、抛出处理1.8、异常-练习&#xff08;键盘录入数据&#xff09;1.9、自定义异常 二、File2.1、File的概述和构造2.2、F…

《Java虚拟机学习》 java代码的运行过程

1. Java文件转换 当我们保存java文件后&#xff0c;首先由编译器编译成class文件&#xff0c;然后通过Java虚拟机将class文件转换成字节码文件 2.Java虚拟机是怎么运行Java文件 首先将java文件加载到java虚拟机中&#xff0c;然后由虚拟机将类元信息存储在 虚拟机的方法区中。…

多态小Tips

目录 1.虚函数 2. 设置为虚函数 3.多态 4.多态类型的调用 5.抽象类和纯虚函数 6.虚表 7.练习题 1.虚函数 虚函数是被virtual修饰的类成员函数 virtual关键字只在声明时加上&#xff0c;在类外实现时不能加。 static和virtual不能同时使用。 2. 设置为虚函数 首先&#xff0c…

企业网盘选购攻略,如何选择最适合你的云存储服务?

在如今的企业办公中&#xff0c;每天都会产出各种不同类型的文件&#xff0c;传统纸质文件的管理方式&#xff0c;不仅不方便协作&#xff0c;而且容易丢失。于是企业将目光转向企业网盘工具&#xff0c;企业网盘的热门肯定了其在文件管理与协作方面的表现。那么企业网盘哪个好…

网络安全(非常详细)从零基础入门到精通,看完这一篇就够了。

学习网络安全方向会遇到哪些问题&#xff1f; 1.打基础的时间长 学基础花费了很长的时间&#xff0c;光学语言都有好几门&#xff0c;有的人会止步于学习linux系统及命令的路上&#xff0c;更多的人会停在学习语言上面&#xff1b; 2.知识点掌握的不够清楚 对于网络安全基础…

OpenPCDet系列 | 5.模型前向传播流程

文章目录 前向传播流程1. 模型初始化2. 模型训练前向传播前向传播流程 这里以PointPillars模型为例,在PointPillars模型中主要划分了以下4个主要的模块,以下某块首先会在build_network中进行初始化,然后在具体前向传播时通过forward函数进行。下面进行区分。 PointPillars…

TCP/IP网络编程(二)

TCP/IP网络编程读书笔记 第7章 优雅地断开套接字连接7.1 基于TCP的半关闭7.1.1 单方面断开连接带来的问题7.1.2 套接字和流&#xff08;Stream&#xff09;7.1.3 针对优雅断开的shutdown函数7.1.4 为何要半关闭7.1.5 基于半关闭的文件传输程序 7.2 基于Windows的实现7.3 习题 第…

揭秘|从帕丽斯·希尔顿引领其帝国进入元宇宙学到的品牌建设经验

你是否曾想过&#xff0c;元宇宙是如何与世界上的知名品牌和名人达成合作的&#xff1f;在本期的文章中&#xff0c;我们邀请了 11:11 媒体的 Web3 和元宇宙总监 Cynthia Miller&#xff0c;一起探讨帕丽斯希尔顿如何通过 Parisland 和 Cryptoween 将她的帝国带入 The Sandbox&…

嵌入式学习笔记——IIC通信

IIC通信 前言IIC概述通信特征物理拓扑结构IIC通信的流程IIC的特点&#xff1a; STM32的IIC通信GPIO模拟IICIIC的时序组成&#xff08;主机对从机写入数据&#xff09;1.起始信号2.器件地址与读写位3.从机应答信号5.传输的数据与结束信号 IIC的时序组成&#xff08;主机对从从机…

MySQL调优系列(二)——数据类型优化

一、总则 1、更小的数据类型更好 应该尽量使用可以正确存储数据的最小数据类型&#xff0c;更小的数据类型通常更快&#xff0c;因为它们占用更少的磁盘、内存和CPU缓存&#xff0c;并且处理时需要的CPU周期更少&#xff0c;但是要确保没有低估需要存储的值的范围&#xff0c…

OpenCV中的图像处理3.1-3.3(三)色彩空间、几何变换、阈值处理

目录 3.1 改变色彩空间目标改变色彩空间对象跟踪如何找到HSV值来追踪&#xff1f;练习 3.2 图像的几何变换目标变换缩放平移旋转仿射变换透视变换其他资源 3.3 图像阈值处理目标简单的阈值处理自适应阈值处理Otsu的二值化Otsu的二值化是如何工作的&#xff1f;其他资源练习 翻译…

Netty基础(二)

1.Netty高性能架构设计 1.1.线程模型基本介绍 1>.不同的线程模式,对程序的性能有很大影响,为了搞清Netty线程模式,我们来系统的讲解下各个线程模式,最后看看Netty线程模型有什么优越性; 2>.目前存在的线程模型有: ①.传统阻塞I/O服务模型; ②.Reactor(反应器)模式; 3…

The Annotated Diffusion Model(翻译)

The Annotated Diffusion Model&#xff08;翻译&#xff09; 来源&#xff1a; https://huggingface.co/blog/annotated-diffusion code: 在这篇博文中&#xff0c;我们将更深入地研究去噪扩散概率模型&#xff08;也称为 DDPM、扩散模型、基于分数的生成模型或简称为自动编…

一、PEMFC基础之热力学

一、PEMFC基础之热力学 1.内能U、焓H、熵S、吉布斯自由能G、赫姆霍兹自由能F关系图2.可逆电压与温度和压力的关系3.能斯特方程4.燃料电池效率 1.内能U、焓H、熵S、吉布斯自由能G、赫姆霍兹自由能F关系图 2.可逆电压与温度和压力的关系 标准状态可逆电压Er计算&#xff1a; E …