当前位置:   article > 正文

Java开发SDK详解_java sdk

java sdk

一、服务端开发

1、前言

1)最近在对接外部平台的接口,对方提供了一个sdk,开发中直接引入到项目中。自己只需要组装参数,直接调用sdk中的方法就可以实现接口对接。
2)sdk中包含了参数校验,加密验签,Http接口调用,还提供了各个接口入参和出参的实体类。 这些为我们减少很多的开发量,同时将一些不合规的入参直接在客户端过滤掉,减少资源浪费。还提供了一套完整的加密验签方法,避免了双发对接中因为加解密验签方法的不同导致的一些问题。很大程度上提高了我们的对接中开发联调的成本。
3)sdk优点这么多,下面我们来开发一个简单的sdk吧。

2、步骤概述

1)首先我们开发一下服务端: 服务端是一个SpringBoot项目提供了一个用户列表查询的接口。入参包含调用方分唯一编号(appId),加密的入参信息(data),入参的加解密方式使用RSA非对称加密算法

2)其次开发SDK: SDK是一个普通的maven项目,提供用户列表查询接口的Http调用方法,还有接口的参数校验,入参的加密,返回信息的解密。最后将项目打成jar包。

3)最后开发客户端调试: 客户端是一个SpringBoot项目,项目中引入上面打包好的SDK,组装参数,调用用户列表查询接口。

3、服务端开发

3.1代码实现

3.1.1 服务端入口(SysUserApiController)

这个类是接收客户端请求的入口,继承了ApiAbstract

  1. package com.zkaw.api;
  2. /**
  3. * @Author: best_liu
  4. * @Description:
  5. * @Date Create in 10:00 2023/5/19
  6. * @Modified By:
  7. */
  8. import com.alibaba.fastjson.JSONObject;
  9. import com.zkaw.service.IUserService;
  10. import org.springframework.beans.factory.annotation.Autowired;
  11. import org.springframework.web.bind.annotation.PostMapping;
  12. import org.springframework.web.bind.annotation.RequestBody;
  13. import org.springframework.web.bind.annotation.RequestMapping;
  14. import org.springframework.web.bind.annotation.RestController;
  15. @RestController
  16. @RequestMapping("/api/user/")
  17. public class SysUserApiController extends ApiAbstract<String> {
  18. @Autowired
  19. private IUserService sysUserService;
  20. @Override
  21. public String work(String type,JSONObject o) {
  22. return sysUserService.invokeApi(type,JSONObject.toJavaObject(o, SysUserDTO.class));
  23. }
  24. @PostMapping("/invokeApi")
  25. public HopeResponse invokeApi(@RequestBody HopeRequest hopeRequest) {
  26. return process(hopeRequest);
  27. }
  28. }

3.1.2 接口的抽象类(ApiAbstract)

这个类提供一些公用的方法,私钥的获取,入参的解密,出参的加密等。

 

  1. package com.zkaw.api;
  2. import com.alibaba.fastjson.JSON;
  3. import com.alibaba.fastjson.JSONObject;
  4. import lombok.extern.slf4j.Slf4j;
  5. import java.util.HashMap;
  6. import java.util.Map;
  7. /**
  8. * @Author: best_liu
  9. * @Description:
  10. * @Date Create in 10:04 2023/5/19
  11. * @Modified By:
  12. */
  13. @Slf4j
  14. public abstract class ApiAbstract<R> {
  15. private static final Map<String, String> PRIVATE_KEY_MAP = new HashMap<>();
  16. static {
  17. PRIVATE_KEY_MAP.put("zkawTest", "MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBALCvyp0epQHwTaU+WPx+Zue2iVR3JcheHZTUEITPHW9anhW8iMkteE3m83Zu2e6V1/LbnaVoNG3GO3i65C6MiBMeJha1PKgYrlvHe5cLzWlWwQ6BxCOCto2m5sLWXd24xJp259qlKypw1F9dMVqJAaCO+2sDTUBbdBL9yJLB6J51AgMBAAECgYBMZseTZ3Pswa+hm7M5A6OV4N3Dc34YBXJ/L7Aw7aqJw0KGna78ZzgVX5+5f7enLo5hysuBgezh5w1CaHZRFp2kBqsYn7z3oGo2Mbs8H6fF1M4r3pRwtt70FgNuTGDm7KLkzHyFHxBmTl15AxujNTTQBxai/rZkUlfVCbHS3+PJpQJBANsY2MxiRLxM2CcWy+AuKLGNx+sT7Z3WfJOKQ09Jay55fsMrIhCKuE/yf4pGVaQuNMsNsRhpiZEE4nbAoZXGtiMCQQDOckUMKy4rEY2i2yI1g8JcaI7lGKA+Ey22Sy2azFSSPpfIW5ZkgCpzKUx241Z6CCNmIw8nhM7SfaYTUoR0+0aHAkEAv/DmjTdRzDzt6GC6Py1xDQuOps0QkARFouOv0Bgbw91ARi7VavR8P93MChFQGcM5EOJv0Vkz4U4ML8jWRmaNTQJAbNaTjmnJak1TxZMPwvTW6A77ns5P1MoZpGyX+29T+tHjBW87p3pmZtZUCK2r7qQRvYwoNiZvP0uc3bz4NhAvSwJBAKjsvDaf/JXdS9wrfHTT/d7DuBOf3WVkiex8pVeStBcd65qHzF+faWw5VJb3Y6IMgtoSt1QMgMuEjlst4bcL6ss=");
  18. }
  19. /**
  20. * 统一处理
  21. *
  22. * @param hopeRequest 统一请求
  23. * @return 统一响应
  24. */
  25. public HopeResponse process(HopeRequest hopeRequest) {
  26. try {
  27. String privateKey = getPrivateKey(hopeRequest.getAppId());
  28. String type = hopeRequest.getType();
  29. JSONObject o = before(hopeRequest.getData(), privateKey);
  30. System.out.println(o);
  31. R r = work(type,o);
  32. return after(r, privateKey);
  33. } catch (Exception e) {
  34. e.printStackTrace();
  35. log.error("ServerAbstract process exception! hopeRequest={}", hopeRequest, e);
  36. return HopeResponse.builder()
  37. .success(false)
  38. .message(e.getCause().toString())
  39. .build();
  40. }
  41. }
  42. /**
  43. * 处理前置解密
  44. *
  45. * @param data 请求密文
  46. * @param privateKey 秘钥
  47. * @return 请求参数
  48. */
  49. private JSONObject before(String data, String privateKey) {
  50. return JSON.parseObject(RsaUtil.decryptPrivate(privateKey, data));
  51. }
  52. /**
  53. * 业务处理
  54. *
  55. * @param o 入参
  56. * @return 返回
  57. */
  58. abstract R work(String type,JSONObject o);
  59. /**
  60. * 后置处理加密
  61. *
  62. * @param r 业务数据
  63. * @param privateKey 秘钥
  64. * @return 统一返回
  65. */
  66. private HopeResponse after(R r, String privateKey) {
  67. return HopeResponse.builder()
  68. .success(true)
  69. .message("访问成功")
  70. .data(RsaUtil.encryptPrivate(privateKey, (String) r))
  71. .build();
  72. }
  73. /**
  74. * 通过appId获取对应的私钥,不同的接入方提供不同的公私钥。
  75. * 实际业务开发中这些会存在文件中或者配置中心中如阿波罗,这里简单实现
  76. *
  77. * @param appId appId
  78. * @return 私钥
  79. */
  80. private String getPrivateKey(String appId) {
  81. return PRIVATE_KEY_MAP.get(appId);
  82. }
  83. }

