Java对接拼多多开放平台API(加密上云等全流程)

您所在的位置:网站首页 拼多多客服用哪个软件接单 Java对接拼多多开放平台API(加密上云等全流程)

Java对接拼多多开放平台API(加密上云等全流程)

2024-07-12 14:51:08| 来源: 网络整理| 查看: 265

前言

 

本文为【小小赫下士 blog】原创,搬运请保留本段,或请在醒目位置设置原文地址和原作者。

作者:小小赫下士

原文地址:Java对接拼多多开放平台API(加密上云等全流程)

 

本文章为企业ERP(ISV软件服务商)对接拼多多开放平台流程总结,文章包括开放平台入驻、商家授权接口流程、API调用流程(订单同步、发货回传以及其他接口的调用)、密文改造流程、拼多多电子面单调用流程、密文环境下发货流程、拼多多云服务以及服务入云流程。

(自研或者其他类型服务商请勿参考)

一、开放平台入驻

open平台地址:拼多多 开放平台

注意事项:

1:手机号如果绑定为子账号不能再次注册开放平台账号:;

2:一个公司主体只能入驻一次,请谨慎选择入驻资质;

3:入驻资质暂时仅支持境内企业。

平台新手指南指导文档:新手指南

使用手机号注册,密码为英文加数字加特殊符号组合,注册好后跳转到首页。

点击立即入驻。

选择开发者角色为【电商软件服务商】,入驻组织资质勾选【企业开发者】。

 

开发者角色的认证业务选择【电商软件服务商】,开发者资质选择企业。 

需要的资料如下图所示,按照要求填写上传。

完成后提交审核,然后可以在上方【工单支持】里发工单给平台技术支持人员,让平台同学加急审核一下。

审核完成后即可开始后续工作。

二、官方沟通工具Knock

资质申请好后先不要着急创建应用开始对接,先了解一下Knock的使用,这个工具是和官方工作人员沟通的一个途径(另一个途径是平台工单功能),平台更具不同的业务场景提供不同的官方群组,先准备好工具以及掌握使用可以提高后续的开发效率。

官方Knock介绍文档:KNOCK使用指南

子账号管理指导文档:子账号管理​

三、创建应用

注意事项:

1:要求需要上传MRD文档(市场需求文档)以及PRD文档(产品需求说明书),创建应用页面会有模板提供下载,我自己保存的模板下载地址:拼多多开放平台应用创建所需文档模板

2:需要提供一个小于100M的视频,内容要求包括需要包含公司门头、职工办公场景,视频需要一镜到底,禁止剪辑。

【应用列表】进入【创建应用】,在【电商软件服务商】栏目下选择【企业ERP】。

官方企业ERP对接文档:企业ERP

应用创建好后依旧需要审核,可以工单催审一下。

应用信息填写只需要注意回调地址一项,回调地址就是用来接收授权信息的服务接口地址,官方解释为:

 应用创建好后,平台会根据应用权限集来提供Java开发SDK。

下载后自行配置到maven或者其他依赖管理工具里。

应用详情页会提供 client_id、client_secret 这两个应用秘钥,保存好并且不要泄露。

四、对接前准备

对接前请认真查阅以下官方提供的文档,遵守平台规则,切勿产生违规的行为:

官方应用开发安全管理规范文档地址:多多云应用开发安全管理规范 收费规则(包括云外调用API以及云内调用的区别):拼多多开放平台技术服务费收费规则 服务市场管理规范:拼多多商家服务市场管理规范 服务市场保证金规则:拼多多商家服务市场保证金规则 违规处理规则:拼多多开放平台违规处理规则 企业ERP类目管理规范:拼多多商家服务市场企业ERP类目管理规范

根据平台2021-04-13 11:44:11发布的规则变更公告【应用安全规范进一步改造通知】一文,要求如下:

官方改造指南文档地址:开放平台应用安全规范改造指南 

新入驻的话可以直接按要求进行对应的开发,减少后续改造工作。

第一要求:确保敏感接口调用入云,也就是涉及到敏感数据的接口调用必须在拼多多云内调用,也就是需要购买拼多多平台的云主机服务,然后在云主机上去调用这些接口;

第二要求:如上图所示;

第三要求:规定不同的应用需要分别部署到不同的云资源上,这个其实是可以部署在同一个云主机上的,云数据库需要区分开。

第四要求和第五要求:没有特殊需求的话只需要使用设置IP白名单就可以。

官方列举的接口包括以下这些:

相关敏感接口(都是包含收件人信息的接口,敏感数据也就是买家收件人信息数据,虽然是密文...):

pdd.mall.info.get

pdd.order.information.get

pdd.order.list.get

pdd.order.number.list.get

pdd.order.number.list.increment.get

pdd.order.status.get

pdd.goods.information.get

pdd.goods.detail.get

pdd.goods.list.get

pdd.refund.address.list.get

pdd.refund.information.get

