SpringBoot序列化、反序列化空字符串为null的三种方式

打印 上一主题 下一主题

主题 873|帖子 873|积分 2629

一、需求:接收前端传入的""空字符串参数,有时候我们必要把它转为null


  • SpringBoot项目
  • 方式:①Jackson(推荐)、②切面+反射、③注解+切面+反射
  • 后两种方式,未做返回值的处理。
二、三种方式

1、Jackson正反序列化(推荐)


  • StdConverter 和 JsonSerializer的区别
  1. 两种方式都可以实现将空字符串修改为 null 值的逻辑,但它们之间有一些区别:
  2. 1. **继承的类不同**:
  3.    - 使用 `StdConverter` 方式时,`StringToNullSerializer` 类继承自 `StdConverter<String, String>`,并实现了 `convert` 方法。
  4.    - 使用 `JsonSerializer` 方式时,`StringToNullSerializer` 类直接继承自 `JsonSerializer<String>`,并实现了 `serialize` 方法。
  5. 2. **接口和方法不同**:
  6.    - `StdConverter` 是 Jackson 库中提供的用于定义转换器的类,其中的 `convert` 方法用于将一个类型转换为另一个类型。
  7.    - `JsonSerializer` 是 Jackson 库中用于定制序列化逻辑的接口,其中的 `serialize` 方法用于将 Java 对象序列化为 JSON 数据。
  8. 3. **对于序列化过程的处理不同**:
  9.    - 在 `StdConverter` 方式中,你需要实现 `convert` 方法来定义如何将空字符串转换为 null 值。
  10.    - 在 `JsonSerializer` 方式中,你需要实现 `serialize` 方法来定义如何将字段序列化为 JSON 数据,并在其中进行空字符串转换为 null 值的处理。
  11. 综上所述,两种方式都可以实现相同的功能,选择哪一种方式取决于个人偏好以及代码的整体结构和风格。通常来说,如果只需要定制序列化逻辑而不需要转换其他类型,直接实现 `JsonSerializer` 接口可能会更清晰和简洁。
复制代码

  • ENTITY
  1. package com.cc.jxtd.entity;
  2. import com.cc.jxtd.serializer.ConverterEmptyStringToNull;
  3. import com.cc.jxtd.serializer.EmptyStringToNullDeserializer;
  4. import com.cc.jxtd.serializer.ConverterEmptyStringToInteger0;
  5. import com.cc.jxtd.serializer.EmptyStringToNullSerializer;
  6. import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
  7. import com.fasterxml.jackson.databind.annotation.JsonSerialize;
  8. import lombok.Data;
  9. import javax.naming.Name;
  10. /**
  11. * <p>请求,返回都用这个</p>
  12. *
  13. * @author --
  14. * @since 2024/4/19
  15. */
  16. @Data
  17. public class UserCs {
  18.     private Long id;
  19.     //反序列化(前端请求):空字符串为null
  20.     @JsonDeserialize(using = EmptyStringToNullDeserializer.class)
  21.     private String name;
  22.     //反序列化(前端请求):转换:为其他类型的值(转换为int的0)
  23.     @JsonDeserialize(converter = ConverterEmptyStringToInteger0.class)
  24.     private Integer descConverter0;
  25.     //序列化(后端返回):空字符串为null
  26.     @JsonSerialize(using = EmptyStringToNullSerializer.class)
  27.     private String descSerialize;
  28.     //序列化(后端返回):转换:空字符串转为null
  29.     @JsonSerialize(converter = ConverterEmptyStringToNull.class)
  30.     private String descConverterNull;
  31.    
  32. }
