如何在 RestController 中使用基于 JsonView 的两个不同的 getter 进行序列化?

Posted

技术标签:

【中文标题】如何在 RestController 中使用基于 JsonView 的两个不同的 getter 进行序列化?【英文标题】:How do I serialize using two different getters based on JsonView in RestController? 【发布时间】:2019-09-18 14:50:19 【问题描述】:

我希望能够基于 JsonView 序列化对象中的字段。不一定非要JsonView,这正是我一直在探索的。基本上在 RestController 类上使用 @JsonView 注释,它会序列化我的 POJO。 但是我有一个用户和管理员视图,其中有一个对象:

地图秘密;

对于管理员视图,我希望 key:value 显示和序列化,但对于用户,我只想要一个 List 键,或者如果它更简单,保留 Map 但只显示键和所有值切换到'****' 4 个星号什么的。

我想过有两个 getter,但 JsonView 注释不像两个 getter 可以有不同的视图,而 Jackson 知道要调用哪一个。

我不确定 JsonView 是不是这里最好的东西。也许是基于视图或一些自定义序列化程序进行序列化的 JsonGetter 方法,但我认为可能有一种更直接的方法来使用 Jackson 和少量注释

我想做的是:

Person.java
Map<String,String> secrets;

这将序列化为(对于管理员):


"person":
  "secrets":
     "password":"123456",
     "creditCard":"1234 5678 9101"
   
 

这将序列化为(对于用户):


"person":
  "secrets":
     "password":"****",
     "creditCard":"****"
   
 

但是我想我能做的事情是这样的


@JsonView(View.User.class)
Map<String,String> getSecrets()
  this.secrets.forEach(value -> "****") //code would be different but basically setting all values to ****
  return secrets;


@JsonView(View.Admin.class)
Map<String,String> getSecrets()
  //Returning secrets as they should be
  return secrets;

【问题讨论】:

请提供示例代码,以便问题更加透明。 @Ananthu 当然,添加了一些示例 既然你想序列化一个集合(map),它会是一个数组[],用于实体(pojo);所有属性都将被序列化,因为每个属性都有吸气剂!!! 【参考方案1】:

您可以尝试为对象映射器定义一个自定义序列化器,这样每当对象映射器用于序列化时,您就可以检查并转换密码和信用卡字段到您选择的值。例如

public class ItemSerializer extends StdSerializer<Item> 

    public ItemSerializer() 
        this(null);
    

    public ItemSerializer(Class<Item> t) 
        super(t);
    

    @Override
    public void serialize(
      Item value, JsonGenerator jgen, SerializerProvider provider) 
      throws IOException, JsonProcessingException 

        jgen.writeStartObject();
        jgen.writeNumberField("id", value.id);
        jgen.writeStringField("itemName", value.itemName);
        jgen.writeNumberField("owner", value.owner.id);
        jgen.writeEndObject();
    

然后您可以提供一个使用此自定义序列化程序的对象映射器,

Item myItem = new Item(1, "theItem", new User(2, "theUser"));
ObjectMapper mapper = new ObjectMapper();

SimpleModule module = new SimpleModule();
module.addSerializer(Item.class, new ItemSerializer());
mapper.registerModule(module);

String serialized = mapper.writeValueAsString(myItem);

在您的情况下,您可以在 spring 上下文中使用自定义序列化程序注册 objectmapper bean,并让 jackson 使用您的 object mapper bean。

或者使用@JsonSerialize注解:

public class Event 
    public String name;

    @JsonSerialize(using = CustomDateSerializer.class)
    public Date eventDate;



Public class CustomDateSerializer extends StdSerializer<Date> 

    private static SimpleDateFormat formatter 
      = new SimpleDateFormat("dd-MM-yyyy hh:mm:ss");

    public CustomDateSerializer()  
        this(null); 
     

    public CustomDateSerializer(Class<Date> t) 
        super(t); 
    

    @Override
    public void serialize(
      Date value, JsonGenerator gen, SerializerProvider arg2) 
      throws IOException, JsonProcessingException 
        gen.writeString(formatter.format(value));
    

参考:

https://www.baeldung.com/jackson-json-view-annotation

https://www.baeldung.com/jackson-custom-serialization

【讨论】:

以上是关于如何在 RestController 中使用基于 JsonView 的两个不同的 getter 进行序列化?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Spring Boot 的另一个 RestController 中使用 @Autowired/@Inject 访问 RestController 的路径?

如何使用 ModelAndView 在 RestController 上实现 REST API

如何在 Spring Boot 的 @RestController 注释用于创建请求处理程序的方法中使用带有参数的构造函数

如何在 Spring RestController 中下载 excel 文件

使用 @RestController 在 Spring Boot 中发布数据时出错

如何在Jpa中使用所选实体创建行,RestController Spring Boot