SpringBoot @JsonMixin + Jackson @JsonProperty注解 实现返回json数据key的转换

参考资料

  1. Springboot 一个注解搞定返回参数key转换 【实用】
  2. Spring Boot 2.7新特性:@JsonMixin


一. 需求

项目中我们有可能调用第三方接口,返回数据。

⏹我们期待的数据为

{
	"id": "110120119",
	"name": "jiafeitian",
	"address": "地球"
}

⏹但是第三方接口返回的数据为

{
	"id": "110120119",
	"name": "jiafeitian",
	"humanAddress": "地球"
}

😵由于返回的数据中有部分不符合我们的需求,因此需要手动getset一下,
如果项目中有多个地方都需要调用此接口,那么每调用一次都需要手动修改一下。

entity.setAddress(apiEntity.getHumanAddress());

二. 前期准备

⏹前台发送请求

$.ajax({
    url: "/test01/getCardInfo1",
    type: 'POST',
    data: null,
    contentType: 'application/json;charset=utf-8',
    success: function (data, status, xhr) {
    	debugger;
        console.log(data);
    }
});

⏹第三方接口与第三方实体类

  • 第三方实体类
import lombok.Builder;
import lombok.Data;

@Data
@Builder
public class Card {
	
	private String id;
	
	private String name;
	
	private String mobile;
}
  • 模拟第三方接口
import org.springframework.stereotype.Service;

@Service
public class Test01Service {
	
	// 第三方接口的方法
	public Card getCardInfo() {
		return Card.builder()
				.id("110")
				.name("Test")
				.mobile("110120119")
				.build();
	}
}

三. 解决方式一: @JsonProperty注解

  • 将该注解直接作用于实体类上,标记想要返回的key
  • 此情况适用于能修改其他包实体类的情况下,部分jar包中的代码我们无法修改
  • 在实际业务中,部分代码可能不允许修改
import com.fasterxml.jackson.annotation.JsonProperty;

import lombok.Builder;
import lombok.Data;

@Data
@Builder
public class Card {
	
	private String id;
	
	private String name;
	
	// 标记我们想要返回的key的名称
	@JsonProperty("jmw_phone")
	private String mobile;
}

⏹调用

@Controller
@RequestMapping("/test01")
public class Test01Controller {
	
	@Resource
	private Test01Service service;
	
	@PostMapping("/getCardInfo1")
	@ResponseBody
	public Card getCardInfo1() {
		Card cardInfo = service.getCardInfo();
		return cardInfo;
	}
}	

💪可以看到,最终返回的是jmw_phone,而不是mobile

在这里插入图片描述

三. 解决方式二: @JsonProperty + @JsonMixin注解

@JsonMixin注解是Spring Boot 2.7.x之后出现的新特性,可以在不修改已有的Java类库的情况下,定制Json的输出。

3.1 方式1 混入单个类

3.1.1 创建一个被@JsonMixin注解修饰的抽象类

  • Spring Boot的Jackson自动配置将扫描应用程序的包以查找带有@JsonMixin注解的类,
    并将它们注册到自动配置的ObjectMapper中。
  • 我们通过@JsonMixin注解将Card.class这个类混入到CardWarp 中,然后在指定需要被定制的属性中使用@JsonProperty注解来修改返回json时的key。
import org.springframework.boot.jackson.JsonMixin;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;

@Data
@JsonMixin(Card.class)
public abstract class CardWarp {
	
	// 自定义返回json的key
	@JsonProperty("jmw_phone")
	private String mobile;
}

3.1.2 调用查看效果

@Controller
@RequestMapping("/test01")
public class Test01Controller {
	
	@Resource
	private Test01Service service;
	
	@PostMapping("/getCardInfo2")
	@ResponseBody
	public Card getCardInfo2() {
		Card cardInfo = service.getCardInfo();
		return cardInfo;
	}
}

💪可以看到,我们只是新创建了CardWarp ,并没有对Card类进行任何改动,
依然能实现效果。

在这里插入图片描述

3.2 方式2 混入多个类

3.2.1 第三方接口中的类

import lombok.Builder;
import lombok.Data;

@Data
@Builder
public class Card {
	