pdd.refund.list.increment.get

pdd.oversea.clearance.get

pdd.open.decrypt.batch

开发者需要确保应用对这些接口的调用是在多多云内发起。(开发测试除外)

需要订购的云服务有(一下推荐配置可根据实际业务程度按需升配或者降配):

1:云主机,服务部署使用,官方提供linux和windows两种,推荐使用windows系统。

规格推荐:2核4G,Windows Server 2008 R2 SP1 64位 服务器版,磁盘规格60GB,大概2460/年。

官方购买云主机指导文档:购买云主机

2:云数据库,店铺授权后,配置好数据推送绑定,数据库会同步店铺的订单信息,后续需要在此数据库内获取店铺的订单数据,配合使用出云访问服务可以把订单数据发出云,本地可以开发一个接口接收数据,并进行后续的操作。

规格推荐:1核2000M,25G存储,大概2211/年。

官方购买云数据库指导文档:购买数据库

平台云数据库的类型列表如下:

3:对象存储 OSS服务,部署使用,Windows 云主机需要通过对象存储 OSS 来上传与下载部署所需的程序包以及其他的文件,通过OSS下载云主机上的文件的时候是需要通过审核的。

OSS服务是按使用量每日计算费用,需要部署服务的时候需要用到,其他时间不计费,使用的当天大概也就几分钱。

官方指导文档:开通对象存储 OSS

4:出云访问服务 EGW,平台为了安全考虑,部署在云服务上的应用无法直接对外网发起访问,如果需要访问外网,比如公司的私有云服务,需要把订单数据发到公司本地的服务接口(刚需),需要使用EGW服务,推荐使用基础版。

EGW服务基础版也是按使用量收费。

其他服务按需订购使用,基础的对接开发使用以上四个服务足够。

本文为【小小赫下士 blog】原创,搬运请保留本段,或请在醒目位置设置原文地址和原作者。

作者:小小赫下士

原文地址:Java对接拼多多开放平台API(加密上云等全流程)

五、对接 0、拼多多密文规则

对接前请先熟知平台敏感信息加密策略,对应文档地址:加密接入流程

官方提供的企业ERP接入流程方案:企业 ERP 类应用接入方案

密文规则:

敏感字段列表

card_info_list:卡号、卡密 inner_transaction_id:支付申报订单号 pay_no:支付单号 receiver_name:收件人姓名 receiver_phone:收件人电话 receiver_address:收件人地址,不拼接省市区 address:收件详细地址 id_card_name:身份证姓名 id_card_num:身份证号

例如原收件人姓名为 【张三】,则相关接口收件人姓名字段不在推送【张三】这个明文信息, 改为密文【~AgAAAAEj89wFUIsEOACIVyeI2r7XMNRS+DzOX5wSpiE=~j8+QVnFC~5~~】这种形式;

可通过下文的获取检索串工具来获取密文的检索串,不同订单但是收件人姓名相同则密文不同但是检索串相同,可通过检索串来进行判断合并订单等操作;

检索串样式【j8+QVnFC】;

然后可通过获取脱敏数据接口:pdd.open.decrypt.mask.batch 批量数据解密脱敏接口

来获取密文的脱敏的数据,可以用来前端展示,或者报表、导出的文档展示使用,样式为【张*】

因为密文长度比较长,要把原数据库对应字段长度变更,并且需要新增两个用来存储检索串以及脱敏数据的字段。

而且密文改造后拼多多的订单要必须使用拼多多电子面单来取号打印发货,所以整个流转过程不需要明文信息,如果有特殊需求需要调用解密接口。

因为部分接口调用需要在云上调用的原因,这里提供的一个解决方案为,本地提供一个openAPI接口,云上部署一个调取订单数据以及发送到openAPI上的线程任务。

简单点来说就是:

本地服务器部署/开发用来接收云服务器请求的API接口,云服务器部署一个专门用来往接口发送数据的任务,其他业务操作在本地服务器执行,接口调用在云服务器执行。

下面会列举几个刚需的接口对接实现以及方案,实际对接可以参考一下。

1、授权

官方指导文档地址:授权说明

授权的具体流程:

客户角度:

客户在服务市场订购本ERP服务后,可进入平台给出的授权页面:

(或在系统使用也面自行添加授权按钮,自主组装授权页URL也是 )

(拼多多店铺web端授权页面示例)

(拼多多店铺h5端授权页面示例)

系统角度:

使用店铺账号授权后,授权码code将返回到回调地址中,以参数code形式组装至回调地址中,应用可以获取并使用该code去换取access_token(接口调用需要使用的调用令牌)。

例如:我们在应用详情页填写的回调地址为 http://www.erp.com:80/pddaccess

则授权后会以 http://www.erp.com:80/pddaccess?code=asdf123asdf123 的形式请求过来。

code授权码十分钟内有效,授权码可以用来访问获取调用令牌(access_token)的接口。