复制代码

  • 序列化处理类
  1. package com.cc.jxtd.serializer;
  2. import com.fasterxml.jackson.core.JsonGenerator;
  3. import com.fasterxml.jackson.databind.JsonSerializer;
  4. import com.fasterxml.jackson.databind.SerializerProvider;
  5. import java.io.IOException;
  6. /** 序列化:String的空转为null
  7. * @author --
  8. * @since 2024/4/18
  9. **/
  10. public class EmptyStringToNullSerializer extends JsonSerializer<String> {
  11.     /**
  12.      * 序列化为null
  13.      */
  14.     @Override
  15.     public void serialize(String value, JsonGenerator gen, SerializerProvider serializerProvider) throws IOException {
  16.         if (value == null || value.trim().isEmpty()) {
  17.             gen.writeNull();
  18.         }else {
  19.             gen.writeString(value);
  20.         }
  21.     }
  22. }
复制代码

  • 反序列化处理类
  1. package com.cc.jxtd.serializer;
  2. import com.fasterxml.jackson.core.JsonParser;
  3. import com.fasterxml.jackson.databind.DeserializationContext;
  4. import com.fasterxml.jackson.databind.JsonDeserializer;
  5. import java.io.IOException;
  6. /** 反序列化:空字符串转换为null
  7. * @author --
  8. * @since 2024/4/18
  9. **/
  10. public class EmptyStringToNullDeserializer extends JsonDeserializer<String> {
  11.     /**
  12.      * 反序列化为null
  13.      */
  14.     @Override
  15.     public String deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
  16.         String value = p.getValueAsString();
  17.         if (value == null || value.trim().isEmpty()) {
  18.             return null;
  19.         }
  20.         return value;
  21.     }
  22. }
复制代码

  • 序列化-转换1
  1. package com.cc.jxtd.serializer;
  2. import com.fasterxml.jackson.databind.util.StdConverter;
  3. /** 序列化-转换:将string的空转为null
  4. * @author --
  5. * @since 2024/4/18
  6. **/
  7. public class ConverterEmptyStringToNull extends StdConverter<String, String> {
  8.     @Override
  9.     public String convert(String value) {
  10.         //把空的string转为int的0
  11.         if (value == null || value.trim().isEmpty()) {
  12.             return null;
  13.         }
  14.         return value;
  15.     }
  16. }
复制代码

  • 序列化-转换2
  1. package com.cc.jxtd.serializer;
  2. import com.fasterxml.jackson.annotation.JsonPropertyOrder;
  3. import com.fasterxml.jackson.databind.util.StdConverter;
  4. /** 序列化:1将string转为int。
  5. *         2转换String的空或null -》 转为Integer的0
  6. * @author --
  7. * @since 2024/4/18
  8. **/
  9. public class ConverterEmptyStringToInteger0 extends StdConverter<String, Integer> {
  10.     @Override
  11.     public Integer convert(String value) {
  12.         //把空的string转为int的0
  13.         if (value == null || value.trim().isEmpty()) {
  14.             return 0;
  15.         }
  16.         return Integer.valueOf(value);
  17.     }
  18. }
复制代码

  • Controller
  1. package com.cc.jxtd.web.controller;
  2. import com.cc.jxtd.entity.UserCs;
  3. import org.springframework.web.bind.annotation.PostMapping;
  4. import org.springframework.web.bind.annotation.RequestBody;
  5. import org.springframework.web.bind.annotation.RequestMapping;
  6. import org.springframework.web.bind.annotation.RestController;
  7. /**
  8. * <p></p>
  9. *
  10. * @author --
  11. * @since 2024/4/19
  12. */
  13. @RestController
  14. @RequestMapping("/userCs")
  15. public class UserController {
  16.     @PostMapping
  17.     public UserCs get(@RequestBody UserCs req){
  18.         System.out.println("请求参数-id:"   + req.getId());
  19.         System.out.println("请求参数-name:" + req.getName());
  20.         System.out.println("请求参数-desc1:" + req.getDescSerialize());
  21.         System.out.println("请求参数-desc2:" + req.getDescConverterNull());
  22.         System.out.println("请求参数-desc3:" + req.getDescConverter0());
  23.         //返回:序列化
  24.         return req;
  25.     }
  26. }
