这里写目录标题

  • 一、前言
  • 二、详情
    • 2.1 创建项目
    • 2.2 开发代码
      • 2.2.1 pom文件
      • 2.2.2 SysUserClient
      • 2.2.3 ClientAbstract
      • 2.2.4 HttpUtil
      • 2.2.5 RsaUtil
      • 2.2.5 App
      • 2.2.6 HopeRequest
      • 2.2.6 HopeResponse
      • 2.2.7 ApiRequest
    • 2.3 打包
      • 2.3.1 设置
      • 2.3.2 构建
  • 三、最后

一、前言

  • 前面已经将服务端开发好了(服务端开发),现在我们来开发SDK吧。

二、详情

2.1 创建项目

  • 创建一个普通的maven项目 maven----》jdk选择1.8-----》next
  • 输入groupId和artifactId
  • 输入项目名称,和项目存放位置

2.2 开发代码

先看看项目的整体结构

2.2.1 pom文件

依赖的jar包

<dependencies><!--json相关--><dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>1.2.32</version></dependency><!-- 添加slf4j日志api --><dependency><groupId>org.slf4j</groupId><artifactId>slf4j-api</artifactId><version>1.7.20</version></dependency><!-- 添加logback-classic依赖 --><dependency><groupId>ch.qos.logback</groupId><artifactId>logback-classic</artifactId><version>1.2.3</version></dependency><!-- 添加logback-core依赖 --><dependency><groupId>ch.qos.logback</groupId><artifactId>logback-core</artifactId><version>1.2.3</version></dependency><!--lombok支持--><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.16.16</version></dependency><!--工具类--><dependency><groupId>org.apache.commons</groupId><artifactId>commons-lang3</artifactId><version>3.4</version></dependency>
</dependencies>
2.2.2 SysUserClient

用户查询的客户端,继承ClientAbstract 类

package com.lh.hope.client;import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import com.lh.hope.common.ReturnCodeEnum;
import com.lh.hope.domain.SysUser;
import com.lh.hope.domain.SysUserDTO;
import com.lh.hope.domain.common.ApiRequest;
import com.lh.hope.domain.common.BaseResponse;
import com.lh.hope.domain.common.PageModel;
import lombok.extern.slf4j.Slf4j;@Slf4j
public class SysUserClient extends ClientAbstract {public static BaseResponse<PageModel<SysUser>> queryUserList(ApiRequest<SysUserDTO> request) {try {String str = post(request);return JSON.parseObject(str, new TypeReference<BaseResponse<PageModel<SysUser>>>() {});} catch (Exception e) {log.error("SysUserClient queryUserList is exception! request={}", request);return BaseResponse.error(ReturnCodeEnum.SYSTEM_ERROR);}}
}
2.2.3 ClientAbstract

提供了入参加密,返回解密的功能,http请求。这里也可以添加参数校验的功能,这里省略。

package com.lh.hope.client;import com.alibaba.fastjson.JSON;
import com.lh.hope.common.HopeException;
import com.lh.hope.common.ReturnCodeEnum;
import com.lh.hope.domain.common.ApiRequest;
import com.lh.hope.domain.common.HopeRequest;
import com.lh.hope.domain.common.HopeResponse;
import com.lh.hope.utils.HttpUtil;
import com.lh.hope.utils.RsaUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;@Slf4j
class ClientAbstract {static String post(ApiRequest request) {HopeRequest hopeRequest = HopeRequest.builder().appId(request.getAppId()).data(RsaUtil.encrypt(request.getPublicKey(), JSON.toJSONString(request.getData()))).build();String s = HttpUtil.doPost(request.getUrl(), JSON.toJSONString(hopeRequest));if (StringUtils.isBlank(s)) {log.error("client post api result is null!");throw new HopeException(ReturnCodeEnum.API_ERROR);}HopeResponse hopeResponse = JSON.parseObject(s, HopeResponse.class);if (!hopeResponse.isSuccess()) {log.error("client post api error! hopeResponse={}", hopeResponse);throw new HopeException(ReturnCodeEnum.API_ERROR.getCode(), hopeResponse.getMessage());}return RsaUtil.decrypt(request.getPublicKey(), hopeResponse.getData());}
}
2.2.4 HttpUtil

Http请求的工具类,这里简单写一个psot请求的方法。参数传递方法为application/json。

