目录

1开放平台需求

1.1调用参数

1.2签名算法

2服务端代码,Java举例

2.1接口入口代码

2.2业务逻辑层

2.3基础工具类

3.SDK代码,Java举例

4.集成SDK,代码举例


现在开放平台越来越多了,下面针对仿京东开放平台框架,封装自己的开放平台,分享给大家。

先感谢一下京东开放平台的技术大佬们,下面从开放平台需求,服务端代码,SDK代码三大块进行分享,有不足之处,欢迎在评论区留言。

1开放平台需求

用户需要按照开放平台的协议规范拼装一个正确的URL,通过Https请求到开放平台既能够获取到所需数据。主要流程包含:填写参数、生成签名、拼装HTTPS请求、发起请求、得到响应结果、解析结果。

1.1调用参数

系统参数:调用任何一个API都需要传入的参数,目前支持的系统参数是:

参数名称

参数类型

是否必传

参数描述

method

String

API接口名称

access_token

String

采用OAuth授权方式是必填参数

app_key

String

应用的app_key

sign

String

详见下文“5.签名算法”描述

timestamp

String

时间戳,格式为yyyy-MM-dd HH:mm:ss,例如:2019-05-01 00:00:00。API服务端允许客户端请求时间误差为10分钟

format

String

暂时只支持json

v

String

API协议版本,参考接口文档版本

360buy_param_json

String

需要将应用级参数作为一个整体对象以json的形式拼接传递

应用级参数(更多API应用参数参考 接口文档)

1.2签名算法

为了防止API在调用过程中被恶意者拦截随意篡改,调用API是需要传入签名参数,开放平台服务端会根据请求参数对签名进行验证,判断请求参数是否合法。开放平台签名规则过程如下:

将所有请求参数按照字母先后顺序排列,例如:access_token,app_key,method,timestamp,v,360buy_param_json ,

排序为360buy_param_json,access_token,app_key,method,timestamp,v

把所有参数名和参数值进行拼接,例如:360buy_param_jsonxxxaccess_tokenxxxapp_keyxxxmethodxxxxxxtimestampxxxxxxvx

把appSecret夹在字符串(上一步拼接串)的两端,例如:appSecret+XXXX+appSecret

使用MD5进行加密,再转化成大写。

2服务端代码,Java举例

服务端基于SpringBoot框架编写,入口放在Controller,业务逻辑写在Service。同时考虑安全性和方便排查问题,会加入输入性校验和访问日志。

2.1接口入口代码

接口只有一个入口,即Controller代码如下:


@Controller
public class RouterController {@Resourceprivate RouterService routerService;@Resourceprivate OpenApiLogService openApiLogService;/*** API接口路由器,接口入口** @param request* @param zrsc_param_json* @return*/@RequestMapping(value = "routerjson", method = RequestMethod.POST)@ResponseBodypublic String routerjson(HttpServletRequest request, String zrsc_param_json) {if (zrsc_param_json==null||"".equals(zrsc_param_json)) {return JsonUtils.objToJson(APIMessageVo.fail(APIErrorEnum.FAIL_PARA_LOSE.getCode(), APIErrorEnum.FAIL_PARA_LOSE.getName()));}APIMessageVo aPIMessageVo=openApiLogService.secrityCheck(request);if(aPIMessageVo.isSuccess()){//安全检测成功aPIMessageVo=routerService.router(request, zrsc_param_json);openApiLogService.insert(request,aPIMessageVo);}return JsonUtils.objToJson(aPIMessageVo);}
}

2.2业务逻辑层

业务逻辑层,简单举例说明,不同业务有所不同。

