请教: json 字符串转 map 时,如何做到驼峰转下划线

79 天前
 NoKey
试了几个库,都是 obj 转 json 的时候可以做到驼峰转下划线
但是 json 转 map 的试试,无法转
请问一下,有啥好办法可以转么?谢谢
1669 次点击
所在节点    程序员
16 条回复
a1b2c3T
79 天前
在将 JSON 字符串转换为 Map 时,如果需要将 JSON 键的命名方式从驼峰命名法( Camel Case )转换为下划线命名法( Snake Case ),可以通过以下步骤实现:

方法一:手动转换
反序列化 JSON 字符串为 Map: 使用 Jackson 或 Gson 等库将 JSON 字符串反序列化为 Map 。
遍历 Map 并修改键名: 遍历 Map ,将每个键名从驼峰格式转换为下划线格式。
代码示例(使用 Jackson ):
java
复制代码
import com.fasterxml.jackson.databind.ObjectMapper;
import java.util.HashMap;
import java.util.Map;

public class CamelToSnake {
public static void main(String[] args) throws Exception {
String jsonString = "{\"userName\":\"JohnDoe\",\"userAge\":30}";

ObjectMapper objectMapper = new ObjectMapper();
// 反序列化 JSON 字符串为 Map
Map<String, Object> originalMap = objectMapper.readValue(jsonString, HashMap.class);

Map<String, Object> resultMap = new HashMap<>();

// 遍历 Map ,将驼峰转换为下划线格式
for (Map.Entry<String, Object> entry : originalMap.entrySet()) {
String snakeKey = camelToSnake(entry.getKey());
resultMap.put(snakeKey, entry.getValue());
}

// 输出转换后的 Map
System.out.println(resultMap);
}

// 将驼峰命名转为下划线命名
private static String camelToSnake(String camelCaseStr) {
StringBuilder result = new StringBuilder();
for (char c : camelCaseStr.toCharArray()) {
if (Character.isUpperCase(c)) {
result.append("_").append(Character.toLowerCase(c));
} else {
result.append(c);
}
}
return result.toString();
}
}
输出结果:
java
复制代码
{user_name=JohnDoe, user_age=30}
方法二:使用 Jackson 自定义策略
如果你希望自动将 JSON 中的字段从驼峰转换为下划线,可以使用 Jackson 的自定义命名策略来实现。

代码示例:
java
复制代码
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.PropertyNamingStrategies;
import java.util.Map;

public class JacksonCamelToSnake {
public static void main(String[] args) throws Exception {
String jsonString = "{\"userName\":\"JohnDoe\",\"userAge\":30}";

// 创建 ObjectMapper 并设置命名策略为下划线
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.setPropertyNamingStrategy(PropertyNamingStrategies.SNAKE_CASE);

// 反序列化 JSON 字符串为 Map
Map<String, Object> resultMap = objectMapper.readValue(jsonString, Map.class);

// 输出转换后的 Map
System.out.println(resultMap);
}
}
输出结果:
java
复制代码
{user_name=JohnDoe, user_age=30}
说明
方法一 适用于需要手动控制转换过程的场景,可以灵活处理不同的命名转换规则。
方法二 使用 Jackson 的内置命名策略,可以自动将驼峰格式转换为下划线格式,非常方便,适用于更大规模的项目。
两种方法可以根据你的需求选择合适的实现方式。
a1b2c3T
79 天前
@a1b2c3T #1 来自 gpt 的回答
NoKey
79 天前
@a1b2c3T 方案 2 我试了,不行,也是 obj 转 json 可以,json 转 obj 不行。。。
chendy
79 天前
以下内容基于你用的是 java:
既然都 Map 了就不用转换了,直接 get("xxx_bbb")
甚至 Map 都不用,有一个神奇的包里面有个神奇的类叫 JSONObject ,直接各种 get(String) 就行

如果真的要 Map 且真的要转换,遍历 key ,改 key ,塞进另外一个新 map ,也不难
chendy
79 天前
随手写一个,然后下班

```java
class Scratch {
public static void main(String[] args) {
HashMap<String, Object> map = new HashMap<>();
map.put("userName", "user01");
map.put("userAge", 18);
map.put("userFriends", Arrays.asList("user02", "user03"));
System.out.println(map);
Map<String, Object> newMap = convertMap(map);
System.out.println(newMap);
}

public static Map<String, Object> convertMap(Map<String, ?> map) {
HashMap<String, Object> newMap = new HashMap<>();
for (Map.Entry<String, ?> e : map.entrySet()) {
String key = e.getKey();
String newKey = convertKey(key);
newMap.put(newKey, e.getValue());
}
return newMap;
}

public static String convertKey(String key) {
StringBuilder b = new StringBuilder(key.length() * 2);
for (int i = 0; i < key.length(); i++) {
char c = key.charAt(i);
if (Character.isUpperCase(c)) {
b.append("_").append(Character.toLowerCase(c));
} else {
b.append(c);
}
}
return b.toString();
}
}```
Ayanokouji
79 天前
实在想不明白,为什么会有这种需求。
twofox
79 天前
jackson 示例

先把 json 字符串转为 JsonNode ,然后递归遍历所有属性,处理所有的 key ,复制到新的 objectNode 不就可以了

```java
public ObjectNode convertJsonToUnderline(JsonNode jsonNode){
if (jsonNode==null){
return null;
}
ObjectNode result = objectMapper.createObjectNode();
jsonNode.properties().forEach((entry -> {
String key = entry.getKey();
StrUtil.toUnderlineCase(key);
result.set(key, convertJsonToUnderline(entry.getValue()));
}));
return result;
}
```
twofox
79 天前
@twofox 噢,有点问题,改一下才行
zsj1029
79 天前
一般 java c# 都是拿反射的 注解实现的 ,js 得用 ts 的开启装饰器 做
twofox
79 天前
修改后的改后的代码

public static JsonNode convertJsonToUnderline(JsonNode jsonNode){
if (!(jsonNode instanceof ObjectNode)){
return jsonNode;
}
ObjectNode result = objectMapper.createObjectNode();
jsonNode.properties().forEach((entry -> {
String key = entry.getKey();
result.set(StrUtil.toUnderlineCase(key), convertJsonToUnderline(entry.getValue()));
}));
return result;
}


原始数据:{"code":0,"data":{"myStartCount":35,"todoCount":0,"doneCount":0},"msg":""}
转换后的数据:
{
"code" : 0,
"data" : {
"my_start_count" : 35,
"todo_count" : 0,
"done_count" : 0
},
"msg" : ""
}
Huelse
79 天前
要么先用正则匹配键值替换,然后再塞进 map ,要么转成 map 后再修改键值
vialon17
79 天前
@Ayanokouji 一样感觉很奇怪的需求,做个映射都好点,
CEBBCAT
79 天前
@a1b2c3T #1 GPT 回复很可能被 MOD 封号
NoKey
78 天前
@Ayanokouji 需求来源就是,json 字符串直接入库,不用 entity 映射,入库的试试,需要字段名和数据表字段一模一样,json 转 map ,map 入库,这样可以写一个通用的入库方法
Ayanokouji
78 天前
@NoKey 那这跟 json 还是没关系,还是想偷懒,bean 对象至少还有注解等原数据做转换。遇到转换后的 key 和数据库的字段还是不匹配,你打算怎么解决。比如 XMLHttpRequest 这种这类的。
a1b2c3T
78 天前
@CEBBCAT #13 啊我去,不知道还有这个规定啊。版规在哪儿呢,我去学习一下

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/1066775

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX