Java开发SDK详解->SDK开发

Java开发SDK详解->SDK开发一、前言前面已经将服务端开发好了(服务端开发),现在我们来开发SDK吧。二、详情2.1创建项目创建一个普通的maven项目maven—-》jdk选择1.8—–》next输入groupId和artifactId输入项目名称,和项目存放位置2.2开发代码先看看项目的整体结构2.2.1pom文件依赖的jar包<dependencies><!–json相关–><dependency>&l

大家好,又见面了,我是你们的朋友全栈君。

一、前言

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

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/157022.html原文链接:https://javaforall.net

(1)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • redflag linux安装教程,硬盘安装REDFlag LINUX体会

    redflag linux安装教程,硬盘安装REDFlag LINUX体会我是一名LINUX的初学者,在看了许多LINUX的介绍之后,在本着大胆和心细的原则下,尝试了一回安装LINUX。现把我的一些心得和体会和大家分享,希望对一些入门级的朋友有所帮助。我装的是REDFlagLINUX,我原来的操作系统是WINXP,本着学习LINUX的和省钱至上的想法,我选择了安装WINXP和LINUX的双系统,我在网上下载了LINUX的ISO文件,先保存在随意的一个硬盘里,只要不是…

    2022年8月20日
    6
  • Docker Compose详解

    Docker Compose详解使用 DockerCompos 预计阅读时间 11 分钟 DockerCompos 是一种用于帮助定义和共享多容器应用程序的工具 使用 Compose 我们可以创建一个 YAML 文件来定义服务 并且使用一个命令 可以启动所有内容或将其全部关闭 使用 Compose 的最大优势是您可以在一个文件中定义您的应用程序堆栈 将其保存在项目 repo 的根目录中 它现在是版本控制的 并且可以轻松地让其他人为您的项目做出贡献 有人只需要克隆您的存储库并启动撰写应用程序 事实上 你现在可能会在 GitHub Gi

    2025年6月17日
    2
  • Python文本情感分析_Python数据分析实战

    Python文本情感分析_Python数据分析实战本文由来为了赚足学分丰富假期生活,初衷是分析老师对学生作业的评价和学生对老师的评价的。本来这个任务是在N多天前就应该完成了,无奈本人懒癌晚期+拖延症不想治疗,不是因为火烧眉毛就绝对没有今天的文章。本文旨在记录自己的学习过程,就这样,开干啦!序幕既然题目是“基于情感词典的文本情感分析”,那么情感词典就是必不可少的了。对于情感词典的要求:要包含积极的词语和消极的词语、每一种类的数量要足够多、包含足够广…

    2022年8月23日
    7
  • 《JavaScript 模式》读书笔记(2)— 基本技巧1

    这篇文章的主要内容,介绍了一些js编程中的基本技巧,其实这些技巧,大家在开发的过程中,或多或少都在使用,或者已经可以熟练的应用于自己的代码或项目中了。那么,这篇文章,就一起来回顾下这些“基本技巧”。

    2022年3月25日
    38
  • java switch是什么意思_java switch语句详解[通俗易懂]

    java switch是什么意思_java switch语句详解[通俗易懂]switch语句的格式:switch(整型或字符型变量){case变量可能值1:分支一;break;case变量可能值2:分支二;break;case变量可能值3:分支三;break;…default:最后分支;}在switch的语法里,我们要学到4个关键字:switch、case、break、default。在 switch(变量) 这一行里,变量只能是整型…

    2022年7月7日
    19
  • 【转载】关于C#静态构造函数的几点说明

    【转载】关于C#静态构造函数的几点说明

    2021年11月20日
    42

发表回复

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

关注全栈程序员社区公众号