SpringMVC对HTTP报文体的处理
2015-12-12 20:23
573 查看
SpringMVC对HTTP报文体的处理
客户端和服务端HTTP报文传递消息,而HTTP报文包含报文头和报文体。通常,解析请求参数以及返回页面都不需要我们关心HTTP报文体的读取和生成过程。但在某些特定场景下需要直接到请求报文中读取报文体,或者将返回的数据直接写入到报文体中。在SpringMVC中,可以利用RequestBody注解表示一个参数,说明解析它需要读取报文体,也可以直接将参数类型声明成HttpEntity<T>类型。与处理请求类似,如果想要将对象写入到响应报文的报文体中,则可以返回HttpEntity<T>类型的数据或者在方法上标注ResponseBody。
RequestBody与ResponseBody对应的处理器是RequestResponseBodyMethodProcessor,它同时负责消息体的读取和写入,它既是参数解析器也是结果处理器。下面看看它读取和写入报文体的逻辑:
public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception { Object arg = readWithMessageConverters(webRequest, parameter, parameter.getParameterType()); Annotation[] annotations = parameter.getParameterAnnotations(); for (Annotation annot : annotations) { if (annot.annotationType().getSimpleName().startsWith("Valid")) { String name = Conventions.getVariableNameForParameter(parameter); WebDataBinder binder = binderFactory.createBinder(webRequest, arg, name); Object hints = AnnotationUtils.getValue(annot); binder.validate(hints instanceof Object[] ? (Object[]) hints : new Object[] {hints}); BindingResult bindingResult = binder.getBindingResult(); if (bindingResult.hasErrors()) { throw new MethodArgumentNotValidException(parameter, bindingResult); } } } return arg; } public void handleReturnValue(Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws IOException, HttpMediaTypeNotAcceptableException { mavContainer.setRequestHandled(true); if (returnValue != null) { writeWithMessageConverters(returnValue, returnType, webRequest); } }
由上面的两个方法可以看出,不管是消息体的读取还是写入都涉及到了HttpMessageConverter,这个对象就是spring负责消息体与Java对象互相转换的工具。另外,HttpEntity类型的数据处理器为HttpEntityMethodProcessor,它对消息体的读取和写入也是利用HttpMessageConverter:
public Object resolveArgument( MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws IOException, HttpMediaTypeNotSupportedException { HttpInputMessage inputMessage = createInputMessage(webRequest); Class<?> paramType = getHttpEntityType(parameter); Object body = readWithMessageConverters(webRequest, parameter, paramType); return new HttpEntity<Object>(body, inputMessage.getHeaders()); } public void handleReturnValue( Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception { mavContainer.setRequestHandled(true); if (returnValue == null) { return; } ServletServerHttpRequest inputMessage = createInputMessage(webRequest); ServletServerHttpResponse outputMessage = createOutputMessage(webRequest); Assert.isInstanceOf(HttpEntity.class, returnValue); HttpEntity<?> responseEntity = (HttpEntity<?>) returnValue; if (responseEntity instanceof ResponseEntity) { outputMessage.setStatusCode(((ResponseEntity<?>) responseEntity).getStatusCode()); } HttpHeaders entityHeaders = responseEntity.getHeaders(); if (!entityHeaders.isEmpty()) { outputMessage.getHeaders().putAll(entityHeaders); } Object body = responseEntity.getBody(); if (body != null) { writeWithMessageConverters(body, returnType, inputMessage, outputMessage); } else { // flush headers to the HttpServletResponse outputMessage.getBody(); } }
既然HttpMessageConverter这么重要,就来看看它的接口定义:
public interface HttpMessageConverter<T> { boolean canRead(Class<?> clazz, MediaType mediaType); boolean canWrite(Class<?> clazz, MediaType mediaType); List<MediaType> getSupportedMediaTypes(); T read(Class<? extends T> clazz, HttpInputMessage inputMessage) throws IOException, HttpMessageNotReadableException; void write(T t, MediaType contentType, HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException; }每个HttpMessageConverter都要实现canRead和canWrite方法,以此来判断当前的HttpMessageConverter是否可以胜任此次报文体处理的任务。MediaType 对应的HTTP的Content-Type头部,只有同时符合数据类型以及Content-Type的描述才可以正确的读取或者写入报文体。与参数解析器和结果处理器一样,HttpMessageConverter的设计也采用了策略模式,也是配置在HandlerAdapter中。
在实际开发,若需要跟客户端实现自己的协议,则可以自己实现HttpMessageConverter并配置到HandlerAdapter中。
相关文章推荐
- Android之判断手机连接的网络类型是WIFI还是2G/3G/4G
- 神经网络
- (Fun)*((int*)*(int*)(&b)); http://bbs.csdn.net/topics/320008423
- 操作系统与网络实现 之十二
- 操作系统与网络实现 之十二
- 《TCP/IP作品详细解释2:实现》笔记--Radix树路由表
- 【拔苗计划】——TCP学习笔记之TCP三次握手四次断连
- C++虚函数及虚函数表解析http://www.cnblogs.com/chinazhangjie/archive/2012/07/11/2586535.html
- 用平常语言介绍神经网络
- Xcode7 HTTP不能正常使用的方法
- wmware虚拟网卡 VMnet8 VMnet1未识别网络解决方法
- Granafa http api使用
- 来这里看HTTP服务器状态代码定义
- 服务器架设笔记——httpd插件支持mysql字符集选择
- http://ahua186186.iteye.com/blog/1830180
- 认识RMI和代理模式
- 通信协议——Http、TCP、UDP
- android 让网络图片正常显示在Imageviw控件设计的大小之中
- 《TCP/IP详解 卷1:协议》 读书笔记 第十五章 TFTP:简单文件传送协议
- 《TCP/IP详解 卷1:协议》 读书笔记 第十一章 UDP:用户数据报协议