3.1.3 接口入参实体类(HopeRequest)

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

  1. package com.zkaw.api;
  2. import lombok.AllArgsConstructor;
  3. import lombok.Builder;
  4. import lombok.Data;
  5. import lombok.NoArgsConstructor;
  6. /**
  7. * @Author: best_liu
  8. * @Description:
  9. * @Date Create in 10:04 2023/5/19
  10. * @Modified By:
  11. */
  12. @Data
  13. @Builder
  14. @NoArgsConstructor
  15. @AllArgsConstructor
  16. public class HopeRequest {
  17. /**
  18. * 客户端唯一编号
  19. */
  20. private String appId;
  21. private String type;
  22. /**
  23. * 加密后业务相关的入参
  24. */
  25. private String data;
  26. }

 

3.1.4 接口返回实体类(HopeResponse)

这个是服务端接口的返回信息。返回的字段有成功表示,提示信息,还有业务相关的查询结果(查询到的用户信息)加密的信息。

 

  1. package com.zkaw.api;
  2. import lombok.AllArgsConstructor;
  3. import lombok.Builder;
  4. import lombok.Data;
  5. import lombok.NoArgsConstructor;
  6. /**
  7. * @Author: best_liu
  8. * @Description:
  9. * @Date Create in 10:05 2023/5/19
  10. * @Modified By:
  11. */
  12. @Data
  13. @Builder
  14. @NoArgsConstructor
  15. @AllArgsConstructor
  16. public class HopeResponse {
  17. /**
  18. * 是否成功
  19. */
  20. private boolean success;
  21. /**
  22. * 返回信息
  23. */
  24. private String message;
  25. /**
  26. * 业务相关的返回信息,私钥加密之后的
  27. */
  28. private String data;
  29. }

3.1.5 具体的业务实现层(SysUserService)
这里是具体的业务层,通过入参去数据库查询对应的结果,在封装成实体类返回,这里不再深入。PageMode是用查询的结果封装的分页实体类。BaseResponse是业务层处理的结果有返回码和提示信息。其实这里不用封装这么多层,我这个是用以前的老代码简单的做个示例。

  1. package com.zkaw.service;
  2. import com.baomidou.mybatisplus.core.metadata.IPage;
  3. import com.zkaw.api.SysUser;
  4. import com.zkaw.api.SysUserDTO;
  5. import com.zkaw.pojo.User;
  6. import java.util.List;
  7. /**
  8. * @Author: LiuXingJie
  9. * @Description:
  10. * @Date Create in 11:06 2022/6/29
  11. * @Modified By:
  12. */
  13. public interface IUserService {
  14. int insertSaveBanch(List<User> list);
  15. int insert( User user);
  16. int delete( User user);
  17. IPage<User> selectPage(User user);
  18. int update( User user);
  19. List<User> selectList(User user);
  20. List<SysUser> queryUserList(SysUserDTO dto);
  21. SysUser selectById(String userId);
  22. String invokeApi(String type,SysUserDTO dto);
  23. }

3.1.6 业务相关的入参(SysUserDTO)

