• Jackson的使用和定制


    springmvc在使用注解@ResponseBody返回一个POJO对象时, 其内部会借助Jackson来完成POJO转化为JSON的工作. 

    public class Message {
     
      private String userId; // 用户id
     
      private String message; // 消息实体
     
      private Date timestamp; // 时间信息, yyyy-MM-dd HH:mm:ss
     
      private String extra; // 额外附带信息
     
    }

    其最终讲转换为如下的json格式:
      
      如果开发者需要如下需求:
      1). json实体的key命名规则, 全小写化, 不同单词以"_"字符连接.
      2). 返回时间字段, 需满足"yyyy-MM-dd HH:mm:ss"格式
      3). 省略掉extra字段
      由此可见我们的最终目标是:

    {"user_id":"1001","message":"message","timestamp":"2015-08-31 12:16:30"}

    解决篇:
      • 重命名
      jackson对重命名的处理, 引入注解JsonProperty来实现. 其对单个属性配置有效.

    @JsonProperty(value="user_id")
    private String userId; // 用户id

    注: value属性设置为用户想要的命名即可.
      当然还有另一种方式注解方式, 是JsonNaming, 其修饰于POJO类上. 用于对所有属性, 进行统一的命名转换.

    @JsonNaming(PropertyNamingStrategy.LowerCaseWithUnderscoresStrategy.class)
    public class Message {
      ...
    }

    注: PropertyNamingStrategy就非常漂亮地把所有的类属性名称都转换为小写, 同时单词(驼峰命令法)之间使用'_'字符来分割.
      自定义的Strategy类, 需要实现如下抽象类:

    public abstract class PropertyNamingStrategy implements Serializable {
      public abstract static class PropertyNamingStrategyBase extends PropertyNamingStrategy {
        public abstract String translate(String var1);
      }
    }

      • 字段可见性
      过滤某些字段属性, jackson引入了注解JsonIgnore. 其对单个属性生效.

    @JsonIgnore
    private String extra; // 额外附带信息

    还有另外一种方式, 是采用JsonIgnoreProperties, 其修饰POJO类, 指定一组需要忽略的字段.

    // *) 字典{}内是property name列表
    @JsonIgnoreProperties({"extra", "extra1", "extra2"})
    public class Message {
      ...
    }

      • 自定义序列化/反序列化
      jackson采用@JsonSerialize@JsonDeserialize来实现自定义序列化/反序列化的实现. 如之前的时间字段作为例子.

    定义时间序列化的实现类.

    public class Message {
     
      @JsonSerialize(using=DemoDateSerializer.class)
      @JsonDeserialize(using=DemoDateDeserializer.class)
      private Date timestamp; // 时间信息, yyyy-MM-dd HH:mm:ss
     
    }
     
    // *) JSON的序列化类
    class DemoDateSerializer extends JsonSerializer<Date> {
      @Override
      public void serialize(Date value, JsonGenerator jgen, SerializerProvider provider) throws IOException, JsonProcessingException {
        DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        jgen.writeString(dateFormat.format(value));
      }
    }
     
    // *) JSON的反序列化类
    class DemoDateDeserializer extends JsonDeserializer<Date> {
      @Override
      public Date deserialize(JsonParser jp, DeserializationContext dctx) throws IOException, JsonProcessingException {
        DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        try {
          return dateFormat.parse(jp.getValueAsString());
        } catch (ParseException e) {
          e.printStackTrace();
        } finally {
        }
        return null;
      }
    }

    除了常规的时间格式转换, 还能正则提取等功能. 序列化和反序列化的自定义, 使得Jackson更加的强大. 犹如hive中的UDF函数.

    最终的定义的类修改如下:

    public class Message {
     
      @JsonProperty(value="user_id")
      private String userId; // 用户id
     
      private String message; // 消息实体
     
      @JsonSerialize(using=DemoDateSerializer.class)
      @JsonDeserialize(using=DemoDateDeserializer.class)
      private Date timestamp; // 时间信息, yyyy-MM-dd HH:mm:ss
     
      @JsonIgnore
      private String extra; // 额外附带信息
     
    }

    @DateTimeFormat 和 @JsonFormat 注解

    定义一个pojo,它有一个 java.util.Date 类型的属性 date。

    import java.util.Date;
    
    public class DateVo {
        private Date date;
    
        public void setDate(Date date){
            this.date = date;
        }
        public Date getDate(){
            return date;
        }
    }

    定义一个Controller

    @RestController
    @RequestMapping("/date/")
    public class DateController {
    
        @RequestMapping("test")
        public DateVo getDate(DateVo vo){
            System.out.println("date1:"+vo.getDate());
    
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            String date = sdf.format(vo.getDate());
            System.out.println("date2:"+date);
    
            DateVo vo2 = new DateVo();
            vo2.setDate(new Date());
            return vo2;
        }
    }

    访问 /date/test ,并传入参数:2018-08-02 22:05:55

    发现并不能访问成功,会抛出异常:

    2. 入参格式化

    这时,就可以使用 Spring 的 @DateTimeFormat 注解格式化参数,来解决上述问题。

    public class DateVo {
        @DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss")
        private Date date;
    
        public void setDate(Date date){
            this.date = date;
        }
        public Date getDate(){
            return date;
        }
    }

    再像上面一样访问 /date/test ,并传入参数:2018-08-02 22:05:55,将在控制台上打印:

    date1:Thu Aug 02 22:05:55 CST 2018

    date2:2018-08-02 22:05:55

    可以看到,加入 @DateTimeFormat 注解后参数可以被接收到了,但日期时间的格式还是需要自己再手动转换一下。

    因为 @DateTimeFormat 注解的 pattern 属性值指定的日期时间格式并不是将要转换成的日期格式,这个指定的格式是和传入的参数对应的,假如注解为:

    @DateTimeFormat(pattern="yyyy/MM/dd HH:mm:ss")则传入的参数应该是这样的:2018/08/02 22:05:55

    3. 出参格式化

    在上述示例中,调用接口的返回结果为:

    "date": "2018-08-01T14:25:31.296+0000"

    这个格式并不是我们想要的,那么如何将其进行格式化?这时就需要用到 jackson 的 @JsonFormat 注解。

    public class DateVo {
        @DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss")
        @JsonFormat(
                pattern = "yyyy-MM-dd HH:mm:ss"
        )
        private Date date;
    
        public void setDate(Date date){
            this.date = date;
        }
        public Date getDate(){
            return date;
        }
    }

    继续访问 /date/test ,并传入参数:2018-08-02 22:05:55,可以看到接口返回的结果为:

    "date": "2018-08-01 14:32:57"

    虽然时间格式正确了,但实际上当前时间是 “2018-08-01 22:32:57” ,早了8个小时。因为,jackson在序列化时间时是按照国际标准时间GMT进行格式化的,而在国内默认时区使用的是CST时区,两者相差8小时。

    所以,@JsonFormat 注解还要再加一个属性:

    @JsonFormat(
        pattern = "yyyy-MM-dd HH:mm:ss",
        timezone = "GMT+8"
    )
    private Date date;

    这样,结果就正确了。

    @JsonInclude(JsonInclude.Include.NON_NULL)标签去除json数据中的空值问题

    @JsonInclude(JsonInclude.Include.NON_NULL)标记是jackson包提供的json序列化方法,已经集成于Springboot2.0中,此方法的配置意在可以对实体json序列化的时候进行对应的数值处理,

    将该标记放在属性上,如果该属性为NULL则不参与序列化 
    如果放在类上边,那对这个类的全部属性起作用 
    Include.Include.ALWAYS 默认 
    Include.NON_DEFAULT 属性为默认值不序列化 
    Include.NON_EMPTY 属性为 空(“”) 或者为 NULL 都不序列化 
    Include.NON_NULL 属性为NULL 不序列化 

  • 相关阅读:
    今天本来还打算继续更新微信开发的,但是没办法接口调用次数已经达到上限了,唉
    夺命雷公狗---微信开发43----用户分组管理接口(删)
    夺命雷公狗---微信开发43----用户分组管理接口(改)
    夺命雷公狗---微信开发42----用户分组管理接口(查)
    夺命雷公狗---微信开发41----用户分组管理接口(增)
    夺命雷公狗---微信开发40----微信语言识别接口2(点歌系统)
    [LeetCode] Balanced Binary Tree
    [LeetCode] Minimum Depth of Binary Tree
    [LeetCode] Path Sum
    [LeetCode] Pascal's Triangle
  • 原文地址:https://www.cnblogs.com/deityjian/p/11080138.html
Copyright © 2020-2023  润新知