请稍等 ...
×

采纳答案成功!

向帮助你的同学说点啥吧!感谢那些助人为乐的人

JsonView和统一封装返回结果的问题

老师您好,项目里很多时候使用统一封装返回结果,例如课程中的SimpleResponse类。

public class User {
   public interface UserInfo{};
   public interface UserDetail extends UserInfo{};
   
   private String username;
   private String password;
   @JsonView(UserInfo.class)
   public String getUsername() {
       return username;
   }
   @JsonView(UserDetail.class)
   public String getPassword() {
       return password;
   }
}

@RequestMapping("/user")
@JsonView(User.UserInfo.class)
public User getUser(@RequestParam String username){
   User user = new User();
   user.setUsername("123");
   user.setPassword("123");
   return user;
}

@RequestMapping("/user")
@JsonView(User.UserInfo.class)
public SimpleResponse getUser(@RequestParam String username){
   User user = new User();
   user.setUsername("123");
   user.setPassword("123");
   return new SimpleResponse(user);
}

在第一个返回中 可以只给前端展示username属性

但是在第二个返回中 用SimpleResponse包装了User对象后,JsonView就失效了,在前端无法获取到User对象的数据。

想问下老师这种包装数据可不可以用@JsonView控制

谢谢老师

正在回答

插入代码

2回答

这个问题我也遇到了,我认为主要发生这个问题的原因在于:将原本的所要进行JsonView视图过滤的A对象置于B对象中。B类我称为包装类,而包装类没有进行JsonView设置。在Controller返回值进行序列化时,包装类没有匹配的JsonView,则全部将其过滤掉了,以至于没有数据返回。
解决思路有2个方向:

  1. 在包装类中添加JsonView注解。

  2. 重写包装类的序列化规则

第一个方向的思路

    如果包装类是本项目的类,那只要在包装类的对象中同样添加JsonView就可以了。

    如果包装类是其他框架引用的类,例如我所遇到的MyBatisPlus的分页对象Page,这种无法修改源码的情况,则考虑2种方法:

        1. 重写Page对象,将新对象添加JsonView注解,然后返回时将原Page对象复制到新Page对象。

        2. 通过反射,为Page对象动态添加JsonView注解。

这个思路我没有尝试下去,我认为这个思路虽然可行,但对代码的入侵性太大,不予考虑。主要尝试了第二种方案。

第二个方向的思路,重写Jackson对包装类的序列化规则。还是以MyBatisPlus的Page类为例

在不动原本代码的情况下,添加以下配置类:

@Configuration
public class JacksonConfig {

    @Bean
    public ObjectMapper objectMapper(Jackson2ObjectMapperBuilder builder){
        ObjectMapper objectMapper = builder.createXmlMapper(false).build();
        SimpleModule simpleModule = new SimpleModule();
        simpleModule.addSerializer(Page.class, new PageJsonSerializer(objectMapper));
        objectMapper.registerModule(simpleModule);
        return objectMapper;
    }
}


public class PageJsonSerializer extends JsonSerializer<Page> {

    private ObjectMapper objectMapper;

    public PageJsonSerializer(ObjectMapper objectMapper){
        this.objectMapper = objectMapper;
    }

    @Override
    public void serialize(Page page, JsonGenerator gen, SerializerProvider serializerProvider) throws IOException {
        gen.writeStartObject();
        gen.writeNumberField("total", page.getTotal());
        gen.writeNumberField("size", page.getSize());
        gen.writeNumberField("current", page.getCurrent());
        gen.writeNumberField("pages", page.getPages());
        gen.writeArrayFieldStart("records");
        objectMapper.writerWithView(serializerProvider.getActiveView()).writeValue(gen, page.getRecords());
        gen.writeEndArray();
        gen.writeEndObject();
    }
}

逻辑很简单,应该不用再解释了。主要思路就是告诉Jackson,当需要序列化Page这个对象时,除了records里按指定的JsonView序列化,其他字段原样进行序列化。

0 回复 有任何疑惑可以回复我~
  • 提问者 醒着长眠 #1
    看明白啦,十分感谢,解答的很详细
    回复 有任何疑惑可以回复我~ 2022-04-25 10:59:06
JoJo 2021-04-14 11:47:38

额...每太看明白问题,你能处理SimpleResponse,想处理SimpleResponse类中包装的返回结果的话,直接get获取到处理就好了。

0 回复 有任何疑惑可以回复我~
  • 提问者 醒着长眠 #1
    老师不好意思没说明白,重新编辑了一下问题
    回复 有任何疑惑可以回复我~ 2021-04-15 16:29:37
问题已解决,确定采纳
还有疑问,暂不采纳
微信客服

购课补贴
联系客服咨询优惠详情

帮助反馈 APP下载

慕课网APP
您的移动学习伙伴

公众号

扫描二维码
关注慕课网微信公众号