code有效期内多次使用code换取access_token是一样的。

简单接收授权码code @Controller public class PddAccess { @GetMapping("/pddaccess") @ResponseBody public void PddRe(HttpServletRequest request,HttpServletResponse response){ try{ int contentlen = request.getContentLength(); String decode = ""; if(-1 != contentlen) { BufferedReader reader = request.getReader(); char[] buf = new char[contentlen]; int len = 0; StringBuffer contentBuffer = new StringBuffer(); while ((len = reader.read(buf)) != -1) { contentBuffer.append(buf, 0, len); } String content = contentBuffer.toString(); if (content == null) { content = ""; } decode = URLDecoder.decode(content, "UTF-8"); } String code = request.getParameter("code"); System.out.println(code); } catch (Exception e) { logger.error("拼多多授权异常:"+e.getMessage()); } } } 使用授权码code 获取访问接口获取调用令牌(access_token)

(以及使用获取到的access_token获取授权的店铺信息,以便维护,数据按需保存)

API文档地址:pdd.pop.auth.token.create 获取 Access Token

获取店铺信息接口:pdd.mall.info.get 店铺信息接口

调用直接使用SDK封装好的方法,简单易用,每个API的文档下都有请求实例,几乎直接copy就可以。

// 应用的 client_id private String clientId = "1111111111"; // 应用的 client_secret private String clientSecret = "2222222222"; @Controller public class PddAccess { @GetMapping("/pddaccess") @ResponseBody public void PddRe(HttpServletRequest request,HttpServletResponse response){ try{ int contentlen = request.getContentLength(); String decode = ""; if(-1 != contentlen) { BufferedReader reader = request.getReader(); char[] buf = new char[contentlen]; int len = 0; StringBuffer contentBuffer = new StringBuffer(); while ((len = reader.read(buf)) != -1) { contentBuffer.append(buf, 0, len); } String content = contentBuffer.toString(); if (content == null) { content = ""; } decode = URLDecoder.decode(content, "UTF-8"); } String code = request.getParameter("code"); if(null != code && "".equals(code)){ PopClient client = new PopHttpClient(clientId, clientSecret); PddPopAuthTokenCreateRequest pddPopAuthTokenCreateRequest = new PddPopAuthTokenCreateRequest(); pddPopAuthTokenCreateRequest.setCode(code); PddPopAuthTokenCreateResponse pddPopAuthTokenCreateResponse = client.syncInvoke(pddPopAuthTokenCreateRequest); String ownerId = popAuthTokenCreateResponse.getOwnerId(); // 商家店铺id,店铺唯一标识 String ownerName = popAuthTokenCreateResponse.getOwnerName(); // 商家账号名称 String accessToken = popAuthTokenCreateResponse.getAccessToken(); // access_token String refreshToken = popAuthTokenCreateResponse.getRefreshToken(); // refresh token,可用来刷新access_token Integer expiresIn = popAuthTokenCreateResponse.getExpiresIn(); // access_token过期时间段,10(表示10秒后过期,现令牌过期时间已与订购时间相同) Date expiresDate = new Date(expiresIn * 1000); Integer refreshTokenExpiresIn = popAuthTokenCreateResponse.getRefreshTokenExpiresIn(); // refresh_token过期时间段,10表示10秒后过期 Date refreshTokenExpiresDate = new Date(refreshTokenExpiresIn * 1000); // 通过店铺信息接口获取店铺详细信息 PddMallInfoGetRequest pddMallInfoGetRequest = new PddMallInfoGetRequest(); PddMallInfoGetResponse pddMallInfoGetResponse = client.syncInvoke(pddMallInfoGetRequest, accessToken); PddMallInfoGetResponse.MallInfoGetResponse mallInfoGetResponse = pddMallInfoGetResponse.getMallInfoGetResponse(); String logo = mallInfoGetResponse.getLogo(); // 店铺logo图片链接 Integer mallCharacter = mallInfoGetResponse.getMallCharacter(); // 店铺身份,0:厂商 1:分销商 2:都不是 3:都是 String mallDesc = mallInfoGetResponse.getMallDesc(); // 店铺描述 Long mallId = mallInfoGetResponse.getMallId(); // 店铺id String mallName = mallInfoGetResponse.getMallName(); // 店铺名称 Integer merchantType = mallInfoGetResponse.getMerchantType(); // 店铺类型,1:个人 2:企业 3:旗舰店 4:专卖店 5:专营店 6:普通店 // 保存店铺信息(所有获取到的数据已在上方陈列,按需保存) // 保存步骤省略,根据业务需求自行保存 // 业务流转完成可以执行重定向到系统登录页面或系统使用地址 StringBuilder sb = new StringBuilder(); sb.append(""); sb.append(""); sb.append(""); sb.append(""); sb.append("订购成功,点击登陆"); sb.append(""); sb.append(""); OutputStream outputStream = response.getOutputStream(); response.setHeader("content-type", "text/html;"); byte[] dataByteArr = sb.toString().getBytes("UTF-8"); outputStream.write(dataByteArr); return; } } catch (Exception e) { logger.error("拼多多授权异常:"+e.getMessage()); } } } 完整版(异常处理+系统内页面构建授权链接,自主组合拼接授权页面):

