diff --git a/.gitignore b/.gitignore index 7716604..2cea96e 100644 --- a/.gitignore +++ b/.gitignore @@ -25,3 +25,4 @@ nbdist/ .nb-gradle/ *.iml~ test-output-*.log +.workbuddy/ diff --git a/Blocker修复报告.md b/Blocker修复报告.md new file mode 100644 index 0000000..70ffced --- /dev/null +++ b/Blocker修复报告.md @@ -0,0 +1,171 @@ +# Blocker 问题修复报告 + +> **项目**: `yexuejc-base` v1.6.0-jre8 +> **修复日期**: 2026-05-15 +> **修复范围**: 代码质量审计报告中的全部 🔴 Blocker 级别问题 + +--- + +## 修复总览 + +| 指标 | 数值 | +|------|------| +| 审计报告 Blocker 总数 | 7 处 | +| 实际需修复 | 6 处(8 个变更点) | +| 已修复 | 6 处(8 个变更点) | +| 无需处理 | 1 处(FileUtil.connectBytes 方法不存在) | + +--- + +## 逐项修复详情 + +### ✅ #1 RSA.java:262 — switch 表达式 → if-else-if(jre8 兼容) + +| 项目 | 内容 | +|------|------| +| **文件** | `src/main/java/com/yexuejc/base/encrypt/RSA.java` | +| **方法** | `ecKeySizeToCurveName(int keySize)` | +| **问题** | 使用了 Java 12+ 的 switch 箭头语法 (`case 256 -> ...`),jre8/jre11 分支无法编译 | +| **修复** | 改为 `if (keySize == 256) { ... } else if (...)` 链式写法 | +| **影响分支** | jre8, jre11 恢复兼容 | + +```diff +- return switch (keySize) { +- case 256 -> "secp256r1"; +- case 384 -> "secp384r1"; +- case 521 -> "secp521r1"; +- default -> throw new IllegalArgumentException(...); +- }; ++ if (keySize == 256) { ++ return "secp256r1"; ++ } else if (keySize == 384) { ++ return "secp384r1"; ++ } else if (keySize == 521) { ++ return "secp521r1"; ++ } else { ++ throw new IllegalArgumentException(...); ++ } +``` + +--- + +### ✅ #2 JwtUtil.java:52 — `instace()` → `instance()`(API 拼写错误) + +| 项目 | 内容 | +|------|------| +| **文件** | `src/main/java/com/yexuejc/base/util/JwtUtil.java` | +| **方法** | 公开静态方法 + 内部类名 | +| **问题** | 单例获取方法名拼写错误 `instace()`,影响所有外部调用者 | +| **修复** | 方法名 `instace()` → `instance()`;内部类 `Instace` → `Instance`;同步更新全部 3 处引用 | +| **影响范围** | 全分支(公开 API 变更,⚠️ 调用方需同步修改) | + +**变更点清单:** +1. L52: `public static JwtUtil instace()` → `instance()` +2. L67: `Instace.jwtUtil` → `Instance.jwtUtil` +3. L94: `Instace.jwtUtil` → `Instance.jwtUtil` +4. L95: `return instace()` → `return instance()` +5. L98: `private static class Instace` → `class Instance` + +> ⚠️ **破坏性变更**: 外部代码中所有 `JwtUtil.instace()` 调用需改为 `JwtUtil.instance()` + +--- + +### ✅ #3 JwtUtil.java:173 — `var` → 显式类型(jre8 兼容) + +| 项目 | 内容 | +|------|------| +| **文件** | `src/main/java/com/yexuejc/base/util/JwtUtil.java` | +| **位置** | `compact()` 方法内 L173 | +| **问题** | 使用 Java 10+ 的 `var` 局部变量类型推断关键字 | +| **修复** | 改为显式类型声明 `io.jsonwebtoken.JwtBuilder builder` | +| **影响分支** | jre8, jre10, jre11 恢复兼容 | + +```diff +- var builder = Jwts.builder() ++ io.jsonwebtoken.JwtBuilder builder = Jwts.builder() +``` + +--- + +### ✅ #4 RequestHeader.java:121 — `geRespTime()` → `getRespTime()` + +| 项目 | 内容 | +|------|------| +| **文件** | `src/main/java/com/yexuejc/base/http/RequestHeader.java` | +| **方法** | L121 | +| **问题** | getter 方法名缺少字母 `t`,与 `RESPONSE_TIME` 常量命名不一致 | +| **修复** | `geRespTime()` → `getRespTime()` | +| **联动修复** | `RSA.java:681` 调用处 `.geRespTime()` → `.getRespTime()` 同步修正 | + +> ⚠️ **破坏性变更**: 外部代码中所有 `.geRespTime()` 调用需改为 `.getRespTime()` + +--- + +### ✅ #5 ImgUtil.java:266 — `connectBytes()` 数组拷贝 Bug + +| 项目 | 内容 | +|------|------| +| **文件** | `src/main/java/com/yexuejc/base/util/ImgUtil.java` | +| **方法** | `connectBytes(byte[] front, byte[] after)` L264-269 | +| **问题** | 第一个 `System.arraycopy` 的 length 参数错误使用了 `after.length` 而非 `front.length`。当 front.length > after.length 时会截断数据;当 front.length < after.length 时会越界读取 | +| **修复** | `System.arraycopy(front, 0, result, 0, after.length)` → `... result, 0, front.length)` | + +```diff + public static byte[] connectBytes(byte[] front, byte[] after) { + byte[] result = new byte[front.length + after.length]; +- System.arraycopy(front, 0, result, 0, after.length); ++ System.arraycopy(front, 0, result, 0, front.length); + System.arraycopy(after, 0, result, front.length, after.length); + return result; + } +``` + +--- + +### ✅ #6 ObjUtil.java:393 — `System.out.println` → 日志框架 + +| 项目 | 内容 | +|------|------| +| **文件** | `src/main/java/com/yexuejc/base/util/ObjUtil.java` | +| **位置** | `getUnderlineMap()` 方法 catch 块 L393 | +| **问题** | 使用 `System.out.println(e.getMessage())` 输出异常信息,生产环境可能丢失关键错误日志 | +| **修复** | 替换为已有的 `java.util.logging.Logger` 实例,使用 `Level.WARNING` 级别记录完整异常堆栈 | + +```diff +- System.out.println(e.getMessage()); ++ log.log(Level.WARNING, "获取对象字段映射失败: ", e); +``` + +--- + +### ⏭ #7 FileUtil.java:295 — connectBytes(无需处理) + +| 项目 | 内容 | +|------|------| +| **状态** | **无需处理** | +| **原因** | 当前代码中 `FileUtil.java` 不存在 `connectBytes()` 方法。审计报告中该条目基于历史版本代码,该方法可能在之前重构中已被移除或从未存在于此文件中。实际仅 `ImgUtil.java` 存在此方法并已修复(见 #5)。 | + +--- + +## 破坏性变更汇总(⚠️ 调用方需关注) + +| # | 原 API | 新 API | 影响文件 | +|---|--------|--------|----------| +| 1 | `JwtUtil.instace()` | `JwtUtil.instance()` | 所有调用方 | +| 2 | `header.geRespTime()` | `header.getRespTime()` | 所有调用方 | + +--- + +## 修复后兼容性矩阵 + +| JDK 版本 | switch 表达式 | var 关键字 | 状态 | +|----------|---------------|------------|------| +| jre8 | ✅ 已改 if-else | ✅ 已改显式类型 | **可编译** | +| jre11 | ✅ 已改 if-else | ✅ 已改显式类型 | **可编译** | +| jre17 | ✅ 兼容 | ✅ 兼容 | **可编译** | +| jre21 (主) | ✅ 兼容 | ✅ 兼容 | **可编译** | + +--- + +*报告生成时间: 2026-05-15* +*修复执行: Code Reviewer Expert* diff --git a/src/main/java/com/yexuejc/base/constant/ExpCode.java b/src/main/java/com/yexuejc/base/constant/ExpCode.java index 6121b17..903722f 100644 --- a/src/main/java/com/yexuejc/base/constant/ExpCode.java +++ b/src/main/java/com/yexuejc/base/constant/ExpCode.java @@ -57,6 +57,26 @@ public class ExpCode { public static final String INVALID_KEY_LENGTH = "INVALID_KEY_LENGTH"; /** 获取字段值[{0}]失败。 */ public static final String GET_FIELD_VALUE_FAILED = "GET_FIELD_VALUE_FAILED"; + /** 读取图片数据失败。 */ + public static final String IMG_READ_FAILED = "IMG_READ_FAILED"; + /** 读取图片信息失败。 */ + public static final String IMG_INFO_READ_FAILED = "IMG_INFO_READ_FAILED"; + /** 文件类型获取失败。 */ + public static final String FILE_TYPE_GET_FAILED = "FILE_TYPE_GET_FAILED"; + /** 创建文件失败。 */ + public static final String FILE_CREATE_FAILED = "FILE_CREATE_FAILED"; + /** 获取文件摘要失败。 */ + public static final String FILE_DIGEST_FAILED = "FILE_DIGEST_FAILED"; + /** MD5计算失败。 */ + public static final String MD5_CALC_FAILED = "MD5_CALC_FAILED"; + /** SHA算法[{0}]计算失败。 */ + public static final String SHA_CALC_FAILED = "SHA_CALC_FAILED"; + /** 无法解析证书。 */ + public static final String PUBLIC_CERT_PARSE_FAILED = "PUBLIC_CERT_PARSE_FAILED"; + /** RSA算法[{0}]不支持。 */ + public static final String RSA_ALGORITHM_UNSUPPORTED = "RSA_ALGORITHM_UNSUPPORTED"; + /** RSA算法参数[{0}]无效。 */ + public static final String RSA_ALGORITHM_PARAM_INVALID = "RSA_ALGORITHM_PARAM_INVALID"; private ExpCode() { } diff --git a/src/main/java/com/yexuejc/base/encrypt/RSA.java b/src/main/java/com/yexuejc/base/encrypt/RSA.java index e9991cc..d1ae0c3 100644 --- a/src/main/java/com/yexuejc/base/encrypt/RSA.java +++ b/src/main/java/com/yexuejc/base/encrypt/RSA.java @@ -192,8 +192,9 @@ public class RSA { * @param keySize 生成长度 * @param base64URLSafe 是否生成 base64URL 格式的密钥:默认false * @return 包含公钥和私钥的Map,key为"publicKey"和"privateKey" + * @throws BaseException 算法不支持或参数无效 */ - public Map initKeys(int keySize, boolean base64URLSafe) { + public Map initKeys(int keySize, boolean base64URLSafe) throws BaseException { boolean originalEncodeBase64URLSafe = this.encodeBase64URLSafe; try { this.encodeBase64URLSafe = base64URLSafe; @@ -208,14 +209,15 @@ public class RSA { * * @param keySize 生成长度 * @return 包含公钥和私钥的Map,key为"publicKey"和"privateKey" + * @throws BaseException 算法不支持或参数无效 */ - public Map initKeys(int keySize) { + public Map initKeys(int keySize) throws BaseException { //为RSA算法创建一个KeyPairGenerator对象 KeyPairGenerator kpg; try { kpg = KeyPairGenerator.getInstance(algorithm); } catch (NoSuchAlgorithmException e) { - throw new IllegalArgumentException("No such algorithm-->[" + algorithm + "]"); + throw new BaseException(e, ExpCode.RSA_ALGORITHM_UNSUPPORTED, algorithm); } //初始化KeyPairGenerator对象,密钥长度 @@ -228,7 +230,7 @@ public class RSA { kpg.initialize(keySize); } } catch (InvalidAlgorithmParameterException e) { - throw new IllegalArgumentException("Invalid algorithm parameter for [" + algorithm + "] keySize=" + keySize, e); + throw new BaseException(e, ExpCode.RSA_ALGORITHM_PARAM_INVALID, algorithm + " keySize=" + keySize); } //生成密匙对 KeyPair keyPair = kpg.generateKeyPair(); diff --git a/src/main/java/com/yexuejc/base/encrypt/RSA2.java b/src/main/java/com/yexuejc/base/encrypt/RSA2.java index e101428..d162835 100644 --- a/src/main/java/com/yexuejc/base/encrypt/RSA2.java +++ b/src/main/java/com/yexuejc/base/encrypt/RSA2.java @@ -73,10 +73,10 @@ public class RSA2 { * * @param filepath 密钥文件路径 * @return RSAPublicKey 公钥对象 - * @throws CertificateException 证书异常 + * @throws BaseException 证书解析异常 * @throws FileNotFoundException 文件未找到异常 */ - public static RSAPublicKey getPublicKey(String filepath) throws CertificateException, FileNotFoundException { + public static RSAPublicKey getPublicKey(String filepath) throws BaseException, FileNotFoundException { try (FileInputStream pubKeyIn = new FileInputStream(filepath)) { byte[] certData = pubKeyIn.readAllBytes(); // 检查是否为PEM格式 @@ -93,7 +93,7 @@ public class RSA2 { return getPublicKey4Pem(certString); } } catch (Exception e) { - throw new CertificateException("无法解析证书: " + e.getMessage(), e); + throw new BaseException(e, ExpCode.PUBLIC_CERT_PARSE_FAILED); } } @@ -155,7 +155,7 @@ public class RSA2 { * @return RSAPublicKey 公钥对象 * @throws CertificateException 证书异常 */ - private static RSAPublicKey getPublicKey4Pem(String pemContent) throws CertificateException { + private static RSAPublicKey getPublicKey4Pem(String pemContent) throws BaseException { try { if (pemContent.contains(PEM_FILE_START_CE)) { String base64Cert = pemContent.replace(PEM_FILE_START_CE, "").replace(PEM_FILE_END_CE, "").replaceAll("\\s", ""); @@ -183,9 +183,9 @@ public class RSA2 { } } } catch (Exception e) { - throw new CertificateException("无法从PEM内容解析公钥: " + e.getMessage(), e); + throw new BaseException(e, ExpCode.PUBLIC_CERT_PARSE_FAILED); } - throw new CertificateException("无法从PEM内容解析公钥"); + throw new BaseException(ExpCode.PUBLIC_CERT_PARSE_FAILED); } /** diff --git a/src/main/java/com/yexuejc/base/util/FileUtil.java b/src/main/java/com/yexuejc/base/util/FileUtil.java index 5850cc4..becf890 100644 --- a/src/main/java/com/yexuejc/base/util/FileUtil.java +++ b/src/main/java/com/yexuejc/base/util/FileUtil.java @@ -61,18 +61,18 @@ public class FileUtil { * 根据文件名获取文件类型/扩展名 * * @param fileName 文件名(可为null) - * @return 文件扩展名(小写),如"txt"、"tar.gz";文件不存在或异常返回null + * @return 文件扩展名(小写),如"txt"、"tar.gz";文件名为null或不含扩展名返回null + * @throws BaseException 获取文件类型失败 */ - public static String getFileType(String fileName) { + public static String getFileType(String fileName) throws BaseException { try { if (fileName.lastIndexOf(TYPE_TAR_GZ) > 0) { return TAR_GZ; } return fileName.substring(fileName.lastIndexOf(CONSTANT_DOT) + 1); } catch (Exception e) { - logger.severe("file doesn't exist or is not a file"); + throw new BaseException(e, ExpCode.FILE_TYPE_GET_FAILED); } - return null; } /** @@ -92,8 +92,9 @@ public class FileUtil { * 判断文件是否存在,不存在就创建一个空的 * * @param file File 对象(不能为null) + * @throws BaseException 创建文件失败 */ - public static void judeFileExists(File file) { + public static void judeFileExists(File file) throws BaseException { if (file.exists()) { logger.severe("file exists"); } else { @@ -103,10 +104,10 @@ public class FileUtil { if (b) { logger.info("file create success"); } else { - logger.severe("file create fail"); + throw new BaseException(ExpCode.FILE_CREATE_FAILED); } } catch (IOException e) { - logger.log(Level.WARNING, "file create fail", e); + throw new BaseException(e, ExpCode.FILE_CREATE_FAILED); } } } @@ -135,9 +136,10 @@ public class FileUtil { * 计算文件的 SHA-1 摘要 * * @param file 文件对象(非null) - * @return SHA-1 十六进制字符串;失败返回null + * @return SHA-1 十六进制字符串 + * @throws BaseException 获取文件摘要失败 */ - public static String sha1(File file) { + public static String sha1(File file) throws BaseException { return getDigest(file, "SHA-1"); } @@ -145,9 +147,10 @@ public class FileUtil { * 计算文件的 MD5 摘要 * * @param file 文件对象(非null) - * @return MD5 十六进制字符串;失败返回null + * @return MD5 十六进制字符串 + * @throws BaseException 获取文件摘要失败 */ - public static String md5(File file) { + public static String md5(File file) throws BaseException { return getDigest(file, "MD5"); } @@ -156,9 +159,10 @@ public class FileUtil { * * @param file 文件对象(非null) * @param digestCode 摘要算法名称(如 "SHA-1"、"MD5") - * @return 摘要十六进制字符串;失败返回null + * @return 摘要十六进制字符串 + * @throws BaseException 获取文件摘要失败 */ - private static String getDigest(File file, String digestCode) { + private static String getDigest(File file, String digestCode) throws BaseException { try (FileInputStream in = new FileInputStream(file)) { MessageDigest digest = MessageDigest.getInstance(digestCode); FileChannel channel = in.getChannel(); @@ -169,22 +173,17 @@ public class FileUtil { digest.update(buffer); // 更新 MessageDigest buffer.clear(); // 清空 Buffer } - // 计算最终的 SHA-1 散列值 - byte[] sha1Bytes = digest.digest(); + // 计算最终的散列值 + byte[] hashBytes = digest.digest(); // 将字节数组转换为十六进制字符串 - StringBuilder sha1Builder = new StringBuilder(); - for (byte b : sha1Bytes) { - sha1Builder.append(String.format("%02x", b)); + StringBuilder hashBuilder = new StringBuilder(); + for (byte b : hashBytes) { + hashBuilder.append(String.format("%02x", b)); } - return sha1Builder.toString(); - } catch (NoSuchAlgorithmException e) { - logger.log(Level.SEVERE, "system algorithm error.", e); - } catch (FileNotFoundException e) { - logger.log(Level.SEVERE, "file doesn't exist or is not a file", e); - } catch (IOException e) { - logger.log(Level.SEVERE, "The operation file is an IO exception.", e); + return hashBuilder.toString(); + } catch (Exception e) { + throw new BaseException(e, ExpCode.FILE_DIGEST_FAILED); } - return null; } /** @@ -217,9 +216,10 @@ public class FileUtil { * * @param file 文件 * @param algorithm 摘要算法名称,如 "MD5"、"SHA-1"、"SHA-256"、"SHA-512" - * @return 摘要的十六进制字符串,失败返回null + * @return 摘要的十六进制字符串 + * @throws BaseException 获取文件摘要失败 */ - public static String digest(File file, String algorithm) { + public static String digest(File file, String algorithm) throws BaseException { return getDigest(file, algorithm); } diff --git a/src/main/java/com/yexuejc/base/util/ImgUtil.java b/src/main/java/com/yexuejc/base/util/ImgUtil.java index 5682514..abb9d9a 100644 --- a/src/main/java/com/yexuejc/base/util/ImgUtil.java +++ b/src/main/java/com/yexuejc/base/util/ImgUtil.java @@ -18,6 +18,9 @@ import java.net.URL; import java.util.Base64; import java.util.Iterator; +import com.yexuejc.base.constant.ExpCode; +import com.yexuejc.base.exception.BaseException; + /** * 图片处理工具类 * @@ -33,8 +36,9 @@ public class ImgUtil { * * @param imgURL 网络图片url * @return String Base64字符串 + * @throws BaseException 读取图片数据失败 */ - public static String getImageStrFromUrl(String imgURL) { + public static String getImageStrFromUrl(String imgURL) throws BaseException { HttpURLConnection conn = null; try { conn = getHttpURLConnection(imgURL); @@ -48,8 +52,7 @@ public class ImgUtil { return new String(Base64.getEncoder().encode(data.toByteArray())); } } catch (IOException e) { - e.printStackTrace(); - return null; + throw new BaseException(e, ExpCode.IMG_READ_FAILED); } finally { if (conn != null) { conn.disconnect(); @@ -184,13 +187,13 @@ public class ImgUtil { * * @param imgBytes 图片字节数组 * @return ImageInfo + * @throws BaseException 读取图片信息失败 */ - public static ImageInfo getImageInfoFromInputStream(byte[] imgBytes) { + public static ImageInfo getImageInfoFromInputStream(byte[] imgBytes) throws BaseException { try (ByteArrayInputStream in = new ByteArrayInputStream(imgBytes)) { return getImageInfoFromInputStream(in); } catch (IOException e) { - e.printStackTrace(); - return null; + throw new BaseException(e, ExpCode.IMG_INFO_READ_FAILED); } } @@ -199,8 +202,9 @@ public class ImgUtil { * * @param inputStream 图片输入流 * @return ImageInfo + * @throws BaseException 读取图片信息失败 */ - public static ImageInfo getImageInfoFromInputStream(InputStream inputStream) { + public static ImageInfo getImageInfoFromInputStream(InputStream inputStream) throws BaseException { ImageInputStream imgStream = null; ImageReader reader = null; try { @@ -217,18 +221,17 @@ public class ImgUtil { bean.setType(reader.getFormatName()); return bean; } catch (IOException e) { - e.printStackTrace(); - return null; + throw new BaseException(e, ExpCode.IMG_INFO_READ_FAILED); } finally { if (reader != null) { reader.dispose(); } - try { - if (imgStream != null) { + if (imgStream != null) { + try { imgStream.close(); + } catch (IOException ignored) { + // close 失败不影响结果,忽略 } - } catch (IOException e) { - e.printStackTrace(); } } } diff --git a/src/main/java/com/yexuejc/base/util/ObjUtil.java b/src/main/java/com/yexuejc/base/util/ObjUtil.java index 817b37b..51e6309 100644 --- a/src/main/java/com/yexuejc/base/util/ObjUtil.java +++ b/src/main/java/com/yexuejc/base/util/ObjUtil.java @@ -36,6 +36,7 @@ import java.util.stream.Collectors; import com.yexuejc.base.annotation.ToUeProperty; import com.yexuejc.base.exception.BaseException; +import com.yexuejc.base.util.MsgUtil; /** * 对象工具:对类的操作 @@ -211,7 +212,7 @@ public class ObjUtil { * @param obj 要转换的对象 * @return 转换后的值以Map返回 */ - public static Map getToUeMap(Object obj) { + public static Map getToUeMap(Object obj) throws BaseException { return getUnderlineMap(obj, true, false); } @@ -222,7 +223,7 @@ public class ObjUtil { * @param obj 要转换的对象 * @return 转换后的值toJson以String返回 */ - public static String getToUeStr(Object obj) { + public static String getToUeStr(Object obj) throws BaseException { return JsonUtil.obj2Json(getUnderlineMap(obj, true, false)); } @@ -233,7 +234,7 @@ public class ObjUtil { * @param obj 要转换的对象 * @return 转换后的值以Map返回 */ - public static Map getUnderlineMap(Object obj) { + public static Map getUnderlineMap(Object obj) throws BaseException { return getUnderlineMap(obj, true, false); } @@ -244,7 +245,7 @@ public class ObjUtil { * @param obj 要转换的对象 * @return 转换后的值toJson以String返回 */ - public static String getUnderlineStr(Object obj) { + public static String getUnderlineStr(Object obj) throws BaseException { return JsonUtil.obj2Json(getUnderlineMap(obj, true, false)); } @@ -256,7 +257,7 @@ public class ObjUtil { * @param putNull 是否映射null * @return 转换后的值toJson以String返回 */ - public static String getUnderlineStr(Object obj, boolean isAnnotationAll, boolean putNull) { + public static String getUnderlineStr(Object obj, boolean isAnnotationAll, boolean putNull) throws BaseException { return JsonUtil.obj2Json(getUnderlineMap(obj, isAnnotationAll, putNull)); } @@ -269,7 +270,7 @@ public class ObjUtil { * @param putNull 是否映射null * @return */ - public static Map getUnderlineMap(Object obj, boolean isAnnotationAll, boolean putNull) { + public static Map getUnderlineMap(Object obj, boolean isAnnotationAll, boolean putNull) throws BaseException { Class bindClass = obj.getClass(); Map objMap = new HashMap<>(0); /* @@ -358,12 +359,12 @@ public class ObjUtil { } else if (o instanceof List) { List list = (List) o; List bodyList = new ArrayList(); - list.forEach(it -> { + for (Object it : list) { if (null != it) { Map underlineMap = getUnderlineMap(it, isAnnotationAll, putNull); bodyList.add(underlineMap); } - }); + } if (bodyList.size() > 0) { objMap.put(fName, bodyList); } @@ -375,12 +376,12 @@ public class ObjUtil { } else if (o instanceof Set) { Set list = (Set) o; Set bodyList = new HashSet(); - list.forEach(it -> { + for (Object it : list) { if (null != it) { Map underlineMap = getUnderlineMap(it, isAnnotationAll, putNull); bodyList.add(underlineMap); } - }); + } if (bodyList.size() > 0) { objMap.put(fName, bodyList); } @@ -390,7 +391,7 @@ public class ObjUtil { } } } catch (IllegalAccessException e) { - log.log(Level.WARNING, "获取对象字段映射失败: ", e); + throw new BaseException(e, MsgUtil.getMsg("OBJ_GET_FIELD_MAP_FAILED")); } return objMap; } @@ -435,7 +436,7 @@ public class ObjUtil { * @param 泛型 * @return 克隆后的新对象 */ - public static T depthClone(T t) { + public static T depthClone(T t) throws BaseException { try (ByteArrayOutputStream baos = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(baos)) { oos.writeObject(t); @@ -444,11 +445,10 @@ public class ObjUtil { return (T) ois.readObject(); } } catch (IOException e) { - log.log(Level.WARNING, "Deep clone IOException", e); + throw new BaseException(e, MsgUtil.getMsg("OBJ_DEPTH_CLONE_IO_FAILED")); } catch (ClassNotFoundException e) { - log.log(Level.WARNING, "Deep clone ClassNotFoundException", e); + throw new BaseException(e, MsgUtil.getMsg("OBJ_DEPTH_CLONE_CLASS_NOT_FOUND")); } - return null; } /** @@ -491,19 +491,18 @@ public class ObjUtil { if (StrUtil.isNotEmpty(includeField)) { allFields = allFields.stream().filter(f -> includeField.contains(f.getName())).collect(Collectors.toList()); } - allFields.forEach(f -> { + for (Field f : allFields) { try { Field field = findTargetField(targetClass, f.getName()); if (field != null) { copyFieldValue(source, o, f, field); } else { - log.log(Level.FINE, "目标类中未找到字段: " + f.getName()); + log.log(Level.FINE, MsgUtil.getMsg("OBJ_TARGET_FIELD_NOT_FOUND", f.getName())); } } 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); + throw new BaseException(e, MsgUtil.getMsg("OBJ_FIELD_COPY_FAILED", f.getName(), e.getMessage())); } - }); + } return o; } @@ -522,7 +521,7 @@ public class ObjUtil { public static O copy(I source, Class targetClass, boolean invokeSetter) throws Exception { List getterMethods = getAllGetterMethods(source.getClass(), "get"); O o = targetClass.getDeclaredConstructor().newInstance(); - getterMethods.forEach(method -> { + for (Method method : getterMethods) { String fieldName = method.getName().replace("get", ""); try { Object v = method.invoke(source); @@ -531,21 +530,20 @@ public class ObjUtil { if (setterMethod != null) { setterMethod.invoke(o, v); } else { - log.log(Level.FINE, "目标类中未找到setter方法: set" + fieldName); + log.log(Level.FINE, MsgUtil.getMsg("OBJ_TARGET_SETTER_NOT_FOUND", "set" + fieldName)); } } else { Field field = findTargetField(targetClass, lowerCaseFirstChar(fieldName)); if (field != null) { setFieldValue(o, field, v); } else { - log.log(Level.FINE, "目标类中未找到字段: " + lowerCaseFirstChar(fieldName)); + log.log(Level.FINE, MsgUtil.getMsg("OBJ_TARGET_FIELD_NOT_FOUND", lowerCaseFirstChar(fieldName))); } } } 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); + throw new BaseException(e, MsgUtil.getMsg("OBJ_FIELD_COPY_FAILED", fieldName, e.getMessage())); } - }); + } return o; } @@ -624,7 +622,7 @@ public class ObjUtil { clazz = clazz.getSuperclass(); } } - log.log(Level.FINEST, "字段未找到: " + fieldName + " in " + targetClass.getSimpleName()); + log.log(Level.FINEST, MsgUtil.getMsg("OBJ_FIELD_NOT_FOUND", fieldName, targetClass.getSimpleName())); return null; } @@ -640,7 +638,7 @@ public class ObjUtil { try { return targetClass.getDeclaredMethod("set" + fieldName, paramType); } catch (NoSuchMethodException e) { - log.log(Level.FINEST, "setter方法未找到: set" + fieldName + " in " + targetClass.getSimpleName()); + log.log(Level.FINEST, MsgUtil.getMsg("OBJ_SETTER_METHOD_NOT_FOUND", fieldName, targetClass.getSimpleName())); return null; } } diff --git a/src/main/java/com/yexuejc/base/util/StrUtil.java b/src/main/java/com/yexuejc/base/util/StrUtil.java index 63d2687..e231158 100644 --- a/src/main/java/com/yexuejc/base/util/StrUtil.java +++ b/src/main/java/com/yexuejc/base/util/StrUtil.java @@ -169,11 +169,12 @@ public final class StrUtil { * * @param str 要计算MD5的字符串 * @return MD5值,如果输入为null则返回null + * @throws BaseException MD5计算失败 * @deprecated MD5 已不安全,存在碰撞风险,禁止用于密码存储等安全敏感场景。 * 仅适用于数据完整性校验(如文件哈希)。如需安全哈希,请使用 {@link #toSHA256(String)}。 */ @Deprecated - public static String toMD5(String str) { + public static String toMD5(String str) throws BaseException { if (str == null) { return null; } @@ -184,8 +185,7 @@ public final class StrUtil { byte[] tmp = md.digest(); return toHex(tmp); } catch (Exception e) { - logger.log(Level.WARNING, "MD5计算失败", e); - return null; + throw new BaseException(e, ExpCode.MD5_CALC_FAILED); } } @@ -194,8 +194,9 @@ public final class StrUtil { * * @param str 要计算SHA256的字符串 * @return SHA256值,如果输入为null则返回null + * @throws BaseException SHA计算失败 */ - public static String toSHA256(final String str) { + public static String toSHA256(final String str) throws BaseException { return toSHA(str, "SHA-256"); } @@ -205,8 +206,9 @@ public final class StrUtil { * @param str 要加密的字符串 * @param algorithm 算法名称(如"SHA-256"、"SHA-1") * @return SHA值,如果输入为null则返回null + * @throws BaseException SHA算法不支持或计算失败 */ - public static String toSHA(final String str, final String algorithm) { + public static String toSHA(final String str, final String algorithm) throws BaseException { if (str == null) { return null; } @@ -222,11 +224,9 @@ public final class StrUtil { byte[] tmp = messageDigest.digest(); return toHex(tmp); } catch (NoSuchAlgorithmException e) { - logger.log(Level.WARNING, "SHA算法不支持: " + algorithm, e); - return null; + throw new BaseException(e, ExpCode.SHA_CALC_FAILED, algorithm); } catch (Exception e) { - logger.log(Level.WARNING, "SHA计算失败", e); - return null; + throw new BaseException(e, ExpCode.SHA_CALC_FAILED, algorithm); } } diff --git a/src/main/resources/i18n/msg_en_US.properties b/src/main/resources/i18n/msg_en_US.properties index 97f675b..880da34 100644 --- a/src/main/resources/i18n/msg_en_US.properties +++ b/src/main/resources/i18n/msg_en_US.properties @@ -18,3 +18,21 @@ MD5_ALGORITHM_UNAVAILABLE=MD5 algorithm is not available. SHA256_ALGORITHM_UNAVAILABLE=SHA-256 algorithm is not available. INVALID_KEY_LENGTH=Key length must not be less than 24. GET_FIELD_VALUE_FAILED=Failed to get field value [{0}]. +OBJ_GET_FIELD_MAP_FAILED=Failed to get object field mapping. +OBJ_TARGET_FIELD_NOT_FOUND=Field not found in target class: {0}. +OBJ_TARGET_SETTER_NOT_FOUND=Setter method not found in target class: set{0}. +OBJ_FIELD_NOT_FOUND=Field not found: {0} in {1}. +OBJ_SETTER_METHOD_NOT_FOUND=Setter method not found: set{0} in {1}. +OBJ_DEPTH_CLONE_IO_FAILED=Deep clone IO exception. +OBJ_DEPTH_CLONE_CLASS_NOT_FOUND=Deep clone class not found exception. +OBJ_FIELD_COPY_FAILED=Field [{0}] copy failed: {1}. +IMG_READ_FAILED=Failed to read image data. +IMG_INFO_READ_FAILED=Failed to read image information. +FILE_TYPE_GET_FAILED=Failed to get file type. +FILE_CREATE_FAILED=Failed to create file. +FILE_DIGEST_FAILED=Failed to get file digest. +MD5_CALC_FAILED=MD5 calculation failed. +SHA_CALC_FAILED=SHA algorithm [{0}] calculation failed. +PUBLIC_CERT_PARSE_FAILED=Failed to parse public key certificate. +RSA_ALGORITHM_UNSUPPORTED=RSA algorithm [{0}] is not supported. +RSA_ALGORITHM_PARAM_INVALID=RSA algorithm parameter [{0}] is invalid. diff --git a/src/main/resources/i18n/msg_ja_JP.properties b/src/main/resources/i18n/msg_ja_JP.properties index 0d2861a..f025bbc 100644 --- a/src/main/resources/i18n/msg_ja_JP.properties +++ b/src/main/resources/i18n/msg_ja_JP.properties @@ -18,3 +18,21 @@ MD5_ALGORITHM_UNAVAILABLE=MD5\u30A2\u30EB\u30B4\u30EA\u30BA\u30E0\u304C\u5229\u7 SHA256_ALGORITHM_UNAVAILABLE=SHA-256\u30A2\u30EB\u30B4\u30EA\u30BA\u30E0\u304C\u5229\u7528\u3067\u304D\u307E\u305B\u3093\u3002 INVALID_KEY_LENGTH=\u30AD\u30FC\u306E\u9577\u3055\u306F24\u672A\u6E80\u3067\u3042\u3063\u3066\u306F\u306A\u308A\u307E\u305B\u3093\u3002 GET_FIELD_VALUE_FAILED=\u30D5\u30A3\u30FC\u30EB\u30C9\u5024[{0}]\u306E\u53D6\u5F97\u306B\u5931\u6557\u3057\u307E\u3057\u305F\u3002 +OBJ_GET_FIELD_MAP_FAILED=\u30AA\u30D6\u30B8\u30A7\u30AF\u30C8\u30D5\u30A3\u30FC\u30EB\u30C9\u30DE\u30C3\u30D4\u30F3\u30B0\u306E\u53D6\u5F97\u306B\u5931\u6557\u3057\u307E\u3057\u305F\u3002 +OBJ_TARGET_FIELD_NOT_FOUND=\u30BF\u30FC\u30B2\u30C3\u30C8\u30AF\u30E9\u30B9\u306B\u30D5\u30A3\u30FC\u30EB\u30C9\u304C\u898B\u3064\u304B\u308A\u307E\u305B\u3093: {0}\u3002 +OBJ_TARGET_SETTER_NOT_FOUND=\u30BF\u30FC\u30B2\u30C3\u30C8\u30AF\u30E9\u30B9\u306Bsetter\u30E1\u30BD\u30C3\u30C9\u304C\u898B\u3064\u304B\u308A\u307E\u305B\u3093: set{0}\u3002 +OBJ_FIELD_NOT_FOUND=\u30D5\u30A3\u30FC\u30EB\u30C9\u304C\u898B\u3064\u304B\u308A\u307E\u305B\u3093: {0} in {1}\u3002 +OBJ_SETTER_METHOD_NOT_FOUND=setter\u30E1\u30BD\u30C3\u30C9\u304C\u898B\u3064\u304B\u308A\u307E\u305B\u3093: set{0} in {1}\u3002 +OBJ_DEPTH_CLONE_IO_FAILED=\u6DF1\u5EA6\u30AF\u30ED\u30FC\u30F3IO\u4F8B\u5916\u3002 +OBJ_DEPTH_CLONE_CLASS_NOT_FOUND=\u6DF1\u5EA6\u30AF\u30ED\u30FC\u30F3\u30AF\u30E9\u30B9\u304C\u898B\u3064\u304B\u308A\u307E\u305B\u3093\u3002 +OBJ_FIELD_COPY_FAILED=\u30D5\u30A3\u30FC\u30EB\u30C9 [{0}] \u306E\u30B3\u30D4\u30FC\u306B\u5931\u6557\u3057\u307E\u3057\u305F: {1}\u3002 +IMG_READ_FAILED=\u753B\u50CF\u30C7\u30FC\u30BF\u306E\u8AAD\u307F\u53D6\u308A\u306B\u5931\u6557\u3057\u307E\u3057\u305F\u3002 +IMG_INFO_READ_FAILED=\u753B\u50CF\u60C5\u5831\u306E\u8AAD\u307F\u53D6\u308A\u306B\u5931\u6557\u3057\u307E\u3057\u305F\u3002 +FILE_TYPE_GET_FAILED=\u30D5\u30A1\u30A4\u30EB\u30BF\u30A4\u30D7\u306E\u53D6\u5F97\u306B\u5931\u6557\u3057\u307E\u3057\u305F\u3002 +FILE_CREATE_FAILED=\u30D5\u30A1\u30A4\u30EB\u306E\u4F5C\u6210\u306B\u5931\u6557\u3057\u307E\u3057\u305F\u3002 +FILE_DIGEST_FAILED=\u30D5\u30A1\u30A4\u30EB\u30C0\u30A4\u30B8\u30A7\u30B9\u30C8\u306E\u53D6\u5F97\u306B\u5931\u6557\u3057\u307E\u3057\u305F\u3002 +MD5_CALC_FAILED=MD5\u8A08\u7B97\u306B\u5931\u6557\u3057\u307E\u3057\u305F\u3002 +SHA_CALC_FAILED=SHA\u30A2\u30EB\u30B4\u30EA\u30BA\u30E0[{0}]\u8A08\u7B97\u306B\u5931\u6557\u3057\u307E\u3057\u305F\u3002 +PUBLIC_CERT_PARSE_FAILED=\u516C\u958B\u9375\u8A3C\u660E\u66F8\u306E\u89E3\u6790\u306B\u5931\u6557\u3057\u307E\u3057\u305F\u3002 +RSA_ALGORITHM_UNSUPPORTED=RSA\u30A2\u30EB\u30B4\u30EA\u30BA\u30E0[{0}]\u306F\u30B5\u30DD\u30FC\u30C8\u3055\u308C\u3066\u3044\u307E\u305B\u3093\u3002 +RSA_ALGORITHM_PARAM_INVALID=RSA\u30A2\u30EB\u30B4\u30EA\u30BA\u30E0\u30D1\u30E9\u30E1\u30FC\u30BF[{0}]\u306F\u7121\u52B9\u3067\u3059\u3002 diff --git a/src/main/resources/i18n/msg_ko_KR.properties b/src/main/resources/i18n/msg_ko_KR.properties index 24d07a2..91863a8 100644 --- a/src/main/resources/i18n/msg_ko_KR.properties +++ b/src/main/resources/i18n/msg_ko_KR.properties @@ -18,3 +18,21 @@ MD5_ALGORITHM_UNAVAILABLE=MD5 \uC54C\uACE0\uB9AC\uC998\uC744 \uC0AC\uC6A9\uD560 SHA256_ALGORITHM_UNAVAILABLE=SHA-256 \uC54C\uACE0\uB9AC\uC998\uC744 \uC0AC\uC6A9\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4. INVALID_KEY_LENGTH=\uD0A4 \uAE38\uC774\uB294 24 \uBBF8\uB9CC\uC774\uC5B4\uC11C\uB294 \uC548 \uB429\uB2C8\uB2E4. GET_FIELD_VALUE_FAILED=\uD544\uB4DC \uAC12 [{0}]\uC744(\uB97C) \uAC00\uC838\uC624\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4. +OBJ_GET_FIELD_MAP_FAILED=\uAC1D\uCCB4 \uD544\uB4DC \uB9E4\uD551 \uAC00\uC838\uC624\uAE30 \uC2E4\uD328. +OBJ_TARGET_FIELD_NOT_FOUND=\uB300\uC0C1 \uD074\uB798\uC2A4\uC5D0\uC11C \uD544\uB4DC\uB97C \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4: {0}. +OBJ_TARGET_SETTER_NOT_FOUND=\uB300\uC0C1 \uD074\uB798\uC2A4\uC5D0\uC11C setter \uBA54\uC11C\uB4DC\uB97C \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4: set{0}. +OBJ_FIELD_NOT_FOUND=\uD544\uB4DC\uB97C \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4: {0} in {1}. +OBJ_SETTER_METHOD_NOT_FOUND=setter \uBA54\uC11C\uB4DC\uB97C \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4: set{0} in {1}. +OBJ_DEPTH_CLONE_IO_FAILED=\uAE4A\uC740 \uBCF5\uC81C IO \uC608\uC678. +OBJ_DEPTH_CLONE_CLASS_NOT_FOUND=\uAE4A\uC740 \uBCF5\uC81C \uD074\uB798\uC2A4 \uCC3E\uAE30 \uC2E4\uD328. +OBJ_FIELD_COPY_FAILED=\uD544\uB4DC [{0}] \uBCF5\uC0AC \uC2E4\uD328: {1}. +IMG_READ_FAILED=\uC774\uBBF8\uC9C0 \uB370\uC774\uD130 \uC77D\uAE30 \uC2E4\uD328. +IMG_INFO_READ_FAILED=\uC774\uBBF8\uC9C0 \uC815\uBCF4 \uC77D\uAE30 \uC2E4\uD328. +FILE_TYPE_GET_FAILED=\uD30C\uC77C \uD0C0\uC785 \uAC00\uC838\uC624\uAE30 \uC2E4\uD328. +FILE_CREATE_FAILED=\uD30C\uC77C \uC0DD\uC131 \uC2E4\uD328. +FILE_DIGEST_FAILED=\uD30C\uC77C \uB2E4\uC774\uC81C\uC2A4\uD2B8 \uAC00\uC838\uC624\uAE30 \uC2E4\uD328. +MD5_CALC_FAILED=MD5 \uACC4\uC0B0 \uC2E4\uD328. +SHA_CALC_FAILED=SHA \uC54C\uACE0\uB9AC\uC998[{0}] \uACC4\uC0B0 \uC2E4\uD328. +PUBLIC_CERT_PARSE_FAILED=\uACF5\uAC1C \uD0A4 \uC778\uC99D\uC11C \uD30C\uC2F1 \uC2E4\uD328. +RSA_ALGORITHM_UNSUPPORTED=RSA \uC54C\uACE0\uB9AC\uC998[{0}]\uC740 \uC9C0\uC6D0\uB418\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4. +RSA_ALGORITHM_PARAM_INVALID=RSA \uC54C\uACE0\uB9AC\uC998 \uB9E4\uAC1C\uBCC0\uC218[{0}]\uAC00 \uC798\uBABB\uB418\uC5C8\uC2B5\uB2C8\uB2E4. diff --git a/src/main/resources/i18n/msg_zh_CN.properties b/src/main/resources/i18n/msg_zh_CN.properties index 6622311..84c9ab5 100644 --- a/src/main/resources/i18n/msg_zh_CN.properties +++ b/src/main/resources/i18n/msg_zh_CN.properties @@ -17,4 +17,22 @@ FILE_NOT_CSV_FORMAT=[{0}]\u6587\u4EF6\u4E0D\u662FCSV\u6587\u4EF6\u683C\u5F0F\u30 MD5_ALGORITHM_UNAVAILABLE=MD5\u7B97\u6CD5\u4E0D\u53EF\u7528\u3002 SHA256_ALGORITHM_UNAVAILABLE=SHA-256\u7B97\u6CD5\u4E0D\u53EF\u7528\u3002 INVALID_KEY_LENGTH=key\u7684length\u4E0D\u5F97\u5C0F\u4E8E24\u3002 -GET_FIELD_VALUE_FAILED=\u83B7\u53D6\u5B57\u6BB5\u503C[{0}]\u5931\u8D25\u3002 \ No newline at end of file +GET_FIELD_VALUE_FAILED=\u83B7\u53D6\u5B57\u6BB5\u503C[{0}]\u5931\u8D25\u3002 +OBJ_GET_FIELD_MAP_FAILED=\u83B7\u53D6\u5BF9\u8C61\u5B57\u6BB5\u6620\u5C04\u5931\u8D25\u3002 +OBJ_TARGET_FIELD_NOT_FOUND=\u76EE\u6807\u7C7B\u4E2D\u672A\u627E\u5230\u5B57\u6BB5: {0}\u3002 +OBJ_TARGET_SETTER_NOT_FOUND=\u76EE\u6807\u7C7B\u4E2D\u672A\u627E\u5230setter\u65B9\u6CD5: set{0}\u3002 +OBJ_FIELD_NOT_FOUND=\u5B57\u6BB5\u672A\u627E\u5230: {0} in {1}\u3002 +OBJ_SETTER_METHOD_NOT_FOUND=setter\u65B9\u6CD5\u672A\u627E\u5230: set{0} in {1}\u3002 +OBJ_DEPTH_CLONE_IO_FAILED=\u6DF1\u5EA6\u514B\u9686IO\u5F02\u5E38\u3002 +OBJ_DEPTH_CLONE_CLASS_NOT_FOUND=\u6DF1\u5EA6\u514B\u9686\u7C7B\u672A\u627E\u5230\u5F02\u5E38\u3002 +OBJ_FIELD_COPY_FAILED=\u5B57\u6BB5 [{0}] \u590D\u5236\u5931\u8D25: {1}\u3002 +IMG_READ_FAILED=\u8BFB\u53D6\u56FE\u7247\u6570\u636E\u5931\u8D25\u3002 +IMG_INFO_READ_FAILED=\u8BFB\u53D6\u56FE\u7247\u4FE1\u606F\u5931\u8D25\u3002 +FILE_TYPE_GET_FAILED=\u83B7\u53D6\u6587\u4EF6\u7C7B\u578B\u5931\u8D25\u3002 +FILE_CREATE_FAILED=\u521B\u5EFA\u6587\u4EF6\u5931\u8D25\u3002 +FILE_DIGEST_FAILED=\u83B7\u53D6\u6587\u4EF6\u6458\u8981\u5931\u8D25\u3002 +MD5_CALC_FAILED=MD5\u8BA1\u7B97\u5931\u8D25\u3002 +SHA_CALC_FAILED=SHA\u7B97\u6CD5[{0}]\u8BA1\u7B97\u5931\u8D25\u3002 +PUBLIC_CERT_PARSE_FAILED=\u65E0\u6CD5\u89E3\u6790\u516C\u9470\u8BC1\u4E66\u3002 +RSA_ALGORITHM_UNSUPPORTED=RSA\u7B97\u6CD5[{0}]\u4E0D\u652F\u6301\u3002 +RSA_ALGORITHM_PARAM_INVALID=RSA\u7B97\u6CD5\u53C2\u6570[{0}]\u65E0\u6548\u3002 \ No newline at end of file diff --git a/src/main/resources/i18n/msg_zh_TW.properties b/src/main/resources/i18n/msg_zh_TW.properties index 662e1e1..bea2944 100644 --- a/src/main/resources/i18n/msg_zh_TW.properties +++ b/src/main/resources/i18n/msg_zh_TW.properties @@ -18,3 +18,21 @@ MD5_ALGORITHM_UNAVAILABLE=MD5\u6F14\u7B97\u6CD5\u4E0D\u53EF\u7528\u3002 SHA256_ALGORITHM_UNAVAILABLE=SHA-256\u6F14\u7B97\u6CD5\u4E0D\u53EF\u7528\u3002 INVALID_KEY_LENGTH=key\u7684length\u4E0D\u5F97\u5C0F\u65BC24\u3002 GET_FIELD_VALUE_FAILED=\u7372\u53D6\u5B57\u6BB5\u503C[{0}]\u5931\u6557\u3002 +OBJ_GET_FIELD_MAP_FAILED=\u7372\u53D6\u7269\u4EF6\u6B04\u4F4D\u6620\u5C04\u5931\u6557\u3002 +OBJ_TARGET_FIELD_NOT_FOUND=\u76EE\u6A19\u985E\u5225\u4E2D\u672A\u627E\u5230\u6B04\u4F4D: {0}\u3002 +OBJ_TARGET_SETTER_NOT_FOUND=\u76EE\u6A19\u985E\u5225\u4E2D\u672A\u627E\u5230setter\u65B9\u6CD5: set{0}\u3002 +OBJ_FIELD_NOT_FOUND=\u6B04\u4F4D\u672A\u627E\u5230: {0} in {1}\u3002 +OBJ_SETTER_METHOD_NOT_FOUND=setter\u65B9\u6CD5\u672A\u627E\u5230: set{0} in {1}\u3002 +OBJ_DEPTH_CLONE_IO_FAILED=\u6DF1\u5EA6\u5B8C\u5168\u8907\u88ABIO\u7570\u5E38\u3002 +OBJ_DEPTH_CLONE_CLASS_NOT_FOUND=\u6DF1\u5EA6\u5B8C\u5168\u8907\u88AB\u985E\u5225\u672A\u627E\u5230\u7570\u5E38\u3002 +OBJ_FIELD_COPY_FAILED=\u6B04\u4F4D [{0}] \u8907\u88AB\u5931\u6557: {1}\u3002 +IMG_READ_FAILED=\u8B80\u53D6\u5716\u7247\u8CC7\u6599\u5931\u6557\u3002 +IMG_INFO_READ_FAILED=\u8B80\u53D6\u5716\u7247\u8CC7\u8A0A\u5931\u6557\u3002 +FILE_TYPE_GET_FAILED=\u7372\u53D6\u6A94\u6848\u985E\u578B\u5931\u6557\u3002 +FILE_CREATE_FAILED=\u5EFA\u7ACB\u6A94\u6848\u5931\u6557\u3002 +FILE_DIGEST_FAILED=\u7372\u53D6\u6A94\u6848\u6458\u8981\u5931\u6557\u3002 +MD5_CALC_FAILED=MD5\u8A08\u7B97\u5931\u6557\u3002 +SHA_CALC_FAILED=SHA\u6F14\u7B97\u6CD5[{0}]\u8A08\u7B97\u5931\u6557\u3002 +PUBLIC_CERT_PARSE_FAILED=\u7121\u6CD5\u89E3\u6790\u516C\u9470\u6191\u8B49\u3002 +RSA_ALGORITHM_UNSUPPORTED=RSA\u6F14\u7B97\u6CD5[{0}]\u4E0D\u652F\u63F4\u3002 +RSA_ALGORITHM_PARAM_INVALID=RSA\u6F14\u7B97\u6CD5\u53C3\u6578[{0}]\u7121\u6548\u3002 diff --git a/src/test/java/com/yexuejc/base/encrypt/RSA2Test.java b/src/test/java/com/yexuejc/base/encrypt/RSA2Test.java index 37499a8..658854b 100644 --- a/src/test/java/com/yexuejc/base/encrypt/RSA2Test.java +++ b/src/test/java/com/yexuejc/base/encrypt/RSA2Test.java @@ -60,8 +60,8 @@ class RSA2Test { * 测试获取公钥的方法 - 异常情况 */ @Test - void shouldThrowCertificateExceptionWhenReadingNonExistentPublicKey() { - assertThrows(CertificateException.class, () -> { + void shouldThrowBaseExceptionWhenReadingNonExistentPublicKey() { + assertThrows(BaseException.class, () -> { RSA2.getPublicKey("non-existent-file.crt"); }); } diff --git a/src/test/java/com/yexuejc/base/encrypt/RSATest.java b/src/test/java/com/yexuejc/base/encrypt/RSATest.java index 46a16ce..bd308fb 100644 --- a/src/test/java/com/yexuejc/base/encrypt/RSATest.java +++ b/src/test/java/com/yexuejc/base/encrypt/RSATest.java @@ -8,6 +8,7 @@ package com.yexuejc.base.encrypt; +import com.yexuejc.base.exception.BaseException; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; @@ -22,7 +23,7 @@ import java.util.Map; class RSATest { @Test - void initKeys_ec256() { + void initKeys_ec256() throws BaseException { /** * ECDSA 密钥的位数通常定义为 NIST 曲线标准,支持的常见密钥尺寸包括: * @@ -41,7 +42,7 @@ class RSATest { } @Test - void initKeys_rsa2048() { + void initKeys_rsa2048() throws BaseException { RSA rsa = RSA.builder(); Map keys = rsa.initKeys(2048); Assertions.assertNotNull(keys); @@ -53,7 +54,7 @@ class RSATest { } @Test - void initKeys_ec384() { + void initKeys_ec384() throws BaseException { RSA rsa = RSA.builder(); rsa.algorithm = "EC"; Map keys = rsa.initKeys(384); @@ -64,7 +65,7 @@ class RSATest { } @Test - void initKeys_ec521() { + void initKeys_ec521() throws BaseException { RSA rsa = RSA.builder(); rsa.algorithm = "EC"; Map keys = rsa.initKeys(521); diff --git a/src/test/java/com/yexuejc/base/encrypt/RSATestNew.java b/src/test/java/com/yexuejc/base/encrypt/RSATestNew.java index 4076dd3..0f6499b 100644 --- a/src/test/java/com/yexuejc/base/encrypt/RSATestNew.java +++ b/src/test/java/com/yexuejc/base/encrypt/RSATestNew.java @@ -9,6 +9,7 @@ package com.yexuejc.base.encrypt; +import com.yexuejc.base.exception.BaseException; import java.nio.file.Files; import java.nio.file.Path; import java.security.KeyPair; @@ -47,7 +48,7 @@ class RSATestNew { } @Test - void shouldGenerateValidKeyMapWithDefaultSettings() { + void shouldGenerateValidKeyMapWithDefaultSettings() throws BaseException { Map keys = rsa.initKeys(1024); assertNotNull(keys); @@ -59,7 +60,7 @@ class RSATestNew { } @Test - void shouldGenerateValidKeyMapWithBase64UrlSafeOption() { + void shouldGenerateValidKeyMapWithBase64UrlSafeOption() throws BaseException { Map keys = rsa.initKeys(1024, true); assertNotNull(keys); diff --git a/src/test/java/com/yexuejc/base/util/FileUtilTest.java b/src/test/java/com/yexuejc/base/util/FileUtilTest.java index 24bcbf6..31c247a 100644 --- a/src/test/java/com/yexuejc/base/util/FileUtilTest.java +++ b/src/test/java/com/yexuejc/base/util/FileUtilTest.java @@ -30,7 +30,7 @@ public class FileUtilTest { // other(); } - private static void other() throws IOException { + private static void other() throws IOException, BaseException { System.out.println(FileUtil.getFileType("C:\\Users\\Administrator\\Desktop\\test.txt")); boolean b = FileUtil.judeDirExists(new File("F:\\coding\\yexuejc-base2\\src\\test\\java\\com\\yexuejc\\base\\util\\test\\a")); File file = new File("F:\\coding\\yexuejc-base2\\src\\test\\java\\com\\yexuejc\\base\\util\\test\\a\\test.txt"); diff --git a/src/test/java/com/yexuejc/base/util/ObjUtilTest.java b/src/test/java/com/yexuejc/base/util/ObjUtilTest.java index 6c1b370..691c006 100644 --- a/src/test/java/com/yexuejc/base/util/ObjUtilTest.java +++ b/src/test/java/com/yexuejc/base/util/ObjUtilTest.java @@ -10,6 +10,7 @@ package com.yexuejc.base.util; import com.yexuejc.base.annotation.ToUeProperty; +import com.yexuejc.base.exception.BaseException; import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.*; @@ -31,7 +32,7 @@ import java.util.Map; class ObjUtilTest { @Test - public void testGetUnderlineMap() { + public void testGetUnderlineMap() throws BaseException { B a = new B(); a.nameFirst = "张三"; a.ageInt = "5165458"; @@ -64,7 +65,7 @@ class ObjUtilTest { } @Test - public void testDepthClone() { + public void testDepthClone() throws BaseException { B original = new B(); original.nameFirst = "张三"; original.ageInt = "123"; diff --git a/src/test/java/com/yexuejc/base/util/StrUtilEnhancedTest.java b/src/test/java/com/yexuejc/base/util/StrUtilEnhancedTest.java index 7b2177b..8594305 100644 --- a/src/test/java/com/yexuejc/base/util/StrUtilEnhancedTest.java +++ b/src/test/java/com/yexuejc/base/util/StrUtilEnhancedTest.java @@ -21,6 +21,8 @@ import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; +import com.yexuejc.base.exception.BaseException; + import static org.junit.jupiter.api.Assertions.*; /** @@ -34,7 +36,7 @@ class StrUtilEnhancedTest { @Test @DisplayName("测试MD5计算的一致性") - void testMD5Consistency() { + void testMD5Consistency() throws BaseException { String input = "Hello World!"; String expected = "ed076287532e86365e841e92bfc50d8c"; // 已知MD5值 @@ -47,7 +49,7 @@ class StrUtilEnhancedTest { @Test @DisplayName("测试SHA256计算的一致性") - void testSHA256Consistency() { + void testSHA256Consistency() throws BaseException { String input = "Hello World!"; String expected = "7f83b1657ff1fc53b92dc18148a1d65dfc2d4b1fa3d677284addd200126d9069"; // 已知SHA256值 @@ -60,26 +62,25 @@ class StrUtilEnhancedTest { @Test @DisplayName("测试MD5处理null值") - void testMD5WithNull() { + void testMD5WithNull() throws BaseException { assertNull(StrUtil.toMD5(null)); } @Test @DisplayName("测试SHA256处理null值") - void testSHA256WithNull() { + void testSHA256WithNull() throws BaseException { assertNull(StrUtil.toSHA256(null)); } @Test @DisplayName("测试不支持的SHA算法") void testUnsupportedSHAAlgorithm() { - String result = StrUtil.toSHA("test", "INVALID_ALGORITHM"); - assertNull(result); + assertThrows(BaseException.class, () -> StrUtil.toSHA("test", "INVALID_ALGORITHM")); } @Test @DisplayName("测试中文字符的MD5计算") - void testMD5WithChinese() { + void testMD5WithChinese() throws BaseException { String input = "你好世界"; String result = StrUtil.toMD5(input); @@ -90,7 +91,7 @@ class StrUtilEnhancedTest { @Test @DisplayName("测试中文字符的SHA256计算") - void testSHA256WithChinese() { + void testSHA256WithChinese() throws BaseException { String input = "你好世界"; String result = StrUtil.toSHA256(input); @@ -101,7 +102,7 @@ class StrUtilEnhancedTest { @Test @DisplayName("测试长字符串的MD5计算") - void testMD5WithLongString() { + void testMD5WithLongString() throws BaseException { StringBuilder longString = new StringBuilder(); for (int i = 0; i < 10000; i++) { longString.append("abcdefghij"); @@ -164,7 +165,7 @@ class StrUtilEnhancedTest { @Test @DisplayName("测试线程安全性 - MD5计算") - void testMD5ThreadSafety() throws InterruptedException { + void testMD5ThreadSafety() throws InterruptedException, BaseException { final int threadCount = 20; final int iterationsPerThread = 100; final String testString = "Thread Safety Test"; @@ -176,8 +177,13 @@ class StrUtilEnhancedTest { 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)) { + try { + String result = StrUtil.toMD5(testString); + if (!expectedMD5.equals(result)) { + hasError.set(true); + break; + } + } catch (BaseException e) { hasError.set(true); break; } @@ -192,7 +198,7 @@ class StrUtilEnhancedTest { @Test @DisplayName("测试线程安全性 - SHA256计算") - void testSHA256ThreadSafety() throws InterruptedException { + void testSHA256ThreadSafety() throws InterruptedException, BaseException { final int threadCount = 20; final int iterationsPerThread = 100; final String testString = "Thread Safety Test"; @@ -204,8 +210,13 @@ class StrUtilEnhancedTest { 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)) { + try { + String result = StrUtil.toSHA256(testString); + if (!expectedSHA256.equals(result)) { + hasError.set(true); + break; + } + } catch (BaseException e) { hasError.set(true); break; } @@ -258,7 +269,7 @@ class StrUtilEnhancedTest { @Test @DisplayName("测试性能 - MD5计算") - void testMD5Performance() { + void testMD5Performance() throws BaseException { String testString = "Performance test string with some content to hash"; long startTime = System.nanoTime(); @@ -278,7 +289,7 @@ class StrUtilEnhancedTest { @Test @DisplayName("测试边界值") - void testBoundaryValues() { + void testBoundaryValues() throws BaseException { // 测试空字符串 String emptyResult = StrUtil.toMD5(""); assertNotNull(emptyResult); diff --git a/src/test/java/com/yexuejc/base/util/StrUtilTest.java b/src/test/java/com/yexuejc/base/util/StrUtilTest.java index 28087cc..058b53c 100644 --- a/src/test/java/com/yexuejc/base/util/StrUtilTest.java +++ b/src/test/java/com/yexuejc/base/util/StrUtilTest.java @@ -9,6 +9,7 @@ package com.yexuejc.base.util; +import com.yexuejc.base.exception.BaseException; import org.junit.jupiter.api.Test; import java.util.ArrayList; @@ -69,7 +70,7 @@ class StrUtilTest { } @Test - void toMD5() { + void toMD5() throws BaseException { String md5 = StrUtil.toMD5("test"); assertNotNull(md5); assertEquals(32, md5.length()); @@ -78,14 +79,14 @@ class StrUtilTest { } @Test - void toSHA256() { + void toSHA256() throws BaseException { String sha256 = StrUtil.toSHA256("test"); assertNotNull(sha256); assertEquals(64, sha256.length()); } @Test - void toSHA() { + void toSHA() throws BaseException { String sha1 = StrUtil.toSHA("test", "SHA-1"); assertNotNull(sha1); assertEquals(40, sha1.length());