SpringBoot2.x系列教程23--整合SpringMVC之自定义JSON序列化器和反序列化器

SpringBoot系列教程23--整合SpringMVC之自定义JSON序列化器和反序列化器

作者:一一哥

一.序列化与反序列化简介

1.概述

通过上一章节,我们学习到,在SpringMVC框架中使用HttpMessageConverter转换器类来转换http请求和响应。

HttpMessageConverter在转换http请求和响应的过程中,就需要将对象转为json,也就是序列化;或者将json转为对象,也就是反序列化。

2.@JsonComponent注解

在Spring Boot中默认是使用Jackson进行序列化和反序列化JSON数据的,那么除了可以用默认的之外,我们也可以编写自己的JsonSerializer和JsonDeserializer类,来进行自定义操作。

自定义序列化器(serializers)通常是通过Module方式注册到Jackson中,但在Spring Boot中提供了@JsonComponent注解这一替代方式,它能帮我们更为轻松的将序列化器注册为Spring Beans

我们可以直接在JsonSerializer 或 JsonDeserializer类上使用 @JsonComponent注解,该注解允许我们将带该注解的类公开为Jackson序列化器或反序列化器,而无需再手动将其添加到ObjectMapper。我们还可以在包含序列化程序/反序列化程序作为内部类的类上使用它,如下例所示:

import java.io.*;
import com.fasterxml.jackson.core.*;
import com.fasterxml.jackson.databind.*;
import org.springframework.boot.jackson.*;

@JsonComponent
public class Example {

    public static class Serializer extends JsonSerializer<SomeObject> {
        // ...
    }

    public static class Deserializer extends JsonDeserializer<SomeObject> {
        // ...
    }

}

ApplicationContext 中的所有 @JsonComponent bean都会自动注册到Jackson。因为 @JsonComponent 是用 @Component进行注解的,所以应用通常的组件扫描规则。

SpringBoot还提供了JsonObjectSerializer和JsonObjectDeserializer 基类,它们在序列化对象时为标准的Jackson版本提供了有用的替代方案。

二.序列化与反序列化实现

1.创建新项目

为了讲解序列化与反序列化的实现,我们创建一个新的工程,demo11_JsonComponent,创建过程类似于之前,此处略过。

最后的完整项目结构如下。


接下来我们说一下具体实现过程。

2.序列化JsonSerializer实现

我们首先继承JsonSerializer,重写Serialize()方法。

/**
*使用@JsonComponent注释会自动被注册到Jackson中.
**/
@JsonComponent
public class CustomeJackSon {

    /**
     * 自定义序列化器,格式化数值
     */
    public static class MySerializer extends JsonSerializer<Double> {

        private DecimalFormat df = new DecimalFormat("##.00");

        /**
         * 序列化操作,继承JsonSerializer,重写Serialize函数
         */
        @Override
        public void serialize(Double value, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
            jsonGenerator.writeString(df.format(value));
        }
    }
    
}

3.反序列化JsonDeserializer实现

继承JsonDeserializer类,重写deserialize()方法,自定义自己的反序列化逻辑。

/**
 * 使用@JsonComponent注释会自动被注册到Jackson中.
 */
@Slf4j
@JsonComponent
public class CustomeJackSon {

    /**
     * 自定义反序列化器,格式化时间
     */
    public static class MyDeserializer extends JsonDeserializer<Date> {

        private SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");

        @Override
        public Date deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException {
            Date date = null;
            try {
                date = sdf.parse(jsonParser.getText());
            } catch (ParseException e) {
                e.printStackTrace();
            }
            return date;
        }
    }

4.构建Bean对象

4.1 常用json注解

  • @JsonIgnoreProperties:
    此注解是类注解,作用是在json序列化时将Java bean中的某些属性忽略掉,序列化和反序列化都受影响。
  • @JsonIgnore:
    此注解用于属性或者方法上(最好是属性上),作用和上面的@JsonIgnoreProperties一样。
  • @JsonFormat:
    此注解用于属性或者方法上(最好是属性上),可以方便的把Date类型直接转化为我们想要的模式,比如@JsonFormat(pattern = "yyyy-MM-dd HH-mm-ss")
  • @JsonSerialize:
    此注解用于属性或者getter方法上,用于在序列化时嵌入我们自定义的序列化器,比如序列化一个double时在其后面限制两位小数点。
  • @JsonDeserializ:
    此注解用于属性或者setter方法上,用于在反序列化时嵌入我们自定义的反序列化器,比如反序列化一个Date类型的时间字符串。
  • @JsonCreator与@JsonProperty:
    该注解的作用就是指定反序列化时替代无参构造函数,构造方法的参数前面需要加上@JsonProperty注解。

4.2 完整的Java bean实体类

package com.yyg.boot.domain;

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.yyg.boot.json.CustomeJackSon;
import lombok.Data;
import lombok.ToString;

import java.util.Date;

/**
 * @NoArgsConstructor
 * @AllArgsConstructor 表示序列化时忽略的属性
 */
@Data
@ToString
@JsonIgnoreProperties(value = {"word"})
public class User {