自主组合拼接授权页面流程:系统内页面添加点击授权超链接,点击后依然请求授权地址,通过请求是否携带code来判断是执行授权流程还是进入拼接平台授权页面流程。

平台给出的组装示例

https://{授权页链接}?response_type=code&client_id={应用client_id}&redirect_uri={client_id对应的回调地址}&state={自定义参数} https://fuwu.pinduoduo.com/service-market/auth?response_type=code&client_id=4b6**********************672e4c9a&redirect_uri=https%3A%2F%2Fwww.oauth.net%2F2%2F&state=1212

要求组装的参数以及可组装的参数如下:

// 应用的 client_id private String clientId = "1111111111"; // 应用的 client_secret private String clientSecret = "2222222222"; @Controller public class PddAccess { @GetMapping("/pddaccess") @ResponseBody public void PddRe(HttpServletRequest request,HttpServletResponse response){ try{ int contentlen = request.getContentLength(); String decode = ""; if(-1 != contentlen) { BufferedReader reader = request.getReader(); char[] buf = new char[contentlen]; int len = 0; StringBuffer contentBuffer = new StringBuffer(); while ((len = reader.read(buf)) != -1) { contentBuffer.append(buf, 0, len); } String content = contentBuffer.toString(); if (content == null) { content = ""; } decode = URLDecoder.decode(content, "UTF-8"); } String code = request.getParameter("code"); if(null != code && "".equals(code)){ // 通过code授权码获取access_token PopClient client = new PopHttpClient(clientId, clientSecret); PddPopAuthTokenCreateRequest pddPopAuthTokenCreateRequest = new PddPopAuthTokenCreateRequest(); pddPopAuthTokenCreateRequest.setCode(code); PddPopAuthTokenCreateResponse pddPopAuthTokenCreateResponse = client.syncInvoke(pddPopAuthTokenCreateRequest); if(null == pddPopAuthTokenCreateResponse.getErrorResponse()){ PddPopAuthTokenCreateResponse.PopAuthTokenCreateResponse popAuthTokenCreateResponse = pddPopAuthTokenCreateResponse.getPopAuthTokenCreateResponse(); String ownerId = popAuthTokenCreateResponse.getOwnerId(); // 商家店铺id,店铺唯一标识 String ownerName = popAuthTokenCreateResponse.getOwnerName(); // 商家账号名称 String accessToken = popAuthTokenCreateResponse.getAccessToken(); // access_token String refreshToken = popAuthTokenCreateResponse.getRefreshToken(); // refresh token,可用来刷新access_token Integer expiresIn = popAuthTokenCreateResponse.getExpiresIn(); // access_token过期时间段,10(表示10秒后过期,现令牌过期时间已与订购时间相同) Date expiresDate = new Date(expiresIn * 1000); Integer refreshTokenExpiresIn = popAuthTokenCreateResponse.getRefreshTokenExpiresIn(); // refresh_token过期时间段,10表示10秒后过期 Date refreshTokenExpiresDate = new Date(refreshTokenExpiresIn * 1000); // 通过店铺信息接口获取店铺详细信息 PddMallInfoGetRequest pddMallInfoGetRequest = new PddMallInfoGetRequest(); PddMallInfoGetResponse pddMallInfoGetResponse = client.syncInvoke(pddMallInfoGetRequest, accessToken); if(null == pddMallInfoGetResponse.getErrorResponse()){ PddMallInfoGetResponse.MallInfoGetResponse mallInfoGetResponse = pddMallInfoGetResponse.getMallInfoGetResponse(); String logo = mallInfoGetResponse.getLogo(); // 店铺logo图片链接 Integer mallCharacter = mallInfoGetResponse.getMallCharacter(); // 店铺身份,0:厂商 1:分销商 2:都不是 3:都是 String mallDesc = mallInfoGetResponse.getMallDesc(); // 店铺描述 Long mallId = mallInfoGetResponse.getMallId(); // 店铺id String mallName = mallInfoGetResponse.getMallName(); // 店铺名称 Integer merchantType = mallInfoGetResponse.getMerchantType(); // 店铺类型,1:个人 2:企业 3:旗舰店 4:专卖店 5:专营店 6:普通店 // 保存店铺信息(所有获取到的数据已在上方陈列,按需保存) // 保存步骤省略,根据业务需求自行保存 // 业务流转完成可以执行重定向到系统登录页面或系统使用地址 StringBuilder sb = new StringBuilder(); sb.append(""); sb.append(""); sb.append(""); sb.append(""); sb.append("订购成功,点击登陆"); sb.append(""); sb.append(""); OutputStream outputStream = response.getOutputStream(); response.setHeader("content-type", "text/html;charset=UTF-8"); byte[] dataByteArr = sb.toString().getBytes("UTF-8"); outputStream.write(dataByteArr); return; }else{ logger.error("拼多多店铺授权获取店铺信息异常,code = "+code+",error_msg = "+pddMallInfoGetResponse.getErrorResponse().getErrorMsg()); String error = toErrorHtmlNotice(returl, "授权异常,请联系ERP系统技术人员!"); OutputStream outputStream = response.getOutputStream(); response.setHeader("content-type", "text/html;charset=UTF-8"); byte[] dataByteArr = error.getBytes("UTF-8"); outputStream.write(dataByteArr); return; } }else{ logger.error("拼多多店铺授权获取AccessToken异常,code = "+code+",error_msg = "+pddPopAuthTokenCreateResponse.getErrorResponse().getErrorMsg()); String error = toErrorHtmlNotice(returl, "授权异常,请联系ERP系统技术人员!"); OutputStream outputStream = response.getOutputStream(); response.setHeader("content-type", "text/html;charset=UTF-8"); byte[] dataByteArr = error.getBytes("UTF-8"); outputStream.write(dataByteArr); return; } } // 如果请求不包含code参数,则执行以下授权页面跳转流程,引导商家进入授权页面 String returl = "https://fuwu.pinduoduo.com/service-market/auth?response_type=code&client_id=" + clientId + "&redirect_uri=" + URLEncoder.encode("http://www.erp.com/pddaccess", "utf-8"); returl = StringEscapeUtils.unescapeHtml(returl); if(null == request.getParameter("error")) { response.sendRedirect(returl); return; }else { switch (request.getParameter("error")) { default: response.sendRedirect(returl); break; case "invalid_client": StringBuilder sb = new StringBuilder(); sb.append(""); sb.append("alert('您还没订购!点确定前往订购!');"); sb.append("window.location.href='"); sb.append(fuwuurl); // ERP应用的服务市场地址,跳转到此位置 sb.append("';"); sb.append(""); OutputStream outputStream = response.getOutputStream(); response.setHeader("content-type", "text/html;charset=UTF-8"); byte[] dataByteArr = sb.toString().getBytes("UTF-8"); outputStream.write(dataByteArr); return; } } } catch (Exception e) { logger.error("拼多多授权异常:"+e.getMessage()); } } } 2、云工作台开启订单同步

