博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
【原创】遨游springmvc之HandlerMethodReturnValueHandler
阅读量:6511 次
发布时间:2019-06-24

本文共 7429 字,大约阅读时间需要 24 分钟。

  hot3.png

1.前言

在springmvc中,很多人都知道@ResponseBody,加了它那就会返回对应的数据结果(json),而不是一张jsp或者其他视图。如果不加,那么它就返回了一个具体的视图,如jsp。那么让我们来深入探析下这里面的究竟。

在前一篇我们主要讲述了springmvc对传入参数的接口。那么springmvc同样也也提供了一系列对响应返回值进行处理的接口,核心接口类就是本篇要介绍的HandlerMethodReturnValueHandler。

2.原理

2.1 接口说明

public interface HandlerMethodReturnValueHandler {	/**	 * Whether the given {@linkplain MethodParameter method return type} is	 * supported by this handler.	 * @param returnType the method return type to check	 * @return {@code true} if this handler supports the supplied return type;	 * {@code false} otherwise	 */	boolean supportsReturnType(MethodParameter returnType);	/**	 * Handle the given return value by adding attributes to the model and	 * setting a view or setting the	 * {@link ModelAndViewContainer#setRequestHandled} flag to {@code true}	 * to indicate the response has been handled directly.	 * @param returnValue the value returned from the handler method	 * @param returnType the type of the return value. This type must have	 * previously been passed to {@link #supportsReturnType} which must	 * have returned {@code true}.	 * @param mavContainer the ModelAndViewContainer for the current request	 * @param webRequest the current request	 * @throws Exception if the return value handling results in an error	 */	void handleReturnValue(Object returnValue, MethodParameter returnType,			ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception;}

HandlerMethodReturnValueHandler是在spring3.1之后引入的

它主要包含2个方法:

1.supportsReturnType()决定了哪类类型的返回值将启用该返回值处理器

2.handleReturnValue则是主要处理返回值的处理逻辑,并且将处理好的值返回给model,还可以处理该返回什么视图

 

2.2 依赖

HandlerMethodReturnValueHandler的实现大多类都是已ReturnValueHandler或者Processor(包含了参数处理)结尾

 

2.3 源码分析

2.3.1 初始化HandlerMethodReturnValueHandler

在初始化RequestMappingHandlerAdapter时候,springmvc默认初始化了一系列返回值处理器,并且提供了自动以的HandlerMethodReturnValueHandler的入口。

private List
getDefaultReturnValueHandlers() { List
handlers = new ArrayList
(); // Single-purpose return value types handlers.add(new ModelAndViewMethodReturnValueHandler()); handlers.add(new ModelMethodProcessor()); handlers.add(new ViewMethodReturnValueHandler()); handlers.add(new ResponseBodyEmitterReturnValueHandler(getMessageConverters())); handlers.add(new StreamingResponseBodyReturnValueHandler()); handlers.add(new HttpEntityMethodProcessor(getMessageConverters(), this.contentNegotiationManager, this.requestResponseBodyAdvice)); handlers.add(new HttpHeadersReturnValueHandler()); handlers.add(new CallableMethodReturnValueHandler()); handlers.add(new DeferredResultMethodReturnValueHandler()); handlers.add(new AsyncTaskMethodReturnValueHandler(this.beanFactory)); // Annotation-based return value types handlers.add(new ModelAttributeMethodProcessor(false)); handlers.add(new RequestResponseBodyMethodProcessor(getMessageConverters(), this.contentNegotiationManager, this.requestResponseBodyAdvice)); // Multi-purpose return value types handlers.add(new ViewNameMethodReturnValueHandler()); handlers.add(new MapMethodProcessor()); // Custom return value types 加入自定义的返回值处理器 if (getCustomReturnValueHandlers() != null) { handlers.addAll(getCustomReturnValueHandlers()); } // Catch-all if (!CollectionUtils.isEmpty(getModelAndViewResolvers())) { handlers.add(new ModelAndViewResolverMethodReturnValueHandler(getModelAndViewResolvers())); } else { handlers.add(new ModelAttributeMethodProcessor(true)); } return handlers; }

 

HandlerMethodReturnValueHandler的匹配是按照初始化的顺序,请看下面table罗列的处理器和对应的处理类型。

处理器 处理类型
针对一中类型
ModelAndViewMethodReturnValueHandler ModelAndView
ModelMethodProcessor Model
ViewMethodReturnValueHandler View
ResponseBodyEmitterReturnValueHandler ResponseEntity<ResponseBodyEmitter>
StreamingResponseBodyReturnValueHandler ResponseEntity<StreamingResponseBody>
HttpHeadersReturnValueHandler HttpHeaders
 CallableMethodReturnValueHandler  Callable
DeferredResultMethodReturnValueHandler DeferredResult、ListenableFuture、CompletionStage
AsyncTaskMethodReturnValueHandler WebAsyncTask
针对注解
ModelAttributeMethodProcessor @ModelAttribute(require=false)
RequestResponseBodyMethodProcessor @ResponseBody
处理多种类型
ViewNameMethodReturnValueHandler void、CharSequence(V4.2)
MapMethodProcessor Map
自定义返回值处理器
ModelAndViewResolverMethodReturnValueHandler 默认处理,如果以上的都不满足就会进入
ModelAttributeMethodProcessor @ModelAttribute(require=true)

 

2.3.2 RequestResponseBodyMethodProcessor

public boolean supportsReturnType(MethodParameter returnType) {//支持类型		return (AnnotatedElementUtils.hasAnnotation(returnType.getContainingClass(), ResponseBody.class) ||				returnType.hasMethodAnnotation(ResponseBody.class));	}

mavContainer.setRequestHandled(true);//请求是否已经完全在处理程序中处理好,如果是fasle,则继续流转到对应的视图,如果设置为true,则不会再进过视图这一 层直接响应,默认是false。

public void handleReturnValue(Object returnValue, MethodParameter returnType,			ModelAndViewContainer mavContainer, NativeWebRequest webRequest)			throws IOException, HttpMediaTypeNotAcceptableException, HttpMessageNotWritableException {		mavContainer.setRequestHandled(true);//如果没有视图,则必须设置为true,否则会返回视图层		ServletServerHttpRequest inputMessage = createInputMessage(webRequest);		ServletServerHttpResponse outputMessage = createOutputMessage(webRequest);		// Try even with null return value. ResponseBodyAdvice could get involved.        //输出		writeWithMessageConverters(returnValue, returnType, inputMessage, outputMessage);	}

 

3.实例

我们来实现一个类似@ResponseBody的功能。

3.1 KingsResponseBody

@Target ( {ElementType.TYPE, ElementType.METHOD})@Retention (RetentionPolicy.RUNTIME)@Documentedpublic @interface KingsResponseBody {    String type() default "json";}

 

3.2 CustomerHandlerMethodReturnValueHandler

public class CustomerHandlerMethodReturnValueHandler implements HandlerMethodReturnValueHandler {    @Override    public boolean supportsReturnType(MethodParameter returnType) {        return (AnnotatedElementUtils.hasAnnotation(returnType.getContainingClass(), KingsResponseBody.class) || returnType.hasMethodAnnotation(KingsResponseBody.class));    }        @Override    public void handleReturnValue(Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {        KingsResponseBody anno = returnType.getMethodAnnotation(KingsResponseBody.class);        mavContainer.setRequestHandled(true);        String type = anno.type();        HttpServletResponse response = webRequest.getNativeResponse(HttpServletResponse.class);        response.setContentType("text/json;charset=UTF-8");        try (PrintWriter out = response.getWriter()) {            Gson jb = new Gson();            out.write(jb.toJson(returnValue));            out.flush();        } catch (IOException e) {            throw e;        }    }}

有时候我们还可以往响应头里面丢一些内容什么的,具体的实现根据需求而定。

 

3.3 配置

 

3.4 控制器

@Controllerpublic class HandlerMethodReturnValueHandlerDemoController {        @RequestMapping (value="/returnvalue/1",method=GET)    @KingsResponseBody    public List
demo() { Person p1 = new Person(); p1.setName("WS"); Person p2 = new Person(); p2.setName("Kings"); return Lists.newArrayList(p1,p2); }}

 

访问:http://localhost:8080/returnvalue/1

返回:

[{"name":"WS"},{"name":"Kings"}]

 

4. 总结

当我们需要统一处理springmvc返回值的时候我们就可以考虑使用HandlerMethodReturnValueHandler,而且也非常简单,比如某些场景会需要我们在响应里面加入特定一些什么响应头或者需要转化为指定格式。

 

转载于:https://my.oschina.net/kings0/blog/735449

你可能感兴趣的文章
第一课 PHP学习要求
查看>>
postfix相关问题整理及处理
查看>>
Linux Redhat系统的三种包的使用
查看>>
修改mysql的监听地址(unknown variable ‘defaults-file) 10 Apr, 2008 mysql
查看>>
实用的网站
查看>>
nginx服务器安装设置全部知识
查看>>
快捷方式的小箭头
查看>>
表字段部分更新
查看>>
“ABC”时代,IT变革下的驱动数据价值之路
查看>>
每日一shell(八)nginx日志切割
查看>>
无法回应的ARP请求包导致的网站缓慢问题排错
查看>>
软件需求间谍
查看>>
struts2+jquery+json集成
查看>>
一个得到内存信息的shell以及遇到的一个坑
查看>>
Reboot/halt/shutdown command on CentOS 7
查看>>
OpenAI最新成果:无监督情绪神经元(水军面临失业威胁……)
查看>>
关于extmail邮件服务器安装extsuite-webman出现的报错
查看>>
NoSQL--Redis 2.4--Set
查看>>
SVN使用教程总结
查看>>
linux和window是服务器时间同步
查看>>