Java开发SDK详解->SDK开发java注释@

一、前言

  • 前面已经将服务端开发好了(服务端开发),现在我们来开发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>> queryUserListApiRequest<SysUserDTO> request) { 

try { 

String str = postrequest);
return JSON.parseObjectstr, new TypeReference<BaseResponse<PageModel<SysUser>>>) { 

});
} catch Exception e) { 

log.error"SysUserClient queryUserList is exception! request={}", request);
return BaseResponse.errorReturnCodeEnum.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 postApiRequest request) { 

HopeRequest hopeRequest = HopeRequest.builder)
.appIdrequest.getAppId))
.dataRsaUtil.encryptrequest.getPublicKey), JSON.toJSONStringrequest.getData))))
.build);
String s = HttpUtil.doPostrequest.getUrl), JSON.toJSONStringhopeRequest));
if StringUtils.isBlanks)) { 

log.error"client post api result is null!");
throw new HopeExceptionReturnCodeEnum.API_ERROR);
}
HopeResponse hopeResponse = JSON.parseObjects, HopeResponse.class);
if !hopeResponse.isSuccess)) { 

log.error"client post api error! hopeResponse={}", hopeResponse);
throw new HopeExceptionReturnCodeEnum.API_ERROR.getCode), hopeResponse.getMessage));
}
return RsaUtil.decryptrequest.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 doPostString 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 URLhttpUrl);
//创建连接
connection = HttpURLConnection) url.openConnection);
//设置请求方法
connection.setRequestMethod"POST");
//设置连接超时时间
connection.setConnectTimeout15000);
//设置读取超时时间
connection.setReadTimeout15000);
//DoOutput设置是否向httpUrlConnection输出,DoInput设置是否从httpUrlConnection读入,此外发送post请求必须设置这两个
//设置是否可读取
connection.setDoOutputtrue);
connection.setDoInputtrue);
//设置通用的请求属性
connection.setRequestProperty"Content-Type", "application/json;charset=utf-8");
connection.setRequestProperty"connection", "Keep-Alive");
//拼装参数
if null != param && !param.equals"")) { 

//设置参数
os = connection.getOutputStream);
//拼装参数
os.writeparam.getBytes"UTF-8"));
}
//开启连接
connection.connect);
//读取响应
if connection.getResponseCode) == 200) { 

is = connection.getInputStream);
if null != is) { 

br = new BufferedReadernew InputStreamReaderis, "UTF-8"));
String temp = null;
while null != temp = br.readLine))) { 

result.appendtemp);
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 encryptString publicKeyString, String text) { 

try { 

PublicKey publicKey = getPublicKeypublicKeyString);
return encryptRSApublicKey, 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 decryptString publicKeyString, String text) { 

try { 

PublicKey publicKey = getPublicKeypublicKeyString);
return decryptRSApublicKey, 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 encryptRSAKey key, String text) throws Exception { 

// 创建加密对象
Cipher cipher = Cipher.getInstanceALGORITHM);
// 对加密进行初始化 第一个参数是加密模式,第二个参数是你想用的公钥加密还是私钥加密
cipher.initCipher.ENCRYPT_MODE, key);
// 分段加密
byte[] make = doCrypttext.getBytes), cipher, MAX_ENCRYPT_BLOCK);
return Base64.encodemake);
}
/** * RSA 解密 * * @param key 密钥 * @param text 密文 * @return 明文 * @throws Exception 异常 */
private static String decryptRSAKey key, String text) throws Exception { 

// 创建加解密对象
Cipher cipher = Cipher.getInstanceALGORITHM);
// 对解密进行初始化 第一个参数是加密模式,第二个参数是你想用的公钥解密还是私钥解密
cipher.initCipher.DECRYPT_MODE, key);
//分段解密
byte[] make = doCryptBase64.decodetext), cipher, MAX_DECRYPT_BLOCK);
return new Stringmake);
}
/** * 分段加解密 * * @param data 要加解密的内容数组 * @param cipher 加解密对象 * @param maxBlock 分段大小 * @return 结果 * @throws IllegalBlockSizeException 异常 * @throws BadPaddingException 异常 */
private static byte[] doCryptbyte[] 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.doFinaldata, offSet, maxBlock);
offSet += maxBlock;
} else { 

cache = cipher.doFinaldata, offSet, inputLength - offSet);
offSet = inputLength;
}
resultBytes = Arrays.copyOfresultBytes, resultBytes.length + cache.length);
System.arraycopycache, 0, resultBytes, resultBytes.length - cache.length, cache.length);
}
return resultBytes;
}
/** * 获取私钥 * * @param privateKeyString 私钥路径 * @return 私钥 */
private static PrivateKey getPrivateKeyString privateKeyString) throws Exception { 

// 创建key的工厂
KeyFactory keyFactory = KeyFactory.getInstanceALGORITHM);
// 创建私钥key的规则
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpecBase64.decodeprivateKeyString));
// 返回私钥对象
return keyFactory.generatePrivatekeySpec);
}
/** * 获取公钥 * * @param publicKeyString 公钥 * @return 公钥 * @throws Exception 异常 */
private static PublicKey getPublicKeyString publicKeyString) throws Exception { 

// 创建key的工厂
KeyFactory keyFactory = KeyFactory.getInstanceALGORITHM);
// 创建公钥key的规则
X509EncodedKeySpec keySpec = new X509EncodedKeySpecBase64.decodepublicKeyString));
// 返回公钥对象
return keyFactory.generatePublickeySpec);
}
}
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 mainString[] args) { 

SysUserDTO dto = new SysUserDTO);
dto.setStatus0);
ApiRequest<SysUserDTO> request = ApiRequest.<SysUserDTO>builder)
.appId"000001")
.url"http://localhost:8081/api/user/queryUserList")
.publicKeyPUBLIC_KEY_STRING)
.datadto)
.build);
BaseResponse<PageModel<SysUser>> pageModelBaseResponse = SysUserClient.queryUserListrequest);
System.out.printlnJSON.toJSONStringpageModelBaseResponse));
}
}
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测试了。

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

Published by

风君子

独自遨游何稽首 揭天掀地慰生平

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注