Spring Boot项目通用JSON转统一Java类映射器实现问询
嘿,这个场景我之前做物联网相关项目的时候刚好碰到过!处理多格式JSON到统一Java类的映射,在Spring Boot里确实是很常见的需求,我来帮你梳理下可行的方案,顺便把你提到的思路补全~
首先先明确咱们的目标:不管是基础格式还是变体格式,最终都要映射到同一个SensorData类,先把这个类定义出来(按需调整字段):
@JsonIgnoreProperties(ignoreUnknown = true) // 先加上这个,避免多余字段触发反序列化报错 public class SensorData { private String id; private String type; private Double value; private String location; // 变体格式里的location字段,按需保留 // 常规的getter、setter、无参/全参构造器就不赘述啦 }
接下来讲两种核心方案:
方案一:自定义Jackson反序列化器(灵活度拉满)
我猜你提到的“Cr...”应该是Custom Deserializer吧?这是最灵活的方式,能完全掌控JSON到对象的映射逻辑,适合结构差异较大的场景。
步骤很清晰:
- 写一个类实现
JsonDeserializer<SensorData>接口,重写deserialize方法 - 在方法里判断JSON的结构:比如检查是否存在
data字段,区分是基础格式还是变体格式 - 分别解析不同字段,组装成统一的
SensorData对象
直接上代码示例:
public class SensorDataDeserializer extends JsonDeserializer<SensorData> { @Override public SensorData deserialize(JsonParser p, DeserializationContext ctxt) throws IOException { JsonNode rootNode = p.getCodec().readTree(p); SensorData result = new SensorData(); // 先处理公共的id字段 result.setId(rootNode.get("id").asText()); // 判断是否是变体格式(包含data节点) if (rootNode.has("data")) { JsonNode dataNode = rootNode.get("data"); // 处理type:把"temp"映射成"temperature",其他值保持原样 String rawType = dataNode.get("type").asText(); result.setType("temp".equals(rawType) ? "temperature" : rawType); // 处理value:对应变体里的val字段 result.setValue(dataNode.get("val").asDouble()); // 处理location字段 if (rootNode.has("location")) { result.setLocation(rootNode.get("location").asText()); } } else { // 基础格式直接映射 result.setType(rootNode.get("type").asText()); result.setValue(rootNode.get("value").asDouble()); } return result; } }
然后在SensorData类上加上注解,告诉Jackson用咱们自定义的反序列化器:
@JsonDeserialize(using = SensorDataDeserializer.class) @JsonIgnoreProperties(ignoreUnknown = true) public class SensorData { // ... 类内容 }
这样之后,你在Controller里用@RequestBody SensorData sensorData接收请求时,两种JSON格式都能自动转成统一的对象啦~
方案二:用Jackson注解简化映射(轻量快捷)
如果JSON的结构差异没那么大,只是字段名或者嵌套层级不同,可以用Jackson的注解来搞定,不用写完整的反序列化器。
核心用到的注解:
@JsonAlias:给字段指定多个别名(比如value和val)@JsonAnySetter:处理未匹配到的字段(比如变体里的data嵌套对象)@JsonSetter:自定义字段的set逻辑(比如把temp转成temperature)
代码示例:
@JsonIgnoreProperties(ignoreUnknown = true) public class SensorData { private String id; private String type; // 给value字段指定别名val,基础格式的value和变体格式的val都能映射过来 @JsonAlias({"value", "val"}) private Double value; private String location; // 自定义type的set逻辑:把temp转成temperature @JsonSetter("type") public void setType(String type) { this.type = "temp".equalsIgnoreCase(type) ? "temperature" : type; } // 处理变体格式里的data嵌套字段 @JsonAnySetter public void handleExtraFields(String fieldName, Object fieldValue) { if ("data".equals(fieldName) && fieldValue instanceof Map) { Map<String, Object> dataMap = (Map<String, Object>) fieldValue; // 处理data里的type if (dataMap.containsKey("type")) { setType((String) dataMap.get("type")); } // 处理data里的val(不过@JsonAlias已经能处理,这里可以作为兜底) if (dataMap.containsKey("val")) { this.value = ((Number) dataMap.get("val")).doubleValue(); } } else if ("location".equals(fieldName)) { this.location = (String) fieldValue; } } // getter、setter省略 }
这种方式更轻量,代码量更少,但如果后续JSON格式有更多变体,自定义反序列化器的扩展性会更好。
最后小提示
不管用哪种方案,@JsonIgnoreProperties(ignoreUnknown = true)一定要加上,这样如果JSON里出现咱们没定义的字段,也不会抛出反序列化异常,系统兼容性更强~
内容的提问来源于stack exchange,提问作者Gazouu
相关产品推荐
相关产品推荐

