spring 请求参数及返回值 类型统一转化(序列化和反序列化)

1.实现WebMvcConfigurer 类中的configureMessageConverters和addFormatters方法

package com.pulpy.knowl.config;

import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.context.annotation.Configuration;
import org.springframework.format.FormatterRegistry;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

import java.util.List;
//@EnableWebMvc表示完全自己控制mvc配置,也就是说所有配置自己重写,所有默认配置都没了
//@EnableWebMvc 
@Configuration
public class HttpMessageConverterConfig implements WebMvcConfigurer {

    /**
     * //TODO 此方式的序列化不建议使用
     * 此方式序列化,如果返回字符串类型的json数据,则会被二次序列化,导致出现\,
     * 配置@PostMapping(produces = "text/plain")/@GetMapping(produces = "text/plain"),可避免多次序列化
     * 
     * 单独配置Jackson2ObjectMapperBuilderCustomizer无需再配置produces = "text/plain"
     * 
     * 解决前端js处理大数字丢失精度问题
     * 将Long和BigInteger转换成string
     * 将LocalDatetime等时间类转出string
     * 反序列化json中string转换成LocalDatetime等时间类
     */
    @Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
        MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
        ObjectMapper objectMapper = NewObjectMapper.newObjectMapper();
        converter.setObjectMapper(objectMapper);
        converters.add(0, converter);//最高优先级
    }

	/**
	 * 反序列化form-data格式的string转换成LocalDateTime等时间类
     */
    @Override
    public void addFormatters(FormatterRegistry registry) {
        registry.addConverter(new LocalDateTimeConverter.StringToLocalDateTimeConverter());
        registry.addConverter(new LocalDateTimeConverter.StringToLocalDateConverter());
        registry.addConverter(new LocalDateTimeConverter.StringToLocalTimeConverter());
    }

}

1.1 Jackson2ObjectMapperBuilderCustomizer 序列化 long、localdatetime、localdate、localtime

@Configuration
public class MessageConverter {
	/**
	 * 也可单独设置每个字段
	 * 
	 * long类型设置
	 * @JsonFormat(shape = JsonFormat.Shape.STRING)
	 * 
	 * localdatetime类型设置
	 * @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
     * @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss")
	 */
    @Bean
    public Jackson2ObjectMapperBuilderCustomizer jackson2ObjectMapperBuilderCustomizer() {

        return jacksonObjectMapperBuilder -> jacksonObjectMapperBuilder
                .serializerByType(Long.class, ToStringSerializer.instance)
                .serializerByType(Long.TYPE, ToStringSerializer.instance)

                .serializerByType(LocalDate.class, new LocalDateTimeSerializer(getFormatter("yyyy-MM-dd")))
                .deserializerByType(LocalDate.class, new LocalDateTimeDeserializer(getFormatter("yyyy-MM-dd")))

                .serializerByType(LocalTime.class, new LocalDateTimeSerializer(getFormatter("HH:mm:ss")))
                .deserializerByType(LocalTime.class, new LocalDateTimeDeserializer(getFormatter("HH:mm:ss")))

                .serializerByType(LocalDateTime.class, new LocalDateTimeSerializer(getFormatter("yyyy-MM-dd HH:mm:ss")))
                .deserializerByType(LocalDateTime.class, new LocalDateTimeDeserializer(getFormatter("yyyy-MM-dd HH:mm:ss")))
                ;
    }

    private static DateTimeFormatter getFormatter(String formatter) {
        return DateTimeFormatter.ofPattern(formatter);
    }

}

2.string转各种时间类 转化器

package com.pulpy.knowl.config;

import com.pulpy.common.core.utils.StringUtils;
import org.springframework.core.convert.converter.Converter;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.Locale;

public class LocalDateTimeConverter {