    public APIMessageVo router(HttpServletRequest request, String zrsc_param_json) {String access_token = request.getParameter("access_token");String app_key = request.getParameter("app_key");String method = request.getParameter("method");String sign = request.getParameter("sign");APIMessageVo checkResult=this.routerParaCheck(request, zrsc_param_json,access_token,app_key,method,sign);if(!checkResult.isSuccess()){//入参检测失败return checkResult;}if (APPInterfaceNameEnum.API_ADDRESS_ADDRESS2PROVICECITY_GET.getName().equals(method)) {//获取省市区街道return this.address2provincecity(zrsc_param_json);} else {//接口不存在return APIMessageVo.fail(APIErrorEnum.FAIL_NOT_FOUND_INTERFACE.getCode(), APIErrorEnum.FAIL_NOT_FOUND_INTERFACE.getName());}}private APIMessageVo routerParaCheck(HttpServletRequest request, String zrsc_param_json, String access_token,String app_key, String method, String sign){//***************参数校验***************if (StringUtils.isBlank(access_token) || StringUtils.isBlank(app_key) || StringUtils.isBlank(method) ||StringUtils.isBlank(sign)) {return APIMessageVo.fail(APIErrorEnum.FAIL_PARA_LOSE.getCode(), APIErrorEnum.FAIL_PARA_LOSE.getName());}if(!APP_KEY.equals(app_key)){return APIMessageVo.fail(APIErrorEnum.FAIL_NOT_EXIST_APP_ID.getCode(), APIErrorEnum.FAIL_NOT_EXIST_APP_ID.getName());}//***************sign校验***************try {//获取request中的参数Map<String, String> sysParams = getSysParams(request, zrsc_param_json);//SDK参数加密String signNew = SDKSignUtils.sign(sysParams, APP_SECRET);//判断参数是否被更改if (!sign.equals(signNew)) {return APIMessageVo.fail(APIErrorEnum.FAIL_ERR_APP_SECRET.getCode(), APIErrorEnum.FAIL_ERR_APP_SECRET.getName());}} catch (Exception e) {return APIMessageVo.fail(APIErrorEnum.FAIL_EXCEPTION.getCode(), APIErrorEnum.FAIL_EXCEPTION.getName());}return APIMessageVo.success();}

2.3基础工具类

APIErrorEnum

public enum APIErrorEnum {FAIL_NOTAUTH(201,"没有授权"),FAIL_TOKEN_EXPIRE(202,"Token过期"),FAIL_PARA_LOSE(203,"缺少参数"),FAIL_NOT_REALAUTH(204,"没有实名认证通过"),FAIL_NOT_METHOD(205,"没有权限访问这个接口"),FAIL_PARA_ERR(206,"参数的值,不正确"),FAIL_NOT_EXIST_ACCOUNT(207,"用户账号不存在"),FAIL_NOT_FOUND_APPLY(208,"应用不存在"),FAIL_NOT_PASS_APPROVAL_APPLY(209,"应用审批未通过"),FAIL_NOT_EXIST_APP_ID(210,"APP_ID不存在"),FAIL_NOT_FOUND_INTERFACE(211,"接口不存在"),FAIL_ERR_APP_SECRET(212,"appSecret错误"),FAIL_CALL_FREQUENTLY(214,"调用太频繁"),FAIL_EXCEPTION(290,"未知错误");private int code;private String name;APIErrorEnum(int code,String name) {this.code = code;this.name = name;}public int getCode() {return code;}public String getName() {return name;}public void setCode(int code) {this.code = code;}public void setName(String name) {this.name = name;}
}
APIMessageVo
public class APIMessageVo {public static final Integer SUCCESS = 100;//成功private boolean success;// 处理是否成功private Integer code = SUCCESS;//状态码private String message = "成功";// 附加消息, 如处理结果失败时的原因等private Object data="";// 可以附带返回一些结果数据public APIMessageVo() {//default}public APIMessageVo(boolean success, Integer code) {this(success, code, "成功", null);}public APIMessageVo(boolean success, Integer code, String message) {this(success, code, message, null);}public APIMessageVo(boolean success, String message, Object data) {this.success = success;this.message = message;this.data = data;}public APIMessageVo(boolean success, Integer code, String message, Object data) {this.success = success;this.code = code;this.message = message;this.data = data;}public APIMessageVo(boolean success, Object data) {this.success = success;this.data = data;}public static APIMessageVo fail(Integer code) {return new APIMessageVo(false, code);}public static APIMessageVo fail(Integer code,String message) {return new APIMessageVo(false,code, message);}public static APIMessageVo fail(Integer code,String message, Object data) {return new APIMessageVo(false,code, message, data);}public static APIMessageVo success() {return new APIMessageVo(true, SUCCESS);}public static APIMessageVo success(String message) {return new APIMessageVo(true, message);}public static APIMessageVo success(String message, Object data) {return new APIMessageVo(true, SUCCESS, message, data);}public static APIMessageVo success(Object data) {return new APIMessageVo(true, "成功", data);}
}
JsonUtils
public class JsonUtils {// 定义jackson对象private static final ObjectMapper MAPPER = new ObjectMapper();/*** 对象转Json** @param obj 对象* @return json串*/public static String objToJson(Object obj) {try {return MAPPER.writeValueAsString(obj);} catch (JsonProcessingException e) {log.error("Json转换异常:{}", e);}return "Json转换异常";}/*** json转对象* @param jsonData json串* @param beanType 对象* @return 对象*/public static <T> T jsonToPojo(String jsonData, Class<T> beanType) {try {T obj = MAPPER.readValue(jsonData, beanType);return obj;} catch (Exception e) {log.error("Json转换异常:{}", e);}return null;}
}

3.SDK代码,Java举例

DefaultZrscClient
public class DefaultZrscClient implements ZrscClient {private String serverUrl;private String accessToken;private int connectTimeout;private int readTimeout;private String appKey;private String fuzz;private String appSecret;public DefaultZrscClient(String serverUrl, String accessToken, String appKey, String appSecret) {this.connectTimeout = 8000;this.readTimeout = 8000;this.serverUrl = serverUrl;this.accessToken = accessToken;this.appKey = appKey;this.appSecret = appSecret;}public <T extends AbstractResponse> T execute(ZrscRequest<T> request) throws ZrscException {try {String url = this.buildUrl(request);Map<String, String> params = new HashMap();String json = request.getAppJsonParams();params.put("zrsc_param_json", json);if (request.getOtherParams() != null) {params.put("other", request.getOtherParams());}String rsp = HttpUtil.doPost(url, params, this.connectTimeout, this.readTimeout,this.accessToken);T resp = this.parse(rsp, request.getResponseClass());StringBuffer sb = new StringBuffer();sb.append(url).append("&").append("zrsc_param_json").append("=").append(json);resp.setUrl(sb.toString());return resp;} catch (Exception var8) {var8.printStackTrace();throw new ZrscException("出现异常,请重试");}}private <T extends AbstractResponse> String buildUrl(ZrscRequest<T> request) throws Exception {Map<String, String> sysParams = request.getSysParams();Map<String, String> pmap = new TreeMap();pmap.put("zrsc_param_json", request.getAppJsonParams());sysParams.put("method", request.getApiMethod());sysParams.put("access_token", this.accessToken);sysParams.put("app_key", this.appKey);pmap.putAll(sysParams);String sign = this.sign(pmap, this.appSecret);sysParams.put("sign", sign);StringBuilder sb = new StringBuilder(this.serverUrl);sb.append("?");sb.append(HttpUtil.buildQuery(sysParams, "UTF-8"));return sb.toString();}private <T extends AbstractResponse> T parse(String rsp, Class<T> responseClass) throws ZrscException {Parser parser;if (this.serverUrl.endsWith("json")) {parser = ParserFactory.getJsonParser();} else {parser = ParserFactory.getXmlParser();}return parser.parse(rsp, responseClass);}private String sign(Map<String, String> pmap, String appSecret) throws Exception {StringBuilder sb = new StringBuilder(appSecret);Iterator i$ = pmap.entrySet().iterator();while(i$.hasNext()) {Map.Entry<String, String> entry = (Map.Entry)i$.next();String name = (String)entry.getKey();String value = (String)entry.getValue();if (StringUtil.areNotEmpty(new String[]{name, value})) {sb.append(name).append(value);}}sb.append(appSecret);String result = CodecUtil.md5(sb.toString());return result;}
}
HttpUtil
public class HttpUtil {public static final String DEFAULT_CHARSET = "UTF-8";private static final String METHOD_POST = "POST";private HttpUtil() {throw new UnsupportedOperationException();}public static String buildQuery(Map<String, String> params, String charset) throws Exception {if (params != null && !params.isEmpty()) {StringBuilder query = new StringBuilder();Set<Entry<String, String>> entries = params.entrySet();boolean hasParam = false;Iterator i$ = entries.iterator();while(i$.hasNext()) {Entry<String, String> entry = (Entry)i$.next();String name = (String)entry.getKey();String value = (String)entry.getValue();if (StringUtil.areNotEmpty(new String[]{name, value})) {if (hasParam) {query.append("&");} else {hasParam = true;}query.append(name).append("=").append(URLEncoder.encode(value, charset));}}return query.toString();} else {return null;}}public static String doPost(String url, Map<String, String> params, int connectTimeout, int readTimeout,String token) throws Exception {return doPost(url, params, "UTF-8", connectTimeout, readTimeout,token);}public static String doPost(String url, Map<String, String> params, String charset, int connectTimeout, int readTimeout,String token) throws Exception {String ctype = "application/x-www-form-urlencoded;charset=" + charset;//String ctype = "application/json;charset=" + charset;String query = buildQuery(params, charset);byte[] content = new byte[0];if (query != null) {content = query.getBytes(charset);}return doPost(url, ctype, content, connectTimeout, readTimeout,token);}public static String doPost(String url, String ctype, byte[] content, int connectTimeout, int readTimeout,String token) throws IOException {HttpURLConnection conn = null;OutputStream out = null;String rsp = null;try {conn = getConnection(new URL(url), "POST", ctype,token);conn.setConnectTimeout(connectTimeout);conn.setReadTimeout(readTimeout);out = conn.getOutputStream();out.write(content);rsp = getResponseAsString(conn);} finally {if (out != null) {out.close();}if (conn != null) {conn.disconnect();}}return rsp;}private static HttpURLConnection getConnection(URL url, String method, String ctype,String token) throws IOException {HttpURLConnection conn = null;if ("https".equals(url.getProtocol())) {SSLContext ctx = null;try {ctx = SSLContext.getInstance("TLS");ctx.init(new KeyManager[0], new DefaultTrustManager[]{new DefaultTrustManager()}, new SecureRandom());} catch (Exception var6) {throw new IOException(var6);}HttpsURLConnection connHttps = (HttpsURLConnection)url.openConnection();connHttps.setSSLSocketFactory(ctx.getSocketFactory());connHttps.setHostnameVerifier(new HostnameVerifier() {public boolean verify(String hostname, SSLSession session) {return true;}});conn = connHttps;} else {conn = (HttpURLConnection)url.openConnection();}((HttpURLConnection)conn).setRequestMethod(method);((HttpURLConnection)conn).setDoInput(true);((HttpURLConnection)conn).setDoOutput(true);((HttpURLConnection)conn).setRequestProperty("Accept", "text/xml,text/javascript,text/html");((HttpURLConnection)conn).setRequestProperty("User-Agent", "kcb-sdk-java");((HttpURLConnection)conn).setRequestProperty("Content-Type", ctype);((HttpURLConnection)conn).setRequestProperty("Authorization", token);return (HttpURLConnection)conn;}protected static String getResponseAsString(HttpURLConnection conn) throws IOException {String charset = getResponseCharset(conn.getContentType());InputStream es = conn.getErrorStream();if (es == null) {return getStreamAsString(conn.getInputStream(), charset);} else {String msg = getStreamAsString(es, charset);if (StringUtil.isEmpty(msg)) {throw new IOException(conn.getResponseCode() + ":" + conn.getResponseMessage());} else {throw new IOException(msg);}}}private static String getStreamAsString(InputStream stream, String charset) throws IOException {try {BufferedReader reader = new BufferedReader(new InputStreamReader(stream, charset));StringWriter writer = new StringWriter();char[] chars = new char[256];boolean var5 = false;int count;while((count = reader.read(chars)) > 0) {writer.write(chars, 0, count);}String var6 = writer.toString();return var6;} finally {if (stream != null) {stream.close();}}}private static String getResponseCharset(String ctype) {String charset = "UTF-8";if (!StringUtil.isEmpty(ctype)) {String[] params = ctype.split(";");String[] arr$ = params;int len$ = params.length;for(int i$ = 0; i$ < len$; ++i$) {String param = arr$[i$];param = param.trim();if (param.startsWith("charset")) {String[] pair = param.split("=", 2);if (pair.length == 2 && !StringUtil.isEmpty(pair[1])) {charset = pair[1].trim();}break;}}}return charset;}private static byte[] getTextEntry(String fieldName, String fieldValue, String charset) throws IOException {StringBuilder entry = new StringBuilder();entry.append("Content-Disposition:form-data;name=\"");entry.append(fieldName);entry.append("\"\r\nContent-Type:text/plain\r\n\r\n");entry.append(fieldValue);return entry.toString().getBytes(charset);}private static byte[] getFileEntry(String fieldName, String fileName, String mimeType, String charset) throws IOException {StringBuilder entry = new StringBuilder();entry.append("Content-Disposition:form-data;name=\"");entry.append(fieldName);entry.append("\";filename=\"");entry.append(fileName);entry.append("\"\r\nContent-Type:");entry.append(mimeType);entry.append("\r\n\r\n");return entry.toString().getBytes(charset);}
}

4.集成SDK,代码举例

    @Testvoid getAddress() throws IOException {Address2provicecityRequest request=new Address2provicecityRequest();request.setAddress("阿胶街东首路北");ZrscClient client = new DefaultZrscClient(serverUrl, accessToken, appKey,appSecret);try {Address2provicecityResponse response= client.execute(request);System.out.println("data="+JsonUtil.toJson(response.getData()));} catch (Exception e) {e.printStackTrace();}}

运行结果:

data={"source":"阿胶街东首路北","province":"山东省","city":"聊城市","area":"东阿县","street":"新城街道","addressInfo":"阿胶街东首路北"}

京东开放平台中的传参和签名算法比较有代表性,此博客,只是分享开放平台开放的主要组成部分,供大家学习,后期有时间,我把项目代码整理一下,分享给大家。

仿京东开放平台框架,开发自己的开放平台(包含需求,服务端代码,SDK代码)相关推荐

  1. TinkPHP内核仿每推推51领啦试客源码_PC源码+WAP端+APP原生代码_自带5套精美模板

    TinkPHP内核仿每推推51领啦试客源码_PC源码+WAP端+APP原生代码_自带5套精美模板 源码说明:TinkPHP内核上制作而成,是全国领先的免费试用网站!程序全开源无加密!带有wap手机端, ...

  2. 前端开发全家桶:UI组件 开发框架 服务端 辅助工具 应用实例 Demo示例

    element ★11612 - 饿了么出品的Vue2的web UI工具套件 Vux ★7503 - 基于Vue和WeUI的组件库 iview ★5801 - 基于 Vuejs 的开源 UI 组件库 ...

  3. Vue+koa2开发一款全栈小程序(服务端环境搭建和项目初始化)

    1.微信公众平台小程序关联腾讯云 腾讯云的开发环境是给免费的一个后台,但是只能够用于开发,如果用于生产是需要花钱的,我们先用开发环境吧 1.用小程序开发邮箱账号登录微信公众平台 2.[设置]→[开发者 ...

  4. java nio 客户端_Java网络编程:Netty框架学习(二)---Java NIO,实现简单的服务端客户端消息传输...

    概述 上篇中已经讲到Java中的NIO类库,Java中也称New IO,类库的目标就是要让Java支持非阻塞IO,基于这个原因,更多的人喜欢称Java NIO为非阻塞IO(Non-Block IO), ...

  5. android 仿京东地址选择_Android 开发:仿美团地址选择

    最近做了这个功能,分享一下,用的是百度地图api,和美团外卖的地址选择界面差不多,也就是可以搜索或者滑动地图展示地址列表给用户选择,看下效果图先. 文章重点 展示地图并定位到"我" ...

  6. java cxf服务端_webservice概述及cxf在Java开发中应用(二) 简单搭建cxf服务端

    首先我们下载cxf的jar包,我这里下载的是apache-cxf-3.0.4这个版本,目前最新的. Eclipse里面新建一个Java project,在工程中引入需要的jar: 这些包里面包含了je ...

  7. 【开发一个简单的音乐播放器+服务端】【一】

  8. SpringBoot使用cxf框架开发WebServices以及配置安全验证机制

    SpringBoot使用cxf框架开发WebServices以及配置安全验证机制 服务端工程 服务接口的实现 服务接口实现类 服务发布类 启动服务端 客户端工程 生成客户端代码 编写客户端代码 客户端 ...

  9. 钉钉 6.0 开放底层“协同框架” 开发多人实时协作程序像编本地程序一样简单...

    2021 年新年伊始,钉钉在 1 月 14 日发布了最新 6.0 版本,同时宣布战略定位全面升级,钉钉将从过去基于IM的协同办公平台,升级为企业协同办公和应用开发平台. 从产品和市场表现,钉钉已经杀出 ...

  10. 数据自治开放的软件开发和运行环境

    数据自治开放的软件开发和运行环境 吴毅坚1,2, 陈士壮1,2, 葛佳丽1,2, 赵文耘1,2 1. 复旦大学计算机科学技术学院,上海 201203 2. 上海市数据科学重点实验室,上海 201203 ...

最新文章

  1. 炎热的夏天过去了,老司机用Python带你爬爬哪个城市最热
  2. 雷军做程序员时写的博客,太牛了!
  3. ​多视图立体视觉: CVPR 2019 与 AAAI 2020 上的ACMH、ACMM及ACMP算法介绍
  4. 吉大20春学期C语言程序设计作业二,吉大18春学期《C语言程序设计》在线作业二【答案】...
  5. JavaScript实现递归楼梯问题(动态规划解决方案)算法(附完整源码)
  6. 数据洞察 | Python解读地摊——你想好摆摊去卖什么了吗?
  7. python车牌识别库_Python+Keras+TensorFlow车牌识别
  8. WAP PUSH解析(3)——Android中实现
  9. 永中office属于职称计算机吗,职称计算机考核永中OFFICE辅导之电子表格.doc
  10. 计算机技术 安防 工程师考试,2020年上半年信息安全工程师考试报考指南
  11. ArcCatalog不能预览地图服务
  12. 再现隐私之争_反谷歌FLoC联盟: selenium谷歌浏览器报错: Error with Permissions-Policy header
  13. 矩阵分析L3内积空间
  14. 用vue封装分页器,让你的页面简单而不失优雅
  15. 一文全搞定:应届生offer,三方,劳动合同区别与注意事项
  16. 零基础入门金融风控-贷款违约预测-Task05——模型融合
  17. uniapp自定义搜索组件实现全部功能
  18. 找不到bridge.dll文件
  19. 清华计算机系超算团队,关注 | 清华大学学生超算团队获国际超级计算机竞赛世界大学生超算竞赛总冠军...
  20. 零基础学Flink:Window Watermark

热门文章

  1. linux 安装jdk11
  2. java策略模式实战示例
  3. 【新书推荐】【2018.10】猎人笔记
  4. mysql多级评论表_多级评论的实现思路
  5. 化工——一个走向数字化的成熟行业
  6. Flutter开发之——Placeholder
  7. vscode 调试参数_VSCode调试配置
  8. 电路原理习题(节点电流法,回路电流法)
  9. Js清除Cookie
  10. SDU 2021.1 图形学考试 回忆版