springboot 参数类型处理

/ 后端 / 没有评论 / 412浏览

1.converter,formatter(默认用于表单Form格式,@RequestParam,@Pathvariable); Formatter就像Converter一样,也是将一种类型转换为另外一种类型,但是Formatter的源类型必须是String,而Converter的源类型可以是任意类型。 Formatter更加适合Web层,而Converter则可以在任意层中。

2.HttpMessageConverter(用于json或自定义格式,@RequestBody,@Requestbody或@RestController) 在SpringMVC中,可以使用@RequestBody和@ResponseBody两个注解,分别完成请求报文到对象和对象到响应报文的转换,底层这种灵活的消息转换机制就是利用HttpMessageConverter来实现的,Spring内置了很多HttpMessageConverter,比如MappingJackson2HttpMessageConverter,StringHttpMessageConverter等,下面我们来自定义自己的消息转换器来满足自己特定的需求,有两种方式:1、使用spring或者第三方提供的现成的HttpMessageConverter,2、自己重写一个HttpMessageConverter。


示例: 添加一个converter的方式有三种(实例中 JavaSerializationConverter 为自定义类) 其中,configureMessageConverters 与 extendMessageConverters 它们的区别的是第一个不会继承框架默认的消息转换器,第二个是继承了的。也就是说使用第一种方法配置就只有方法里面自己配置的消息转换器,而是用第二种则除了自己配置的还有框架自带的。

    // 添加converter的第一种方式,代码很简单,单个转换类的化也是推荐的方式,如果是多个,则推荐下面两种
    // 这样做springboot会把我们自定义的converter放在顺序上的最高优先级(List的头部)
    // 即有多个converter都满足Accpet/ContentType/MediaType的规则时,优先使用我们这个

    @Bean
    public JavaSerializationConverter javaSerializationConverter() {
     
        return new JavaSerializationConverter();
    }

    // 添加converter的第二种方式
    // 通常在只有一个自定义WebMvcConfigurerAdapter时,会把这个方法里面添加的converter(s)依次放在最高优先级(List的头部)
    // 虽然第一种方式的代码先执行,但是bean的添加比这种方式晚,所以方式二的优先级 大于 方式一
    @Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
        // add方法可以指定顺序,有多个自定义的WebMvcConfigurerAdapter时,可以改变相互之间的顺序
        // 但是都在springmvc内置的converter前面
        converters.add(new JavaSerializationConverter());
    }

    // 添加converter的第三种方式
    // 同一个WebMvcConfigurerAdapter中的configureMessageConverters方法先于extendMessageConverters方法执行
    // 可以理解为是三种方式中最后执行的一种,不过这里可以通过add指定顺序来调整优先级,也可以使用remove/clear来删除converter,功能强大
    // 使用converters.add(xxx)会放在最低优先级(List的尾部)
    // 使用converters.add(0,xxx)会放在最高优先级(List的头部)
    @Override
    public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
        converters.add(new JavaSerializationConverter());
    }

示例:

@Configuration
public class MyConfig implements WebMvcConfigurer {

    
    
    //此处处理form入参参数的转换
    @Override
    public void addFormatters(FormatterRegistry registry) {
        registry.addConverter(dateConverter());
        registry.addConverter(localDateTimeConverter());
        registry.addConverter(localDateConverter());
    }


    
    public Converter<String, Date> dateConverter() {
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH🇲🇲ss");
        Converter<String, Date> converter = new Converter<String, Date>() {
            @Override
            public Date convert(String s) {
                try {
                    return format.parse(s);
                } catch (ParseException e) {
                    e.printStackTrace();
                    return new Date();
                }
            }
        };
        return converter;
    }

    
    public Converter<String, LocalDateTime> localDateTimeConverterConverter() {
        Converter<String, LocalDateTime> converter = new Converter<String, LocalDateTime>() {
            @Override
            public LocalDateTime convert(String s) {
                DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH🇲🇲ss");
                return LocalDateTime.from(formatter.parse(s));
            }
        };
        return converter;
    }