    /**
     * 因为 Spring 默认不支持将 String 类型的请求参数转换为 LocalDateTime 类型,所以我们需要自定义 converter 「转换器」完整整个转换过程
     */
    public static class StringToLocalDateTimeConverter implements Converter<String, LocalDateTime> {
        @Override
        public LocalDateTime convert(String s) {
            if(StringUtils.isBlank(s)){
                return null;
            }
            DateTimeFormatter formatter = DateTimeFormatter.ofPattern(DateConstant.PATTERN, Locale.CHINESE);
            return LocalDateTime.parse(s, formatter);
        }
    }
    
    public static class StringToLocalDateConverter implements Converter<String, LocalDate> {
        @Override
        public LocalDate convert(String s) {
            if(StringUtils.isBlank(s)){
                return null;
            }
            DateTimeFormatter formatter = DateTimeFormatter.ofPattern(DateConstant.PATTERN_YYYY_MM_DD, Locale.CHINESE);
            return LocalDate.parse(s, formatter);
        }
    }

    public static class StringToLocalTimeConverter implements Converter<String, LocalTime> {
        @Override
        public LocalTime convert(String s) {
            if(StringUtils.isBlank(s)){
                return null;
            }
            DateTimeFormatter formatter = DateTimeFormatter.ofPattern(DateConstant.PATTERN_HH_MM_SS, Locale.CHINESE);
            return LocalTime.parse(s, formatter);
        }
    }

}

3.创建新ObjectMapper,定义json 序列化 及 反序列化 类型

package com.pulpy.knowl.config;

import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
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.LocalDateDeserializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalTimeSerializer;

import java.math.BigInteger;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;

public class NewObjectMapper {

    public static ObjectMapper newObjectMapper() {
        ObjectMapper objectMapper = new ObjectMapper();

        objectMapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true);
        objectMapper.configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true);
//		result.setSerializationInclusion(JsonInclude.Include.NON_NULL);
        objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);

        objectMapper.registerModules(newJavaTimeModule(), newSimpleModule());
        return objectMapper;
    }

    public static JavaTimeModule newJavaTimeModule(){
        JavaTimeModule javaTimeModule = new JavaTimeModule();

        //序列化LocalDateTime等时间类
        javaTimeModule.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(DateConstant.getFormatter(DateConstant.PATTERN)));
        javaTimeModule.addSerializer(LocalDate.class, new LocalDateSerializer(DateConstant.getFormatter(DateConstant.PATTERN_YYYY_MM_DD)));
        javaTimeModule.addSerializer(LocalTime.class, new LocalTimeSerializer(DateConstant.getFormatter(DateConstant.PATTERN_HH_MM_SS)));

        //反序列化 json格式中 字符串 为LocalDateTime等时间类
        javaTimeModule.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(DateConstant.getFormatter(DateConstant.PATTERN)));
        javaTimeModule.addDeserializer(LocalDate.class, new LocalDateDeserializer(DateConstant.getFormatter(DateConstant.PATTERN_YYYY_MM_DD)));
        javaTimeModule.addDeserializer(LocalTime.class, new LocalTimeDeserializer(DateConstant.getFormatter(DateConstant.PATTERN_HH_MM_SS)));

        return javaTimeModule;
    }

    public static SimpleModule newSimpleModule(){
        SimpleModule simpleModule = new SimpleModule();

        // 序列化成json时,将所有的long变成string 因为js中得数字类型不能包含所有的java long值
        simpleModule.addSerializer(BigInteger.class, ToStringSerializer.instance);
        simpleModule.addSerializer(Long.class, ToStringSerializer.instance);
        simpleModule.addSerializer(Long.TYPE, ToStringSerializer.instance);

        return simpleModule;
    }
}

时间类工具

package com.pulpy.knowl.config;

import java.time.format.DateTimeFormatter;

public class DateConstant {

    public static DateTimeFormatter getFormatter(String formatter){
        return DateTimeFormatter.ofPattern(formatter);
    }

    public static final String PATTERN = "yyyy-MM-dd HH:mm:ss";
    public static final String PATTERN_YYYY_MM_DD = "yyyy-MM-dd";
    public static final String PATTERN_HH_MM_SS = "HH:mm:ss";

}

