HTTP参数与响应处理:在SpringBoot中自定义参数解析器,反序列化器和类型转换器
本文介绍了在Spring Boot中如何使用自定义参数解析器和自定义类型转换器来处理HTTP请求和响应中的自定义参数类型。
HTTP,GET,自定义参数解析器
在Java和Spring Boot中,可以通过自定义参数解析器(Argument Resolver)来处理请求中的自定义参数类型,从而实现更为灵活的参数解析。
实现自定义参数解析器(HandlerMethodArgumentResolver
)
public class MyArgumentResolver implements HandlerMethodArgumentResolver {
@Override
public boolean supportsParameter(MethodParameter parameter) {
return parameter.getParameterType().equals(MyParam.class);
}
@Override
public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
HttpServletRequest request = (HttpServletRequest) webRequest.getNativeRequest();
String value = request.getParameter("myParam");
// 解析请求中的自定义参数,返回解析结果
return new MyParam(value);
}
}
首先,我们需要创建一个自定义参数解析器,实现HandlerMethodArgumentResolver接口。例如,我们创建一个名为MyArgumentResolver的类,用于解析请求中的自定义参数类型MyParam:
在supportsParameter()方法中,我们判断参数类型是否为自定义参数类型MyParam,如果是则返回true,表示该解析器支持这个参数类型。
在resolveArgument()方法中,我们首先通过NativeWebRequest获取HttpServletRequest对象,然后从请求中获取自定义参数myParam的值,并解析成MyParam对象,最后返回解析结果。
注册自定义参数解析器
将自定义参数解析器注册到Spring Boot中。我们可以在@Configuration类中使用addArgumentResolvers()方法将自定义参数解析器添加到Spring Boot中:
@Configuration
public class MyConfig implements WebMvcConfigurer {
@Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
argumentResolvers.add(new MyArgumentResolver());
}
}
在上述配置中,我们实现了WebMvcConfigurer接口,重写了addArgumentResolvers()方法,并将MyArgumentResolver对象添加到了参数解析器列表中。
使用
最后,我们可以在Controller中使用自定义参数类型MyParam:
@RestController
@RequestMapping("/test")
public class MyController {
@GetMapping("/myparam")
public String testMyParam(@RequestParam("myParam") MyParam myParam) {
// 处理自定义参数类型MyParam
return "success";
}
}
在上述代码中,我们使用了@RequestParam注解来绑定请求中的自定义参数myParam到Controller方法的参数MyParam中。
HTTP,POST,自定义参数解析器
在Java和SpringBoot中处理HTTP POST请求的请求体时,可以使用多种参数解析器。
在SpringBoot中,默认使用的是HttpMessageConverters,它会根据请求头中的Content-Type来选择合适的参数解析器。
Content-Type | Param Resolver |
---|---|
application/json | MappingJackson2HttpMessageConverter |
application/x-www-form-urlencoded | FormHttpMessageConverter |
multipart/form-data | MultipartResolver |
接收和发送 snake_case 格式的 JSON 数据
配置高优级的ObjectMapper
@Bean
@Primary
public ObjectMapper objectMapper() {
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
objectMapper.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS);
objectMapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
objectMapper.getFactory().configure(JsonGenerator.Feature.ESCAPE_NON_ASCII, true);
objectMapper.setPropertyNamingStrategy(PropertyNamingStrategy.SNAKE_CASE);
return objectMapper;
}
原理如下
- 当您使用
@Primary
注解标记ObjectMapper
Bean 时,您告诉 Spring 在有多个ObjectMapper
Bean 可用时,优先使用这个 Bean。这样,您配置的ObjectMapper
实例将成为 Spring Boot 应用中处理 JSON 序列化和反序列化任务的首选实例。 - Spring Boot 使用
HttpMessageConverter
接口实现将 Java 对象转换为 HTTP 响应消息,以及将 HTTP 请求消息转换为 Java 对象。默认情况下,Spring Boot 配置了一组HttpMessageConverter
,包括处理 JSON 数据的MappingJackson2HttpMessageConverter
。 MappingJackson2HttpMessageConverter
使用 Jackson 库中的ObjectMapper
实例来处理 Java 对象与 JSON 数据之间的序列化和反序列化。在您的代码中,您已经配置了ObjectMapper
以使用 snake_case 格式。- 当 Spring Boot 处理一个 HTTP 请求或响应时,它会使用
MappingJackson2HttpMessageConverter
(如果请求或响应的内容类型为 JSON)。因为您已经配置了一个首选的ObjectMapper
Bean(使用 snake_case),MappingJackson2HttpMessageConverter
将使用这个ObjectMapper
实例来处理 JSON 数据。
Jackson2ObjectMapperBuilderCustomizer
import com.fasterxml.jackson.databind.PropertyNamingStrategies;
import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class JacksonConfig {
@Bean
public Jackson2ObjectMapperBuilderCustomizer jackson2ObjectMapperBuilderCustomizer() {
return builder -> builder.propertyNamingStrategy(PropertyNamingStrategies.SNAKE_CASE);
}
}
自定义JSON反序列化器(JsonDeserializer)
我们从一个Long过长导致js自动截断的case处理出出发,学习一下JsonDeserializer.
JS内置有32位整数,而number类型的安全整数是53位,但是java的long类型却是64位,如果数值过大的直接传递会有问题.
一般做法是把long型字段转成string进行处理。(可以使用json注解转换或者springmvc统一拦截处理)
定义JsonDeserializer
public class StringToLongDeserializer extends JsonDeserializer<Long> {
@Override
public Long deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException {
String val = p.getText();
if(StringUtils.isBlank(val)){
return null;
}else {
return Long.valueOf(val);
}
}
}
public class LongToStingSerializer extends JsonSerializer<Long> {
@Override
public void serialize(Long value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
if(value == null){
gen.writeString("");
}else {
gen.writeString(String.valueOf(value));
}
}
}
使用JsonDeserializer
前端传过来的请求是string 我们需要转成Long
public class Request {
@JsonDeserialize(using = StringToLongDeserializer.class)
private Long pddGoodsId;
}
后端数据类型为Long ,前端需要String 类型
public class VO implements Serializable {
@JsonSerialize(using = LongToStingSerializer.class)
private Long goodsId;
}
自定义类型转换器
实现自定义类型转换器(Converter
)
public class StringToDateConverter implements Converter<String, Date> {
private SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
@Override
public Date convert(String source) {
try {
return dateFormat.parse(source);
} catch (ParseException e) {
throw new IllegalArgumentException("无效的日期格式:" + source);
}
}
}
上述代码中,定义了一个将字符串转换为日期类型的转换器,通过实现Converter接口的convert方法来实现类型转换。在convert方法中,使用SimpleDateFormat类将字符串解析为日期类型,并处理解析异常。
注册自定义类型转换器
为了让Spring框架能够自动地使用这个转换器,需要将其注册到Spring框架中
通过 DefaultConversionService 注册
@Configuration
public class AppConfig {
@Bean
public StringToDateConverter stringToDateConverter() {
return new StringToDateConverter();
}
@Bean
public ConversionService conversionService() {
DefaultConversionService conversionService = new DefaultConversionService();
conversionService.addConverter(stringToDateConverter());
return conversionService;
}
}
上述代码中,使用@Configuration注解定义了一个配置类,并在该类中定义了一个StringToDateConverter类型的Bean和一个ConversionService类型的Bean。
在ConversionService类型的Bean中,调用addConverter方法将StringToDateConverter类型的转换器注册到ConversionService中。
现在,当 Spring 需要将 String
类型转换为 LocalDate
类型时,将使用我们的自定义 StringToLocalDateConverter
转换器。
通过 FormattingConversionServiceFactoryBean 注册
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.format.FormatterRegistry;
import org.springframework.format.support.FormattingConversionServiceFactoryBean;
@Configuration
public class ConversionConfiguration {
@Bean
public FormattingConversionServiceFactoryBean conversionService() {
FormattingConversionServiceFactoryBean factoryBean = new FormattingConversionServiceFactoryBean();
factoryBean.setConverters(Set.of(new StringToLocalDateConverter("yyyy-MM-dd")));
return factoryBean;
}
}
通过为 FormattingConversionServiceFactoryBean
提供一组转换器,我们可以在 Spring 应用上下文中注册自定义转换器。
现在,当 Spring 需要将 String
类型转换为 LocalDate
类型时,将使用我们的自定义 StringToLocalDateConverter
转换器。
转载自:https://juejin.cn/post/7243592123801960507