package com.lh.hope.utils;import lombok.extern.slf4j.Slf4j;import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;@Slf4j
public class HttpUtil {/*** Http post请求** @param httpUrl 连接* @param param   参数* @return*/public static String doPost(String httpUrl, String param) {log.info(" HttpUtil doPost begin! httpUrl={} param={}", httpUrl, param);StringBuilder result = new StringBuilder();//连接HttpURLConnection connection = null;OutputStream os = null;InputStream is = null;BufferedReader br = null;try {//创建连接对象URL url = new URL(httpUrl);//创建连接connection = (HttpURLConnection) url.openConnection();//设置请求方法connection.setRequestMethod("POST");//设置连接超时时间connection.setConnectTimeout(15000);//设置读取超时时间connection.setReadTimeout(15000);//DoOutput设置是否向httpUrlConnection输出,DoInput设置是否从httpUrlConnection读入,此外发送post请求必须设置这两个//设置是否可读取connection.setDoOutput(true);connection.setDoInput(true);//设置通用的请求属性connection.setRequestProperty("Content-Type", "application/json;charset=utf-8");connection.setRequestProperty("connection", "Keep-Alive");//拼装参数if (null != param && !param.equals("")) {//设置参数os = connection.getOutputStream();//拼装参数os.write(param.getBytes("UTF-8"));}//开启连接connection.connect();//读取响应if (connection.getResponseCode() == 200) {is = connection.getInputStream();if (null != is) {br = new BufferedReader(new InputStreamReader(is, "UTF-8"));String temp = null;while (null != (temp = br.readLine())) {result.append(temp);result.append("\r\n");}}}} catch (Exception e) {e.printStackTrace();log.error("HttpUtil doPost exception! httpUrl={} param={}", httpUrl, param, e);} finally {//关闭连接if (br != null) {try {br.close();} catch (IOException e) {e.printStackTrace();}}if (os != null) {try {os.close();} catch (IOException e) {e.printStackTrace();}}if (is != null) {try {is.close();} catch (IOException e) {e.printStackTrace();}}//关闭连接if (connection != null) {connection.disconnect();}}log.info(" HttpUtil doPost end! result={}", result);return result.toString();}}
2.2.5 RsaUtil

RSA加解密的工具类

package com.lh.hope.utils;import com.sun.org.apache.xerces.internal.impl.dv.util.Base64;
import lombok.extern.slf4j.Slf4j;import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import java.security.Key;
import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Arrays;@Slf4j
public class RsaUtil {/*** 算法加解密算法*/private static final String ALGORITHM = "RSA";/*** 最大加密字节数,超出最大字节数需要分组加密*/private static final Integer MAX_ENCRYPT_BLOCK = 117;private static final Integer MAX_DECRYPT_BLOCK = 128;/*** 请求报文公钥解密** @param publicKeyString 公钥* @param text            报文* @return 加密报文*/public static String encrypt(String publicKeyString, String text) {try {PublicKey publicKey = getPublicKey(publicKeyString);return encryptRSA(publicKey, text);} catch (Exception e) {e.printStackTrace();log.error("RsaUtil encrypt exception! publicKeyString={} text={}", publicKeyString, text);return null;}}/*** 应答报文公钥解密** @param publicKeyString 公钥* @param text            应答密文* @return 解密报文*/public static String decrypt(String publicKeyString, String text) {try {PublicKey publicKey = getPublicKey(publicKeyString);return decryptRSA(publicKey, text);} catch (Exception e) {e.printStackTrace();log.error("RsaUtil decrypt exception! publicKeyString={} text={}", publicKeyString, text);return null;}}/*** RSA 加密** @param key  密钥* @param text 原文* @return 密文* @throws Exception 异常*/private static String encryptRSA(Key key, String text) throws Exception {// 创建加密对象Cipher cipher = Cipher.getInstance(ALGORITHM);// 对加密进行初始化 第一个参数是加密模式,第二个参数是你想用的公钥加密还是私钥加密cipher.init(Cipher.ENCRYPT_MODE, key);// 分段加密byte[] make = doCrypt(text.getBytes(), cipher, MAX_ENCRYPT_BLOCK);return Base64.encode(make);}/*** RSA 解密** @param key  密钥* @param text 密文* @return 明文* @throws Exception 异常*/private static String decryptRSA(Key key, String text) throws Exception {// 创建加解密对象Cipher cipher = Cipher.getInstance(ALGORITHM);// 对解密进行初始化 第一个参数是加密模式,第二个参数是你想用的公钥解密还是私钥解密cipher.init(Cipher.DECRYPT_MODE, key);//分段解密byte[] make = doCrypt(Base64.decode(text), cipher, MAX_DECRYPT_BLOCK);return new String(make);}/*** 分段加解密** @param data     要加解密的内容数组* @param cipher   加解密对象* @param maxBlock 分段大小* @return 结果* @throws IllegalBlockSizeException 异常* @throws BadPaddingException       异常*/private static byte[] doCrypt(byte[] data, Cipher cipher, Integer maxBlock) throws IllegalBlockSizeException, BadPaddingException {int inputLength = data.length;// 标识int offSet = 0;byte[] resultBytes = {};byte[] cache;while (inputLength - offSet > 0) {if (inputLength - offSet > maxBlock) {cache = cipher.doFinal(data, offSet, maxBlock);offSet += maxBlock;} else {cache = cipher.doFinal(data, offSet, inputLength - offSet);offSet = inputLength;}resultBytes = Arrays.copyOf(resultBytes, resultBytes.length + cache.length);System.arraycopy(cache, 0, resultBytes, resultBytes.length - cache.length, cache.length);}return resultBytes;}/*** 获取私钥** @param privateKeyString 私钥路径* @return 私钥*/private static PrivateKey getPrivateKey(String privateKeyString) throws Exception {// 创建key的工厂KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM);// 创建私钥key的规则PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(Base64.decode(privateKeyString));// 返回私钥对象return keyFactory.generatePrivate(keySpec);}/*** 获取公钥** @param publicKeyString 公钥* @return 公钥* @throws Exception 异常*/private static PublicKey getPublicKey(String publicKeyString) throws Exception {// 创建key的工厂KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM);// 创建公钥key的规则X509EncodedKeySpec keySpec = new X509EncodedKeySpec(Base64.decode(publicKeyString));// 返回公钥对象return keyFactory.generatePublic(keySpec);}
}
2.2.5 App

测试类

package com.lh.hope;import com.alibaba.fastjson.JSON;
import com.lh.hope.client.SysUserClient;
import com.lh.hope.domain.SysUser;
import com.lh.hope.domain.SysUserDTO;
import com.lh.hope.domain.common.ApiRequest;
import com.lh.hope.domain.common.BaseResponse;
import com.lh.hope.domain.common.PageModel;public class App {/*** 公钥*/private static final String PUBLIC_KEY_STRING = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCllRJyNyA5/kOKpF+VV322IN7fownz5GMltjnWLHJPE+xdusVYHz/3C0ck27sv7mHP0TrJ7PLxUHyeUJ9PGOZ2fyrBRikKNE4ce1ihNgQxorIJ68G+70eHyOr65mQxRYa4lUOHMMPHgicN/2vGCjwL/ET8eQU0yIRAoOnO8avAuQIDAQAB";public static void main(String[] args) {SysUserDTO dto = new SysUserDTO();dto.setStatus(0);ApiRequest<SysUserDTO> request = ApiRequest.<SysUserDTO>builder().appId("000001").url("http://localhost:8081/api/user/queryUserList").publicKey(PUBLIC_KEY_STRING).data(dto).build();BaseResponse<PageModel<SysUser>> pageModelBaseResponse = SysUserClient.queryUserList(request);System.out.println(JSON.toJSONString(pageModelBaseResponse));}}
2.2.6 HopeRequest

这个是接口的入参,这里简单演示,一个客户端唯一编号(用来获取对应的私钥),一个是加密的入参。

package com.lh.entity.api;import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class HopeRequest {/*** 客户端唯一编号*/private String appId;/*** 加密后业务相关的入参*/private String data;
}
2.2.6 HopeResponse
package com.lh.entity.api;import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class HopeResponse {/*** 是否成功*/private boolean success;/*** 返回信息*/private String message;/*** 业务相关的返回信息,私钥加密之后的*/private String data;}
2.2.7 ApiRequest

这个类是创建入参是用的,有客户端唯一Id(appId),请求的接口地址,公钥还有业务相关的入参。

package com.lh.hope.domain.common;import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class ApiRequest<T> {private String url;private String publicKey;private String appId;private T data;}

2.3 打包

2.3.1 设置

File ——》 Project Structure ——》 Project Settings ——》 Artifacts ——》 右栏左上角+ ——》JAR ——》 From Modules with dependencies——》OK

直接确定无需指定主类

不用更改 点击apply

2.3.2 构建

Build ——》 Build Artifacts

  • Build(第一次构建)
  • Rebuild(重新构建,会先自定清理上次构建jar包)
  • Clean(清理构建好的jar包)

    jar生成在out文件夹下

三、最后

现在一个简单的SDK已经开发打包好了,服务端之前也已经开发并启动了,现在就剩下最后一步客户端引用SDK测试了。

  • 上一篇服务端开发
  • 下一篇客户端测试

Java开发SDK详解->SDK开发相关推荐

  1. solidworks api二次开发实例详解_Solidworks开发语言对比及分析

    很多初学Solidworks二次开发的同学,也许都会纠结使用何种语言进行二次开发.对于Solidworks二次开发的语言,官方有VBA,VB.NET,C#以及C++,四种语言. 用户通常会有如下疑问, ...

  2. java 开发模式详解_Java开发中的23种设计模式详解4

    其实每个设计模式都是很重要的一种思想,看上去很熟,其实是因为我们在学到的东西中都有涉及,尽管有时我们并不知道,其实在Java本身的设计之中处处都有体现,像AWT.JDBC.集合类.IO管道或者是Web ...

  3. Android NFC开发实战详解

    Android NFC开发实战详解 Android开发实战详解NFC国内第一本AndroidNFC开发书籍带你开启AndroidNFC开发的神秘之旅大综合案例帮助读者快速进入实战角色:WiFi快速连接 ...

  4. STM32开发 -- 串口详解

    如需转载请注明出处:https://blog.csdn.net/qq_29350001/article/details/80708964 讲完GPIO,接下来看一下串口. 串口通信,已经讲了很多次了. ...

  5. Android高效率编码-第三方SDK详解系列(二)——Bmob后端云开发,实现登录注册,更改资料,修改密码,邮箱验证,上传,下载,推送消息,缩略图加载等功能

    Android高效率编码-第三方SDK详解系列(二)--Bmob后端云开发,实现登录注册,更改资料,修改密码,邮箱验证,上传,下载,推送消息,缩略图加载等功能 我的本意是第二篇写Mob的shareSD ...

  6. 《Java和Android开发实战详解》——1.2节Java基础知识

    本节书摘来自异步社区<Java和Android开发实战详解>一书中的第1章,第1.2节Java基础知识,作者 陈会安,更多章节内容可以访问云栖社区"异步社区"公众号查看 ...

  7. java基础(十三)-----详解内部类——Java高级开发必须懂的

    java基础(十三)-----详解内部类--Java高级开发必须懂的 目录 为什么要使用内部类 内部类基础 静态内部类 成员内部类 成员内部类的对象创建 继承成员内部类 局部内部类 推荐博客 匿名内部 ...

  8. 《Java和Android开发实战详解》——2.5节良好的Java程序代码编写风格

    本节书摘来自异步社区<Java和Android开发实战详解>一书中的第2章,第2.5节良好的Java程序代码编写风格,作者 陈会安,更多章节内容可以访问云栖社区"异步社区&quo ...

  9. java注解式开发_JAVA语言之Spring MVC注解式开发使用详解[Java代码]

    本文主要向大家介绍了JAVA语言的Spring MVC注解式开发使用详解,通过具体的内容向大家展示,希望对大家学习JAVA语言有所帮助. MVC注解式开发即处理器基于注解的类开发, 对于每一个定义的处 ...

  10. 《Java和Android开发实战详解》——2.2节构建Java应用程序

    本节书摘来自异步社区<Java和Android开发实战详解>一书中的第2章,第2.2节构建Java应用程序,作者 陈会安,更多章节内容可以访问云栖社区"异步社区"公众号 ...

最新文章

  1. linux nfs 进程,【Linux】 nfs 故障处理
  2. Office365邮箱Imap迁移步骤
  3. 电子地图开发中栅格模型与矢量模型的区别
  4. php中的parse_ini_file函数
  5. 对Spring事务一些问题的讨论
  6. [css] 如何自定义radio按钮的样式
  7. mac iterm2 安装 lrzsz rz sz命令
  8. 简介如何查看执行计划以及执行计划的准确性
  9. apache服务器进程配置文件是,apache服务器进程配置文件是
  10. 混沌实践访谈:混沌工程和系统可观测性密不可分
  11. jiangdongsheng
  12. 计算机视觉之--使用opencv生成简笔画小视频
  13. sql字段转换字符串——CONVERT (VARCHAR(50),字段)
  14. Perl中use strict
  15. [转帖]实时协同设计CAD平台
  16. 怎么画因果图?因果图绘图步骤详解
  17. SQL Server AlwaysON从入门到进阶(3)——基础架构
  18. arndale octa开发板编译u-boot和kernel
  19. 文件存档、加密和解密
  20. 回顾“90后”——MISRA的25年岁月

热门文章

  1. 华为HCIP-DATACOM题库解析51-70(821)
  2. php 变声,视频后期配音变声 有什么方法可以给视频配音进行变声处理
  3. JVM笔记——根据黑马jvm课程课件+自己总结
  4. 一文看懂机器人使用的惯性测量/IMU中常见的名词:陀螺仪/ 加速度计/ 磁力计/MEMS/ IMU/ AHRS/ 6轴(6DOF) /9轴(9DOF)/ 欧拉角/四元数
  5. 如何修复u盘损坏的文件?
  6. Wappalyzer 是一个Firefox插件,也是一个网站
  7. 解决win7打印机共享 出现“无法保存打印机设置,操作无法完成(错误0x000006d9)...
  8. Spring Hibernate sqlquery 查询结果 缓存问题
  9. (0)FPGA自学之路-笔记0
  10. 数据挖掘 代码整理(1)