注意:如果需要将某系列接口进行序列化或反序列化,可以如下操作

package com.pulpy.knowl.config;

import org.springframework.http.MediaType;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import java.lang.reflect.Type;

public class CustomMappingJackson2HttpMessageConverter extends MappingJackson2HttpMessageConverter {

    /**
     * 判断该转换器是否能将请求内容转换成 Java 对象
     */
    @Override
    public boolean canRead(Class<?> clazz, MediaType mediaType) {
        if (super.canRead(clazz, mediaType)) {
            ServletRequestAttributes ra = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
            if (ra != null) { // web请求
                String uri = ra.getRequest().getRequestURI();
//                if (uri.startsWith("/web/")) {
                return true;
//                }
            }
        }
        // 不需要反序列化
        return false;
    }

    /**
     * 判断该转换器是否能将请求内容转换成 Java 对象
     */
    @Override
    public boolean canRead(Type type, Class<?> contextClass, MediaType mediaType) {
        if (super.canRead(type, contextClass, mediaType)) {
            ServletRequestAttributes ra = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
            if (ra != null) { // web请求
                String uri = ra.getRequest().getRequestURI();
//                if (uri.startsWith("/web/")) {
                return true;
//                }
            }
        }
        // 不需要反序列化
        return false;
    }

    /**
     * 判断该转换器是否可以将 Java 对象转换成返回内容.
     * 匹配web api(形如/web/xxxx)中的接口方法的返回参数
     */
    @Override
    public boolean canWrite(Class<?> clazz, MediaType mediaType) {
        if (super.canWrite(clazz, mediaType)) {
            ServletRequestAttributes ra = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
            if (ra != null) { // web请求
                String uri = ra.getRequest().getRequestURI();
//                if (uri.startsWith("/web/")) {
                    return true;
//                }
            }
        }
        return false;
    }

}

再重新1中的configureMessageConverters方法

@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
    CustomMappingJackson2HttpMessageConverter converter = new CustomMappingJackson2HttpMessageConverter();
    ObjectMapper objectMapper = NewObjectMapper.newObjectMapper();
    converter.setObjectMapper(objectMapper);
    converters.add(0, converter);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Spring MVC中,Controller的序列化反序列化是通过使用注解来实现的。对于请求体的反序列化,可以使用 @RequestBody 注解来接收请求体。而对于响应体的序列化,可以使用 @ResponseBody 注解将返回值作为响应体。 具体来说,在Spring MVC中,使用 @RequestBody 注解标注的Controller方法参数可以用来接收请求体。而使用 @ResponseBody 注解标注的Controller方法则会将返回值作为响应体。请求体和响应体还可以具有不同的内容类型,比如json、xml等等。 在Spring MVC中,Controller方法参数的解析统一使用HandlerMethodArgumentResolver接口。该接口定义了两个方法:supportsParameter用于判断是否支持给定的方法参数,resolveArgument用于解析方法参数。 对于使用 @RequestBody 注解标注的参数,同样也是通过HandlerMethodArgumentResolver进行解析。 在具体实现中,RequestResponseBodyMethodProcessor是一个处理器,它负责将Controller方法返回值转换为响应体。其中,核心代码如下: ```java public class RequestResponseBodyMethodProcessor { // ... public void writeWithMessageConverters(Object returnValue, MethodParameter returnType, ServletServerHttpResponse response) throws IOException, HttpMediaTypeNotAcceptableException { // ... } // ... } ``` 总结起来,Spring MVC使用注解来实现Controller的序列化反序列化。对于请求体的反序列化,可以使用 @RequestBody 注解标注参数;而对于响应体的序列化,可以使用 @ResponseBody 注解标注方法。具体的参数解析和返回值转换则是通过HandlerMethodArgumentResolver和RequestResponseBodyMethodProcessor来完成的。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [Spring MVC @RequestBody @ResponseBody 序列化反序列化实现](https://blog.csdn.net/zzuhkp/article/details/122935899)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值