	private String id;
	
	private String name;
	
	private String mobile;
}
import lombok.Builder;
import lombok.Data;

@Data
@Builder
public class Person {

	private String personId;

    private String humanName;

    private String age;
}

3.2.2 @JsonMixin注解混入多个类

import org.springframework.boot.jackson.JsonMixin;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;

@Data
@JsonMixin({Card.class, Person.class})
public abstract class CardWarp {
	
	// 将Card中的mobile修改为jmw_phone
	@JsonProperty("jmw_phone")
	private String mobile;
	
	// 将Person中的humanName修改为personName
	@JsonProperty("personName")
	private String humanName;
}

3.2.3 定义实体类组合第三方接口中的类

import lombok.Builder;
import lombok.Data;

@Data
@Builder
public class Test02Entity {
	
	private String uuid;
	
	// 组合Card 类
	private Card card;
	
	// 组合person类
	private Person person;
}

3.2.4 调用查看效果

@Controller
@RequestMapping("/test01")
public class Test01Controller {
	
	@Resource
	private Test01Service service;
	
	@PostMapping("/getCardInfo3")
	@ResponseBody
	public Test02Entity getCardInfo3() {
		
		return Test02Entity.builder()
				.uuid("X6u8iy&y")
				.card(Card.builder().id("10").mobile("15165244").name("测试").build())
				.person(Person.builder().personId("20").humanName("贾飞天").age("100").build())
				.build();
	}
}

💪可以看到,我们的对key的修改起到了效果

在这里插入图片描述

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
问题描述 在 SpringBoot 中,当向前端返回一个数组对象时,对象里面的键是无序的。通过使用 @JsonPropertyOrder 注解指定键的顺序,但是该注解似乎无效。 问题分析 在 Java 中,Map 接口的实现类 HashMap 是无序的,LinkedHashMap 则是有序的。因此,当使用 @JsonPropertyOrder 注解来指定键的顺序时,实际上是针对 LinkedHashMap 的,而不是针对 HashMap。在 SpringBoot 中,默认使用的是 Jackson 库来处理 JSON 数据Jackson 库在反序列化 JSON 数据时,会将 JSON 数据转换成 LinkedHashMap 对象,因此 @JsonPropertyOrder 注解对于 LinkedHashMap 是有效的。但是,在将 LinkedHashMap 对象序列化成 JSON 数据时,Jackson 库会将 LinkedHashMap 对象转换成 HashMap 对象,因此 @JsonPropertyOrder 注解对于 HashMap 是无效的。 解决方法 1. 使用 LinkedHashMap 将对象中的 Map 属性改为 LinkedHashMap 类型,这样在将对象序列化成 JSON 数据时,Jackson 库不会将 LinkedHashMap 对象转换成 HashMap 对象,@JsonPropertyOrder 注解就可以生效了。 2. 使用 @JsonSerialize 使用 @JsonSerialize 注解,可以指定自定义的序列化器来控制 JSON 数据的输出顺序。示例代码如下: ```java @JsonSerialize(using = CustomSerializer.class) public class CustomObject { private Map<String, Object> data; // getter and setter } public class CustomSerializer extends JsonSerializer<CustomObject> { @Override public void serialize(CustomObject value, JsonGenerator gen, SerializerProvider serializers) throws IOException { gen.writeStartObject(); LinkedHashMap<String, Object> data = new LinkedHashMap<>(value.getData()); for (Map.Entry<String, Object> entry : data.entrySet()) { gen.writeObjectField(entry.getKey(), entry.getValue()); } gen.writeEndObject(); } } ``` 在 CustomObject 类上,使用 @JsonSerialize 注解指定 CustomSerializer 作为序列化器。在 CustomSerializer 中,将 CustomObject 中的 Map 属性转换成 LinkedHashMap,然后遍历 LinkedHashMap,按照指定的顺序输出 JSON 数据,这样就可以实现键有序输出了。 参考链接 1. https://stackoverflow.com/questions/29214776/jsonpropertyorder-not-working-for-json-arrays 2. https://stackoverflow.com/questions/54952412/jsonpropertyorder-not-working-with-spring-boot-2-1-3-and-jackson-2-9-8

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值