这个类是真正传递业务相关查询条件的实体类。PageBase 是一个分页相关的类,参数为pageSize和pageIndex。

 

  1. package com.zkaw.api;
  2. import lombok.Data;
  3. /**
  4. * @Author: best_liu
  5. * @Description:
  6. * @Date Create in 10:05 2023/5/19
  7. * @Modified By:
  8. */
  9. @Data
  10. public class SysUserDTO extends PageBase {
  11. private int id;
  12. /**
  13. * 昵称
  14. */
  15. private String userId;
  16. private String age;
  17. /**
  18. * 用户名称
  19. */
  20. private String userName;
  21. /**
  22. * 用户手机号
  23. */
  24. private String userPhone;
  25. /**
  26. * 用户邮箱
  27. */
  28. private String userEmail;
  29. /**
  30. * 用户状态 0、正常 1、锁定 2、注销
  31. */
  32. private Integer status;
  33. }

3.1.7 RSA加解密的工具类(RsaUtil)

  1. package com.zkaw.api;
  2. import com.sun.org.apache.xerces.internal.impl.dv.util.Base64;
  3. import lombok.extern.slf4j.Slf4j;
  4. import javax.crypto.BadPaddingException;
  5. import javax.crypto.Cipher;
  6. import javax.crypto.IllegalBlockSizeException;
  7. import java.security.*;
  8. import java.security.interfaces.RSAPrivateKey;
  9. import java.security.interfaces.RSAPublicKey;
  10. import java.security.spec.PKCS8EncodedKeySpec;
  11. import java.security.spec.X509EncodedKeySpec;
  12. import java.util.Arrays;
  13. /**
  14. * @Author: best_liu
  15. * @Description:
  16. * @Date Create in 10:07 2023/5/19
  17. * @Modified By:
  18. */
  19. @Slf4j
  20. public class RsaUtil {
  21. /**
  22. * 算法加解密算法
  23. */
  24. private static final String ALGORITHM = "RSA";
  25. /**
  26. * 最大加密字节数,超出最大字节数需要分组加密
  27. */
  28. private static final Integer MAX_ENCRYPT_BLOCK = 117;
  29. /**
  30. * 最大解密字节数,超出最大字节数需要分组解密
  31. */
  32. private static final Integer MAX_DECRYPT_BLOCK = 128;
  33. /**
  34. * RSA密钥长度必须是64的倍数,在512~65536之间。默认是1024
  35. */
  36. public static final int KEY_SIZE = 1024;
  37. /**
  38. * 请求报文公钥解密
  39. *
  40. * @param publicKeyString 公钥
  41. * @param text 报文
  42. * @return 加密报文
  43. */
  44. public static String encryptPublic(String publicKeyString, String text) {
  45. try {
  46. PublicKey publicKey = getPublicKey(publicKeyString);
  47. return encryptRSA(publicKey, text);
  48. } catch (Exception e) {
  49. e.printStackTrace();
  50. log.error("RsaUtil encryptPublic exception! publicKeyString={} text={}", publicKeyString, text);
  51. return null;
  52. }
  53. }
  54. /**
  55. * 应答报文公钥解密
  56. *
  57. * @param publicKeyString 公钥
  58. * @param text 应答密文
  59. * @return 解密报文
  60. */
  61. public static String decryptPublic(String publicKeyString, String text) {
  62. try {
  63. PublicKey publicKey = getPublicKey(publicKeyString);
  64. return decryptRSA(publicKey, text);
  65. } catch (Exception e) {
  66. e.printStackTrace();
  67. log.error("RsaUtil decryptPublic exception! publicKeyString={} text={}", publicKeyString, text);
  68. return null;
  69. }
  70. }
  71. /**
  72. * 请求报文私钥解密
  73. *
  74. * @param privateKeyString 私钥
  75. * @param text 报文
  76. * @return 加密报文
  77. */
  78. public static String encryptPrivate(String privateKeyString, String text) {
  79. try {
  80. PrivateKey privateKey = getPrivateKey(privateKeyString);
  81. return encryptRSA(privateKey, text);
  82. } catch (Exception e) {
  83. e.printStackTrace();
  84. log.error("RsaUtil encryptPrivate exception! publicKeyString={} text={}", privateKeyString, text);
  85. return null;
  86. }
  87. }
  88. /**
  89. * 应答报文私钥解密
  90. *
  91. * @param privateKeyString 私钥
  92. * @param text 应答密文
  93. * @return 解密报文
  94. */
  95. public static String decryptPrivate(String privateKeyString, String text) {
  96. try {
  97. PrivateKey privateKey = getPrivateKey(privateKeyString);
  98. return decryptRSA(privateKey, text);
  99. } catch (Exception e) {
  100. e.printStackTrace();
  101. log.error("RsaUtil decryptPrivate exception! privateKeyString={} text={}", privateKeyString, text);
  102. return null;
  103. }
  104. }
  105. /**
  106. * RSA 加密
  107. *
  108. * @param key 密钥
  109. * @param text 原文
  110. * @return 密文
  111. * @throws Exception 异常
  112. */
  113. private static String encryptRSA(Key key, String text) throws Exception {
  114. // 创建加密对象
  115. Cipher cipher = Cipher.getInstance(ALGORITHM);
  116. // 对加密进行初始化 第一个参数是加密模式,第二个参数是你想用的公钥加密还是私钥加密
  117. cipher.init(Cipher.ENCRYPT_MODE, key);
  118. // 分段加密
  119. byte[] make = doCrypt(text.getBytes(), cipher, MAX_ENCRYPT_BLOCK);
  120. return Base64.encode(make);
  121. }
  122. /**
  123. * RSA 解密
  124. *
  125. * @param key 密钥
  126. * @param text 密文
  127. * @return 明文
  128. * @throws Exception 异常
  129. */
  130. private static String decryptRSA(Key key, String text) throws Exception {
  131. // 创建加解密对象
  132. Cipher cipher = Cipher.getInstance(ALGORITHM);
  133. // 对解密进行初始化 第一个参数是加密模式,第二个参数是你想用的公钥解密还是私钥解密
  134. cipher.init(Cipher.DECRYPT_MODE, key);
  135. //分段解密
  136. byte[] make = doCrypt(Base64.decode(text), cipher, MAX_DECRYPT_BLOCK);
  137. return new String(make);
  138. }
  139. /**
  140. * 分段加解密
  141. *
  142. * @param data 要加解密的内容数组
  143. * @param cipher 加解密对象
  144. * @param maxBlock 分段大小
  145. * @return 结果
  146. * @throws IllegalBlockSizeException 异常
  147. * @throws BadPaddingException 异常
  148. */
  149. private static byte[] doCrypt(byte[] data, Cipher cipher, Integer maxBlock) throws IllegalBlockSizeException, BadPaddingException {
  150. int inputLength = data.length;
  151. // 标识
  152. int offSet = 0;
  153. byte[] resultBytes = {};
  154. byte[] cache;
  155. while (inputLength - offSet > 0) {
  156. if (inputLength - offSet > maxBlock) {
  157. cache = cipher.doFinal(data, offSet, maxBlock);
  158. offSet += maxBlock;
  159. } else {
  160. cache = cipher.doFinal(data, offSet, inputLength - offSet);
  161. offSet = inputLength;
  162. }
  163. resultBytes = Arrays.copyOf(resultBytes, resultBytes.length + cache.length);
  164. System.arraycopy(cache, 0, resultBytes, resultBytes.length - cache.length, cache.length);
  165. }
  166. return resultBytes;
  167. }
  168. /**
  169. * 获取私钥
  170. *
  171. * @param privateKeyString 私钥路径
  172. * @return 私钥
  173. */
  174. private static PrivateKey getPrivateKey(String privateKeyString) throws Exception {
  175. // 创建key的工厂
  176. KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM);
  177. // 创建私钥key的规则
  178. PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(Base64.decode(privateKeyString));
  179. // 返回私钥对象
  180. return keyFactory.generatePrivate(keySpec);
  181. }
  182. /**
  183. * 获取公钥
  184. *
  185. * @param publicKeyString 公钥
  186. * @return 公钥
  187. * @throws Exception 异常
  188. */
  189. private static PublicKey getPublicKey(String publicKeyString) throws Exception {
  190. // 创建key的工厂
  191. KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM);
  192. // 创建公钥key的规则
  193. X509EncodedKeySpec keySpec = new X509EncodedKeySpec(Base64.decode(publicKeyString));
  194. // 返回公钥对象
  195. return keyFactory.generatePublic(keySpec);
  196. }
  197. public static void main(String[] args) throws NoSuchAlgorithmException {
  198. KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
  199. //所以当密钥位数为2048时,最大解密长度应为256.
  200. keyPairGenerator.initialize(KEY_SIZE);
  201. KeyPair keyPair = keyPairGenerator.generateKeyPair();
  202. RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
  203. RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
  204. System.out.println("publicKey="+publicKey);
  205. System.out.println("==============================");
  206. System.out.println("privateKey="+privateKey);
  207. }
  208. }