只有开启订单同步服务后订购的云数据库才能同步到授权商家的订单信息,开启步骤参考下方订单同步使用手册文档。

订单同步服务产品介绍:产品简介  订单同步服务使用手册:订单同步使用手册

商家店铺授权完成后需要在商家管理里添加商家店铺ID,按照实际需要选择同步历史订单信息,添加完成,同步完成历史订单信息后云数据库就会实时的新增商家店铺的新订单信息。

后续同步商家订单信息只需要在云主机上查询云数据库内的数据并发送到我们设置好的外部API服务上即可。

3、云主机订单数据操作Java线程处理任务方案

为了接口API安全性,请自行配置加密策略或其他安全策略来接收传递相关数据,以下流程为直接传递(非安全)。

在线程处理任务程序中,查询云数据库内的订单列表,可以根据传统的时间段调用方式。

首次启动从两天前的时间点以半小时的时间段查询一次,然后把查询出的数据传递给API,API在本地对订单数据进行序列化存储到本地数据库内,查询可以根据订单更新时间 update_at 字段来判断,本地订单如果存在,并且更新时间一致则跳过,不一致并且本地存储的订单更新时间早于新的数据更新时间的话则把新的订单详情更新到本地数据库。

执行成功会返回请求结果信息,如果执行成功,则根据当前时间前进半个小时继续执行,以此类推,直到执行到当前时间,则以当前时间前二十分以及后十分钟为维度,慢慢查询遍历执行。

具体Java线程自动执行任务,可以根据实际系统配置进行开发,或自行寻找流程,这边不在展示架构。

云服务器部署的自动处理线程任务:

