赞
踩
1)最近在对接外部平台的接口,对方提供了一个sdk,开发中直接引入到项目中。自己只需要组装参数,直接调用sdk中的方法就可以实现接口对接。
2)sdk中包含了参数校验,加密验签,Http接口调用,还提供了各个接口入参和出参的实体类。 这些为我们减少很多的开发量,同时将一些不合规的入参直接在客户端过滤掉,减少资源浪费。还提供了一套完整的加密验签方法,避免了双发对接中因为加解密验签方法的不同导致的一些问题。很大程度上提高了我们的对接中开发联调的成本。
3)sdk优点这么多,下面我们来开发一个简单的sdk吧。
1)首先我们开发一下服务端: 服务端是一个SpringBoot项目提供了一个用户列表查询的接口。入参包含调用方分唯一编号(appId),加密的入参信息(data),入参的加解密方式使用RSA非对称加密算法。
2)其次开发SDK: SDK是一个普通的maven项目,提供用户列表查询接口的Http调用方法,还有接口的参数校验,入参的加密,返回信息的解密。最后将项目打成jar包。
3)最后开发客户端调试: 客户端是一个SpringBoot项目,项目中引入上面打包好的SDK,组装参数,调用用户列表查询接口。
3.1.1 服务端入口(SysUserApiController)
这个类是接收客户端请求的入口,继承了ApiAbstract
- package com.zkaw.api;
-
- /**
- * @Author: best_liu
- * @Description:
- * @Date Create in 10:00 2023/5/19
- * @Modified By:
- */
-
- import com.alibaba.fastjson.JSONObject;
- import com.zkaw.service.IUserService;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.web.bind.annotation.PostMapping;
- import org.springframework.web.bind.annotation.RequestBody;
- import org.springframework.web.bind.annotation.RequestMapping;
- import org.springframework.web.bind.annotation.RestController;
-
- @RestController
- @RequestMapping("/api/user/")
- public class SysUserApiController extends ApiAbstract<String> {
-
- @Autowired
- private IUserService sysUserService;
-
- @Override
- public String work(String type,JSONObject o) {
- return sysUserService.invokeApi(type,JSONObject.toJavaObject(o, SysUserDTO.class));
- }
-
- @PostMapping("/invokeApi")
- public HopeResponse invokeApi(@RequestBody HopeRequest hopeRequest) {
- return process(hopeRequest);
- }
-
- }
3.1.2 接口的抽象类(ApiAbstract)
这个类提供一些公用的方法,私钥的获取,入参的解密,出参的加密等。
- package com.zkaw.api;
-
-
- import com.alibaba.fastjson.JSON;
- import com.alibaba.fastjson.JSONObject;
- import lombok.extern.slf4j.Slf4j;
-
- import java.util.HashMap;
- import java.util.Map;
-
- /**
- * @Author: best_liu
- * @Description:
- * @Date Create in 10:04 2023/5/19
- * @Modified By:
- */
-
-
- @Slf4j
- public abstract class ApiAbstract<R> {
-
- private static final Map<String, String> PRIVATE_KEY_MAP = new HashMap<>();
-
- static {
- 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=");
- }
-
- /**
- * 统一处理
- *
- * @param hopeRequest 统一请求
- * @return 统一响应
- */
- public HopeResponse process(HopeRequest hopeRequest) {
- try {
- String privateKey = getPrivateKey(hopeRequest.getAppId());
- String type = hopeRequest.getType();
- JSONObject o = before(hopeRequest.getData(), privateKey);
- System.out.println(o);
- R r = work(type,o);
- return after(r, privateKey);
- } catch (Exception e) {
- e.printStackTrace();
- log.error("ServerAbstract process exception! hopeRequest={}", hopeRequest, e);
- return HopeResponse.builder()
- .success(false)
- .message(e.getCause().toString())
- .build();
- }
-
- }
-
- /**
- * 处理前置解密
- *
- * @param data 请求密文
- * @param privateKey 秘钥
- * @return 请求参数
- */
- private JSONObject before(String data, String privateKey) {
- return JSON.parseObject(RsaUtil.decryptPrivate(privateKey, data));
- }
-
- /**
- * 业务处理
- *
- * @param o 入参
- * @return 返回
- */
- abstract R work(String type,JSONObject o);
-
- /**
- * 后置处理加密
- *
- * @param r 业务数据
- * @param privateKey 秘钥
- * @return 统一返回
- */
- private HopeResponse after(R r, String privateKey) {
- return HopeResponse.builder()
- .success(true)
- .message("访问成功")
- .data(RsaUtil.encryptPrivate(privateKey, (String) r))
- .build();
- }
-
- /**
- * 通过appId获取对应的私钥,不同的接入方提供不同的公私钥。
- * 实际业务开发中这些会存在文件中或者配置中心中如阿波罗,这里简单实现
- *
- * @param appId appId
- * @return 私钥
- */
- private String getPrivateKey(String appId) {
- return PRIVATE_KEY_MAP.get(appId);
- }
- }
-
3.1.3 接口入参实体类(HopeRequest)
这个是接口的入参,这里简单演示,一个客户端唯一编号(用来获取对应的私钥),一个是加密的入参。
- package com.zkaw.api;
-
- import lombok.AllArgsConstructor;
- import lombok.Builder;
- import lombok.Data;
- import lombok.NoArgsConstructor;
-
- /**
- * @Author: best_liu
- * @Description:
- * @Date Create in 10:04 2023/5/19
- * @Modified By:
- */
-
- @Data
- @Builder
- @NoArgsConstructor
- @AllArgsConstructor
- public class HopeRequest {
- /**
- * 客户端唯一编号
- */
- private String appId;
-
- private String type;
- /**
- * 加密后业务相关的入参
- */
- private String data;
- }
-
-
3.1.4 接口返回实体类(HopeResponse)
这个是服务端接口的返回信息。返回的字段有成功表示,提示信息,还有业务相关的查询结果(查询到的用户信息)加密的信息。
- package com.zkaw.api;
-
- import lombok.AllArgsConstructor;
- import lombok.Builder;
- import lombok.Data;
- import lombok.NoArgsConstructor;
-
- /**
- * @Author: best_liu
- * @Description:
- * @Date Create in 10:05 2023/5/19
- * @Modified By:
- */
-
- @Data
- @Builder
- @NoArgsConstructor
- @AllArgsConstructor
- public class HopeResponse {
-
- /**
- * 是否成功
- */
- private boolean success;
-
- /**
- * 返回信息
- */
- private String message;
-
- /**
- * 业务相关的返回信息,私钥加密之后的
- */
- private String data;
-
- }
-
3.1.5 具体的业务实现层(SysUserService)
这里是具体的业务层,通过入参去数据库查询对应的结果,在封装成实体类返回,这里不再深入。PageMode是用查询的结果封装的分页实体类。BaseResponse是业务层处理的结果有返回码和提示信息。其实这里不用封装这么多层,我这个是用以前的老代码简单的做个示例。
- package com.zkaw.service;
-
- import com.baomidou.mybatisplus.core.metadata.IPage;
- import com.zkaw.api.SysUser;
- import com.zkaw.api.SysUserDTO;
- import com.zkaw.pojo.User;
-
- import java.util.List;
-
- /**
- * @Author: LiuXingJie
- * @Description:
- * @Date Create in 11:06 2022/6/29
- * @Modified By:
- */
- public interface IUserService {
-
- int insertSaveBanch(List<User> list);
-
- int insert( User user);
-
- int delete( User user);
-
- IPage<User> selectPage(User user);
-
- int update( User user);
-
- List<User> selectList(User user);
-
- List<SysUser> queryUserList(SysUserDTO dto);
-
- SysUser selectById(String userId);
-
- String invokeApi(String type,SysUserDTO dto);
- }
3.1.6 业务相关的入参(SysUserDTO)
这个类是真正传递业务相关查询条件的实体类。PageBase 是一个分页相关的类,参数为pageSize和pageIndex。
- package com.zkaw.api;
- import lombok.Data;
-
- /**
- * @Author: best_liu
- * @Description:
- * @Date Create in 10:05 2023/5/19
- * @Modified By:
- */
-
- @Data
- public class SysUserDTO extends PageBase {
-
-
- private int id;
-
- /**
- * 昵称
- */
- private String userId;
- private String age;
-
- /**
- * 用户名称
- */
- private String userName;
-
- /**
- * 用户手机号
- */
- private String userPhone;
-
- /**
- * 用户邮箱
- */
- private String userEmail;
-
- /**
- * 用户状态 0、正常 1、锁定 2、注销
- */
- private Integer status;
- }
-
3.1.7 RSA加解密的工具类(RsaUtil)
- package com.zkaw.api;
-
- 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.*;
- import java.security.interfaces.RSAPrivateKey;
- import java.security.interfaces.RSAPublicKey;
- import java.security.spec.PKCS8EncodedKeySpec;
- import java.security.spec.X509EncodedKeySpec;
- import java.util.Arrays;
-
- /**
- * @Author: best_liu
- * @Description:
- * @Date Create in 10:07 2023/5/19
- * @Modified By:
- */
-
- @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;
- /**
- * RSA密钥长度必须是64的倍数,在512~65536之间。默认是1024
- */
- public static final int KEY_SIZE = 1024;
-
-
- /**
- * 请求报文公钥解密
- *
- * @param publicKeyString 公钥
- * @param text 报文
- * @return 加密报文
- */
- public static String encryptPublic(String publicKeyString, String text) {
- try {
- PublicKey publicKey = getPublicKey(publicKeyString);
- return encryptRSA(publicKey, text);
- } catch (Exception e) {
- e.printStackTrace();
- log.error("RsaUtil encryptPublic exception! publicKeyString={} text={}", publicKeyString, text);
- return null;
- }
- }
-
- /**
- * 应答报文公钥解密
- *
- * @param publicKeyString 公钥
- * @param text 应答密文
- * @return 解密报文
- */
- public static String decryptPublic(String publicKeyString, String text) {
- try {
- PublicKey publicKey = getPublicKey(publicKeyString);
- return decryptRSA(publicKey, text);
- } catch (Exception e) {
- e.printStackTrace();
- log.error("RsaUtil decryptPublic exception! publicKeyString={} text={}", publicKeyString, text);
- return null;
- }
- }
-
- /**
- * 请求报文私钥解密
- *
- * @param privateKeyString 私钥
- * @param text 报文
- * @return 加密报文
- */
- public static String encryptPrivate(String privateKeyString, String text) {
- try {
- PrivateKey privateKey = getPrivateKey(privateKeyString);
- return encryptRSA(privateKey, text);
- } catch (Exception e) {
- e.printStackTrace();
- log.error("RsaUtil encryptPrivate exception! publicKeyString={} text={}", privateKeyString, text);
- return null;
- }
- }
-
- /**
- * 应答报文私钥解密
- *
- * @param privateKeyString 私钥
- * @param text 应答密文
- * @return 解密报文
- */
- public static String decryptPrivate(String privateKeyString, String text) {
- try {
- PrivateKey privateKey = getPrivateKey(privateKeyString);
- return decryptRSA(privateKey, text);
- } catch (Exception e) {
- e.printStackTrace();
- log.error("RsaUtil decryptPrivate exception! privateKeyString={} text={}", privateKeyString, 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);
- }
-
-
- public static void main(String[] args) throws NoSuchAlgorithmException {
- KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
- //所以当密钥位数为2048时,最大解密长度应为256.
- keyPairGenerator.initialize(KEY_SIZE);
- KeyPair keyPair = keyPairGenerator.generateKeyPair();
- RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
- RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
- System.out.println("publicKey="+publicKey);
- System.out.println("==============================");
- System.out.println("privateKey="+privateKey);
- }
-
- }
-
创建项目步骤不在这里面说了,相信大家应该都已经会了。
先看看项目的整体结构
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>
- </dependency>
- <dependency>
- <groupId>org.projectlombok</groupId>
- <artifactId>lombok</artifactId>
- </dependency>
- <!--工具类-->
- <dependency>
- <groupId>org.apache.commons</groupId>
- <artifactId>commons-lang3</artifactId>
- <version>3.4</version>
- </dependency>
- </dependencies>
2.2.2 SysUserClient
用户查询的客户端,继承ClientAbstract 类
- package com.best.hope.client;
-
- import com.alibaba.fastjson.JSON;
- import com.alibaba.fastjson.JSONObject;
- import com.alibaba.fastjson.TypeReference;
- import com.best.hope.domain.SysUserDTO;
- import com.best.hope.domain.common.ApiRequest;
- import com.best.hope.domain.common.HopeRequest;
- import lombok.extern.slf4j.Slf4j;
-
- /**
- * @Author: best_liu
- * @Description:
- * @Date Create in 10:16 2023/5/19
- * @Modified By:
- */
-
- @Slf4j
- public class SysUserClient extends ClientAbstract {
-
- public static String invokeApi(HopeRequest hopeRequest) {
- ApiRequest<SysUserDTO> request = ApiRequest.<SysUserDTO>builder()
- .appId(hopeRequest.getAppId())
- .type(hopeRequest.getType())
- .url("http://localhost:8090/api/user/invokeApi")
- .publicKey(hopeRequest.getPublicKey())
- .data(JSONObject.parseObject(hopeRequest.getData(),SysUserDTO.class))
- .build();
- try {
- String str = post(request);
- return JSON.parseObject(str, new TypeReference<String>() {
- });
- } catch (Exception e) {
- log.error("SysUserClient queryUserList is exception! request={}", request);
- return null;
- }
- }
- }
-
2.2.3 ClientAbstract
提供了入参加密,返回解密的功能,http请求。这里也可以添加参数校验的功能,这里省略。
- package com.best.hope.client;
-
- import com.alibaba.fastjson.JSON;
-
- import com.alibaba.fastjson.JSONObject;
- import com.best.hope.domain.common.ApiRequest;
- import com.best.hope.domain.common.HopeRequest;
- import com.best.hope.domain.common.HopeResponse;
- import com.best.hope.enums.ReturnCodeEnum;
- import com.best.hope.exception.HopeException;
- import com.best.hope.utils.HttpUtil;
- import com.best.hope.utils.RsaUtil;
- import lombok.extern.slf4j.Slf4j;
- import org.apache.commons.lang3.StringUtils;
-
- /**
- * @Author: best_liu
- * @Description:
- * @Date Create in 10:16 2023/5/19
- * @Modified By:
- */
-
- @Slf4j
- class ClientAbstract {
-
- static String post(ApiRequest request) {
- HopeRequest hopeRequest = HopeRequest.builder()
- .appId(request.getAppId())
- .type(request.getType())
- .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("400", "请求结果为null");
- }
- HopeResponse hopeResponse = JSON.parseObject(s, HopeResponse.class);
- if (!hopeResponse.isSuccess()) {
- log.error("client post api error! hopeResponse={}", hopeResponse);
- throw new HopeException("400", hopeResponse.getMessage());
- }
- hopeResponse.setData(RsaUtil.decrypt(request.getPublicKey(), hopeResponse.getData()));
- return JSONObject.toJSONString(hopeResponse);
- }
- }
-
2.2.4 HttpUtil
Http请求的工具类,这里简单写一个psot请求的方法。参数传递方法为application/json。
- package com.best.hope.utils;
-
- import lombok.extern.slf4j.Slf4j;
-
- import java.io.*;
- import java.net.HttpURLConnection;
- import java.net.URL;
-
- /**
- * @Author: best_liu
- * @Description:
- * @Date Create in 10:17 2023/5/19
- * @Modified By:
- */
-
- @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.best.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;
-
- /**
- * @Author: best_liu
- * @Description:
- * @Date Create in 10:18 2023/5/19
- * @Modified By:
- */
-
- @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.best.hope;
-
- /**
- * @Author: best_liu
- * @Description:
- * @Date Create in 10:18 2023/5/19
- * @Modified By:
- */
-
- import com.alibaba.fastjson.JSONObject;
- import com.best.hope.client.SysUserClient;
- import com.best.hope.domain.SysUserDTO;
- import com.best.hope.domain.common.HopeRequest;
-
- import java.lang.reflect.InvocationTargetException;
- import java.lang.reflect.Method;
- import java.lang.reflect.Modifier;
-
- public class App {
-
- /**
- * 公钥
- */
- private static final String PUBLIC_KEY_STRING = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCwr8qdHqUB8E2lPlj8fmbntolUdyXIXh2U1BCEzx1vWp4VvIjJLXhN5vN2btnuldfy252laDRtxjt4uuQujIgTHiYWtTyoGK5bx3uXC81pVsEOgcQjgraNpubC1l3duMSadufapSsqcNRfXTFaiQGgjvtrA01AW3QS/ciSweiedQIDAQAB";
-
- // public static void main(String[] args) {
- // SysUserDTO dto = new SysUserDTO();
- // dto.setUserName("吴素");
- // dto.setId(9);
- // dto.setAge("20");
- // dto.setUserEmail("nangong@163.com");
- // HopeRequest hopeRequest = new HopeRequest();
- // hopeRequest.setAppId("zkawTest");
- // hopeRequest.setPublicKey(PUBLIC_KEY_STRING);
- // hopeRequest.setType("list");
- // hopeRequest.setData(JSONObject.toJSONString(dto));
- // String pageModelBaseResponse = SysUserClient.invokeApi(hopeRequest);
- // System.out.println(pageModelBaseResponse);
- // }
-
- /** @Author: best_liu
- * @Description:java中通过反射调用某个类中的方法
- * @Date: 9:38 2023/5/26
- * @Param [args]
- * @return void
- **/
- public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
- SysUserDTO dto = new SysUserDTO();
- // dto.setUserName("吴素");
- dto.setId(9);
- dto.setAge("20");
- dto.setUserEmail("nangong@163.com");
- HopeRequest hopeRequest = new HopeRequest();
- hopeRequest.setAppId("zkawTest");
- hopeRequest.setPublicKey(PUBLIC_KEY_STRING);
- hopeRequest.setType("list");
- hopeRequest.setData(JSONObject.toJSONString(dto));
- Class clazz = SysUserClient.class;
- Method method = clazz.getDeclaredMethod("invokeApi",new Class[]{HopeRequest.class});
- Object invoke = method.invoke(new SysUserClient(), new Object[]{hopeRequest});
- System.out.println(invoke);
- }
-
- /** @Author: best_liu
- * @Description: java中通过反射获取某个类中的所有方法信息
- * @Date: 14:52 2023/5/25
- * @Param [args]
- * @return void
- **/
- // public static void main(String args[]) throws Exception {
- // Class<?> cls = SysUserClient.class;
- public Method[] getMethods();//获取包括自身和继承(实现)过来的所有的public方法——Method不支持泛型<>,即后面不接<>
- public Method[] getDeclaredMethods();//获取自身所有的方法(private、public、protected,和访问权限无关),不包括继承的
- // Method methods[] = cls.getDeclaredMethods();
- // for (Method met : methods) {
- // String res = "";
- // int mod = met.getModifiers();
- // //先输出方法名字
- // res = res + Modifier.toString(mod) + " " + met.getReturnType().getName() + " " + met.getName() + "(";
- // Class<?> params[] = met.getParameterTypes();
- // for (int x = 0; x < params.length; x ++) {
- // //拼凑出方法要求的数据类型
- // res = res + params[x].getName() + " " + "args-" + x;
- // if (x < params.length - 1) {
- // res = res +",";
- // }
- // }
- // res = res + ") ";
- // Class<?> exp[] = met.getExceptionTypes();
- // if (exp.length > 0) {
- // //获取其支持处理的异常信息
- // res = res + "throws ";
- // }
- // for (int x = 0 ; x < exp.length ; x ++) {
- // res = res + exp[x].getName();
- // if (x < exp.length - 1) {
- // res = res +",";
- // }
- // }
- // System.out.println(res);
- // System.out.println(); //换行
- // }
- // }
- }
-
2.2.6 HopeRequest
这个是接口的入参,这里简单演示,一个客户端唯一编号(用来获取对应的私钥),一个是加密的入参。
- package com.best.hope.domain.common;
-
- import lombok.AllArgsConstructor;
- import lombok.Builder;
- import lombok.Data;
- import lombok.NoArgsConstructor;
-
- /**
- * @Author: best_liu
- * @Description:
- * @Date Create in 10:20 2023/5/19
- * @Modified By:
- */
-
- @Data
- @Builder
- @NoArgsConstructor
- @AllArgsConstructor
- public class HopeRequest {
- /**
- * 客户端唯一编号
- */
- private String appId;
-
- private String publicKey;
-
- private String type;
-
- /**
- * 加密后业务相关的入参
- */
- private String data;
- }
-
2.2.6 HopeResponse
- package com.best.hope.domain.common;
-
- import lombok.AllArgsConstructor;
- import lombok.Builder;
- import lombok.Data;
- import lombok.NoArgsConstructor;
-
- /**
- * @Author: best_liu
- * @Description:
- * @Date Create in 10:21 2023/5/19
- * @Modified By:
- */
-
- @Data
- @Builder
- @NoArgsConstructor
- @AllArgsConstructor
- public class HopeResponse {
-
- /**
- * 是否成功
- */
- private boolean success;
-
- /**
- * 返回信息
- */
- private String message;
-
- /**
- * 业务相关的返回信息,私钥加密之后的
- */
- private String data;
-
- }
-
2.2.7 ApiRequest
这个类是创建入参是用的,有客户端唯一Id(appId),请求的接口地址,公钥还有业务相关的入参。
- package com.best.hope.domain.common;
-
- import lombok.AllArgsConstructor;
- import lombok.Builder;
- import lombok.Data;
- import lombok.NoArgsConstructor;
-
- /**
- * @Author: best_liu
- * @Description:
- * @Date Create in 10:21 2023/5/19
- * @Modified By:
- */
-
- @Data
- @Builder
- @NoArgsConstructor
- @AllArgsConstructor
- public class ApiRequest<T> {
-
- private String url;
- private String type;
- 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文件夹下
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
参数
- Dmaven.repo.local 指定的maven仓库的地址
- DgroupId 指maven创库存放jar包的路径, 也是pom文件中groupId:标签中的值;
- DartifactId 指是pom文件中artifactId标签中的值
- Dversion 指版本号;
- Dfile 指当前jar所存放的位置
- <dependency>
- <groupId>com.best.hope</groupId>
- <artifactId>hope-sdk</artifactId>
- <version>1.0.1</version>
- <exclusions>
- <exclusion>
- <groupId>org.slf4j</groupId>
- <artifactId>slf4j-api</artifactId>
- </exclusion>
- <exclusion>
- <groupId>ch.qos.logback</groupId>
- <artifactId>logback-classic</artifactId>
- </exclusion>
- </exclusions>
- </dependency>
- /** @Author: best_liu
- * @Description:java中通过反射调用某个类中的方法
- * @Date: 9:38 2023/5/26
- * @Param [args]
- * @return void
- **/
- public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
- SysUserDTO dto = new SysUserDTO();
- // dto.setUserName("吴素");
- dto.setId(9);
- dto.setAge("20");
- dto.setUserEmail("nangong@163.com");
- HopeRequest hopeRequest = new HopeRequest();
- hopeRequest.setAppId("zkawTest");
- hopeRequest.setPublicKey(PUBLIC_KEY_STRING);
- hopeRequest.setType("list");
- hopeRequest.setData(JSONObject.toJSONString(dto));
- Class clazz = SysUserClient.class;
- Method method = clazz.getDeclaredMethod("invokeApi",new Class[]{HopeRequest.class});
- Object invoke = method.invoke(new SysUserClient(), new Object[]{hopeRequest});
- System.out.println(invoke);
- }
接口已经调通结果已经打印在控制台
一个简单的java开发sdk得demo完成~
maven 引入本地sdk包:JAVA----maven 引入本地sdk包_Best_Liu~的博客-CSDN博客
java反射获取类方法及调用类方法:java反射获取方法以及调用方法_Best_Liu~的博客-CSDN博客
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。