WebDataBinder与HttpMessageConverter

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了WebDataBinder与HttpMessageConverter相关的知识,希望对你有一定的参考价值。



HttpMessageConverter

​HttpMessageConverter<T>​​ 是 Spring3.0 新添加的一个接口,负责将请求信息转换为一个对象(类型为 T),将对象(类型为 T)输出为响应信息

// 指定转换器可以读取的对象类型,即转换器是否可将请求信息转换为 clazz 类型的对象,同时指定支持 MIME 类型(text/html,applaiction/json等)
Boolean canRead(Class<?> clazz,MediaType mediaType);
// 指定转换器是否可将 clazz 类型的对象写到响应流中,响应流支持的媒体类型在MediaType 中定义。
Boolean canWrite(Class<?> clazz,MediaType mediaType);
// 该转换器支持的媒体类型。
List<MediaType> getSupportMediaTypes();
// 将请求信息流转换为 T 类型的对象。
T read(Class<? extends T> clazz,HttpInputMessage inputMessage);
//将T类型的对象写到响应流中,同时指定相应的媒体类型为 contentType
void write(T t,MediaType contnetType,HttpOutputMessgae outputMessage);

WebDataBinder与HttpMessageConverter_参数解析


WebDataBinder与HttpMessageConverter_参数解析_02

HttpInputMessage

/**
* Represents an HTTP input message, consisting of @linkplain #getHeaders() headers
* and a readable @linkplain #getBody() body.
*/
public interface HttpInputMessage extends HttpMessage

/**
* Return the body of the message as an input stream.
* @return the input stream body (never @code null)
* @throws IOException in case of I/O errors
*/
InputStream getBody() throws IOException;

根据注释我们能知道,其内部包含请求体和请求头的内容,这就意味着,HttpMessageConverter​能解析请求头和请求行的内容,当然这还得看具体的HttpMessageConverter的实现了,大部分的HttpMessageConverter并没有从请求头中获取内容,都只是获取请求体的内容,比如FastJsonHttpMessageConverter

WebDataBinderwebDataBinder

​webDataBinder是继承自DataBinder的,DataBinder是Spring提供的,WebDataBinder是springmvc提供的。 它的作用就是从web request里把web请求的parameters绑定到JavaBean上

Controller方法的参数类型可以是基本类型,也可以是封装后的普通Java类型。若这个普通Java类型没有声明任何注解,则意味着它的每一个属性都需要到Request中去查找对应的请求参数,这种情况的参数解析是交给ModelAttributeMethodProcessor这个参数解析器来做的 ​

/**
* 从方法中可以看出,这个参数解析器是支持被@ModelAttribute注解标识的参数,或者是复杂类型对象,也就是普通的Java类型的对象
*/
@Override
public boolean supportsParameter(MethodParameter parameter)
return (parameter.hasParameterAnnotation(ModelAttribute.class) ||
(this.annotationNotRequired && !BeanUtils.isSimpleProperty(parameter.getParameterType())));


DataBinder不仅完成数据的绑定,还会和数据校验,WebDataBinder是继承自DataBinder的,当然也就具有这些能力

WebDataBinder对父类进行了增强,提供的增强能力如下:

支持对属性名以_打头的默认值处理(自动挡,能够自动处理所有的Bool、Collection、Map等) 支持对属性名以!打头的默认值处理(手动档,需要手动给某个属性赋默认值,自己控制的灵活性很高) 提供方法,支持把MultipartFile绑定到JavaBean的属性上 具体的WebDataBinder和DataBinder,可以查看下面两个文章! WebDataBinder DataBinder

WebDataBinder和HttpMessageConverter 根据上面的叙述我们可能能看出来,WebDataBinder提供数据的绑定功能,可以将传递进来的属性值绑定到对象上,同时还可以进行一些类型转换。HttpMessageConverter也是提供了数据绑定功能,也具有类型转换的能力。那么springmvc在使用的时候,在什么时候,用哪一个呢? 首先HttpMessageConverter与WebDataBinder的最大区别在于能否自己获取对象需要的属性值,HttpMessageConverter其能自己去从HttpInputMessage中解析出对象需要的参数值进行绑定,但是WebDataBinder不行,WebDataBinder进行数据绑定的时候要传递给其一个MutablePropertyValues对象,这个对象中包含了对象所需要的所有数据(WebDataBinder进行绑定的同时也会进行数据类型转换,也能进行数据格式化)。此外WebDataBinder能进行数据效验。WebDataBinder的应用范围是比HttpMessageConverter更广的