二、SDK开发

1、前言

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

2、SDK开发

2.1 创建项目

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

创建项目步骤不在这里面说了,相信大家应该都已经会了。

2.2 开发代码

先看看项目的整体结构

 

 

2.2.1 pom文件

依赖的jar包

 

  1. <dependencies>
  2. <!--json相关-->
  3. <dependency>
  4. <groupId>com.alibaba</groupId>
  5. <artifactId>fastjson</artifactId>
  6. <version>1.2.32</version>
  7. </dependency>
  8. <!-- 添加slf4j日志api -->
  9. <dependency>
  10. <groupId>org.slf4j</groupId>
  11. <artifactId>slf4j-api</artifactId>
  12. </dependency>
  13. <dependency>
  14. <groupId>org.projectlombok</groupId>
  15. <artifactId>lombok</artifactId>
  16. </dependency>
  17. <!--工具类-->
  18. <dependency>
  19. <groupId>org.apache.commons</groupId>
  20. <artifactId>commons-lang3</artifactId>
  21. <version>3.4</version>
  22. </dependency>
  23. </dependencies>

2.2.2 SysUserClient

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

 

  1. package com.best.hope.client;
  2. import com.alibaba.fastjson.JSON;
  3. import com.alibaba.fastjson.JSONObject;
  4. import com.alibaba.fastjson.TypeReference;
  5. import com.best.hope.domain.SysUserDTO;
  6. import com.best.hope.domain.common.ApiRequest;
  7. import com.best.hope.domain.common.HopeRequest;
  8. import lombok.extern.slf4j.Slf4j;
  9. /**
  10. * @Author: best_liu
  11. * @Description:
  12. * @Date Create in 10:16 2023/5/19
  13. * @Modified By:
  14. */
  15. @Slf4j
  16. public class SysUserClient extends ClientAbstract {
  17. public static String invokeApi(HopeRequest hopeRequest) {
  18. ApiRequest<SysUserDTO> request = ApiRequest.<SysUserDTO>builder()
  19. .appId(hopeRequest.getAppId())
  20. .type(hopeRequest.getType())
  21. .url("http://localhost:8090/api/user/invokeApi")
  22. .publicKey(hopeRequest.getPublicKey())
  23. .data(JSONObject.parseObject(hopeRequest.getData(),SysUserDTO.class))
  24. .build();
  25. try {
  26. String str = post(request);
  27. return JSON.parseObject(str, new TypeReference<String>() {
  28. });
  29. } catch (Exception e) {
  30. log.error("SysUserClient queryUserList is exception! request={}", request);
  31. return null;
  32. }
  33. }
  34. }