public class PddOrderSyncTask implements Runnable { // 记录开始时间 private Date lastjdpmodify = new Date(); // 记录最后更新时间 private Date newUpdateTime; @Override public void run() { pdptbTradeService = (IPdptbTradeService)applicationContext.getBean("PdptbTradeService"); while (true) { try { SyncPddOrderStateFrom(); } catch (Exception e) { e.printStackTrace(); } try { Thread.sleep(1000); } catch (Exception e) { e.printStackTrace(); } } } public void SyncPddOrderStateFrom() throws Exception { String url = "http://www.erp.com/pddOrderApi";// 远程API接口地址 Date nowdate = new Date(); Calendar calendar = Calendar.getInstance(); calendar.setTime(nowdate); // 时间推后一天 calendar.add(Calendar.DAY_OF_MONTH, -2); lastjdpmodify = calendar.getTime(); // 如果最后更新时间不为空,并且记录的开始时间小于记录的更新时间,则使用最后更新时间进行后续操作 if(newUpdateTime != null){ if (lastjdpmodify.getTime() =44; } } if (separator == SEP_NORMAL) { if (data.charAt(data.length() - 2) == separator) { if (dataArray.length != 3) { return false; } return BASE64_PATTERN.matcher(dataArray[0]).matches() && BASE64_PATTERN.matcher(dataArray[1]).matches() && dataArray[0].length()>=44; } else { if (dataArray.length != 2) { return false; } return BASE64_PATTERN.matcher(dataArray[0]).matches() && dataArray[0].length()>=44; } } return false; } /** 拼多多敏感数据获取密文检索串 **/ public static String extractIndex(String encryptedData) { if (encryptedData == null || encryptedData.length() < 4) { return null; } char sepInData = encryptedData.charAt(0); if (encryptedData.charAt(encryptedData.length() - 2) != sepInData) { return null; } String[] parts = StringUtils.split(encryptedData, sepInData); if (sepInData == '$' || sepInData == '#') { return parts[0]; } else { return parts[1]; } } }

通过接口获取订单敏感数据密文的脱敏数据(例:王*虎)

接口文档地址:pdd.open.decrypt.mask.batch 批量数据解密脱敏接口

// 应用的 client_id private String clientId = "1111111111"; // 应用的 client_secret private String clientSecret = "2222222222"; @Service("PddEncryptionService") public class PddEncryptionServiceImpl implements IPddEncryptionService { // 密文脱敏 @Override public OrderInfo getDecryptMask(OrderInfo orderInfo) throws Exception { PopClient client = new PopHttpClient("http://gw-api.pinduoduo.com/api/router",clientId , clientSecret ); ShopInfo shopInfo = shopService.selectById(orderInfo.getShopid()); String accessToken = shopInfo.getSessionkey(); PddOpenDecryptMaskBatchRequest request = new PddOpenDecryptMaskBatchRequest(); List dataList = new ArrayList(); boolean success = true; //判断收货人 (不为空并且是密文) if(orderInfo.getReceivername()!=null && PddUtils.isEncryptData(orderInfo.getReceivername())){ PddOpenDecryptMaskBatchRequest.DataListItem item0 = new PddOpenDecryptMaskBatchRequest.DataListItem(); item0.setDataTag(orderInfo.getId()); item0.setEncryptedData(orderInfo.getReceivername()); dataList.add(item0); success = false; } //判断收货地址 (不为空并且是密文) if(orderInfo.getReceiveraddress()!=null && PddUtils.isEncryptData(orderInfo.getReceiveraddress())){ PddOpenDecryptMaskBatchRequest.DataListItem item1 = new PddOpenDecryptMaskBatchRequest.DataListItem(); item1.setDataTag(orderInfo.getId()); item1.setEncryptedData(orderInfo.getReceiveraddress()); dataList.add(item1); success = false; } //判断买家昵称 (不为空并且是密文) if(orderInfo.getBuyernick()!=null && PddUtils.isEncryptData(orderInfo.getBuyernick())){ PddOpenDecryptMaskBatchRequest.DataListItem item2 = new PddOpenDecryptMaskBatchRequest.DataListItem(); item2.setDataTag(orderInfo.getId()); item2.setEncryptedData(orderInfo.getBuyernick()); dataList.add(item2); success = false; } //判断手机号 (不为空并且是密文) if(orderInfo.getReceivermobile()!=null && PddUtils.isEncryptData(orderInfo.getReceivermobile())){ PddOpenDecryptMaskBatchRequest.DataListItem item3 = new PddOpenDecryptMaskBatchRequest.DataListItem(); item3.setDataTag(orderInfo.getId()); item3.setEncryptedData(orderInfo.getReceivermobile()); dataList.add(item3); success = false; } //判断电话 (不为空并且是密文) if(orderInfo.getReceiverphone()!=null && PddUtils.isEncryptData(orderInfo.getReceiverphone())){ PddOpenDecryptMaskBatchRequest.DataListItem item4 = new PddOpenDecryptMaskBatchRequest.DataListItem(); item4.setDataTag(orderInfo.getId()); item4.setEncryptedData(orderInfo.getReceiverphone()); dataList.add(item4); success = false; } if(success){ return orderInfo; } request.setDataList(dataList); PddOpenDecryptMaskBatchResponse response = client.syncInvoke(request, accessToken); PddOpenDecryptMaskBatchResponse.OpenDecryptMaskBatchResponse openDecryptMaskBatchResponse = response.getOpenDecryptMaskBatchResponse(); if (null == openDecryptMaskBatchResponse || null == openDecryptMaskBatchResponse.getDataDecryptList()){ return orderInfo; } List dataDecryptList = openDecryptMaskBatchResponse.getDataDecryptList(); for (int i = 0; i < dataDecryptList.size(); i++) { PddOpenDecryptMaskBatchResponse.OpenDecryptMaskBatchResponseDataDecryptListItem openListItem = dataDecryptList.get(i); if(openListItem.getEncryptedData().equals(orderInfo.getAlipayno()) && openListItem.getErrorCode() == 0){ orderInfo.setAlipaynomask(openListItem.getDecryptedData()); orderInfo.setAlipaynosearchstring(PddUtils.extractIndex(orderInfo.getAlipayno())); } if(openListItem.getEncryptedData().equals(orderInfo.getBuyernick()) && openListItem.getErrorCode() == 0){ String replace = openListItem.getDecryptedData().replace("'", "’").replace("/", ""); replace = filterOffUtf8Mb4(replace); if(StringUtils.isBlank(replace)){ replace = "未知"; } orderInfo.setBuyernickmask(replace); String s = PddUtils.extractIndex(orderInfo.getBuyernick()); orderInfo.setBuyernicksearchstring(s); } if(openListItem.getEncryptedData().equals(orderInfo.getReceivername()) && openListItem.getErrorCode() == 0){ String replace = openListItem.getDecryptedData().replace("'", "’").replace("/", ""); replace = filterOffUtf8Mb4(replace); if(StringUtils.isBlank(replace)){ replace = "未知"; } orderInfo.setReceivernamemask(replace); String s = PddUtils.extractIndex(orderInfo.getReceivername()); orderInfo.setNamesearchstring(s); } if(openListItem.getEncryptedData().equals(orderInfo.getReceiveraddress()) && openListItem.getErrorCode() == 0){ String replace = openListItem.getDecryptedData().replace("'", "’").replace("/", ""); replace = filterOffUtf8Mb4(replace); orderInfo.setReceiveraddressmask(replace); orderInfo.setAddresssearchstring(PddUtils.extractIndex(orderInfo.getReceiveraddress())); } if(openListItem.getEncryptedData().equals(orderInfo.getReceivermobile()) && openListItem.getErrorCode() == 0){ String replace = openListItem.getDecryptedData().replace("'", "’").replace("/", ""); replace = filterOffUtf8Mb4(replace); orderInfo.setReceivermobilemask(replace); String s = PddUtils.extractIndex(orderInfo.getReceivermobile()); orderInfo.setMobilesearchstring(s); } if(openListItem.getEncryptedData().equals(orderInfo.getReceiverphone()) && openListItem.getErrorCode() == 0){ String replace = openListItem.getDecryptedData().replace("'", "’").replace("/", ""); replace = filterOffUtf8Mb4(replace); orderInfo.setReceiverphonemask(replace); String s = PddUtils.extractIndex(orderInfo.getReceivermobile()); orderInfo.setPhonesearchstring(s); } } return orderInfo; } // 过滤特殊字符,emoji表情等 public String filterOffUtf8Mb4(String text) throws UnsupportedEncodingException { byte[] bytes = text.getBytes("utf-8"); ByteBuffer buffer = ByteBuffer.allocate(bytes.length); int i = 0; while (i 0) { buffer.put(bytes[i++]); continue; } b += 256; // 去掉符号位 if (((b >> 5) ^ 0x6) == 0) { buffer.put(bytes, i, 2); i += 2; } else if (((b >> 4) ^ 0xE) == 0) { buffer.put(bytes, i, 3); i += 3; } else if (((b >> 3) ^ 0x1E) == 0) { i += 4; } else if (((b >> 2) ^ 0x3E) == 0) { i += 5; } else if (((b >> 1) ^ 0x7E) == 0) { i += 6; } else { buffer.put(bytes[i++]); } } buffer.flip(); return new String(buffer.array(), "utf-8"); } }

业务处理接口:

@Controller public class PddOrderController{ @PostMapping("pddOrderApi") @ResponseBody public String PddRespon (HttpServletRequest request, HttpServletResponse response){ PddResponse resp = new PddResponse(); String plantform = "PDD"; try{ int contentlen = request.getContentLength(); BufferedReader reader = request.getReader(); char[] buf = new char[contentlen]; int len = 0; StringBuffer contentBuffer = new StringBuffer(); while ((len = reader.read(buf)) != -1) { contentBuffer.append(buf, 0, len); } String content = contentBuffer.toString(); if(content == null){ content = ""; } PdptbTradeInfo pdptbTradeInfo = JSONObject.parseObject(content, PdptbTradeInfo.class); //店铺id为"PDD"+mallid拼接而成 String shopid = plantform+pdptbTradeInfo.getMall_id(); //根据店铺id查询店铺是否存在或给以后的其他判断作准备 ShopInfo shopInfo = shopService.selectOneByShopCode(shopid); if(shopInfo == null){ resp.setCode("error"); resp.setMessages("[店铺【"+shopInfo.getShopname()+"】:不存在!]"); logger.error(resp.getMessages()); }else if(shopInfo.getExpiretime()==null || shopInfo.getExpiretime().before(new Date())){ resp.setCode("error"); resp.setMessages("[店铺【"+shopInfo.getShopname()+"】:已过期!]"); logger.error(resp.getMessages()); }else if(shopInfo.getShoptype()==0){ resp.setCode("error"); resp.setMessages("[店铺【"+shopInfo.getShopname()+"】:已关闭!]"); logger.error(resp.getMessages()); }else{ // 查询订单是否存在,如果存在并且新推来的订单更新时间小于或者等于本地存储的订单更新时间,则直接跳过 OrderInfo orderInfo = orderService.selectOrderInfoById(pdptbTradeInfo.getOrder_sn(), shopInfo.getId()); if(orderInfo!=null){ long a = orderInfo.getJdpmodified().getTime()/1000; long b = pdptbTradeInfo.getUpdated_at().getTime()/1000; if(a==b || a>b){ resp.setCode("success"); return JSONArray.toJSONString(resp); } } // 进入订单操作流程,存储或者修改本地订单状态等 String s = SyncDataToSql(shopInfo, pdptbTradeInfo); if(s.equals("success")){ resp.setCode("success"); } else if(s.equals("error")){ resp.setCode("error"); } } } catch (Exception e) { resp.setCode("error"); resp.setMessages("[发生异常]"); logger.error(e.getMessage()); e.printStackTrace(); } return JSONArray.toJSONString(resp); } // 订单操作流程,存储或者修改本地订单状态等 public String SyncDataToSql(ShopInfo shopInfo,PdptbTradeInfo pdptbTradeInfo) throws ParseException { SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); // 保存一份原始订单数据 PddOrderInfo pddOrderInfo = new PddOrderInfo(); String pdp_response = pdptbTradeInfo.getPdp_response(); JSONObject pddOrderItem = JSONObject.parseObject(pdp_response); pddOrderInfo.setId(pddOrderItem.getString("order_sn")); pddOrderInfo.setTenantid(shopInfo.getTenantid()); pddOrderInfo.setShopid(shopInfo.getId()); pddOrderInfo.setTidstr(pddOrderItem.getString("order_sn")); //1:待发货,2:已发货待签收,3:已签收 pddOrderInfo.setStatus(pddOrderItem.getString("order_status")); pddOrderInfo.setSellernick(shopInfo.getShopnick()); String remark = pddOrderItem.getString("remark"); String buyer_memo = pddOrderItem.getString("buyer_memo"); String receiver_name = pddOrderItem.getString("receiver_name"); String address = pddOrderItem.getString("address"); String receiver_address = pddOrderItem.getString("receiver_address"); try{ if(StringUtils.isNotBlank(remark)){ remark = pddOrderItem.getString("remark").replace("'","’").replace("/","//"); remark = filterOffUtf8Mb4(remark); } if(StringUtils.isNotBlank(buyer_memo)){ buyer_memo = pddOrderItem.getString("buyer_memo").replace("'","’").replace("/","//"); buyer_memo = filterOffUtf8Mb4(buyer_memo); } String item_list_str = pddOrderItem.getString("item_list"); JSONArray itemList = JSONArray.parseArray(item_list_str); for(int j=0;j


【本文地址】

公司简介

联系我们

今日新闻


点击排行

实验室常用的仪器、试剂和
说到实验室常用到的东西,主要就分为仪器、试剂和耗
不用再找了,全球10大实验
01、赛默飞世尔科技(热电)Thermo Fisher Scientif
三代水柜的量产巅峰T-72坦
作者:寞寒最近,西边闹腾挺大,本来小寞以为忙完这
通风柜跟实验室通风系统有
说到通风柜跟实验室通风,不少人都纠结二者到底是不
集消毒杀菌、烘干收纳为一
厨房是家里细菌较多的地方,潮湿的环境、没有完全密
实验室设备之全钢实验台如
全钢实验台是实验室家具中较为重要的家具之一,很多

推荐新闻


图片新闻

实验室药品柜的特性有哪些
实验室药品柜是实验室家具的重要组成部分之一,主要
小学科学实验中有哪些教学
计算机 计算器 一般 打孔器 打气筒 仪器车 显微镜
实验室各种仪器原理动图讲
1.紫外分光光谱UV分析原理:吸收紫外光能量,引起分
高中化学常见仪器及实验装
1、可加热仪器:2、计量仪器:(1)仪器A的名称:量
微生物操作主要设备和器具
今天盘点一下微生物操作主要设备和器具,别嫌我啰嗦
浅谈通风柜使用基本常识
 众所周知,通风柜功能中最主要的就是排气功能。在

专题文章

    CopyRight 2018-2019 实验室设备网 版权所有 win10的实时保护怎么永久关闭