复制代码

  • 测试

2、切面+反射/3、注解+切面+反射


  • 区别
  1. 2、切面+反射:所有空字符串的字段都转为null
  2. 3、注解+切面+反射:只有打了@EmptyToNull的字段才会转换
复制代码

  • 导入包
  1.                
  2.         <dependency>
  3.             <groupId>org.springframework.boot</groupId>
  4.             <artifactId>spring-boot-starter-aop</artifactId>
  5.         </dependency>
复制代码

  • 切面
  1. package com.cc.jxtd.aspect;
  2. import com.cc.jxtd.annotation.EmptyToNull;
  3. import org.aspectj.lang.ProceedingJoinPoint;
  4. import org.aspectj.lang.annotation.Around;
  5. import org.aspectj.lang.annotation.Aspect;
  6. import org.aspectj.lang.annotation.Pointcut;
  7. import org.slf4j.Logger;
  8. import org.slf4j.LoggerFactory;
  9. import org.springframework.stereotype.Component;
  10. import java.lang.reflect.Field;
  11. import java.util.Objects;
  12. /** 切面
  13. * @author --
  14. */
  15. @Aspect
  16. @Component
  17. public class UpdateAspect {
  18.     private static final Logger logger = LoggerFactory.getLogger(UpdateAspect.class);
  19.     //切入点
  20.     @Pointcut("@annotation(com.cc.jxtd.annotation.OptConverter)")
  21.     public void validPointCut() {
  22.     }
  23.     /**
  24.      * 环绕修改参数
  25.      */
  26.     @Around("validPointCut()")
  27.     public Object around(ProceedingJoinPoint point) throws Throwable {
  28.         Object[] args = point.getArgs();
  29.         Object arg = args[0];
  30.         //2、切面+反射:全部转换
  31.         this.allEmptyToNull(arg);
  32.         //3、注解+切面+反射:部分转换
  33. //        this.assignEmptyToNull(arg);
  34.         return point.proceed();
  35.     }
  36.     /**
  37.      * 设置请求参数中 所有字段的空值(如:String的空字符串)为null
  38.      * @param arg arg
  39.      */
  40.     public void allEmptyToNull(Object arg) {
  41.         if (Objects.isNull(arg)) {
  42.             return;
  43.         }
  44.         Field[] fields = arg.getClass().getDeclaredFields();
  45.         for (Field field : fields) {
  46.             // 设置字段可访问
  47.             field.setAccessible(true);
  48.             // 如果字段是 String 类型且值为空字符串,则设置为 null
  49.             if (field.getType() == String.class) {
  50.                 try {
  51.                     String value = (String) field.get(arg);
  52.                     if (value != null && value.isEmpty()) {
  53.                         field.set(arg, null);
  54.                     }
  55.                 } catch (IllegalAccessException e) {
  56.                     e.printStackTrace();
  57.                 }
  58.             }
  59.             // 可以扩展其他类型的参数……
  60.         }
  61.     }
  62.     /** 指定空转null
  63.      * @param arg arg
  64.      * @since 2024/4/18
  65.      **/
  66.     private void assignEmptyToNull(Object arg) {
  67.         if (Objects.isNull(arg)) {
  68.             return;
  69.         }
  70.         Field[] fields = arg.getClass().getDeclaredFields();
  71.         for (Field field : fields) {
  72.             if (field.isAnnotationPresent(EmptyToNull.class)) {
  73.                 // 设置字段可访问
  74.                 field.setAccessible(true);
  75.                 // 如果字段是 String 类型且值为空字符串,则设置为 null
  76.                 if (field.getType() == String.class) {
  77.                     try {
  78.                         String value = (String) field.get(arg);
  79.                         if (value != null && value.isEmpty()) {
  80.                             field.set(arg, null);
  81.                         }
  82.                     } catch (IllegalAccessException e) {
  83.                         e.printStackTrace();
  84.                     }
  85.                 }
  86.                 // 可以扩展其他类型的参数……
  87.             }
  88.         }
  89.     }
  90. }
