springboot 根据url动态控制序列化字段
分类:spring-boot
阅读:41
作者:皇太极
发布:2020-07-01 11:31:10

springboot的出现简化了web程序的开发, 想返回一个json的内容,只需在controller上加上 @RestController 即可实现. 非常方便.

但是项目中往往会有一些特殊的场景, 需要我们对返回json内容做特殊定制化处理.

需求场景

比如一个返回json内容

  1. {
  2. "name":"孙悟空",
  3. "img":"http://www.majingjing.cn/static/123.png",
  4. "bankCard":{
  5. "bankName":"农业银行",
  6. "cardId":"ABC-10001"
  7. }
  8. }

现在有两个url请求, 分别会得到这个user的json内容

  • GET /customer/user
  • GET /admin/user

此时有个场景是这样的

  • GET /customer/user 返回内容如下
    1. {
    2. "name":"孙悟空",
    3. "img":"http://www.majingjing.cn/static/123.png"
    4. }
  • GET /admin/user
    1. {
    2. "name":"孙悟空",
    3. "img":"http://www.majingjing.cn/static/123.png",
    4. "bankCard":{
    5. "bankName":"农业银行",
    6. "cardId":"ABC-10001"
    7. }
    8. }
    返回内容为全部信息

分析

在不考虑写多个UserDto的情况下, 如何来实现了.
我们看下如何利用 jackson 来完成不同url来动态处理 对象的序列化操作.


实现

定义UserDto
  1. @Getter
  2. @Setter
  3. public class UserDto {
  4. private String name;
  5. private String img;
  6. private BankCard bankCard;
  7. @Getter
  8. @Setter
  9. public static class BankCard{
  10. private String bankName;
  11. private String cardId;
  12. }
  13. }
定义Api
  1. @RestController
  2. public class UserController {
  3. @GetMapping("/customer/user")
  4. public UserDto user(){
  5. return getUser();
  6. }
  7. @GetMapping("/admin/user")
  8. public UserDto adminUser(){
  9. return getUser();
  10. }
  11. private UserDto getUser(){
  12. UserDto.BankCard bankCard = new UserDto.BankCard();
  13. bankCard.setBankName("农业银行");
  14. bankCard.setCardId("ABC-10001");
  15. UserDto userDto = new UserDto();
  16. userDto.setName("孙悟空");
  17. userDto.setImg("http://www.majingjing.cn/static/123.png");
  18. userDto.setBankCard(bankCard);
  19. return userDto;
  20. }
  21. }
自定义MappingJackson2HttpMessageConverter
  1. public abstract class AbstractMappingJackson2HttpMessageConverter extends MappingJackson2HttpMessageConverter {
  2. public AbstractMappingJackson2HttpMessageConverter(ObjectMapper objectMapper) {
  3. super(objectMapper);
  4. }
  5. /**
  6. * 判断给定的url是否匹配
  7. *
  8. * @param url 请求的url
  9. * @return boolean 是否匹配
  10. */
  11. abstract boolean isMatch(String url);
  12. private boolean isMatch() {
  13. //从上下文中拿到请求地址
  14. ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
  15. if(null ==requestAttributes){
  16. return false;
  17. }
  18. String requestPath = requestAttributes.getRequest().getRequestURI();
  19. if (StringUtils.isBlank(requestPath)) {
  20. return false;
  21. }
  22. return isMatch(requestPath);
  23. }
  24. @Override
  25. public boolean canRead(Class<?> clazz, MediaType mediaType) {
  26. if (!isMatch()) {
  27. return false;
  28. }
  29. return super.canRead(clazz, mediaType);
  30. }
  31. @Override
  32. public boolean canRead(Type type, Class<?> contextClass, MediaType mediaType) {
  33. if (!isMatch()) {
  34. return false;
  35. }
  36. return super.canRead(type, contextClass, mediaType);
  37. }
  38. @Override
  39. public boolean canWrite(Class<?> clazz, MediaType mediaType) {
  40. if (!isMatch()) {
  41. return false;
  42. }
  43. return super.canWrite(clazz, mediaType);
  44. }
  45. @Override
  46. public boolean canWrite(Type type, Class<?> clazz, MediaType mediaType) {
  47. if (!isMatch()) {
  48. return false;
  49. }
  50. return super.canWrite(type, clazz, mediaType);
  51. }
  52. }
  1. public class AdminMappingJackson2HttpMessageConverter extends AbstractMappingJackson2HttpMessageConverter {
  2. public AdminMappingJackson2HttpMessageConverter(ObjectMapper objectMapper) {
  3. super(objectMapper);
  4. }
  5. /**
  6. * 判断给定的url是否匹配
  7. *
  8. * @param url 请求的url
  9. * @return boolean 是否匹配
  10. */
  11. boolean isMatch(String url){
  12. return url.startsWith("/admin/");
  13. }
  14. }
  15. ``````java
  16. public class CustomerMappingJackson2HttpMessageConverter extends AbstractMappingJackson2HttpMessageConverter {
  17. public CustomerMappingJackson2HttpMessageConverter(ObjectMapper objectMapper) {
  18. super(objectMapper);
  19. }
  20. /**
  21. * 判断给定的url是否匹配
  22. *
  23. * @param url 请求的url
  24. * @return boolean 是否匹配
  25. */
  26. boolean isMatch(String url){
  27. return url.startsWith("/customer/");
  28. }
  29. }
配置HttpMessageConverter
  1. @JsonIgnoreType
  2. public @interface IgnoreType {
  3. }
  1. @Configuration
  2. public class WebConfiguration implements WebMvcConfigurer {
  3. @Override
  4. public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
  5. Jackson2ObjectMapperBuilder customerBuilder = new Jackson2ObjectMapperBuilder()
  6. //忽略UserDto.BankCard
  7. .mixIn(UserDto.BankCard.class, IgnoreType.class);
  8. Jackson2ObjectMapperBuilder adminBuilder = new Jackson2ObjectMapperBuilder();
  9. converters.add(0, new CustomerMappingJackson2HttpMessageConverter(customerBuilder.build()));
  10. converters.add(1, new AdminMappingJackson2HttpMessageConverter(adminBuilder.build()));
  11. }
  12. }

此时我们已经将自定义的两个 HttpMessageConverter 加人到WebConfiguration中了

结果验证

启动项目, 验证下结果

可以看到已经实现了预期的结果, 实现了

  • GET /customer/user 不显示 bankCard
  • GET /admin/user 显示 bankCard

通过此示例介绍, 我们可以在项目中配合jackson完成各种定制化的操作.

比如之前写过的文章, 多语言 , 特殊对象的解析等.