仿京东平台框架开发开放平台(包含需求,服务端代码,SDK代码)

发布时间:2023-07-05 08:00

目录
  • 1开放平台需求
    • 1.1调用参数
    • 1.2签名算法
  • 2服务端代码,Java举例
    • 2.1接口入口代码
    • 2.2业务逻辑层
    • 2.3基础工具类
  • 3.SDK代码,Java举例
    • 4.集成SDK,代码举例
      • 5.总结

        1开放平台需求

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

        1.1调用参数

        参数名称

        参数类型

        是否必传

        参数描述

        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 {
            @Resource
            private RouterService routerService;
            @Resource
            private OpenApiLogService openApiLogService;
            /**
             * API接口路由器,接口入口
             *
             * @param request
             * @param zrsc_param_json
             * @return
             */
            @RequestMapping(value = \"routerjson\", method = RequestMethod.POST)
            @ResponseBody
            public 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 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 jsonToPojo(String jsonData, Class 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 execute(ZrscRequest request) throws ZrscException {
                try {
                    String url = this.buildUrl(request);
                    Map 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  String buildUrl(ZrscRequest request) throws Exception {
                Map sysParams = request.getSysParams();
                Map 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 parse(String rsp, Class 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 pmap, String appSecret) throws Exception {
                StringBuilder sb = new StringBuilder(appSecret);
                Iterator i$ = pmap.entrySet().iterator();
                while(i$.hasNext()) {
                    Map.Entry 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 params, String charset) throws Exception {
                if (params != null && !params.isEmpty()) {
                    StringBuilder query = new StringBuilder();
                    Set> entries = params.entrySet();
                    boolean hasParam = false;
                    Iterator i$ = entries.iterator();
                    while(i$.hasNext()) {
                        Entry 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 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 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,代码举例

            @Test
            void 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\":\"阿胶街东首路北\"}

        5.总结

        京东开放平台中的传参和签名算法比较有代表性,此博客,只是分享开放平台开放的主要组成部分,希望大家可以多多关注脚本之家的其他内容!

        ItVuer - 免责声明 - 关于我们 - 联系我们

        本网站信息来源于互联网,如有侵权请联系:561261067@qq.com

        桂ICP备16001015号