【原创】遨游springmvc之HandlerMethodReturnValueHandler

怎甘沉沦 提交于 2019-11-27 18:52:16

1.前言

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

在前一篇我们主要讲述了springmvc对传入参数的接口HandlerMethodArgumentResolver。那么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<HandlerMethodReturnValueHandler> getDefaultReturnValueHandlers() {
		List<HandlerMethodReturnValueHandler> handlers = new ArrayList<HandlerMethodReturnValueHandler>();

		// 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)
@Documented
public @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 配置

    <mvc:annotation-driven >
        <mvc:return-value-handlers>
            <bean class="com.kings.template.mvc.CustomerHandlerMethodReturnValueHandler"/>
        </mvc:return-value-handlers>
    </mvc:annotation-driven>

 

3.4 控制器

@Controller
public class HandlerMethodReturnValueHandlerDemoController {
    
    @RequestMapping (value="/returnvalue/1",method=GET)
    @KingsResponseBody
    public List<Person> 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,而且也非常简单,比如某些场景会需要我们在响应里面加入特定一些什么响应头或者需要转化为指定格式。

 

发现一个机制的导航😳

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!