2.2.3 ClientAbstract

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

 

  1. package com.best.hope.client;
  2. import com.alibaba.fastjson.JSON;
  3. import com.alibaba.fastjson.JSONObject;
  4. import com.best.hope.domain.common.ApiRequest;
  5. import com.best.hope.domain.common.HopeRequest;
  6. import com.best.hope.domain.common.HopeResponse;
  7. import com.best.hope.enums.ReturnCodeEnum;
  8. import com.best.hope.exception.HopeException;
  9. import com.best.hope.utils.HttpUtil;
  10. import com.best.hope.utils.RsaUtil;
  11. import lombok.extern.slf4j.Slf4j;
  12. import org.apache.commons.lang3.StringUtils;
  13. /**
  14. * @Author: best_liu
  15. * @Description:
  16. * @Date Create in 10:16 2023/5/19
  17. * @Modified By:
  18. */
  19. @Slf4j
  20. class ClientAbstract {
  21. static String post(ApiRequest request) {
  22. HopeRequest hopeRequest = HopeRequest.builder()
  23. .appId(request.getAppId())
  24. .type(request.getType())
  25. .data(RsaUtil.encrypt(request.getPublicKey(), JSON.toJSONString(request.getData())))
  26. .build();
  27. String s = HttpUtil.doPost(request.getUrl(), JSON.toJSONString(hopeRequest));
  28. if (StringUtils.isBlank(s)) {
  29. log.error("client post api result is null!");
  30. throw new HopeException("400", "请求结果为null");
  31. }
  32. HopeResponse hopeResponse = JSON.parseObject(s, HopeResponse.class);
  33. if (!hopeResponse.isSuccess()) {
  34. log.error("client post api error! hopeResponse={}", hopeResponse);
  35. throw new HopeException("400", hopeResponse.getMessage());
  36. }
  37. hopeResponse.setData(RsaUtil.decrypt(request.getPublicKey(), hopeResponse.getData()));
  38. return JSONObject.toJSONString(hopeResponse);
  39. }
  40. }

2.2.4 HttpUtil

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

 

  1. package com.best.hope.utils;
  2. import lombok.extern.slf4j.Slf4j;
  3. import java.io.*;
  4. import java.net.HttpURLConnection;
  5. import java.net.URL;
  6. /**
  7. * @Author: best_liu
  8. * @Description:
  9. * @Date Create in 10:17 2023/5/19
  10. * @Modified By:
  11. */
  12. @Slf4j
  13. public class HttpUtil {
  14. /**
  15. * Http post请求
  16. *
  17. * @param httpUrl 连接
  18. * @param param 参数
  19. * @return
  20. */
  21. public static String doPost(String httpUrl, String param) {
  22. log.info(" HttpUtil doPost begin! httpUrl={} param={}", httpUrl, param);
  23. StringBuilder result = new StringBuilder();
  24. //连接
  25. HttpURLConnection connection = null;
  26. OutputStream os = null;
  27. InputStream is = null;
  28. BufferedReader br = null;
  29. try {
  30. //创建连接对象
  31. URL url = new URL(httpUrl);
  32. //创建连接
  33. connection = (HttpURLConnection) url.openConnection();
  34. //设置请求方法
  35. connection.setRequestMethod("POST");
  36. //设置连接超时时间
  37. connection.setConnectTimeout(15000);
  38. //设置读取超时时间
  39. connection.setReadTimeout(15000);
  40. //DoOutput设置是否向httpUrlConnection输出,DoInput设置是否从httpUrlConnection读入,此外发送post请求必须设置这两个
  41. //设置是否可读取
  42. connection.setDoOutput(true);
  43. connection.setDoInput(true);
  44. //设置通用的请求属性
  45. connection.setRequestProperty("Content-Type", "application/json;charset=utf-8");
  46. connection.setRequestProperty("connection", "Keep-Alive");
  47. //拼装参数
  48. if (null != param && !param.equals("")) {
  49. //设置参数
  50. os = connection.getOutputStream();
  51. //拼装参数
  52. os.write(param.getBytes("UTF-8"));
  53. }
  54. //开启连接
  55. connection.connect();
  56. //读取响应
  57. if (connection.getResponseCode() == 200) {
  58. is = connection.getInputStream();
  59. if (null != is) {
  60. br = new BufferedReader(new InputStreamReader(is, "UTF-8"));
  61. String temp = null;
  62. while (null != (temp = br.readLine())) {
  63. result.append(temp);
  64. result.append("\r\n");
  65. }
  66. }
  67. }
  68. } catch (Exception e) {
  69. e.printStackTrace();
  70. log.error("HttpUtil doPost exception! httpUrl={} param={}", httpUrl, param, e);
  71. } finally {
  72. //关闭连接
  73. if (br != null) {
  74. try {
  75. br.close();
  76. } catch (IOException e) {
  77. e.printStackTrace();
  78. }
  79. }
  80. if (os != null) {
  81. try {
  82. os.close();
  83. } catch (IOException e) {
  84. e.printStackTrace();
  85. }
  86. }
  87. if (is != null) {
  88. try {
  89. is.close();
  90. } catch (IOException e) {
  91. e.printStackTrace();
  92. }
  93. }
  94. //关闭连接
  95. if (connection != null) {
  96. connection.disconnect();
  97. }
  98. }
  99. log.info(" HttpUtil doPost end! result={}", result);
  100. return result.toString();
  101. }
  102. }