    //方式1,添加到消息转换器列表中,默认添加到最后
    //此处设置添加消息转换器的位置为0,不加默认加到后面,则默认走jackson
    @Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
        converters.add(0,extendMessageConverters());
    }

    //方式2,直接注册消息转换器,则会在消息处理器列表第一位
    //@Bean
    public FastJsonHttpMessageConverter extendMessageConverters() {
        FastJsonHttpMessageConverter converter = new FastJsonHttpMessageConverter();
        converter.setDefaultCharset(Charset.forName("UTF-8"));
        converter.setSupportedMediaTypes(Arrays.asList(
                MediaType.APPLICATION_JSON_UTF8));
        FastJsonConfig config = new FastJsonConfig();
        config.setSerializerFeatures(SerializerFeature.WriteNullListAsEmpty,
                SerializerFeature.WriteNullStringAsEmpty,
                SerializerFeature.DisableCircularReferenceDetect);
        //设置Date序列化
        config.setDateFormat("yyyy-MM-dd HH🇲🇲ss");
        converter.setFastJsonConfig(config);

        SerializeConfig serializeConfig = SerializeConfig.globalInstance;
        
        //将long值改为字符串显示,解决js精度缺失问题
        serializeConfig.put(BigInteger.class, ToStringSerializer.instance);
        serializeConfig.put(Long.class, ToStringSerializer.instance);
        serializeConfig.put(Long.TYPE, ToStringSerializer.instance);
        
        //返回序列化后的时间格式;
        serializeConfig.put(LocalDateTime.class, (jsonSerializer, o, o1, type, i) -> {
            SerializeWriter out = jsonSerializer.out;
            if (o == null) {
                out.writeNull();
            } else {
                LocalDateTime result = (LocalDateTime) o;
                out.writeString(result.format(DateTimeFormatter.ofPattern("yyyy/-MM/dd HH🇲🇲ss")));
            }
        });

        config.setSerializeConfig(serializeConfig);
        return converter;
    }
    
    //方式2,直接注册消息转换器,则会在消息处理器列表第一位
    //@Bean
    public Jackson2ObjectMapperBuilderCustomizer customJackson() {
        return jacksonObjectMapperBuilder -> {
            //若POJO对象的属性值为null,序列化时不进行显示
            jacksonObjectMapperBuilder.serializationInclusion(JsonInclude.Include.NON_NULL);
            //针对于Date类型,文本格式化
            jacksonObjectMapperBuilder.simpleDateFormat("yyyy/MM/dd HH🇲🇲ss");
            //针对于JDK新时间类。序列化时带有T的问题,自定义格式化字符串
            JavaTimeModule javaTimeModule = new JavaTimeModule();
            //序列化
            javaTimeModule.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(DateTimeFormatter.ofPattern("yyyy-MM-dd HH🇲🇲ss")));
            //反序列化
            javaTimeModule.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern("yyyy-MM-dd HH🇲🇲ss")));
            jacksonObjectMapperBuilder.modules(javaTimeModule);
        };
    }

    // @Bean
    public GsonHttpMessageConverter gsonHttpMessageConverter() {
        GsonHttpMessageConverter gsonHttpMessageConverter = new GsonHttpMessageConverter();
        GsonBuilder b = new GsonBuilder();
        b.setDateFormat("yyyy-MM-dd HH🇲🇲ss").
                registerTypeAdapter(LocalDateTime.class, (JsonSerializer<LocalDateTime>) (time, type, jsonSerializationContext) ->
                        new JsonPrimitive(time.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH🇲🇲ss")))).

                // registerTypeAdapter(LocalDateTime.class, (JsonDeserializer<LocalDateTime>) (json, type, jsonDeserializationContext) -> {
                //     String datetime = json.getAsJsonPrimitive().getAsString();
                //     return LocalDateTime.parse(datetime, DateTimeFormatter.ofPattern("yyyy-MM-dd HH🇲🇲ss"));
                // }).
                        registerTypeAdapter(LocalDate.class, (JsonDeserializer<LocalDate>) (json, type, jsonDeserializationContext) -> {
                    String datetime = json.getAsJsonPrimitive().getAsString();
                    return LocalDate.parse(datetime, DateTimeFormatter.ofPattern("yyyy-MM-dd"));
                });
        gsonHttpMessageConverter.setGson(b.create());
        gsonHttpMessageConverter.setSupportedMediaTypes(Arrays
                .asList(MediaType.APPLICATION_JSON));
        return gsonHttpMessageConverter;
    }
}

响应参数的格式化设置,可直接设置配置文件:


spring:
    jackson:
        date-format: yyyy-MM-dd HH🇲🇲ss
        time-zone: GMT+8