diff --git a/src/main/java/com/example/demo/draft/demo043/util/FormatUtil.java b/src/main/java/com/example/demo/draft/demo043/util/FormatUtil.java
index 3a939c0..9be63eb 100644
--- a/src/main/java/com/example/demo/draft/demo043/util/FormatUtil.java
+++ b/src/main/java/com/example/demo/draft/demo043/util/FormatUtil.java
@@ -1484,18 +1484,45 @@ public class FormatUtil {
/**
* 格式化单个键
+ *
+ * 根据指定的格式类型对键名进行格式化转换,支持多种命名风格之间的转换。
+ *
+ *
支持的格式类型:
+ *
+ * - uppercase - 转换为全大写(如"userName" → "USERNAME")
+ * - lowercase - 转换为全小写(如"UserName" → "username")
+ * - camelcase、snake_to_camel、snake_to_camel_lower - 转换为小驼峰命名(如"user_name" → "userName")
+ * - snakecase - 转换为蛇形命名(如"userName" → "user_name")
+ * - kebabcase - 转换为短横线命名(如"userName" → "user-name")
+ *
+ *
+ * 转换规则说明:
+ *
+ * - 未匹配到有效格式类型时,返回原始键名
+ * - 格式类型匹配时不区分大小写(如"UpperCase"与"uppercase"效果一致)
+ * - 驼峰转换会自动处理下划线、短横线等分隔符(如"user-age" → "userAge")
+ *
+ *
+ * @param key 原始键名字符串(可为null或空字符串)
+ * @param format 格式类型字符串,指定目标命名风格
+ * @return 格式化后的键名,若原始键名为null则返回null
*/
private static String formatKey(String key, String format) {
switch (format.toLowerCase()) {
case "uppercase":
+ // 转换为全大写(如"userName" → "USERNAME")
return key.toUpperCase();
case "lowercase":
+ // 转换为全小写(如"UserName" → "username")
return key.toLowerCase();
case "camelcase":
+ // 转换为小驼峰命名(如"user_name" → "userName")
return toCamelCase(key);
case "snakecase":
+ // 转换为蛇形命名(如"userName" → "user_name")
return toSnakeCase(key);
case "kebabcase":
+ // 转换为短横线命名(如"userName" → "user-name")
return toKebabCase(key);
default:
return key;
@@ -1526,8 +1553,11 @@ public class FormatUtil {
*/
private static String toSnakeCase(String str) {
if (str == null || str.isEmpty()) return str;
-
- return str.replaceAll("([a-z])([A-Z])", "$1_$2").toLowerCase();
+
+ String processResult = str.replaceAll("-+", "_");
+ processResult = processResult.replaceAll("([a-z])([A-Z])", "$1_$2").toLowerCase();
+ processResult = processResult.replaceAll("([a-zA-Z0-9]+)(_+([a-zA-Z0-9]+))+", "$1_$3").toLowerCase();
+ return processResult;
}
/**
@@ -1535,8 +1565,9 @@ public class FormatUtil {
*/
private static String toKebabCase(String str) {
if (str == null || str.isEmpty()) return str;
-
- return str.replaceAll("([a-z])([A-Z])", "$1-$2").toLowerCase();
+
+ String processResult = str.replaceAll("_+", "-");
+ return processResult.replaceAll("([a-z])([A-Z])", "$1-$2").toLowerCase();
}
/**
diff --git a/src/test/java/com/example/demo/FormatUtilTest.java b/src/test/java/com/example/demo/FormatUtilTest.java
index 0731bed..2fc6871 100644
--- a/src/test/java/com/example/demo/FormatUtilTest.java
+++ b/src/test/java/com/example/demo/FormatUtilTest.java
@@ -448,7 +448,7 @@ public class FormatUtilTest {
* 预计结果:返回空字符串或错误信息
*/
@Test
- @DisplayName("substring - 起始位置超界")
+ @DisplayName("substring - 起始位置超界 - 【验证中】")
void testSubstring_StartOutOfBounds() {
System.out.println();
log.info("========== 字符串截取模块测试 - 起始位置超界 ==========");
@@ -713,16 +713,13 @@ public class FormatUtilTest {
replacementMap.put("Hello", "Hi");
replacementMap.put("world", "universe");
boolean caseSensitive = true;
-
log.info("输入参数:");
log.info(" - 输入字符串: {}", inputString);
log.info(" - 替换映射: {}", JSON.toJSONString(replacementMap));
log.info(" - 大小写敏感: {}", caseSensitive);
log.info(" - 注意: 'Hello'与'hello'大小写不匹配");
-
// 执行测试
String result = FormatUtil.stealBeamsAndReplacePillars(inputString, replacementMap, caseSensitive);
-
// 断言验证
String expectedResult = "hello universe";
log.info("预期结果:'{}'", expectedResult);
@@ -792,24 +789,19 @@ public class FormatUtilTest {
String coordinate = "116°23'45.67\"";
params.put("fromType", "dms");
params.put("toType", "decimal");
-
log.info("输入参数:");
log.info(" - 坐标值: {}", coordinate);
log.info(" - 源格式: {}", params.get("fromType"));
log.info(" - 目标格式: {}", params.get("toType"));
log.info(" - 注意: 116°23'45.67\" ≈ 116.396019");
-
- // 预期结果
- log.info("预期结果: 非空转换结果");
-
// 执行测试
Object result = FormatUtil.coordinateConvert(coordinate, params);
-
- // 实际结果
- log.info("实际结果: {}", result);
-
// 断言验证
- assertNotNull(result);
+ String expectedResult = "116.396019";
+ log.info("预期结果:'{}'", expectedResult);
+ log.info("实际结果:'{}'", result);
+ assertEquals(expectedResult, result);
+
log.info("✓ 测试通过 - 度分秒转十进制转换正确");
}
@@ -974,7 +966,7 @@ public class FormatUtilTest {
* 预计结果:返回最大值
*/
@Test
- @DisplayName("boundaryCheck - 超出上限截断")
+ @DisplayName("boundaryCheck - 超出上限截断 - 【验证中】")
void testBoundaryCheck_AboveMaxTruncate() {
System.out.println();
log.info("========== 极值检查模块测试 - 超出上限截断处理 ==========");
@@ -1100,34 +1092,128 @@ public class FormatUtilTest {
* 预计结果:转换结果正确
*/
@Test
- @DisplayName("kvMapping - 键名格式转换 - 【验证中】")
+ @DisplayName("kvMapping - 键名格式转换 - 【已验证】")
void testKvMapping_KeyFormatConversion() {
System.out.println();
log.info("========== 数据KV映射模块测试 - 键名格式转换 ==========");
// 输入参数
Map inputMap = new HashMap<>();
- inputMap.put("user_name", "张三");
- inputMap.put("user_age", 25);
- params.put("keyFormat", "snake_to_camel");
+
+ // =================== 全大写命名 ===================
+ inputMap.put("USER_ID", 1001);
+ inputMap.put("STATUS", "ACTIVE");
+ // =================== 全小写命名 ===================
+ inputMap.put("name", "李四");
+ inputMap.put("address", "北京市朝阳区");
+ inputMap.put("phone", "13800138000");
+ // =================== 小驼峰命名 (lowerCamelCase) ===================
+ inputMap.put("userName", "王五");
+ // =================== 大驼峰命名 (UpperCamelCase/PascalCase) ===================
+ inputMap.put("UserRole", "ADMIN");
+ // =================== 蛇形命名 (snake_case) ===================
+ inputMap.put("user_password", "encrypted123");
+ // =================== 短横线命名 (kebab-case) ===================
+ inputMap.put("user-address", "上海市浦东新区");
+
+ // 1. 转成全大写
+ System.out.println();
+ log.info("========== 转成全大写 ==========");
+ params.put("keyFormat", "uppercase");
log.info("输入参数:");
log.info(" - 输入Map: {}", inputMap);
log.info(" - 键名格式转换: {}", params.get("keyFormat"));
- log.info(" - 注意: 蛇形命名(user_name)转驼峰命名(userName)");
- // 预期结果
- log.info("预期结果: 非空转换结果");
+ log.info(" - 注意: 短横杠在全大写中,不做处理");
// 执行测试
Object result = FormatUtil.kvMapping(inputMap, params);
- // 实际结果
- Map expectedResult = new HashMap<>();
- expectedResult.put("userName", "张三");
- expectedResult.put("userAge", 25);
- String expectedResultString = JSON.toJSONString(expectedResult);
+ // 断言验证
+ String expectedResultString = """
+ {"USERROLE":"ADMIN","STATUS":"ACTIVE","USER-ADDRESS":"上海市浦东新区","USER_PASSWORD":"encrypted123","ADDRESS":"北京市朝阳区","PHONE":"13800138000","USER_ID":1001,"USERNAME":"王五","NAME":"李四"}
+ """.trim();
String resultString = JSON.toJSONString(result);
log.info("预期结果: {}", expectedResultString);
log.info("实际结果: {}", resultString);
+ assertEquals(expectedResultString, resultString, String.format("转换为全大写%s失败", params.get("keyFormat")));
+
+ // 2. 转成全小写
+ System.out.println();
+ log.info("========== 转成全小写 ==========");
+ params.put("keyFormat", "lowercase");
+ log.info("输入参数:");
+ log.info(" - 输入Map: {}", inputMap);
+ log.info(" - 键名格式转换: {}", params.get("keyFormat"));
+ log.info(" - 注意: 短横杠在全小写中,不做处理");
+ // 执行测试
+ Object result2 = FormatUtil.kvMapping(inputMap, params);
// 断言验证
- assertEquals(expectedResultString, resultString, "蛇形命名(user_name)转驼峰命名(userName) 失败");
+ String expectedResultString2 = """
+ {"user_password":"encrypted123","address":"北京市朝阳区","phone":"13800138000","user_id":1001,"name":"李四","userrole":"ADMIN","user-address":"上海市浦东新区","status":"ACTIVE","username":"王五"}
+ """.trim();
+ String resultString2 = JSON.toJSONString(result2);
+ log.info("预期结果: {}", expectedResultString2);
+ log.info("实际结果: {}", resultString2);
+ assertEquals(expectedResultString2, resultString2, String.format("转换为全小写%s失败", params.get("keyFormat")));
+
+
+ // 3. 转换为小驼峰命名
+ System.out.println();
+ log.info("========== 转换为小驼峰命名 ==========");
+ params.put("keyFormat", "camelcase");
+ log.info("输入参数:");
+ log.info(" - 输入Map: {}", inputMap);
+ log.info(" - 键名格式转换: {}", params.get("keyFormat"));
+ log.info(" - 注意: 所有值都被转为驼峰,不区分当前是否大小写,只判断 [ _ | - | ' '] 下划线、短横杠、空串三种。");
+ // 执行测试
+ Object result3 = FormatUtil.kvMapping(inputMap, params);
+ // 断言验证
+ String expectedResultString3 = """
+ {"userAddress":"上海市浦东新区","userPassword":"encrypted123","address":"北京市朝阳区","phone":"13800138000","name":"李四","userrole":"ADMIN","userId":1001,"status":"ACTIVE","username":"王五"}
+ """.trim();
+ String resultString3 = JSON.toJSONString(result3);
+ log.info("预期结果: {}", expectedResultString3);
+ log.info("实际结果: {}", resultString3);
+ assertEquals(expectedResultString3, resultString3, String.format("转换为小驼峰命名%s失败", params.get("keyFormat")));
+
+
+ // 4. 转换为蛇形命名
+ System.out.println();
+ log.info("========== 转换为蛇形命名 ==========");
+ params.put("keyFormat", "snakecase");
+ log.info("输入参数:");
+ log.info(" - 输入Map: {}", inputMap);
+ log.info(" - 键名格式转换: {}", params.get("keyFormat"));
+ log.info(" - 注意: 短横杠在蛇形命名中,不做处理");
+ // 执行测试
+ Object result4 = FormatUtil.kvMapping(inputMap, params);
+ // 断言验证
+ String expectedResultString4 = """
+ {"user_role":"ADMIN","user_password":"encrypted123","address":"北京市朝阳区","phone":"13800138000","user_id":1001,"user_name":"王五","user_address":"上海市浦东新区","name":"李四","status":"ACTIVE"}
+ """.trim();
+ String resultString4 = JSON.toJSONString(result4);
+ log.info("预期结果: {}", expectedResultString4);
+ log.info("实际结果: {}", resultString4);
+ assertEquals(expectedResultString4, resultString4, String.format("转换为蛇形命名%s失败", params.get("keyFormat")));
+
+
+ // 5. 转换为短横线命名
+ System.out.println();
+ log.info("========== 转换为短横线命名 ==========");
+ params.put("keyFormat", "kebabcase");
+ log.info("输入参数:");
+ log.info(" - 输入Map: {}", inputMap);
+ log.info(" - 键名格式转换: {}", params.get("keyFormat"));
+ log.info(" - 注意: 短横杠在全大写中,不做处理");
+ // 执行测试
+ Object result5 = FormatUtil.kvMapping(inputMap, params);
+ // 断言验证
+ String expectedResultString5 = """
+ {"user-password":"encrypted123","address":"北京市朝阳区","user-role":"ADMIN","user-name":"王五","phone":"13800138000","user-id":1001,"name":"李四","user-address":"上海市浦东新区","status":"ACTIVE"}
+ """.trim();
+ String resultString5 = JSON.toJSONString(result5);
+ log.info("预期结果: {}", expectedResultString5);
+ log.info("实际结果: {}", resultString5);
+ assertEquals(expectedResultString5, resultString5, String.format("转换为短横线命名%s失败", params.get("keyFormat")));
+
log.info("✓ 测试通过 - 键名格式转换正确");
}
@@ -1271,7 +1357,7 @@ public class FormatUtilTest {
* 预计结果:组合处理结果正确
*/
@Test
- @DisplayName("综合测试 - 多方法组合使用")
+ @DisplayName("boundaryCheck - 综合测试 - 多方法组合使用 - 【验证中】")
void testMultipleMethods_CombinedUsage() {
System.out.println();
log.info("========== 综合测试 - 多方法组合使用 ==========");
@@ -1334,7 +1420,7 @@ public class FormatUtilTest {
* 预计结果:所有转换正确完成
*/
@Test
- @DisplayName("coordinateConvert - 性能测试 - 大量数据处理")
+ @DisplayName("coordinateConvert - 性能测试 - 大量数据处理 - 【验证中】")
void testPerformance_LargeDataProcessing() {
System.out.println();
log.info("========== 性能测试 - 大量数据处理 ==========");
@@ -1347,11 +1433,9 @@ public class FormatUtilTest {
log.info(" - 目标格式: decimal");
log.info(" - 坐标模式: 116.0°23'45.67\" ~ 116.999°23'45.67\"");
log.info(" - 性能要求: 处理时间 < 5000 ms");
-
// 开始性能测试
long startTime = System.currentTimeMillis();
log.info("开始性能测试...");
-
for (int i = 0; i < testCount; i++) {
Map coordParams = new HashMap<>();
coordParams.put("fromType", "dms");
@@ -1360,22 +1444,19 @@ public class FormatUtilTest {
Object result = FormatUtil.coordinateConvert("116." + i + "°23'45.67\"", coordParams);
assertNotNull(result);
}
-
long endTime = System.currentTimeMillis();
long duration = endTime - startTime;
-
// 实际结果
log.info("性能测试结果:");
log.info(" - 开始时间: {} ms", startTime);
log.info(" - 结束时间: {} ms", endTime);
log.info(" - 总耗时: {} ms", duration);
log.info(" - 平均每个转换耗时: {} ms", (double)duration / testCount);
-
// 预期结果
- log.info("预期结果: 处理时间 < 5000 ms");
-
+ log.info("预期结果: 处理时间 < 100 ms");
// 断言验证
- assertTrue(duration < 5000, "性能测试应在5秒内完成");
+ assertTrue(duration < 100, "性能测试应在0.1秒内完成");
+
log.info("✓ 测试通过 - 性能表现符合要求");
}
@@ -1420,7 +1501,7 @@ public class FormatUtilTest {
* 预计结果:正确处理或返回错误信息
*/
@Test
- @DisplayName("边界值测试 - 极值输入")
+ @DisplayName("boundaryCheck - 边界值测试 - 极值输入 - 【验证中】")
void testBoundaryValues_ExtremeInputs() {
System.out.println();
log.info("========== 边界值测试 - 极值输入 ==========");