2.2.5 RsaUtil

RSA加解密的工具类

  1. package com.best.hope.utils;
  2. import com.sun.org.apache.xerces.internal.impl.dv.util.Base64;
  3. import lombok.extern.slf4j.Slf4j;
  4. import javax.crypto.BadPaddingException;
  5. import javax.crypto.Cipher;
  6. import javax.crypto.IllegalBlockSizeException;
  7. import java.security.Key;
  8. import java.security.KeyFactory;
  9. import java.security.PrivateKey;
  10. import java.security.PublicKey;
  11. import java.security.spec.PKCS8EncodedKeySpec;
  12. import java.security.spec.X509EncodedKeySpec;
  13. import java.util.Arrays;
  14. /**
  15. * @Author: best_liu
  16. * @Description:
  17. * @Date Create in 10:18 2023/5/19
  18. * @Modified By:
  19. */
  20. @Slf4j
  21. public class RsaUtil {
  22. /**
  23. * 算法加解密算法
  24. */
  25. private static final String ALGORITHM = "RSA";
  26. /**
  27. * 最大加密字节数,超出最大字节数需要分组加密
  28. */
  29. private static final Integer MAX_ENCRYPT_BLOCK = 117;
  30. private static final Integer MAX_DECRYPT_BLOCK = 128;
  31. /**
  32. * 请求报文公钥解密
  33. *
  34. * @param publicKeyString 公钥
  35. * @param text 报文
  36. * @return 加密报文
  37. */
  38. public static String encrypt(String publicKeyString, String text) {
  39. try {
  40. PublicKey publicKey = getPublicKey(publicKeyString);
  41. return encryptRSA(publicKey, text);
  42. } catch (Exception e) {
  43. e.printStackTrace();
  44. log.error("RsaUtil encrypt exception! publicKeyString={} text={}", publicKeyString, text);
  45. return null;
  46. }
  47. }
  48. /**
  49. * 应答报文公钥解密
  50. *
  51. * @param publicKeyString 公钥
  52. * @param text 应答密文
  53. * @return 解密报文
  54. */
  55. public static String decrypt(String publicKeyString, String text) {
  56. try {
  57. PublicKey publicKey = getPublicKey(publicKeyString);
  58. return decryptRSA(publicKey, text);
  59. } catch (Exception e) {
  60. e.printStackTrace();
  61. log.error("RsaUtil decrypt exception! publicKeyString={} text={}", publicKeyString, text);
  62. return null;
  63. }
  64. }
  65. /**
  66. * RSA 加密
  67. *
  68. * @param key 密钥
  69. * @param text 原文
  70. * @return 密文
  71. * @throws Exception 异常
  72. */
  73. private static String encryptRSA(Key key, String text) throws Exception {
  74. // 创建加密对象
  75. Cipher cipher = Cipher.getInstance(ALGORITHM);
  76. // 对加密进行初始化 第一个参数是加密模式,第二个参数是你想用的公钥加密还是私钥加密
  77. cipher.init(Cipher.ENCRYPT_MODE, key);
  78. // 分段加密
  79. byte[] make = doCrypt(text.getBytes(), cipher, MAX_ENCRYPT_BLOCK);
  80. return Base64.encode(make);
  81. }
  82. /**
  83. * RSA 解密
  84. *
  85. * @param key 密钥
  86. * @param text 密文
  87. * @return 明文
  88. * @throws Exception 异常
  89. */
  90. private static String decryptRSA(Key key, String text) throws Exception {
  91. // 创建加解密对象
  92. Cipher cipher = Cipher.getInstance(ALGORITHM);
  93. // 对解密进行初始化 第一个参数是加密模式,第二个参数是你想用的公钥解密还是私钥解密
  94. cipher.init(Cipher.DECRYPT_MODE, key);
  95. //分段解密
  96. byte[] make = doCrypt(Base64.decode(text), cipher, MAX_DECRYPT_BLOCK);
  97. return new String(make);
  98. }
  99. /**
  100. * 分段加解密
  101. *
  102. * @param data 要加解密的内容数组
  103. * @param cipher 加解密对象
  104. * @param maxBlock 分段大小
  105. * @return 结果
  106. * @throws IllegalBlockSizeException 异常
  107. * @throws BadPaddingException 异常
  108. */
  109. private static byte[] doCrypt(byte[] data, Cipher cipher, Integer maxBlock) throws IllegalBlockSizeException, BadPaddingException {
  110. int inputLength = data.length;
  111. // 标识
  112. int offSet = 0;
  113. byte[] resultBytes = {};
  114. byte[] cache;
  115. while (inputLength - offSet > 0) {
  116. if (inputLength - offSet > maxBlock) {
  117. cache = cipher.doFinal(data, offSet, maxBlock);
  118. offSet += maxBlock;
  119. } else {
  120. cache = cipher.doFinal(data, offSet, inputLength - offSet);
  121. offSet = inputLength;
  122. }
  123. resultBytes = Arrays.copyOf(resultBytes, resultBytes.length + cache.length);
  124. System.arraycopy(cache, 0, resultBytes, resultBytes.length - cache.length, cache.length);
  125. }
  126. return resultBytes;
  127. }
  128. /**
  129. * 获取私钥
  130. *
  131. * @param privateKeyString 私钥路径
  132. * @return 私钥
  133. */
  134. private static PrivateKey getPrivateKey(String privateKeyString) throws Exception {
  135. // 创建key的工厂
  136. KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM);
  137. // 创建私钥key的规则
  138. PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(Base64.decode(privateKeyString));
  139. // 返回私钥对象
  140. return keyFactory.generatePrivate(keySpec);
  141. }
  142. /**
  143. * 获取公钥
  144. *
  145. * @param publicKeyString 公钥
  146. * @return 公钥
  147. * @throws Exception 异常
  148. */
  149. private static PublicKey getPublicKey(String publicKeyString) throws Exception {
  150. // 创建key的工厂
  151. KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM);
  152. // 创建公钥key的规则
  153. X509EncodedKeySpec keySpec = new X509EncodedKeySpec(Base64.decode(publicKeyString));
  154. // 返回公钥对象
  155. return keyFactory.generatePublic(keySpec);
  156. }
  157. }

 

