Springboot2以代码的方式统一配置Jackson

说明

本文主要配置Jackson对Long、Date、LocalDate、LocalDateTime的序列化和反序列化。

  1. 由于js中整数可精确表示范围小于java Long的范围,故将Long序列化为String,反序列化Jackson会自动处理String转Long,故不需要显式配置。
  2. 由于时间戳在各语言间的兼容性良好,故将Date、LocalDate、LocalDateTime序列化为Long(目前时间戳类的Long类型在js的可精确表示范围内),将Long反序列化为Date、LocalDate、LocalDateTime。
  3. 将String空字符串反序列化为null。
  4. 本文除了配置Springboot整合的Jackson,还配置了功能一致的Jackson工具类,方便在代码中显示使用Jackson的序列化和反序列化功能。

7个序列化和反序列化规则

package com.xxx.config.serializers;

import java.io.IOException;
import java.util.Date;

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;

public class DateSerializer extends JsonSerializer<Date> {

	@Override
	public void serialize(Date value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
		if (value != null) {
			gen.writeNumber(value.getTime());
		}
	}

}
package com.xxx.config.serializers;

import java.io.IOException;
import java.time.LocalDate;
import java.time.ZoneId;

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;

public class LocalDateSerializer extends JsonSerializer<LocalDate> {

	@Override
	public void serialize(LocalDate value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
		if (value != null) {
			long millis = value.atStartOfDay(ZoneId.of("+8")).toInstant().toEpochMilli();
			gen.writeNumber(millis);
		}
		
	}

}
package com.xxx.config.serializers;

import java.io.IOException;
import java.time.LocalDateTime;
import java.time.ZoneId;

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;

public class LocalDateTimeSerializer extends JsonSerializer<LocalDateTime> {

	@Override
	public void serialize(LocalDateTime value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
		if (value != null) {
			long millis = value.atZone(ZoneId.of("+8")).toInstant().toEpochMilli();
			gen.writeNumber(millis);
		}
	}

}
package com.xxx.config.serializers;

import java.io.IOException;

import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;

public class StringDeserializer extends JsonDeserializer<String> {

	@Override
	public String deserialize(JsonParser p, DeserializationContext ctxt)
			throws IOException, JsonProcessingException {
		String text = p.getText();
		if ("".equals(text)) {
			return null;
		}
		return text;
	}

}

package com.xxx.config.serializers;
import java.io.IOException;
import java.util.Date;

import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;

public class DateDeserializer extends JsonDeserializer<Date> {

	@Override
	public Date deserialize(JsonParser p, DeserializationContext ctxt)
			throws IOException, JsonProcessingException {
		long timestamp = p.getValueAsLong();
        if (timestamp > 0){
            return new Date(timestamp);
        }else{
            return null;
        }
	}

}
package com.xxx.config.serializers;
import java.io.IOException;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;

import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;

public class LocalDateDeserializer extends JsonDeserializer<LocalDate> {

	@Override
	public LocalDate deserialize(JsonParser p, DeserializationContext ctxt)
			throws IOException, JsonProcessingException {
		long timestamp = p.getValueAsLong();
        if (timestamp > 0){
            return LocalDateTime.ofInstant(Instant.ofEpochMilli(timestamp),ZoneId.of("+8")).toLocalDate();
        }else{
            return null;
        }
	}

}
package com.xxx.config.serializers;
import java.io.IOException;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;

import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;

public class LocalDateTimeDeserializer extends JsonDeserializer<LocalDateTime> {

	@Override
	public LocalDateTime deserialize(JsonParser p, DeserializationContext ctxt)
			throws IOException, JsonProcessingException {
		long timestamp = p.getValueAsLong();
        if (timestamp > 0){
            return LocalDateTime.ofInstant(Instant.ofEpochMilli(timestamp),ZoneId.of("+8"));
        }else{
            return null;
        }
	}

}

Jackson统一配置类

package com.xxx.config;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.Date;

import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;

import com.xxx.config.serializers.DateDeserializer;
import com.xxx.config.serializers.DateSerializer;
import com.xxx.config.serializers.LocalDateDeserializer;
import com.xxx.config.serializers.LocalDateSerializer;
import com.xxx.config.serializers.LocalDateTimeDeserializer;
import com.xxx.config.serializers.LocalDateTimeSerializer;
import com.xxx.config.serializers.StringDeserializer;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;

@Configuration
public class JacksonConfig {

