SpringBoot中Jackson的@JsonView注解选择性序列化POJO配置问题
解决方案:SpringBoot 2.7.17 中实现@JsonView的局部生效
完全可行,核心思路是不对全局ObjectMapper做修改,只为新控制器单独配置开启MapperFeature.DEFAULT_VIEW_INCLUSION = false的序列化规则,具体实现步骤如下:
1. 创建自定义ObjectMapper
创建一个仅用于新控制器的ObjectMapper实例,开启DEFAULT_VIEW_INCLUSION为false:
@Configuration public class CustomJsonViewConfig { @Bean(name = "jsonViewObjectMapper") public ObjectMapper jsonViewObjectMapper() { ObjectMapper mapper = new ObjectMapper(); // 开启该配置后,仅序列化带指定@JsonView的字段 mapper.configure(MapperFeature.DEFAULT_VIEW_INCLUSION, false); return mapper; } }
2. 为新控制器配置专属的消息转换器
通过@ControllerAdvice指定作用范围(比如新控制器所在的包或自定义注解),替换该范围内控制器的消息转换器为使用上述自定义ObjectMapper:
@ControllerAdvice(basePackages = "com.yourproject.newcontrollers") // 新控制器所在包 public class NewControllerJsonViewAdvice extends AbstractJsonResponseBodyAdvice { private final ObjectMapper jsonViewObjectMapper; public NewControllerJsonViewAdvice(@Qualifier("jsonViewObjectMapper") ObjectMapper jsonViewObjectMapper) { this.jsonViewObjectMapper = jsonViewObjectMapper; } @Override protected void beforeBodyWriteInternal(MappingJacksonValue bodyContainer, MediaType contentType, MethodParameter returnType, ServerHttpRequest request, ServerHttpResponse response) { bodyContainer.setMapper(jsonViewObjectMapper); } }
3. 新控制器中使用@JsonView
在新控制器的接口方法上标注@JsonView指定视图,对应的POJO字段添加相同视图注解:
// 定义视图接口 public class Views { public static class Public {} public static class Internal extends Public {} } // POJO示例(老POJO无需修改,新POJO按需添加@JsonView) public class User { private Long id; // 默认序列化(老控制器和未指定视图的新控制器接口都会返回) private String username; // 默认序列化 @JsonView(Views.Internal.class) private String email; // 仅在新控制器指定Views.Internal视图时返回 } // 新控制器示例 @RestController @RequestMapping("/new-api/users") public class NewUserController { @GetMapping("/{id}") @JsonView(Views.Public.class) public User getUserPublicInfo(@PathVariable Long id) { // 返回的User对象仅序列化未标注@JsonView或标注Views.Public的字段 return userService.getUserById(id); } @GetMapping("/{id}/internal") @JsonView(Views.Internal.class) public User getUserInternalInfo(@PathVariable Long id) { // 返回的User对象会序列化标注Views.Internal或其父视图的字段 return userService.getUserById(id); } @GetMapping("/{id}/all") public User getUserAllInfo(@PathVariable Long id) { // 未标注@JsonView,新控制器会用自定义ObjectMapper,但因为没指定视图,会序列化所有字段(包括未加@JsonView的) return userService.getUserById(id); } }
4. 老代码不受影响
老控制器和未添加@JsonView的新控制器接口,依然保持默认行为:序列化POJO的所有字段,无需修改任何老POJO或控制器。
内容的提问来源于stack exchange,提问作者Shvalb
相关产品推荐
相关产品推荐