2.2.5 App

测试类

 

  1. package com.best.hope;
  2. /**
  3. * @Author: best_liu
  4. * @Description:
  5. * @Date Create in 10:18 2023/5/19
  6. * @Modified By:
  7. */
  8. import com.alibaba.fastjson.JSONObject;
  9. import com.best.hope.client.SysUserClient;
  10. import com.best.hope.domain.SysUserDTO;
  11. import com.best.hope.domain.common.HopeRequest;
  12. import java.lang.reflect.InvocationTargetException;
  13. import java.lang.reflect.Method;
  14. import java.lang.reflect.Modifier;
  15. public class App {
  16. /**
  17. * 公钥
  18. */
  19. private static final String PUBLIC_KEY_STRING = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCwr8qdHqUB8E2lPlj8fmbntolUdyXIXh2U1BCEzx1vWp4VvIjJLXhN5vN2btnuldfy252laDRtxjt4uuQujIgTHiYWtTyoGK5bx3uXC81pVsEOgcQjgraNpubC1l3duMSadufapSsqcNRfXTFaiQGgjvtrA01AW3QS/ciSweiedQIDAQAB";
  20. // public static void main(String[] args) {
  21. // SysUserDTO dto = new SysUserDTO();
  22. // dto.setUserName("吴素");
  23. // dto.setId(9);
  24. // dto.setAge("20");
  25. // dto.setUserEmail("nangong@163.com");
  26. // HopeRequest hopeRequest = new HopeRequest();
  27. // hopeRequest.setAppId("zkawTest");
  28. // hopeRequest.setPublicKey(PUBLIC_KEY_STRING);
  29. // hopeRequest.setType("list");
  30. // hopeRequest.setData(JSONObject.toJSONString(dto));
  31. // String pageModelBaseResponse = SysUserClient.invokeApi(hopeRequest);
  32. // System.out.println(pageModelBaseResponse);
  33. // }
  34. /** @Author: best_liu
  35. * @Description:java中通过反射调用某个类中的方法
  36. * @Date: 9:38 2023/5/26
  37. * @Param [args]
  38. * @return void
  39. **/
  40. public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
  41. SysUserDTO dto = new SysUserDTO();
  42. // dto.setUserName("吴素");
  43. dto.setId(9);
  44. dto.setAge("20");
  45. dto.setUserEmail("nangong@163.com");
  46. HopeRequest hopeRequest = new HopeRequest();
  47. hopeRequest.setAppId("zkawTest");
  48. hopeRequest.setPublicKey(PUBLIC_KEY_STRING);
  49. hopeRequest.setType("list");
  50. hopeRequest.setData(JSONObject.toJSONString(dto));
  51. Class clazz = SysUserClient.class;
  52. Method method = clazz.getDeclaredMethod("invokeApi",new Class[]{HopeRequest.class});
  53. Object invoke = method.invoke(new SysUserClient(), new Object[]{hopeRequest});
  54. System.out.println(invoke);
  55. }
  56. /** @Author: best_liu
  57. * @Description: java中通过反射获取某个类中的所有方法信息
  58. * @Date: 14:52 2023/5/25
  59. * @Param [args]
  60. * @return void
  61. **/
  62. // public static void main(String args[]) throws Exception {
  63. // Class<?> cls = SysUserClient.class;
  64. public Method[] getMethods();//获取包括自身和继承(实现)过来的所有的public方法——Method不支持泛型<>,即后面不接<>
  65. public Method[] getDeclaredMethods();//获取自身所有的方法(private、public、protected,和访问权限无关),不包括继承的
  66. // Method methods[] = cls.getDeclaredMethods();
  67. // for (Method met : methods) {
  68. // String res = "";
  69. // int mod = met.getModifiers();
  70. // //先输出方法名字
  71. // res = res + Modifier.toString(mod) + " " + met.getReturnType().getName() + " " + met.getName() + "(";
  72. // Class<?> params[] = met.getParameterTypes();
  73. // for (int x = 0; x < params.length; x ++) {
  74. // //拼凑出方法要求的数据类型
  75. // res = res + params[x].getName() + " " + "args-" + x;
  76. // if (x < params.length - 1) {
  77. // res = res +",";
  78. // }
  79. // }
  80. // res = res + ") ";
  81. // Class<?> exp[] = met.getExceptionTypes();
  82. // if (exp.length > 0) {
  83. // //获取其支持处理的异常信息
  84. // res = res + "throws ";
  85. // }
  86. // for (int x = 0 ; x < exp.length ; x ++) {
  87. // res = res + exp[x].getName();
  88. // if (x < exp.length - 1) {
  89. // res = res +",";
  90. // }
  91. // }
  92. // System.out.println(res);
  93. // System.out.println(); //换行
  94. // }
  95. // }
  96. }