    /**
     * 注意:在进行JSON序列化和反序列化时,要么提供一个无参的构造方法,要么在其他构造方法上添加@JsonCreator注解.
     */
    private String name;
    private int age;
    private boolean sex;
    private Date birthday;
    private String word;
    private double salary;

    @JsonCreator
    public User(@JsonProperty("name") String name, @JsonProperty("age") int age, @JsonProperty("sex") boolean sex, @JsonProperty("birthday") Date birthday,
                @JsonProperty("word") String word, @JsonProperty("salary") double salary) {
        super();
        this.name = name;
        this.age = age;
        this.sex = sex;
        this.birthday = birthday;
        this.word = word;
        this.salary = salary;
    }

    /**
     * 反序列化一个固定格式的Date
     */
    @JsonDeserialize(using = CustomeJackSon.MyDeserializer.class)
    public void setBirthday(Date birthday) {
        this.birthday = birthday;
    }

    /**
     * 序列化指定格式的double格式
     */
    @JsonSerialize(using = CustomeJackSon.MySerializer.class)
    public double getSalary() {
        return salary;
    }

}

注意:

当json在反序列化时,默认选择类的无参构造函数创建类对象,当没有无参构造函数时则会报错,@JsonCreator注解的作用就是指定反序列化时用的无参构造函数。构造方法的参数前面需要加上@JsonProperty,否则会报错!

例如:

@JsonCreator
    public Person(@JsonProperty("id") String id) {
        this.id = id;
}

5.编写Controller

package com.yyg.boot.web;

import com.yyg.boot.domain.User;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;

import java.util.Date;

@Slf4j
@RestController
public class UserController {

    /**
     * 将对象转为json字符串-->序列化
     */
    @GetMapping("/user/{salary}")
    public User home(@PathVariable("salary") Long salary) {
        return new User("一一哥", 30, true, new Date(), "程序员", salary);
    }

    /**
     * 将一个json转化为对象-->反序列化
     */
    @RequestMapping(value = "user")
    public String getValue(@RequestBody User user) {
        log.warn("user=" + user.toString());
        return user.toString();
    }

}

6.编写入口类

package com.yyg.boot;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

/**
 * json的序列化与反序列化
 */
@SpringBootApplication
public class SerializeApplication {

    public static void main(String[] args) {
        SpringApplication.run(SerializeApplication.class, args);
    }

}

7.运行程序,检查结果

序列化测试结果:

因为我们要接受一个json参数,所以可以利用postman进行反序列化测试。

最终我们在SpringBoot项目中实现了自定义的JSON序列化与反序列化操作。

发布了298 篇原创文章 · 获赞 82 · 访问量 10万+
App 阅读领勋章
微信扫码 下载APP
阅读全文

spring-boot与elasticsearch整合时如何定义内嵌对象的分词策略

04-01

@Document(indexName = "logmodel", type = "logs", shards = 4, replicas = 1,indexStoreType="fs", refreshInterval = "-1") public class LogES { @Id private String id; private String itcode; @Field(type = FieldType.String,index = FieldIndex.not_analyzed) private String ip; private String ad_type; @Field(type = FieldType.String,index = FieldIndex.not_analyzed) private String telephone; @Field(type = FieldType.String,index = FieldIndex.not_analyzed) private String mobile; @Field(type = FieldType.String,index = FieldIndex.not_analyzed) private String email; @Field(type = FieldType.String,index = FieldIndex.not_analyzed) private String firstname; @Field(type = FieldType.String,index = FieldIndex.not_analyzed) private String firstnameen; @Field(type = FieldType.String,index = FieldIndex.not_analyzed) private String boss; @Field(type = FieldType.String,index = FieldIndex.not_analyzed) private String position; @Field(type = FieldType.String,index = FieldIndex.not_analyzed) private String organization; @Field(type = FieldType.String,index = FieldIndex.not_analyzed) private String country; @Field(type = FieldType.String,index = FieldIndex.not_analyzed) private String cityname; @Field(type = FieldType.String,index = FieldIndex.not_analyzed) private String givenname; private String employeeNumber; @Field(type = FieldType.String,index = FieldIndex.not_analyzed) private String employeetype; private boolean ismanager; @Field(type = FieldType.String,index = FieldIndex.not_analyzed) private String bossname; @Field(type = FieldType.String,index = FieldIndex.not_analyzed) private String bigboss; @Field(type = FieldType.String,index = FieldIndex.not_analyzed) private String bigbossname; @Field(type = FieldType.String,index = FieldIndex.not_analyzed) private String enterprise; @JsonFormat (shape = JsonFormat.Shape.STRING, pattern ="yyyy-MM-dd'T'hh:mm:ss.SSS'Z'") private Date dt; private String dev_platform; private String app_version; private String dev_version; @Field(type = FieldType.String,index = FieldIndex.not_analyzed) private String dev_info; @Field(type = FieldType.String,index = FieldIndex.not_analyzed) private String dev_imei; @Field(type = FieldType.String,index = FieldIndex.not_analyzed) private String func; @Field( type = FieldType.Auto) private Object content; private CochatResponseEntity cochatResponseEntity; 比如怎么设置content对象内部字段的分词策略,如:@Field(type = FieldType.String,index = FieldIndex.not_analyzed) 问答

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 编程工作室 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览