SpringMVC在什么时候使用HttpMessageConverter什么时候使用WebDataBinder呢? 既然是根绑定有关的,那么他们俩一定在springmvc的参数解析器中有所使用。 springmvc的HandlerMethodArgumentResolver这个接口,是负责handler方法的参数解析的核心接口,在调用handlerMethod之前都会利用该接口解析出每一个参数值​

    // 这里面包含了一个参数为WebDataBinderFactory
    Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
    NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception;

从上面的WebDataBinderFactory类型的参数就能看出来,只要是参数解析的类,都可以使用到WebDataBinder,因为每一个参数解析器中都包含了一个WebDataBinderFactory

那么HttpMessageConverter呢? AbstractMessageConverterMethodArgumentResolver:该类也是属于HandlerMethodArgumentResolver接口的一个实现类,所以其也是进行参数解析的。从名字就能看出其与HttpMessageConverter密不可分,这个类中有这样一个方法​

/**
* 这个类的一个官方描述
* A base class for resolving method argument values by reading from the body of
* a request with @link HttpMessageConverter HttpMessageConverters.
*/

// 该类中包含了很多的HttpMessageConverter,可以用来进行参数解析
protected final List<HttpMessageConverter<?>> messageConverters;

@Nullable
protected <T> Object readWithMessageConverters(NativeWebRequest webRequest, MethodParameter parameter,
Type paramType) throws IOException, HttpMediaTypeNotSupportedException, HttpMessageNotReadableException

HttpInputMessage inputMessage = createInputMessage(webRequest);
return readWithMessageConverters(inputMessage, parameter, paramType);

当然一般都不是直接使用该类,因为其是一个抽象类,其有以下几个实现。

​(后缀以Processor结束的这些类,他们不仅仅提供参数解析的功能,同时还进行返回值的处理,这些类一般都实现了两个接口:HandlerMethodArgumentResolver和HandlerMethodReturnValueHandler)​

WebDataBinder与HttpMessageConverter_spring_03


这就能看出来哪些类使用了HttpMessageConverter了

其中的RequestResponseBodyMethodProcessor是一个常用的类,查看其supportsParameter方法,其负责解析被@RequestBody注解标识的参数

// 其负责解析被@RequestBody注解标识的参数
@Override
public boolean supportsParameter(MethodParameter parameter)
return parameter.hasParameterAnnotation(RequestBody.class);

json格式的数据就是由​​RequestResponseBodyMethodProcessor​​这个参数解析器交给HttpMessageConverter解析出来的,然后叫给了WebDataBInder进行数据效验,注意是数据效验,因为HttpMessageConverter返回的是一个完整的已经绑定好数据的对象。

总结

由上述我们就能知道,WebDataBinder基本是所有的参数解析器都会使用,而HttpMessageConverter只是在几个特殊的类中使用,其


spring-web中的WebDataBinder理解

Spring可以自动封装Bean,也就是说前台通过SpringMVC传递过来的属性值会自动对应到对象中的属性并封装成javaBean,但是只能是基本数据类型(int,String等)。如果传递过来的是特殊对象,则需要手动进行封装。

Spring提供了@InitBinder(初始化绑定封装)注解和WebDataBinder工具。用户只需要向WebDataBinder注册自己需要的类型的属性编辑器即可。

/*
前台传递过来的String类型时间,通过下面的初始化绑定,转换成Date类型
*/
@initBinder
public void initBinder(WebDataBinder binder){
  SimpleDateFormate sdf=new SimpleDateFormate("yyyy-MM-dd HH:mm");  
  binder.registerCustomEditor(Date.class,new CustomDateEditor(sdf,true));//true表示允许空值,false不允许
}

 

以上是关于WebDataBinder与HttpMessageConverter的主要内容,如果未能解决你的问题,请参考以下文章

如何在 C# 中访问 Json(这是 HttpMessage 的结果)?

Python3中HTTPMessage object has no attribute getheaders错误解决办法

HttpComponents 基础接口/类与HTTP message的对应关系

springMVC-InitBinder

urllib使用二

WebDataBinderServletRequestDataBinderWebBindingInitializer