Java开发SDK详解->SDK开发(java注释@)
生活随笔
收集整理的這篇文章主要介紹了
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>> 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开发(java注释@)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: SAP Spartacus Unit L
- 下一篇: java ftl_.ftl文件 是什么文