package com.youlai.boot.config; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.SerializationFeature; import com.fasterxml.jackson.databind.module.SimpleModule; import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer; import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer; import jakarta.validation.Validation; import jakarta.validation.Validator; import jakarta.validation.ValidatorFactory; import lombok.extern.slf4j.Slf4j; import org.hibernate.validator.HibernateValidator; import org.springframework.beans.factory.config.AutowireCapableBeanFactory; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.http.converter.HttpMessageConverter; import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; import org.springframework.validation.beanvalidation.SpringConstraintValidatorFactory; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; import java.math.BigInteger; import java.text.SimpleDateFormat; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; import java.util.List; import java.util.TimeZone; /** * Web 配置 * * @author Ray.Hao * @since 2020/10/16 */ @Configuration @Slf4j public class WebMvcConfig implements WebMvcConfigurer { private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); /** * 配置消息转换器 * * @param converters 消息转换器列表 */ @Override public void configureMessageConverters(List> converters) { MappingJackson2HttpMessageConverter jackson2HttpMessageConverter = new MappingJackson2HttpMessageConverter(); ObjectMapper objectMapper = new ObjectMapper(); // 注册 JavaTimeModule(替代手动注册 LocalDateTimeSerializer) JavaTimeModule javaTimeModule = new JavaTimeModule(); // 返回指定字符串格式 javaTimeModule.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(DATE_TIME_FORMATTER)); // 反序列化,接受前端传来的格式 javaTimeModule.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(DATE_TIME_FORMATTER)); objectMapper.registerModule(javaTimeModule); // 配置全局日期格式和时区 objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS); objectMapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss")); objectMapper.setTimeZone(TimeZone.getTimeZone("GMT+8")); // 处理 Long/BigInteger 的精度问题 SimpleModule simpleModule = new SimpleModule(); simpleModule.addSerializer(Long.class, ToStringSerializer.instance); simpleModule.addSerializer(BigInteger.class, ToStringSerializer.instance); objectMapper.registerModule(simpleModule); jackson2HttpMessageConverter.setObjectMapper(objectMapper); converters.add(1, jackson2HttpMessageConverter); } /** * 配置校验器 * * @param autowireCapableBeanFactory 用于注入 SpringConstraintValidatorFactory * @return Validator 实例 */ @Bean public Validator validator(final AutowireCapableBeanFactory autowireCapableBeanFactory) { try (ValidatorFactory validatorFactory = Validation.byProvider(HibernateValidator.class) .configure() .failFast(true) // failFast=true 时,遇到第一个校验失败则立即返回,false 表示校验所有参数 .constraintValidatorFactory(new SpringConstraintValidatorFactory(autowireCapableBeanFactory)) .buildValidatorFactory()) { // 使用 try-with-resources 确保 ValidatorFactory 被正确关闭 return validatorFactory.getValidator(); } } }