复制代码

  • 注解
  1. package com.cc.jxtd.annotation;
  2. import java.lang.annotation.ElementType;
  3. import java.lang.annotation.Retention;
  4. import java.lang.annotation.RetentionPolicy;
  5. import java.lang.annotation.Target;
  6. /**
  7. * 转换
  8. * @author --
  9. */
  10. @Target(ElementType.METHOD)
  11. @Retention(RetentionPolicy.RUNTIME)
  12. public @interface OptConverter {
  13.    
  14. }
复制代码

  • 注解2
  1. package com.cc.jxtd.annotation;
  2. import java.lang.annotation.ElementType;
  3. import java.lang.annotation.Retention;
  4. import java.lang.annotation.RetentionPolicy;
  5. import java.lang.annotation.Target;
  6. /** 转化空为null
  7. * @author --
  8. * @since 2024/4/18
  9. **/
  10. @Target(ElementType.FIELD)
  11. @Retention(RetentionPolicy.RUNTIME)
  12. public @interface EmptyToNull {
  13. }
复制代码

  • entity
  1. package com.cc.jxtd.entity;
  2. import com.cc.jxtd.serializer.ConverterEmptyStringToInteger0;
  3. import com.cc.jxtd.serializer.ConverterEmptyStringToNull;
  4. import com.cc.jxtd.serializer.EmptyStringToNullDeserializer;
  5. import com.cc.jxtd.serializer.EmptyStringToNullSerializer;
  6. import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
  7. import com.fasterxml.jackson.databind.annotation.JsonSerialize;
  8. import lombok.Data;
  9. /**
  10. * <p>请求,返回都用这个</p>
  11. *
  12. * @author --
  13. * @since 2024/4/19
  14. */
  15. @Data
  16. public class UserCs2 {
  17.     private Long id;
  18.     private String name;
  19.     private String desc;
  20. }
复制代码

  • controller
  1. package com.cc.jxtd.web.controller;
  2. import com.cc.jxtd.annotation.OptConverter;
  3. import com.cc.jxtd.entity.UserCs;
  4. import com.cc.jxtd.entity.UserCs2;
  5. import org.springframework.web.bind.annotation.PostMapping;
  6. import org.springframework.web.bind.annotation.RequestBody;
  7. import org.springframework.web.bind.annotation.RequestMapping;
  8. import org.springframework.web.bind.annotation.RestController;
  9. /**
  10. * <p></p>
  11. *
  12. * @author --
  13. * @since 2024/4/19
  14. */
  15. @RestController
  16. @RequestMapping("/userCs")
  17. public class UserController {
  18. //    @PostMapping
  19. //    public UserCs get(@RequestBody UserCs req){
  20. //        System.out.println("请求参数-id:"   + req.getId());
  21. //        System.out.println("请求参数-name:" + req.getName());
  22. //        System.out.println("请求参数-DescSerialize:" + req.getDescSerialize());
  23. //        System.out.println("请求参数-DescConverterNull:" + req.getDescConverterNull());
  24. //        System.out.println("请求参数-DescConverter0:" + req.getDescConverter0());
  25. //
  26. //        //返回:序列化
  27. //        return req;
  28. //    }
  29.     @OptConverter
  30.     @PostMapping
  31.     public UserCs2 get(@RequestBody UserCs2 req){
  32.         System.out.println("请求参数-id:"   + req.getId());
  33.         System.out.println("请求参数-name:" + req.getName());
  34.         System.out.println("请求参数-desc:" + req.getDesc());
  35.         //返回:序列化
  36.         return req;
  37.     }
  38. }
复制代码

  • 测试2

  • 测试3




免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

正序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

篮之新喜

金牌会员
这个人很懒什么都没写!
快速回复 返回顶部 返回列表