	@Bean
	public Jackson2ObjectMapperBuilderCustomizer jackson2ObjectMapperBuilderCustomizer() {
		Jackson2ObjectMapperBuilderCustomizer customizer = new Jackson2ObjectMapperBuilderCustomizer() {
			
			@Override
			public void customize(Jackson2ObjectMapperBuilder jacksonObjectMapperBuilder) {
				jacksonObjectMapperBuilder
						.serializerByType(Long.TYPE, ToStringSerializer.instance)
						.serializerByType(Long.class, ToStringSerializer.instance)
						.serializerByType(Date.class, new DateSerializer())
						.serializerByType(LocalDate.class, new LocalDateSerializer())
						.serializerByType(LocalDateTime.class, new LocalDateTimeSerializer())
						.deserializerByType(String.class, new StringDeserializer())
						.deserializerByType(Date.class, new DateDeserializer())
						.deserializerByType(LocalDate.class, new LocalDateDeserializer())
						.deserializerByType(LocalDateTime.class, new LocalDateTimeDeserializer())
						.failOnEmptyBeans(false)
						.failOnUnknownProperties(false);
			}
		};
		return customizer;
	}
}

Jackson工具类

package com.xxx.util;

import java.io.IOException;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.Date;
import java.util.TimeZone;

import com.xxx.config.serializers.StringDeserializer;
import com.xxx.config.serializers.DateDeserializer;
import com.xxx.config.serializers.DateSerializer;
import com.xxx.config.serializers.LocalDateDeserializer;
import com.xxx.config.serializers.LocalDateSerializer;
import com.xxx.config.serializers.LocalDateTimeDeserializer;
import com.xxx.config.serializers.LocalDateTimeSerializer;
import com.fasterxml.jackson.core.JsonParser.Feature;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;

public class JsonUtils {
	 
	private static final ObjectMapper objectMapper;

	static {
		objectMapper = new ObjectMapper();
		// 去掉默认的时间戳格式
		objectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
		// 设置为中国北京时区
		objectMapper.setTimeZone(TimeZone.getTimeZone("GMT+8"));
		// 空值不序列化
//		objectMapper.setSerializationInclusion(Include.NON_NULL);//已过时
//		objectMapper.setDefaultPropertyInclusion(Include.NON_NULL);//新API
		// 反序列化时,属性不存在的兼容处理
		objectMapper.getDeserializationConfig().withoutFeatures(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
 
		objectMapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
		objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
		// 单引号处理
		objectMapper.configure(Feature.ALLOW_SINGLE_QUOTES, true);
		
		JavaTimeModule javaTimeModule = new JavaTimeModule();
		javaTimeModule.addSerializer(Long.TYPE, ToStringSerializer.instance);
		javaTimeModule.addSerializer(Long.class, ToStringSerializer.instance);
		javaTimeModule.addSerializer(Date.class, new DateSerializer());
		javaTimeModule.addSerializer(LocalDate.class, new LocalDateSerializer());
        javaTimeModule.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer());
        
        javaTimeModule.addDeserializer(String.class, new StringDeserializer());
        javaTimeModule.addDeserializer(Date.class, new DateDeserializer());
        javaTimeModule.addDeserializer(LocalDate.class, new LocalDateDeserializer());
        javaTimeModule.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer());
        objectMapper.registerModule(javaTimeModule);
	}
 
	/**
	 * json 转换成 Object
	 *
	 * @param json
	 * @param clazz
	 * @return
	 */
	public static <T> T json2Object(String json, Class<T> clazz) {
		try {
			return objectMapper.readValue(json, clazz);
		} catch (IOException e) {
			throw new RuntimeException("解析json错误");
		}
	}
 
	@SuppressWarnings("unchecked")
	public static <T> T json2Object(String json, TypeReference<T> tr) {
		try {
			return (T)objectMapper.readValue(json, tr);
		} catch (IOException e) {
			throw new RuntimeException("解析json错误", e);
		}
	}
 
	/**
	 * obj 转换成json
	 *
	 * @param entity
	 * @return
	 */
	public static <T> String object2Json(T entity) {
		try {
			return objectMapper.writeValueAsString(entity);
		} catch (IOException e) {
			throw new RuntimeException("转换json错误");
		}
	}
 
	/**
	 * obj对象 转换成树型JSON
	 *
	 * @param obj
	 * @return
	 */
	public static JsonNode object2TreeJson(Object obj) {
		try {
			return objectMapper.valueToTree(obj);
		} catch (Exception e) {
			throw new RuntimeException("转换json错误");
		}
	}
 
	  /**
     * 解码json串成对象
     *
     * @param <T>
     * @param json
     * @param valueType
     * @return T
     */
    @SuppressWarnings("unchecked")
    public static <T> T decode(String json, Class<?> valueType) {
        try {
            return (T) objectMapper.readValue(json, valueType);
        } catch (Exception e) {
            throw new RuntimeException(json, e);
        }
    }

	/**
     * 解码json串成JsonNode
     * @param json
     * @return
     */
    public static JsonNode readTree(String json) {
    	try {
			return objectMapper.readTree(json);
		} catch (Exception e) {
			throw new RuntimeException(json, e);
		}
    }
    
}

结语

有不足之处或错误之处,欢迎指正

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值