2.2.6 HopeRequest

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

 

  1. package com.best.hope.domain.common;
  2. import lombok.AllArgsConstructor;
  3. import lombok.Builder;
  4. import lombok.Data;
  5. import lombok.NoArgsConstructor;
  6. /**
  7. * @Author: best_liu
  8. * @Description:
  9. * @Date Create in 10:20 2023/5/19
  10. * @Modified By:
  11. */
  12. @Data
  13. @Builder
  14. @NoArgsConstructor
  15. @AllArgsConstructor
  16. public class HopeRequest {
  17. /**
  18. * 客户端唯一编号
  19. */
  20. private String appId;
  21. private String publicKey;
  22. private String type;
  23. /**
  24. * 加密后业务相关的入参
  25. */
  26. private String data;
  27. }

2.2.6 HopeResponse

  1. package com.best.hope.domain.common;
  2. import lombok.AllArgsConstructor;
  3. import lombok.Builder;
  4. import lombok.Data;
  5. import lombok.NoArgsConstructor;
  6. /**
  7. * @Author: best_liu
  8. * @Description:
  9. * @Date Create in 10:21 2023/5/19
  10. * @Modified By:
  11. */
  12. @Data
  13. @Builder
  14. @NoArgsConstructor
  15. @AllArgsConstructor
  16. public class HopeResponse {
  17. /**
  18. * 是否成功
  19. */
  20. private boolean success;
  21. /**
  22. * 返回信息
  23. */
  24. private String message;
  25. /**
  26. * 业务相关的返回信息,私钥加密之后的
  27. */
  28. private String data;
  29. }

2.2.7 ApiRequest

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

 

  1. package com.best.hope.domain.common;
  2. import lombok.AllArgsConstructor;
  3. import lombok.Builder;
  4. import lombok.Data;
  5. import lombok.NoArgsConstructor;
  6. /**
  7. * @Author: best_liu
  8. * @Description:
  9. * @Date Create in 10:21 2023/5/19
  10. * @Modified By:
  11. */
  12. @Data
  13. @Builder
  14. @NoArgsConstructor
  15. @AllArgsConstructor
  16. public class ApiRequest<T> {
  17. private String url;
  18. private String type;
  19. private String publicKey;
  20. private String appId;
  21. private T data;
  22. }

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文件夹下

三、maven 引入本地sdk包

3.1、cmd执行以下命令

mvn install:install-file -Dmaven.repo.local=C:\Users\lx\.m2\repository -DgroupId=com.taobao -DartifactId=taobao-sdk-java-auto -Dversion=1.0.1 -Dpackaging=jar -Dfile=C:\Users\lx\Downloads\taobao-sdk-java-auto_1479188381469-20211105.jar

参数

  1. Dmaven.repo.local 指定的maven仓库的地址
  2. DgroupId 指maven创库存放jar包的路径, 也是pom文件中groupId:标签中的值;
  3. DartifactId 指是pom文件中artifactId标签中的值
  4. Dversion 指版本号;
  5. Dfile 指当前jar所存放的位置

3.2、在pom中引入依赖

  1. <dependency>
  2. <groupId>com.best.hope</groupId>
  3. <artifactId>hope-sdk</artifactId>
  4. <version>1.0.1</version>
  5. <exclusions>
  6. <exclusion>
  7. <groupId>org.slf4j</groupId>
  8. <artifactId>slf4j-api</artifactId>
  9. </exclusion>
  10. <exclusion>
  11. <groupId>ch.qos.logback</groupId>
  12. <artifactId>logback-classic</artifactId>
  13. </exclusion>
  14. </exclusions>
  15. </dependency>

3.3、测试

  1. /** @Author: best_liu
  2. * @Description:java中通过反射调用某个类中的方法
  3. * @Date: 9:38 2023/5/26
  4. * @Param [args]
  5. * @return void
  6. **/
  7. public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
  8. SysUserDTO dto = new SysUserDTO();
  9. // dto.setUserName("吴素");
  10. dto.setId(9);
  11. dto.setAge("20");
  12. dto.setUserEmail("nangong@163.com");
  13. HopeRequest hopeRequest = new HopeRequest();
  14. hopeRequest.setAppId("zkawTest");
  15. hopeRequest.setPublicKey(PUBLIC_KEY_STRING);
  16. hopeRequest.setType("list");
  17. hopeRequest.setData(JSONObject.toJSONString(dto));
  18. Class clazz = SysUserClient.class;
  19. Method method = clazz.getDeclaredMethod("invokeApi",new Class[]{HopeRequest.class});
  20. Object invoke = method.invoke(new SysUserClient(), new Object[]{hopeRequest});
  21. System.out.println(invoke);
  22. }

接口已经调通结果已经打印在控制台

四、最后 

一个简单的java开发sdk得demo完成~

maven 引入本地sdk包:JAVA----maven 引入本地sdk包_Best_Liu~的博客-CSDN博客

 java反射获取类方法及调用类方法:java反射获取方法以及调用方法_Best_Liu~的博客-CSDN博客

声明:本文内容由网友自发贡献,转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号