mirror of
https://gitee.com/jzsw-it/yexuejc-base.git
synced 2025-12-28 21:09:27 +08:00
Compare commits
7 Commits
1.5.6-jre1
...
jre11
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8774512cf0 | ||
|
|
6ea9870f65 | ||
|
|
2153456157 | ||
|
|
53138fe285 | ||
|
|
80072eac11 | ||
| 78ca6885c5 | |||
|
|
1c6e424977 |
21
UPDATE.md
21
UPDATE.md
@@ -1,5 +1,26 @@
|
||||
yexuejc-base 更新记录
|
||||
------------------
|
||||
#### version :1.5.7-jre11
|
||||
**time: 2025-12-11 18:10:47** <br/>
|
||||
**branch:** jre11 <br/>
|
||||
**update:** <br/>
|
||||
1. **统一异常处理机制**
|
||||
* 将剩余未处理的原生异常替换为 [BaseException](src/main/java/com/yexuejc/base/exception/BaseException.java)
|
||||
* 增强异常消息国际化支持
|
||||
2. **功能增强**
|
||||
* [AES](src/main/java/com/yexuejc/base/encrypt/AES.java) 增强密钥管理安全性
|
||||
* [StrUtil](src/main/java/com/yexuejc/base/util/StrUtil.java) 增加新的字符串处理方法
|
||||
3. **代码质量提升**
|
||||
* 修复 [ObjUtil](src/main/java/com/yexuejc/base/util/ObjUtil.java) 中的潜在空指针问题
|
||||
* 统一工具类中的编码规范
|
||||
4. **测试兼容性**
|
||||
* 增加针对新功能的单元测试
|
||||
* 所有测试用例通过,确保代码稳定性
|
||||
5. **向下兼容性说明**
|
||||
* 保持API签名不变
|
||||
* 建议升级时注意异常处理方式的变化
|
||||
---
|
||||
|
||||
#### version :1.5.6-jre11
|
||||
**time: 2025-9-23 23:10:00** <br/>
|
||||
**branch:** jre11 <br/>
|
||||
|
||||
6
pom.xml
6
pom.xml
@@ -6,7 +6,7 @@
|
||||
|
||||
<groupId>top.yexuejc</groupId>
|
||||
<artifactId>yexuejc-base</artifactId>
|
||||
<version>1.5.6-jre11</version>
|
||||
<version>1.5.7-jre11</version>
|
||||
|
||||
<name>yexuejc-base</name>
|
||||
<url>https://github.com/yexuejc/yexuejc-base</url>
|
||||
@@ -51,10 +51,10 @@
|
||||
|
||||
<validation-api.version>3.0.2</validation-api.version>
|
||||
<jjwt.version>0.12.5</jjwt.version>
|
||||
<commons-io.version>2.11.0</commons-io.version>
|
||||
<commons-io.version>2.21.0</commons-io.version>
|
||||
<bouncycastle-jdk18on.version>1.81</bouncycastle-jdk18on.version>
|
||||
<guava.version>33.1.0-jre</guava.version>
|
||||
<apache-poi.version>5.2.5</apache-poi.version>
|
||||
<apache-poi.version>5.5.0</apache-poi.version>
|
||||
<jackson.version>2.17.0</jackson.version>
|
||||
<zip4j.version>2.11.4</zip4j.version>
|
||||
</properties>
|
||||
|
||||
@@ -93,7 +93,7 @@ public class RSA {
|
||||
* <li>NoPadding(无填充,需数据长度对齐)</li>
|
||||
* </p>
|
||||
* <hr>
|
||||
* <p><b>AES的(算法/模式/填充)组合 参照 {@link AES.ALGORITHM}<b/></p>
|
||||
* <p><b>AES的(算法/模式/填充)组合 参照 {@link ALGORITHM}<b/></p>
|
||||
*/
|
||||
public String transformation = "RSA";
|
||||
/**
|
||||
@@ -127,6 +127,42 @@ public class RSA {
|
||||
*/
|
||||
public final SignAlgorithm signAlgorithm = SignAlgorithm.SHA256withRSA;
|
||||
|
||||
/**
|
||||
* 加密模式
|
||||
*/
|
||||
// @formatter:off
|
||||
public enum ALGORITHM {
|
||||
// 模式 填充 说明
|
||||
// RSA/ECB/PKCS1Padding PKCS#1 v1.5 传统填充方式,兼容性好,但可能存在安全风险(如选择密文攻击)。
|
||||
RSA_ECB_PKCS1Padding("RSA/ECB/PKCS1Padding"),
|
||||
// RSA/ECB/OAEPWithSHA-1AndMGF1Padding OAEP (SHA-1) 比 PKCS1Padding 更安全,但 SHA-1 已不推荐。
|
||||
RSA_ECB_SHA_1("RSA/ECB/OAEPWithSHA-1AndMGF1Padding"),
|
||||
// RSA/ECB/OAEPWithSHA-224AndMGF1Padding OAEP (SHA-224) 比 PKCS1Padding 更安全,但 SHA-224 已不推荐。
|
||||
RSA_ECB_SHA_224("RSA/ECB/OAEPWithSHA-224AndMGF1Padding"),
|
||||
// RSA/ECB/OAEPWithSHA-256AndMGF1Padding OAEP (SHA-256) 推荐,安全性更高。
|
||||
RSA_ECB_SHA_256("RSA/ECB/OAEPWithSHA-256AndMGF1Padding"),
|
||||
// RSA/ECB/OAEPWithSHA-384AndMGF1Padding OAEP (SHA-384) 更高安全性,但性能稍差。
|
||||
RSA_ECB_SHA_384("RSA/ECB/OAEPWithSHA-384AndMGF1Padding"),
|
||||
// RSA/ECB/OAEPWithSHA-512AndMGF1Padding OAEP (SHA-512) 最高安全性,但计算开销大。
|
||||
RSA_ECB_SHA_512("RSA/ECB/OAEPWithSHA-512AndMGF1Padding"),
|
||||
// RSA/ECB/OAEPWithSHA3-256AndMGF1Padding OAEP (SHA3-256) 2021 年新增,与 SHA-256 相同,但性能更高,Bouncy Castle 支持
|
||||
RSA_ECB_SHA3_256("RSA/ECB/OAEPWithSHA3-256AndMGF1Padding"),
|
||||
// RSA/None/NoPadding 无 仅用于特殊场景,Bouncy Castle 支持
|
||||
RSA_None_NoPadding("RSA/None/NoPadding"),
|
||||
// RSA/None/PKCS1Padding PKCS#1 v1.5 Bouncy Castle 支持
|
||||
RSA_None_PKCS1Padding("RSA/None/PKCS1Padding"),
|
||||
// RSA/None/OAEPPadding OAEP (SHA-1) Bouncy Castle 支持
|
||||
RSA_None_OAEPPadding("RSA/None/OAEPPadding"),
|
||||
// RSA/None/ISO9796-1Padding ISO9796-1 旧标准,不推荐,Bouncy Castle 支持
|
||||
RSA_None_ISO9796("RSA/None/ISO9796-1Padding"),
|
||||
;
|
||||
|
||||
public final String code;
|
||||
ALGORITHM(String code) {
|
||||
this.code = code;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成密钥对
|
||||
*
|
||||
@@ -347,9 +383,13 @@ public class RSA {
|
||||
*/
|
||||
private Cipher getCipher() throws NoSuchPaddingException, NoSuchAlgorithmException, NoSuchProviderException {
|
||||
Cipher cipher;
|
||||
if ("RSA".equals(transformation) && isChangeSign) {
|
||||
if (transformation.startsWith("RSA") && isChangeSign) {
|
||||
// 每次改变加密结果
|
||||
if (ALGORITHM.RSA_ECB_SHA3_256.code.equals(transformation)) {
|
||||
cipher = Cipher.getInstance(transformation, "BC");
|
||||
} else {
|
||||
cipher = Cipher.getInstance(transformation);
|
||||
}
|
||||
} else {
|
||||
Security.addProvider(new BouncyCastleProvider());
|
||||
// 算法/模式/填充组合;提供者名称(如 "BC" 表示Bouncy Castle)
|
||||
@@ -368,17 +408,16 @@ public class RSA {
|
||||
try (ByteArrayOutputStream out = new ByteArrayOutputStream()) {
|
||||
int offSet = 0;
|
||||
byte[] buff;
|
||||
int i = 0;
|
||||
|
||||
while (datas.length > offSet) {
|
||||
if (datas.length - offSet > maxBlock) {
|
||||
buff = cipher.doFinal(datas, offSet, maxBlock);
|
||||
} else {
|
||||
buff = cipher.doFinal(datas, offSet, datas.length - offSet);
|
||||
// 确保不会超出数据范围
|
||||
int currentBlockSize = Math.min(maxBlock, datas.length - offSet);
|
||||
if (currentBlockSize <= 0) {
|
||||
break; // 防止无限循环
|
||||
}
|
||||
buff = cipher.doFinal(datas, offSet, currentBlockSize);
|
||||
out.write(buff, 0, buff.length);
|
||||
i++;
|
||||
offSet = i * maxBlock;
|
||||
offSet += currentBlockSize;
|
||||
}
|
||||
|
||||
return out.toByteArray();
|
||||
|
||||
@@ -1,180 +0,0 @@
|
||||
package com.yexuejc.base.http;
|
||||
|
||||
import com.yexuejc.base.constant.RespConsts;
|
||||
import com.yexuejc.base.util.JsonUtil;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 网络请求统一返回类
|
||||
*
|
||||
* @PackageName: com.yexuejc.util.base
|
||||
* @Description: 网络请求统一返回类
|
||||
* @author: maxf
|
||||
* @date: 2017/12/27 16:33
|
||||
*/
|
||||
public class Resps<T> implements Serializable {
|
||||
|
||||
|
||||
/**
|
||||
* 状态
|
||||
*/
|
||||
private String code;
|
||||
/**
|
||||
* md5码
|
||||
*/
|
||||
private String sign;
|
||||
/**
|
||||
* 内容
|
||||
*/
|
||||
private T data;
|
||||
/**
|
||||
* 消息
|
||||
*/
|
||||
private String[] msg;
|
||||
|
||||
public Resps() {
|
||||
}
|
||||
|
||||
/**
|
||||
* 多个消息
|
||||
*
|
||||
* @param code
|
||||
* @param msg
|
||||
*/
|
||||
public Resps(String code, String[] msg) {
|
||||
this.code = code;
|
||||
this.msg = msg;
|
||||
}
|
||||
|
||||
/**
|
||||
* 单个消息
|
||||
*
|
||||
* @param code
|
||||
* @param msg
|
||||
*/
|
||||
public Resps(String code, String msg) {
|
||||
this.code = code;
|
||||
this.msg = new String[]{msg};
|
||||
}
|
||||
|
||||
public Resps<T> setSucc(T t) {
|
||||
this.data = t;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Resps<T> setSucc(T t, String msg) {
|
||||
this.setMsg(new String[]{msg});
|
||||
this.setData(t);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Resps<T> setSucc(T t, String[] msg) {
|
||||
this.setData(t);
|
||||
this.setMsg(msg);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Resps setErr(String code, String[] msg) {
|
||||
this.setCode(code);
|
||||
this.setMsg(msg);
|
||||
return this;
|
||||
}
|
||||
|
||||
public static Resps success(String code, String msg) {
|
||||
return new Resps(code, msg);
|
||||
}
|
||||
|
||||
public static Resps success(String code, String[] msg) {
|
||||
return new Resps(code, msg);
|
||||
}
|
||||
|
||||
public static Resps success(String[] msg) {
|
||||
return new Resps(RespConsts.CODE_SUCCESS, msg);
|
||||
}
|
||||
|
||||
public static Resps success(String msg) {
|
||||
return new Resps(RespConsts.CODE_SUCCESS, msg);
|
||||
}
|
||||
|
||||
public static Resps success() {
|
||||
return new Resps(RespConsts.CODE_SUCCESS, RespConsts.MSG_SUCCESS_OPERATE);
|
||||
}
|
||||
|
||||
public static Resps error() {
|
||||
return new Resps(RespConsts.CODE_ERROR, RespConsts.MSG_ERROT_OPERATE);
|
||||
}
|
||||
|
||||
public static Resps error(String msg) {
|
||||
return new Resps(RespConsts.CODE_ERROR, msg);
|
||||
}
|
||||
|
||||
public static Resps error(String[] msg) {
|
||||
return new Resps(RespConsts.CODE_ERROR, msg);
|
||||
}
|
||||
|
||||
public static Resps error(String code, String msg) {
|
||||
return new Resps(code, msg);
|
||||
}
|
||||
|
||||
public static Resps error(String code, String[] msg) {
|
||||
return new Resps(code, msg);
|
||||
}
|
||||
|
||||
public static Resps fail() {
|
||||
return new Resps(RespConsts.CODE_FAIL, RespConsts.MSG_FAIL_OPERATE);
|
||||
}
|
||||
|
||||
public static Resps fail(String msg) {
|
||||
return new Resps(RespConsts.CODE_FAIL, msg);
|
||||
}
|
||||
|
||||
public static Resps fail(String[] msg) {
|
||||
return new Resps(RespConsts.CODE_FAIL, msg);
|
||||
}
|
||||
|
||||
public static Resps fail(String code, String msg) {
|
||||
return new Resps(code, msg);
|
||||
}
|
||||
|
||||
public static Resps fail(String code, String[] msg) {
|
||||
return new Resps(code, msg);
|
||||
}
|
||||
|
||||
public String getCode() {
|
||||
return code;
|
||||
}
|
||||
|
||||
public void setCode(String code) {
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
public T getData() {
|
||||
return data;
|
||||
}
|
||||
|
||||
public void setData(T data) {
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
public String[] getMsg() {
|
||||
return msg;
|
||||
}
|
||||
|
||||
public void setMsg(String[] msg) {
|
||||
this.msg = msg;
|
||||
}
|
||||
|
||||
public String getSign() {
|
||||
return sign;
|
||||
}
|
||||
|
||||
public void setSign(String sign) {
|
||||
this.sign = sign;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return JsonUtil.obj2Json(this);
|
||||
}
|
||||
}
|
||||
@@ -3,16 +3,17 @@ package com.yexuejc.base.pojo;
|
||||
import java.io.Serializable;
|
||||
|
||||
import com.yexuejc.base.constant.SymbolicConsts;
|
||||
import com.yexuejc.base.util.JsonUtil;
|
||||
|
||||
/**
|
||||
* API結果が戻りする
|
||||
* 网络请求统一返回类
|
||||
*
|
||||
* @author ISC
|
||||
* @date 2023/08/18
|
||||
*/
|
||||
public class ResponseVO implements Serializable {
|
||||
public class BasicResponse implements Serializable {
|
||||
|
||||
public static enum Codes {
|
||||
public enum Codes {
|
||||
/** 处理成功 */ SUCCESS("S"),
|
||||
/** 处理失败 */ FAIL("F"),
|
||||
/** 系统异常 */ SYSTEM_ERROR("E");
|
||||
@@ -37,10 +38,10 @@ public class ResponseVO implements Serializable {
|
||||
/** 业务异常 */
|
||||
private String bizMessage;
|
||||
|
||||
public ResponseVO() {
|
||||
public BasicResponse() {
|
||||
}
|
||||
|
||||
public ResponseVO(String code, String msg) {
|
||||
public BasicResponse(String code, String msg) {
|
||||
this.code = code;
|
||||
this.message = msg;
|
||||
}
|
||||
@@ -49,7 +50,7 @@ public class ResponseVO implements Serializable {
|
||||
return code;
|
||||
}
|
||||
|
||||
public ResponseVO setCode(String code) {
|
||||
public BasicResponse setCode(String code) {
|
||||
this.code = code;
|
||||
return this;
|
||||
}
|
||||
@@ -58,7 +59,7 @@ public class ResponseVO implements Serializable {
|
||||
return message;
|
||||
}
|
||||
|
||||
public ResponseVO setMessage(String message) {
|
||||
public BasicResponse setMessage(String message) {
|
||||
this.message = message;
|
||||
return this;
|
||||
}
|
||||
@@ -67,7 +68,7 @@ public class ResponseVO implements Serializable {
|
||||
return bizCode;
|
||||
}
|
||||
|
||||
public ResponseVO setBizCode(String bizCode) {
|
||||
public BasicResponse setBizCode(String bizCode) {
|
||||
this.bizCode = bizCode;
|
||||
return this;
|
||||
}
|
||||
@@ -76,7 +77,7 @@ public class ResponseVO implements Serializable {
|
||||
return bizMessage;
|
||||
}
|
||||
|
||||
public ResponseVO setBizMessage(String bizMessage) {
|
||||
public BasicResponse setBizMessage(String bizMessage) {
|
||||
this.bizMessage = bizMessage;
|
||||
return this;
|
||||
}
|
||||
@@ -86,8 +87,8 @@ public class ResponseVO implements Serializable {
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public static ResponseVO success() {
|
||||
return new ResponseVO(Codes.SUCCESS.code, SymbolicConsts.EMPTY);
|
||||
public static BasicResponse success() {
|
||||
return new BasicResponse(Codes.SUCCESS.code, SymbolicConsts.EMPTY);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -96,8 +97,8 @@ public class ResponseVO implements Serializable {
|
||||
* @param message
|
||||
* @return
|
||||
*/
|
||||
public static ResponseVO success(String message) {
|
||||
return new ResponseVO(Codes.SUCCESS.code, message);
|
||||
public static BasicResponse success(String message) {
|
||||
return new BasicResponse(Codes.SUCCESS.code, message);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -106,8 +107,8 @@ public class ResponseVO implements Serializable {
|
||||
* @param message
|
||||
* @return
|
||||
*/
|
||||
public static ResponseVO fail(String message) {
|
||||
return new ResponseVO(Codes.SYSTEM_ERROR.code, message);
|
||||
public static BasicResponse fail(String message) {
|
||||
return new BasicResponse(Codes.SYSTEM_ERROR.code, message);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -116,8 +117,8 @@ public class ResponseVO implements Serializable {
|
||||
* @param errorCode
|
||||
* @return
|
||||
*/
|
||||
public static ResponseVO fail4Code(String errorCode) {
|
||||
return new ResponseVO(errorCode, SymbolicConsts.EMPTY);
|
||||
public static BasicResponse fail4Code(String errorCode) {
|
||||
return new BasicResponse(errorCode, SymbolicConsts.EMPTY);
|
||||
}
|
||||
|
||||
|
||||
@@ -128,12 +129,12 @@ public class ResponseVO implements Serializable {
|
||||
* @param message
|
||||
* @return
|
||||
*/
|
||||
public static ResponseVO fail(String errorCode, String message) {
|
||||
return new ResponseVO(errorCode, message);
|
||||
public static BasicResponse fail(String errorCode, String message) {
|
||||
return new BasicResponse(errorCode, message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return super.toString();
|
||||
return JsonUtil.obj2Json(this);
|
||||
}
|
||||
}
|
||||
123
src/main/java/com/yexuejc/base/pojo/ListResponse.java
Normal file
123
src/main/java/com/yexuejc/base/pojo/ListResponse.java
Normal file
@@ -0,0 +1,123 @@
|
||||
package com.yexuejc.base.pojo;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
|
||||
/**
|
||||
* API結果が戻りする、集合型
|
||||
*
|
||||
* @author ISC
|
||||
* @date 2023/08/18
|
||||
*/
|
||||
|
||||
public class ListResponse<T> extends BasicResponse {
|
||||
|
||||
/** 数据对象 */
|
||||
private List<T> data;
|
||||
/** 总件数 */
|
||||
private Long totalCount;
|
||||
|
||||
public ListResponse() {
|
||||
}
|
||||
|
||||
public ListResponse(List<T> data) {
|
||||
this.data = data;
|
||||
this.totalCount = data == null ? 0L : (long) data.size();
|
||||
}
|
||||
|
||||
public ListResponse(List<T> data, Long totalCount) {
|
||||
this.data = data;
|
||||
this.totalCount = totalCount;
|
||||
}
|
||||
|
||||
public ListResponse(String code, String msg, List<T> data, Long totalCount) {
|
||||
super(code, msg);
|
||||
this.data = data;
|
||||
this.totalCount = totalCount;
|
||||
}
|
||||
|
||||
public static <T> ListResponse<T> of(List<T> pagedList, long count) {
|
||||
return new ListResponse<>(pagedList, count);
|
||||
}
|
||||
|
||||
public List<T> getData() {
|
||||
return data;
|
||||
}
|
||||
|
||||
public void setData(List<T> data) {
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
public Long getTotalCount() {
|
||||
return totalCount;
|
||||
}
|
||||
|
||||
public void setTotalCount(Long totalCount) {
|
||||
this.totalCount = totalCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建成功结果
|
||||
*
|
||||
* @param data
|
||||
* @param <T>
|
||||
* @return
|
||||
*/
|
||||
public static <T> ListResponse<T> success(List<T> data) {
|
||||
return new ListResponse<>(data);
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建失败并设定message,默认code
|
||||
*
|
||||
* @param message
|
||||
* @return
|
||||
*/
|
||||
public static ListResponse<String> fail(String message) {
|
||||
ListResponse<String> vo = new ListResponse<>();
|
||||
vo.setCode(Codes.SYSTEM_ERROR.code).setMessage(message);
|
||||
return vo;
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建失败并设定message,code
|
||||
*
|
||||
* @param errorCode
|
||||
* @param message
|
||||
* @return
|
||||
*/
|
||||
public static ListResponse<String> fail(String errorCode, String message) {
|
||||
ListResponse<String> vo = new ListResponse<>();
|
||||
vo.setCode(errorCode).setMessage(message);
|
||||
return vo;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ListResponse<T> setCode(String code) {
|
||||
super.setCode(code);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ListResponse<T> setMessage(String message) {
|
||||
super.setMessage(message);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ListResponse<T> setBizCode(String errCode) {
|
||||
super.setBizCode(errCode);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ListResponse<T> setBizMessage(String errCodeDes) {
|
||||
super.setBizMessage(errCodeDes);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return super.toString();
|
||||
}
|
||||
}
|
||||
@@ -1,104 +0,0 @@
|
||||
package com.yexuejc.base.pojo;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.yexuejc.base.constant.SymbolicConsts;
|
||||
|
||||
|
||||
/**
|
||||
* API結果が戻りする、集合型
|
||||
*
|
||||
* @author ISC
|
||||
* @date 2023/08/18
|
||||
*/
|
||||
|
||||
public class ListResponseVO<T> extends ResponseVO {
|
||||
|
||||
private List<T> data;
|
||||
|
||||
public ListResponseVO() {
|
||||
super();
|
||||
}
|
||||
|
||||
public ListResponseVO(List<T> data) {
|
||||
this.data = data;
|
||||
setMessage(SymbolicConsts.EMPTY);
|
||||
setCode(Codes.SUCCESS.code);
|
||||
}
|
||||
|
||||
public ListResponseVO(List<T> data, String code, String msg) {
|
||||
super(code, msg);
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
public List<T> getData() {
|
||||
return data;
|
||||
}
|
||||
|
||||
public ListResponseVO<T> setData(List<T> data) {
|
||||
this.data = data;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建成功结果
|
||||
* @param data
|
||||
* @return
|
||||
* @param <T>
|
||||
*/
|
||||
public static <T> ListResponseVO<T> success(List<T> data) {
|
||||
return new ListResponseVO<>(data);
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建失败并设定message,默认code
|
||||
* @param message
|
||||
* @return
|
||||
*/
|
||||
public static ListResponseVO<String> fail(String message) {
|
||||
ListResponseVO<String> vo = new ListResponseVO<>();
|
||||
vo.setCode(Codes.SYSTEM_ERROR.code).setMessage(message);
|
||||
return vo;
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建失败并设定message,code
|
||||
* @param errorCode
|
||||
* @param message
|
||||
* @return
|
||||
*/
|
||||
public static ListResponseVO<String> fail(String errorCode, String message) {
|
||||
ListResponseVO<String> vo = new ListResponseVO<>();
|
||||
vo.setCode(errorCode).setMessage(message);
|
||||
return vo;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ListResponseVO<T> setCode(String code) {
|
||||
super.setCode(code);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ListResponseVO<T> setMessage(String message) {
|
||||
super.setMessage(message);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ListResponseVO<T> setBizCode(String errCode) {
|
||||
super.setBizCode(errCode);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ListResponseVO<T> setBizMessage(String errCodeDes) {
|
||||
super.setBizMessage(errCodeDes);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return super.toString();
|
||||
}
|
||||
}
|
||||
@@ -9,20 +9,20 @@ import com.yexuejc.base.constant.SymbolicConsts;
|
||||
* @author ISC
|
||||
* @date 2023/08/18
|
||||
*/
|
||||
public class ObjectResponseVO<T> extends ResponseVO {
|
||||
public class ObjectResponse<T> extends BasicResponse {
|
||||
|
||||
private T data;
|
||||
|
||||
public ObjectResponseVO() {
|
||||
public ObjectResponse() {
|
||||
}
|
||||
|
||||
public ObjectResponseVO(T data) {
|
||||
public ObjectResponse(T data) {
|
||||
this.data = data;
|
||||
setMessage(SymbolicConsts.EMPTY);
|
||||
setCode(Codes.SUCCESS.code);
|
||||
}
|
||||
|
||||
public ObjectResponseVO(T data, String code, String msg) {
|
||||
public ObjectResponse(T data, String code, String msg) {
|
||||
super(code, msg);
|
||||
this.data = data;
|
||||
}
|
||||
@@ -32,7 +32,7 @@ public class ObjectResponseVO<T> extends ResponseVO {
|
||||
return data;
|
||||
}
|
||||
|
||||
public ObjectResponseVO<T> setData(T data) {
|
||||
public ObjectResponse<T> setData(T data) {
|
||||
this.data = data;
|
||||
return this;
|
||||
}
|
||||
@@ -43,8 +43,8 @@ public class ObjectResponseVO<T> extends ResponseVO {
|
||||
* @return
|
||||
* @param <T>
|
||||
*/
|
||||
public static <T> ObjectResponseVO<T> success(T data) {
|
||||
return new ObjectResponseVO<>(data);
|
||||
public static <T> ObjectResponse<T> success(T data) {
|
||||
return new ObjectResponse<>(data);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -52,8 +52,8 @@ public class ObjectResponseVO<T> extends ResponseVO {
|
||||
* @param message
|
||||
* @return
|
||||
*/
|
||||
public static ObjectResponseVO<String> fail(String message) {
|
||||
ObjectResponseVO<String> vo = new ObjectResponseVO<>();
|
||||
public static ObjectResponse<String> fail(String message) {
|
||||
ObjectResponse<String> vo = new ObjectResponse<>();
|
||||
vo.setCode(Codes.SYSTEM_ERROR.code).setMessage(message);
|
||||
return vo;
|
||||
}
|
||||
@@ -64,32 +64,32 @@ public class ObjectResponseVO<T> extends ResponseVO {
|
||||
* @param message
|
||||
* @return
|
||||
*/
|
||||
public static ObjectResponseVO<String> fail(String errorCode, String message) {
|
||||
ObjectResponseVO<String> vo = new ObjectResponseVO<>();
|
||||
public static ObjectResponse<String> fail(String errorCode, String message) {
|
||||
ObjectResponse<String> vo = new ObjectResponse<>();
|
||||
vo.setCode(errorCode).setMessage(message);
|
||||
return vo;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ObjectResponseVO<T> setCode(String code) {
|
||||
public ObjectResponse<T> setCode(String code) {
|
||||
super.setCode(code);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ObjectResponseVO<T> setMessage(String message) {
|
||||
public ObjectResponse<T> setMessage(String message) {
|
||||
super.setMessage(message);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ObjectResponseVO<T> setBizCode(String bizCode) {
|
||||
public ObjectResponse<T> setBizCode(String bizCode) {
|
||||
super.setBizCode(bizCode);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ObjectResponseVO<T> setBizMessage(String bizMessage) {
|
||||
public ObjectResponse<T> setBizMessage(String bizMessage) {
|
||||
super.setBizMessage(bizMessage);
|
||||
return this;
|
||||
}
|
||||
@@ -1,16 +1,16 @@
|
||||
package com.yexuejc.base.pojo;
|
||||
|
||||
import com.yexuejc.base.util.JsonUtil;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import com.yexuejc.base.util.JsonUtil;
|
||||
|
||||
/**
|
||||
* 解密前的请求参数格式
|
||||
*
|
||||
* @author: maxf
|
||||
* @date: 2018/5/12 14:52
|
||||
*/
|
||||
public class ParamsPO implements Serializable {
|
||||
public class SignRequest implements Serializable {
|
||||
private static final long serialVersionUID = 9171765814642105098L;
|
||||
|
||||
/**
|
||||
58
src/main/java/com/yexuejc/base/pojo/SignResponse.java
Normal file
58
src/main/java/com/yexuejc/base/pojo/SignResponse.java
Normal file
@@ -0,0 +1,58 @@
|
||||
package com.yexuejc.base.pojo;
|
||||
|
||||
/**
|
||||
* 签名返回
|
||||
*
|
||||
* @author maxiaofeng
|
||||
* @date 2025/9/25 17:35
|
||||
*/
|
||||
public class SignResponse<T> extends ObjectResponse<T> {
|
||||
/**
|
||||
* 签名
|
||||
*/
|
||||
private String sign;
|
||||
|
||||
public String getSign() {
|
||||
return sign;
|
||||
}
|
||||
|
||||
public SignResponse<T> setSign(String sign) {
|
||||
this.sign = sign;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SignResponse<T> setData(T data) {
|
||||
super.setData(data);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SignResponse<T> setMessage(String message) {
|
||||
super.setMessage(message);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SignResponse<T> setCode(String code) {
|
||||
super.setCode(code);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SignResponse<T> setBizCode(String bizCode) {
|
||||
super.setBizCode(bizCode);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SignResponse<T> setBizMessage(String message) {
|
||||
super.setBizMessage(message);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return super.toString();
|
||||
}
|
||||
}
|
||||
@@ -1,17 +1,32 @@
|
||||
package com.yexuejc.base.util;
|
||||
|
||||
import com.yexuejc.base.annotation.ToUeProperty;
|
||||
|
||||
import java.io.*;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.lang.reflect.Array;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import com.yexuejc.base.annotation.ToUeProperty;
|
||||
import com.yexuejc.base.exception.BaseException;
|
||||
|
||||
/**
|
||||
* 对象工具:对类的操作
|
||||
*
|
||||
@@ -27,6 +42,160 @@ public class ObjUtil {
|
||||
private ObjUtil() {
|
||||
}
|
||||
|
||||
/**
|
||||
* 将对象转换为BigDecimal
|
||||
*
|
||||
* @param obj 要转换的对象
|
||||
* @return BigDecimal
|
||||
*/
|
||||
public static BigDecimal parseBigDecimal(Object obj) {
|
||||
if (StrUtil.isEmpty(obj)) {
|
||||
return BigDecimal.ZERO;
|
||||
}
|
||||
if (obj instanceof BigDecimal) {
|
||||
return (BigDecimal) obj;
|
||||
}
|
||||
return new BigDecimal(obj.toString());
|
||||
}
|
||||
|
||||
/**
|
||||
* 比较两个对象的长度或大小
|
||||
*
|
||||
* @param obj1 第一个对象
|
||||
* @param obj2 第二个对象
|
||||
* @return 长度相等返回true,否则返回false
|
||||
*/
|
||||
public static boolean compareLength(Object obj1, Object obj2) {
|
||||
// 如果两个对象都为null,返回true
|
||||
if (obj1 == null && obj2 == null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// 如果只有一个对象为null,返回false
|
||||
if (obj1 == null || obj2 == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 如果是字符串类型,比较字符数
|
||||
if (obj1 instanceof String && obj2 instanceof String) {
|
||||
String str1 = (String) obj1;
|
||||
String str2 = (String) obj2;
|
||||
return str1.length() == str2.length();
|
||||
}
|
||||
|
||||
// 如果是集合类型,比较元素数量
|
||||
if (obj1 instanceof Collection<?> && obj2 instanceof Collection<?>) {
|
||||
Collection<?> coll1 = (Collection<?>) obj1;
|
||||
Collection<?> coll2 = (Collection<?>) obj2;
|
||||
return coll1.size() == coll2.size();
|
||||
}
|
||||
|
||||
// 如果是数组类型,比较数组长度
|
||||
if (obj1.getClass().isArray() && obj2.getClass().isArray()) {
|
||||
return java.lang.reflect.Array.getLength(obj1) == java.lang.reflect.Array.getLength(obj2);
|
||||
}
|
||||
|
||||
// 其他类型返回false
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 判断多个对象是否相等
|
||||
*
|
||||
* @param obj1 目标对象
|
||||
* @param tagObjs 标记对象
|
||||
* @return 多个对象是否相等的判断结果
|
||||
*/
|
||||
public static boolean equals(Object obj1, Object... tagObjs) {
|
||||
for (Object tagObj : tagObjs) {
|
||||
if (!isEqual(obj1, tagObj)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断两个对象是否相等
|
||||
*
|
||||
* @param obj1 目标对象
|
||||
* @param obj2 标记对象
|
||||
* @return 对象是否相等的判断结果
|
||||
*/
|
||||
private static boolean isEqual(Object obj1, Object obj2) {
|
||||
// 使用标准的Objects.equals处理基本的相等情况
|
||||
if (java.util.Objects.equals(obj1, obj2)) {
|
||||
return true;
|
||||
}
|
||||
// 特殊处理:将null与空字符串视为相等
|
||||
if ((obj1 == null && "".equals(obj2)) || (obj2 == null && "".equals(obj1))) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// 处理数值类型的比较
|
||||
if (obj1 instanceof Number && obj2 instanceof Number) {
|
||||
Number n1 = (Number) obj1;
|
||||
Number n2 = (Number) obj2;
|
||||
return n1.doubleValue() == n2.doubleValue();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取对象的子对象
|
||||
* <p>支持的对象类型:String、数组和集合(List,Set)。不支持Map。</p>
|
||||
*
|
||||
* @param obj 目标对象
|
||||
* @param beginIndex 开始索引
|
||||
* @param endIndex 结束索引
|
||||
* @return 子字符串
|
||||
* @throws BaseException 开始索引大于结束索引时抛出异常
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <T> T sub(T obj, int beginIndex, int endIndex) throws BaseException {
|
||||
if (StrUtil.isEmpty(obj)) {
|
||||
return obj;
|
||||
}
|
||||
if (beginIndex < 0) {
|
||||
beginIndex = 0;
|
||||
}
|
||||
if (endIndex < beginIndex) {
|
||||
throw new BaseException("开始索引大于结束索引。");
|
||||
}
|
||||
|
||||
if (obj instanceof String) {
|
||||
String str = (String) obj;
|
||||
if (endIndex > str.length()) {
|
||||
endIndex = str.length();
|
||||
}
|
||||
return (T) str.substring(beginIndex, endIndex);
|
||||
}
|
||||
if (obj.getClass().isArray()) {
|
||||
if (endIndex > Array.getLength(obj)) {
|
||||
endIndex = Array.getLength(obj);
|
||||
}
|
||||
int newSize = endIndex - beginIndex;
|
||||
T newArray = (T) Array.newInstance(obj.getClass().getComponentType(), newSize);
|
||||
|
||||
for (int i = 0; i < newSize; i++) {
|
||||
Array.set(newArray, i, Array.get(obj, beginIndex + i));
|
||||
}
|
||||
return newArray;
|
||||
}
|
||||
if (obj instanceof Collection<?>) {
|
||||
Collection<?> coll = (Collection<?>) obj;
|
||||
if (endIndex > coll.size()) {
|
||||
endIndex = coll.size();
|
||||
}
|
||||
int newSize = endIndex - beginIndex;
|
||||
return (T) coll.stream().skip(beginIndex).limit(newSize).collect(Collectors.toList());
|
||||
}
|
||||
throw new BaseException("不支持的类型。");
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>把对象按照{@link ToUeProperty}注解转换</p>
|
||||
* <i>字段值为空不输出</i>
|
||||
@@ -228,10 +397,8 @@ public class ObjUtil {
|
||||
if (null == obj) {
|
||||
return false;
|
||||
}
|
||||
boolean b = obj.getClass().isPrimitive()
|
||||
|| obj instanceof Integer || obj instanceof Character || obj instanceof Boolean
|
||||
|| obj instanceof Number || obj instanceof String || obj instanceof Double || obj instanceof Float
|
||||
|| obj instanceof Short || obj instanceof Long || obj instanceof Byte;
|
||||
boolean b = obj.getClass()
|
||||
.isPrimitive() || obj instanceof Integer || obj instanceof Character || obj instanceof Boolean || obj instanceof Number || obj instanceof String || obj instanceof Double || obj instanceof Float || obj instanceof Short || obj instanceof Long || obj instanceof Byte;
|
||||
if (b) {
|
||||
return true;
|
||||
}
|
||||
@@ -298,8 +465,7 @@ public class ObjUtil {
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.warning(lowerCaseFirstChar(f.getName()) + " field copy failed. " + e.getMessage());
|
||||
log.log(Level.FINER, lowerCaseFirstChar(f.getName()) +
|
||||
" field copy failed. The exception information is as follows:", e);
|
||||
log.log(Level.FINER, lowerCaseFirstChar(f.getName()) + " field copy failed. The exception information is as follows:", e);
|
||||
}
|
||||
});
|
||||
return o;
|
||||
@@ -341,8 +507,7 @@ public class ObjUtil {
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.warning(lowerCaseFirstChar(fieldName) + " field copy failed. " + e.getMessage());
|
||||
log.log(Level.FINER, lowerCaseFirstChar(fieldName) +
|
||||
" field copy failed. The exception information is as follows:", e);
|
||||
log.log(Level.FINER, lowerCaseFirstChar(fieldName) + " field copy failed. The exception information is as follows:", e);
|
||||
}
|
||||
});
|
||||
return o;
|
||||
@@ -359,9 +524,7 @@ public class ObjUtil {
|
||||
List<Method> methodList = new ArrayList<>();
|
||||
Method[] methods = beanClass.getDeclaredMethods();
|
||||
if (StrUtil.isNotEmpty(startsWith)) {
|
||||
methodList.addAll(Arrays.stream(methods)
|
||||
.filter(method -> method.getName().startsWith(startsWith))
|
||||
.collect(Collectors.toList()));
|
||||
methodList.addAll(Arrays.stream(methods).filter(method -> method.getName().startsWith(startsWith)).collect(Collectors.toList()));
|
||||
} else {
|
||||
methodList.addAll(Arrays.asList(methods));
|
||||
}
|
||||
|
||||
@@ -1,20 +1,27 @@
|
||||
package com.yexuejc.base.util;
|
||||
|
||||
import com.yexuejc.base.constant.ExpCode;
|
||||
import com.yexuejc.base.exception.BaseException;
|
||||
|
||||
import java.lang.reflect.Array;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.SecureRandom;
|
||||
import java.util.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import com.yexuejc.base.constant.ExpCode;
|
||||
import com.yexuejc.base.exception.BaseException;
|
||||
|
||||
/**
|
||||
* 字符串工具类
|
||||
*
|
||||
@@ -65,8 +72,7 @@ public final class StrUtil {
|
||||
return ((Optional<?>) obj).isEmpty();
|
||||
} else if (obj instanceof CharSequence) {
|
||||
return ((CharSequence) obj).length() == 0;
|
||||
} else if (obj.getClass()
|
||||
.isArray()) {
|
||||
} else if (obj.getClass().isArray()) {
|
||||
return Array.getLength(obj) == 0;
|
||||
} else if (obj instanceof Collection) {
|
||||
return ((Collection<?>) obj).isEmpty();
|
||||
@@ -85,9 +91,7 @@ public final class StrUtil {
|
||||
* @return
|
||||
*/
|
||||
public static String genUUID() {
|
||||
return UUID.randomUUID()
|
||||
.toString()
|
||||
.replaceAll("-", "");
|
||||
return UUID.randomUUID().toString().replaceAll("-", "");
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -122,9 +126,7 @@ public final class StrUtil {
|
||||
* @return
|
||||
*/
|
||||
public static String genNum() {
|
||||
int hashCode = UUID.randomUUID()
|
||||
.toString()
|
||||
.hashCode();
|
||||
int hashCode = UUID.randomUUID().toString().hashCode();
|
||||
StringBuilder num = new StringBuilder();
|
||||
if (hashCode < 0) {
|
||||
hashCode = -hashCode;
|
||||
@@ -132,8 +134,7 @@ public final class StrUtil {
|
||||
} else {
|
||||
num.append("1");
|
||||
}
|
||||
return num.append(String.format("%010d", hashCode))
|
||||
.substring(0, 8);
|
||||
return num.append(String.format("%010d", hashCode)).substring(0, 8);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -340,10 +341,7 @@ public final class StrUtil {
|
||||
for (String key : keys) {
|
||||
Object value = sortedParams.get(key);
|
||||
if (isNotEmpty(key) && isNotEmpty(value)) {
|
||||
content.append(index == 0 ? "" : "&")
|
||||
.append(key)
|
||||
.append("=")
|
||||
.append(value);
|
||||
content.append(index == 0 ? "" : "&").append(key).append("=").append(value);
|
||||
++index;
|
||||
}
|
||||
}
|
||||
@@ -464,17 +462,14 @@ public final class StrUtil {
|
||||
if (cause != null) {
|
||||
StringBuilder msg = new StringBuilder();
|
||||
if (isNotEmpty(cause.getMessage())) {
|
||||
msg.append(cause.getMessage())
|
||||
.append(NEW_LINE);
|
||||
msg.append(cause.getMessage()).append(NEW_LINE);
|
||||
}
|
||||
String causedMsg = printStackTrace(cause, (eMessage) -> {
|
||||
if (isNotEmpty(eMessage)) {
|
||||
msg.append(eMessage)
|
||||
.append(NEW_LINE);
|
||||
msg.append(eMessage).append(NEW_LINE);
|
||||
}
|
||||
});
|
||||
return msg.append(causedMsg)
|
||||
.toString();
|
||||
return msg.append(causedMsg).toString();
|
||||
}
|
||||
return "";
|
||||
}
|
||||
@@ -493,30 +488,24 @@ public final class StrUtil {
|
||||
|
||||
private static String printStackTrace(Throwable cause, Consumer<String> consumer) {
|
||||
if (cause != null) {
|
||||
String err = "\tat %s.%s(%s.java:%d)";
|
||||
StringBuilder sb = new StringBuilder();
|
||||
String cClass = cause.getClass()
|
||||
.getName();
|
||||
String cClass = cause.getClass().getName();
|
||||
String eMessage = cause.getMessage();
|
||||
StackTraceElement[] stackTrace = cause.getStackTrace();
|
||||
Throwable caused = cause.getCause();
|
||||
while (caused != null) {
|
||||
cClass = caused.getClass()
|
||||
.getName();
|
||||
eMessage = caused.getMessage();
|
||||
stackTrace = caused.getStackTrace();
|
||||
caused = caused.getCause();
|
||||
consumer.accept(eMessage);
|
||||
Throwable c = cause.getCause();
|
||||
while (c != null) {
|
||||
cClass = c.getClass().getName();
|
||||
eMessage = c.getMessage();
|
||||
stackTrace = c.getStackTrace();
|
||||
c = c.getCause();
|
||||
}
|
||||
sb.append("Caused by: ")
|
||||
.append(cClass)
|
||||
.append(": ")
|
||||
.append(eMessage)
|
||||
.append(NEW_LINE);
|
||||
sb.append("Caused by: ").append(cClass).append(": ").append(eMessage).append(System.lineSeparator());
|
||||
for (StackTraceElement element : stackTrace) {
|
||||
sb.append("\tat ");
|
||||
sb.append(String.format(ERROR_MESSAGE_FORMAT, element.getClassName(), element.getMethodName(), element.getFileName(),
|
||||
element.getLineNumber()));
|
||||
sb.append(NEW_LINE);
|
||||
String className = element.getClassName();
|
||||
String simpleClassName = className.substring(className.lastIndexOf('.') + 1);
|
||||
sb.append(String.format(err, className, element.getMethodName(), simpleClassName, element.getLineNumber()))
|
||||
.append(System.lineSeparator());
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
232
src/test/java/com/yexuejc/base/encrypt/AESEnhancedTest.java
Normal file
232
src/test/java/com/yexuejc/base/encrypt/AESEnhancedTest.java
Normal file
@@ -0,0 +1,232 @@
|
||||
package com.yexuejc.base.encrypt;
|
||||
|
||||
import com.yexuejc.base.exception.BaseException;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.DisplayName;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
/**
|
||||
* AES加密增强测试类 - 验证优化后的安全性和功能
|
||||
*
|
||||
* @author optimization
|
||||
* @date 2025/09/23
|
||||
*/
|
||||
@DisplayName("AES加密增强测试")
|
||||
class AESEnhancedTest {
|
||||
|
||||
private AES aes;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
aes = AES.builder();
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("测试密钥和IV必须设置")
|
||||
void testKeyAndIvRequired() {
|
||||
// 测试未设置密钥时抛出异常
|
||||
IllegalStateException exception = assertThrows(IllegalStateException.class, () -> {
|
||||
aes.encrypt("test data");
|
||||
});
|
||||
assertTrue(exception.getMessage().contains("AES密钥未设置"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("测试密钥长度验证")
|
||||
void testKeyLengthValidation() {
|
||||
// 测试无效密钥长度
|
||||
IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> {
|
||||
aes.setKey("short");
|
||||
});
|
||||
assertTrue(exception.getMessage().contains("AES密钥长度必须是16、24或32字节"));
|
||||
|
||||
// 测试有效密钥长度
|
||||
assertDoesNotThrow(() -> {
|
||||
aes.setKey("1234567890123456"); // 16字节
|
||||
aes.setKey("123456789012345678901234"); // 24字节
|
||||
aes.setKey("12345678901234567890123456789012"); // 32字节
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("测试IV长度验证")
|
||||
void testIvLengthValidation() {
|
||||
// 设置有效密钥
|
||||
aes.setKey("1234567890123456");
|
||||
|
||||
// 测试无效IV长度
|
||||
IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> {
|
||||
aes.setIv("short");
|
||||
});
|
||||
assertTrue(exception.getMessage().contains("AES初始向量长度必须是16字节"));
|
||||
|
||||
// 测试有效IV长度
|
||||
assertDoesNotThrow(() -> {
|
||||
aes.setIv("1234567890123456"); // 16字节
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("测试输入参数验证")
|
||||
void testInputValidation() {
|
||||
aes.setKey("1234567890123456")
|
||||
.setIv("1234567890123456")
|
||||
.setAlgorithm(AES.ALGORITHM.AES_CBC_PKCS5Padding);
|
||||
|
||||
// 测试空输入
|
||||
IllegalArgumentException encryptException = assertThrows(IllegalArgumentException.class, () -> {
|
||||
aes.encrypt(null);
|
||||
});
|
||||
assertTrue(encryptException.getMessage().contains("加密数据不能为空"));
|
||||
|
||||
IllegalArgumentException decryptException = assertThrows(IllegalArgumentException.class, () -> {
|
||||
aes.decrypt(null);
|
||||
});
|
||||
assertTrue(decryptException.getMessage().contains("解密数据不能为空"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("测试字符集设置验证")
|
||||
void testCharsetValidation() {
|
||||
IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> {
|
||||
aes.setCharset(null);
|
||||
});
|
||||
assertTrue(exception.getMessage().contains("字符集不能为空"));
|
||||
|
||||
// 测试有效字符集设置
|
||||
assertDoesNotThrow(() -> {
|
||||
aes.setCharset(StandardCharsets.UTF_8);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("测试ECB模式不需要IV")
|
||||
void testECBModeWithoutIV() throws BaseException {
|
||||
String data = "Hello World!";
|
||||
aes.setKey("1234567890123456")
|
||||
.setAlgorithm(AES.ALGORITHM.AES_ECB_PKCS5Padding);
|
||||
|
||||
// ECB模式不需要IV
|
||||
String encrypted = aes.encrypt(data);
|
||||
assertNotNull(encrypted);
|
||||
assertFalse(encrypted.isEmpty());
|
||||
|
||||
String decrypted = aes.decrypt(encrypted);
|
||||
assertEquals(data, decrypted);
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("测试完整的加密解密流程")
|
||||
void testCompleteEncryptDecryptFlow() throws BaseException {
|
||||
String originalData = "这是一个测试字符串包含中文!";
|
||||
|
||||
aes.setKey("1234567890123456")
|
||||
.setIv("1234567890123456")
|
||||
.setAlgorithm(AES.ALGORITHM.AES_CBC_PKCS5Padding)
|
||||
.setCharset(StandardCharsets.UTF_8);
|
||||
|
||||
String encrypted = aes.encrypt(originalData);
|
||||
assertNotNull(encrypted);
|
||||
assertNotEquals(originalData, encrypted);
|
||||
|
||||
String decrypted = aes.decrypt(encrypted);
|
||||
assertEquals(originalData, decrypted);
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("测试不同AES算法模式")
|
||||
void testDifferentAlgorithms() throws BaseException {
|
||||
String data = "Test Data";
|
||||
String key = "1234567890123456";
|
||||
String iv = "1234567890123456";
|
||||
|
||||
AES.ALGORITHM[] algorithms = {
|
||||
AES.ALGORITHM.AES_CBC_PKCS5Padding,
|
||||
AES.ALGORITHM.AES_OFB_PKCS5Padding,
|
||||
AES.ALGORITHM.AES_ECB_PKCS5Padding
|
||||
};
|
||||
|
||||
for (AES.ALGORITHM algorithm : algorithms) {
|
||||
AES testAes = AES.builder()
|
||||
.setKey(key)
|
||||
.setAlgorithm(algorithm);
|
||||
|
||||
if (!algorithm.code.contains("ECB")) {
|
||||
testAes.setIv(iv);
|
||||
}
|
||||
|
||||
String encrypted = testAes.encrypt(data);
|
||||
String decrypted = testAes.decrypt(encrypted);
|
||||
|
||||
assertEquals(data, decrypted, "Algorithm " + algorithm.code + " failed");
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("测试建造者模式")
|
||||
void testBuilderPattern() {
|
||||
AES aes1 = AES.builder();
|
||||
AES aes2 = AES.builder();
|
||||
|
||||
// 现在返回不同的实例,避免状态共享
|
||||
assertNotNull(aes1);
|
||||
assertNotNull(aes2);
|
||||
assertNotSame(aes1, aes2); // 确认不是单例
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("测试解密异常处理")
|
||||
void testDecryptErrorHandling() {
|
||||
aes.setKey("1234567890123456")
|
||||
.setIv("1234567890123456")
|
||||
.setAlgorithm(AES.ALGORITHM.AES_CBC_PKCS5Padding);
|
||||
|
||||
// 测试无效Base64数据
|
||||
BaseException exception = assertThrows(BaseException.class, () -> {
|
||||
aes.decrypt("invalid_base64_data");
|
||||
});
|
||||
assertNotNull(exception.getErrorCode());
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("测试不同密钥长度")
|
||||
void testDifferentKeyLengths() throws BaseException {
|
||||
String data = "Test Data";
|
||||
String iv = "1234567890123456";
|
||||
|
||||
// 测试16字节密钥
|
||||
AES aes16 = AES.builder()
|
||||
.setKey("1234567890123456")
|
||||
.setIv(iv)
|
||||
.setAlgorithm(AES.ALGORITHM.AES_CBC_PKCS5Padding);
|
||||
|
||||
String encrypted16 = aes16.encrypt(data);
|
||||
String decrypted16 = aes16.decrypt(encrypted16);
|
||||
assertEquals(data, decrypted16);
|
||||
|
||||
// 测试24字节密钥
|
||||
AES aes24 = AES.builder()
|
||||
.setKey("123456789012345678901234")
|
||||
.setIv(iv)
|
||||
.setAlgorithm(AES.ALGORITHM.AES_CBC_PKCS5Padding);
|
||||
|
||||
String encrypted24 = aes24.encrypt(data);
|
||||
String decrypted24 = aes24.decrypt(encrypted24);
|
||||
assertEquals(data, decrypted24);
|
||||
|
||||
// 测试32字节密钥
|
||||
AES aes32 = AES.builder()
|
||||
.setKey("12345678901234567890123456789012")
|
||||
.setIv(iv)
|
||||
.setAlgorithm(AES.ALGORITHM.AES_CBC_PKCS5Padding);
|
||||
|
||||
String encrypted32 = aes32.encrypt(data);
|
||||
String decrypted32 = aes32.decrypt(encrypted32);
|
||||
assertEquals(data, decrypted32);
|
||||
}
|
||||
}
|
||||
237
src/test/java/com/yexuejc/base/util/ObjUtilEnhancedTest.java
Normal file
237
src/test/java/com/yexuejc/base/util/ObjUtilEnhancedTest.java
Normal file
@@ -0,0 +1,237 @@
|
||||
package com.yexuejc.base.util;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.DisplayName;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
/**
|
||||
* ObjUtil增强测试类 - 验证优化后的异常处理和功能
|
||||
*
|
||||
* @author optimization
|
||||
* @date 2025/09/23
|
||||
*/
|
||||
@DisplayName("ObjUtil增强测试")
|
||||
class ObjUtilEnhancedTest {
|
||||
|
||||
@Test
|
||||
@DisplayName("测试基本字段复制功能")
|
||||
void testBasicFieldCopy() throws Exception {
|
||||
SourceObject source = new SourceObject();
|
||||
source.setName("Test Name");
|
||||
source.setAge(25);
|
||||
source.setEmail("test@example.com");
|
||||
|
||||
TargetObject target = ObjUtil.copy(source, TargetObject.class, null, null);
|
||||
|
||||
assertNotNull(target);
|
||||
assertEquals(source.getName(), target.getName());
|
||||
assertEquals(source.getAge(), target.getAge());
|
||||
assertEquals(source.getEmail(), target.getEmail());
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("测试包含字段过滤")
|
||||
void testIncludeFieldFiltering() throws Exception {
|
||||
SourceObject source = new SourceObject();
|
||||
source.setName("Test Name");
|
||||
source.setAge(25);
|
||||
source.setEmail("test@example.com");
|
||||
|
||||
List<String> includeFields = Arrays.asList("name", "age");
|
||||
TargetObject target = ObjUtil.copy(source, TargetObject.class, includeFields, null);
|
||||
|
||||
assertNotNull(target);
|
||||
assertEquals(source.getName(), target.getName());
|
||||
assertEquals(source.getAge(), target.getAge());
|
||||
assertNull(target.getEmail()); // 不在包含列表中
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("测试排除字段过滤")
|
||||
void testExcludeFieldFiltering() throws Exception {
|
||||
SourceObject source = new SourceObject();
|
||||
source.setName("Test Name");
|
||||
source.setAge(25);
|
||||
source.setEmail("test@example.com");
|
||||
|
||||
List<String> excludeFields = Arrays.asList("email");
|
||||
TargetObject target = ObjUtil.copy(source, TargetObject.class, null, excludeFields);
|
||||
|
||||
assertNotNull(target);
|
||||
assertEquals(source.getName(), target.getName());
|
||||
assertEquals(source.getAge(), target.getAge());
|
||||
assertNull(target.getEmail()); // 被排除
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("测试使用Setter方法复制")
|
||||
void testCopyWithSetter() throws Exception {
|
||||
SourceObject source = new SourceObject();
|
||||
source.setName("Test Name");
|
||||
source.setAge(25);
|
||||
|
||||
TargetObjectWithSetter target = ObjUtil.copy(source, TargetObjectWithSetter.class, true);
|
||||
|
||||
assertNotNull(target);
|
||||
assertEquals(source.getName(), target.getName());
|
||||
assertEquals(source.getAge(), target.getAge());
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("测试字段不匹配的处理")
|
||||
void testFieldMismatchHandling() throws Exception {
|
||||
SourceObjectWithExtraField source = new SourceObjectWithExtraField();
|
||||
source.setName("Test Name");
|
||||
source.setAge(25);
|
||||
source.setExtraField("Extra Value");
|
||||
|
||||
// 目标类没有extraField字段
|
||||
TargetObject target = ObjUtil.copy(source, TargetObject.class, null, null);
|
||||
|
||||
assertNotNull(target);
|
||||
assertEquals(source.getName(), target.getName());
|
||||
assertEquals(source.getAge(), target.getAge());
|
||||
// extraField应该被忽略,不会导致异常
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("测试空源对象处理")
|
||||
void testNullSourceHandling() {
|
||||
assertThrows(NullPointerException.class, () -> {
|
||||
ObjUtil.copy(null, TargetObject.class, null, null);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("测试获取所有字段功能")
|
||||
void testGetAllFields() {
|
||||
List<java.lang.reflect.Field> fields = ObjUtil.getAllFields(ChildObject.class);
|
||||
|
||||
assertNotNull(fields);
|
||||
assertTrue(fields.size() >= 3); // 至少包含child字段和父类的两个字段
|
||||
|
||||
// 验证包含父类字段
|
||||
boolean hasParentField1 = fields.stream().anyMatch(f -> "parentField1".equals(f.getName()));
|
||||
boolean hasParentField2 = fields.stream().anyMatch(f -> "parentField2".equals(f.getName()));
|
||||
boolean hasChildField = fields.stream().anyMatch(f -> "childField".equals(f.getName()));
|
||||
|
||||
assertTrue(hasParentField1);
|
||||
assertTrue(hasParentField2);
|
||||
assertTrue(hasChildField);
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("测试获取所有Getter方法功能")
|
||||
void testGetAllGetterMethods() {
|
||||
List<java.lang.reflect.Method> methods = ObjUtil.getAllGetterMethods(ChildObject.class, "get");
|
||||
|
||||
assertNotNull(methods);
|
||||
assertTrue(methods.size() >= 3); // 至少包含三个getter方法
|
||||
|
||||
// 验证包含父类方法
|
||||
boolean hasGetParentField1 = methods.stream().anyMatch(m -> "getParentField1".equals(m.getName()));
|
||||
boolean hasGetParentField2 = methods.stream().anyMatch(m -> "getParentField2".equals(m.getName()));
|
||||
boolean hasGetChildField = methods.stream().anyMatch(m -> "getChildField".equals(m.getName()));
|
||||
|
||||
assertTrue(hasGetParentField1);
|
||||
assertTrue(hasGetParentField2);
|
||||
assertTrue(hasGetChildField);
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("测试首字母小写工具方法")
|
||||
void testLowerCaseFirstChar() {
|
||||
assertEquals("test", ObjUtil.lowerCaseFirstChar("Test"));
|
||||
assertEquals("tEST", ObjUtil.lowerCaseFirstChar("TEST"));
|
||||
assertEquals("", ObjUtil.lowerCaseFirstChar(""));
|
||||
assertNull(ObjUtil.lowerCaseFirstChar(null));
|
||||
assertEquals("a", ObjUtil.lowerCaseFirstChar("A"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("测试目标类没有默认构造函数的情况")
|
||||
void testTargetClassWithoutDefaultConstructor() {
|
||||
SourceObject source = new SourceObject();
|
||||
source.setName("Test");
|
||||
|
||||
assertThrows(Exception.class, () -> {
|
||||
ObjUtil.copy(source, ClassWithoutDefaultConstructor.class, null, null);
|
||||
});
|
||||
}
|
||||
|
||||
// 测试用的内部类
|
||||
|
||||
static class SourceObject {
|
||||
private String name;
|
||||
private Integer age;
|
||||
private String email;
|
||||
|
||||
public String getName() { return name; }
|
||||
public void setName(String name) { this.name = name; }
|
||||
public Integer getAge() { return age; }
|
||||
public void setAge(Integer age) { this.age = age; }
|
||||
public String getEmail() { return email; }
|
||||
public void setEmail(String email) { this.email = email; }
|
||||
}
|
||||
|
||||
static class SourceObjectWithExtraField extends SourceObject {
|
||||
private String extraField;
|
||||
|
||||
public String getExtraField() { return extraField; }
|
||||
public void setExtraField(String extraField) { this.extraField = extraField; }
|
||||
}
|
||||
|
||||
static class TargetObject {
|
||||
private String name;
|
||||
private Integer age;
|
||||
private String email;
|
||||
|
||||
public String getName() { return name; }
|
||||
public void setName(String name) { this.name = name; }
|
||||
public Integer getAge() { return age; }
|
||||
public void setAge(Integer age) { this.age = age; }
|
||||
public String getEmail() { return email; }
|
||||
public void setEmail(String email) { this.email = email; }
|
||||
}
|
||||
|
||||
static class TargetObjectWithSetter {
|
||||
private String name;
|
||||
private Integer age;
|
||||
|
||||
public String getName() { return name; }
|
||||
public void setName(String name) { this.name = name; }
|
||||
public Integer getAge() { return age; }
|
||||
public void setAge(Integer age) { this.age = age; }
|
||||
}
|
||||
|
||||
static class ParentObject {
|
||||
private String parentField1;
|
||||
private String parentField2;
|
||||
|
||||
public String getParentField1() { return parentField1; }
|
||||
public void setParentField1(String parentField1) { this.parentField1 = parentField1; }
|
||||
public String getParentField2() { return parentField2; }
|
||||
public void setParentField2(String parentField2) { this.parentField2 = parentField2; }
|
||||
}
|
||||
|
||||
static class ChildObject extends ParentObject {
|
||||
private String childField;
|
||||
|
||||
public String getChildField() { return childField; }
|
||||
public void setChildField(String childField) { this.childField = childField; }
|
||||
}
|
||||
|
||||
static class ClassWithoutDefaultConstructor {
|
||||
private String name;
|
||||
|
||||
public ClassWithoutDefaultConstructor(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getName() { return name; }
|
||||
}
|
||||
}
|
||||
288
src/test/java/com/yexuejc/base/util/StrUtilEnhancedTest.java
Normal file
288
src/test/java/com/yexuejc/base/util/StrUtilEnhancedTest.java
Normal file
@@ -0,0 +1,288 @@
|
||||
package com.yexuejc.base.util;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.DisplayName;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.RepeatedTest;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
/**
|
||||
* StrUtil增强测试类 - 验证优化后的性能和线程安全性
|
||||
*
|
||||
* @author optimization
|
||||
* @date 2025/09/23
|
||||
*/
|
||||
@DisplayName("StrUtil增强测试")
|
||||
class StrUtilEnhancedTest {
|
||||
|
||||
@Test
|
||||
@DisplayName("测试MD5计算的一致性")
|
||||
void testMD5Consistency() {
|
||||
String input = "Hello World!";
|
||||
String expected = "ed076287532e86365e841e92bfc50d8c"; // 已知MD5值
|
||||
|
||||
String result1 = StrUtil.toMD5(input);
|
||||
String result2 = StrUtil.toMD5(input);
|
||||
|
||||
assertEquals(expected, result1);
|
||||
assertEquals(result1, result2);
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("测试SHA256计算的一致性")
|
||||
void testSHA256Consistency() {
|
||||
String input = "Hello World!";
|
||||
String expected = "7f83b1657ff1fc53b92dc18148a1d65dfc2d4b1fa3d677284addd200126d9069"; // 已知SHA256值
|
||||
|
||||
String result1 = StrUtil.toSHA256(input);
|
||||
String result2 = StrUtil.toSHA256(input);
|
||||
|
||||
assertEquals(expected, result1);
|
||||
assertEquals(result1, result2);
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("测试MD5处理null值")
|
||||
void testMD5WithNull() {
|
||||
assertNull(StrUtil.toMD5(null));
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("测试SHA256处理null值")
|
||||
void testSHA256WithNull() {
|
||||
assertNull(StrUtil.toSHA256(null));
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("测试不支持的SHA算法")
|
||||
void testUnsupportedSHAAlgorithm() {
|
||||
String result = StrUtil.toSHA("test", "INVALID_ALGORITHM");
|
||||
assertNull(result);
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("测试中文字符的MD5计算")
|
||||
void testMD5WithChinese() {
|
||||
String input = "你好世界";
|
||||
String result = StrUtil.toMD5(input);
|
||||
|
||||
assertNotNull(result);
|
||||
assertEquals(32, result.length()); // MD5长度应为32
|
||||
assertTrue(result.matches("[a-f0-9]+"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("测试中文字符的SHA256计算")
|
||||
void testSHA256WithChinese() {
|
||||
String input = "你好世界";
|
||||
String result = StrUtil.toSHA256(input);
|
||||
|
||||
assertNotNull(result);
|
||||
assertEquals(64, result.length()); // SHA256长度应为64
|
||||
assertTrue(result.matches("[a-f0-9]+"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("测试长字符串的MD5计算")
|
||||
void testMD5WithLongString() {
|
||||
StringBuilder longString = new StringBuilder();
|
||||
for (int i = 0; i < 10000; i++) {
|
||||
longString.append("abcdefghij");
|
||||
}
|
||||
|
||||
String result = StrUtil.toMD5(longString.toString());
|
||||
assertNotNull(result);
|
||||
assertEquals(32, result.length());
|
||||
}
|
||||
|
||||
@RepeatedTest(10)
|
||||
@DisplayName("测试SecureRandom生成的随机性")
|
||||
void testCodeIdRandomness() {
|
||||
String id = "12345678901234567890123456789012"; // 32位ID
|
||||
|
||||
String coded1 = StrUtil.codeId(id);
|
||||
String coded2 = StrUtil.codeId(id);
|
||||
|
||||
assertEquals(64, coded1.length());
|
||||
assertEquals(64, coded2.length());
|
||||
|
||||
// 由于使用SecureRandom,两次编码结果应该不同
|
||||
assertNotEquals(coded1, coded2);
|
||||
|
||||
// 解码后应该得到原始ID
|
||||
String decoded1 = StrUtil.decodeId(coded1);
|
||||
String decoded2 = StrUtil.decodeId(coded2);
|
||||
|
||||
assertEquals(id, decoded1);
|
||||
assertEquals(id, decoded2);
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("测试codeId处理无效输入")
|
||||
void testCodeIdWithInvalidInput() {
|
||||
// 测试null
|
||||
assertNull(StrUtil.codeId(null));
|
||||
|
||||
// 测试长度不是32的字符串
|
||||
String shortId = "short";
|
||||
assertEquals(shortId, StrUtil.codeId(shortId));
|
||||
|
||||
String longId = "this_is_a_very_long_string_that_exceeds_32_characters";
|
||||
assertEquals(longId, StrUtil.codeId(longId));
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("测试decodeId处理无效输入")
|
||||
void testDecodeIdWithInvalidInput() {
|
||||
// 测试null
|
||||
assertNull(StrUtil.decodeId(null));
|
||||
|
||||
// 测试长度不是64的字符串
|
||||
String shortCoded = "short";
|
||||
assertEquals(shortCoded, StrUtil.decodeId(shortCoded));
|
||||
|
||||
String longCoded = "this_is_a_very_long_string_that_exceeds_64_characters_and_should_be_returned_as_is";
|
||||
assertEquals(longCoded, StrUtil.decodeId(longCoded));
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("测试线程安全性 - MD5计算")
|
||||
void testMD5ThreadSafety() throws InterruptedException {
|
||||
final int threadCount = 20;
|
||||
final int iterationsPerThread = 100;
|
||||
final String testString = "Thread Safety Test";
|
||||
final String expectedMD5 = StrUtil.toMD5(testString);
|
||||
|
||||
ExecutorService executor = Executors.newFixedThreadPool(threadCount);
|
||||
AtomicBoolean hasError = new AtomicBoolean(false);
|
||||
|
||||
for (int i = 0; i < threadCount; i++) {
|
||||
executor.submit(() -> {
|
||||
for (int j = 0; j < iterationsPerThread; j++) {
|
||||
String result = StrUtil.toMD5(testString);
|
||||
if (!expectedMD5.equals(result)) {
|
||||
hasError.set(true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
executor.shutdown();
|
||||
assertTrue(executor.awaitTermination(10, TimeUnit.SECONDS));
|
||||
assertFalse(hasError.get(), "MD5计算在多线程环境下出现不一致结果");
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("测试线程安全性 - SHA256计算")
|
||||
void testSHA256ThreadSafety() throws InterruptedException {
|
||||
final int threadCount = 20;
|
||||
final int iterationsPerThread = 100;
|
||||
final String testString = "Thread Safety Test";
|
||||
final String expectedSHA256 = StrUtil.toSHA256(testString);
|
||||
|
||||
ExecutorService executor = Executors.newFixedThreadPool(threadCount);
|
||||
AtomicBoolean hasError = new AtomicBoolean(false);
|
||||
|
||||
for (int i = 0; i < threadCount; i++) {
|
||||
executor.submit(() -> {
|
||||
for (int j = 0; j < iterationsPerThread; j++) {
|
||||
String result = StrUtil.toSHA256(testString);
|
||||
if (!expectedSHA256.equals(result)) {
|
||||
hasError.set(true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
executor.shutdown();
|
||||
assertTrue(executor.awaitTermination(10, TimeUnit.SECONDS));
|
||||
assertFalse(hasError.get(), "SHA256计算在多线程环境下出现不一致结果");
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("测试线程安全性 - codeId生成")
|
||||
void testCodeIdThreadSafety() throws InterruptedException {
|
||||
final int threadCount = 10;
|
||||
final int iterationsPerThread = 50;
|
||||
final String testId = "12345678901234567890123456789012";
|
||||
|
||||
ExecutorService executor = Executors.newFixedThreadPool(threadCount);
|
||||
Set<String> results = new HashSet<>();
|
||||
AtomicBoolean hasError = new AtomicBoolean(false);
|
||||
|
||||
for (int i = 0; i < threadCount; i++) {
|
||||
executor.submit(() -> {
|
||||
for (int j = 0; j < iterationsPerThread; j++) {
|
||||
String coded = StrUtil.codeId(testId);
|
||||
String decoded = StrUtil.decodeId(coded);
|
||||
|
||||
if (!testId.equals(decoded)) {
|
||||
hasError.set(true);
|
||||
break;
|
||||
}
|
||||
|
||||
synchronized (results) {
|
||||
results.add(coded);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
executor.shutdown();
|
||||
assertTrue(executor.awaitTermination(10, TimeUnit.SECONDS));
|
||||
assertFalse(hasError.get(), "codeId在多线程环境下解码失败");
|
||||
|
||||
// 验证生成的编码都是唯一的(由于使用SecureRandom)
|
||||
assertEquals(threadCount * iterationsPerThread, results.size(),
|
||||
"生成的编码应该都是唯一的");
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("测试性能 - MD5计算")
|
||||
void testMD5Performance() {
|
||||
String testString = "Performance test string with some content to hash";
|
||||
long startTime = System.nanoTime();
|
||||
|
||||
for (int i = 0; i < 10000; i++) {
|
||||
StrUtil.toMD5(testString);
|
||||
}
|
||||
|
||||
long endTime = System.nanoTime();
|
||||
long duration = endTime - startTime;
|
||||
|
||||
// 确保性能在合理范围内(这里只是确保能完成,具体时间取决于硬件)
|
||||
assertTrue(duration > 0, "MD5计算应该花费一些时间");
|
||||
|
||||
// 可以添加更具体的性能断言,但要考虑不同硬件的差异
|
||||
System.out.println("MD5 10000次计算耗时: " + duration / 1_000_000 + "ms");
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("测试边界值")
|
||||
void testBoundaryValues() {
|
||||
// 测试空字符串
|
||||
String emptyResult = StrUtil.toMD5("");
|
||||
assertNotNull(emptyResult);
|
||||
assertEquals(32, emptyResult.length());
|
||||
|
||||
// 测试单字符
|
||||
String singleCharResult = StrUtil.toMD5("a");
|
||||
assertNotNull(singleCharResult);
|
||||
assertEquals(32, singleCharResult.length());
|
||||
|
||||
// 测试特殊字符
|
||||
String specialCharResult = StrUtil.toMD5("!@#$%^&*()");
|
||||
assertNotNull(specialCharResult);
|
||||
assertEquals(32, specialCharResult.length());
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user