springMvc之HandlerMethodArgumentResolver & HandlerMethodReturnValueHandler

org.springframework.web.method.support.HandlerMethodArgumentResolver

package org.springframework.web.method.support;

import org.springframework.core.MethodParameter;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.support.WebDataBinderFactory;
import org.springframework.web.context.request.NativeWebRequest;

public interface HandlerMethodArgumentResolver {
	//用于断定是否须要处理该参数分解,返回true为须要,并会去调用下面的方法resolveArgument。
	boolean supportsParameter(MethodParameter parameter);
	//真正用于处理参数分解的方法,返回的Object就是controller方法上的形参对象。
	Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
			NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception;
}

springmvc自带的一些实现:java

  • ServletRequestMethodArgumentResolverServletResponseMethodArgumentResolver处理了自动绑定HttpServletRequest和HttpServletResponse
  • RequestParamMapMethodArgumentResolver处理了@RequestParam
  • RequestHeaderMapMethodArgumentResolver处理了@RequestHeader
  • PathVariableMapMethodArgumentResolver处理了@PathVariable
  • ModelAttributeMethodProcessor处理了@ModelAttribute
  • RequestResponseBodyMethodProcessor(实际处理类AutoWrapperRequestResponseBodyMethodProcessor)处理了@RequestBody 。同时也继承: org.springframework.web.method.support.HandlerMethodReturnValueHandler 用来处理 @ResponseBody

org.springframework.web.method.support.HandlerMethodReturnValueHandler 

public interface HandlerMethodReturnValueHandler {
	//检验是否支持本处理器处理,返回true会执行handleReturnValue
	boolean supportsReturnType(MethodParameter returnType);
  
	//处理返回值的方法,returnValue便是controller方法中的返回值
	void handleReturnValue(Object returnValue, MethodParameter returnType,
			ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception;

常见如:AutoWrapperRequestResponseBodyMethodProcessor处理了@RequestBody  web

执行链路

Servlet.service -> DispatcherServlet.doDispatch -> AbstractHandlerMethodAdapter.handle -> RequestMappingHandlerAdapter.handleInternal -> ServletInvocableHandlerMethod.invokeAndHandle:spring

  1. 从集合argumentResolvers选中惟一的HandlerMethodArgumentResolver处理!
  2. 从集合returnValueHandlers选中惟一的HandlerMethodReturnValueHandler处理!

因此:  使用自定义实现后,须要去除controller方法上的@ResponseBody注解(或类上的@RestController 注解换为 @Controller),否则由于自定义的优先级比较低,仍是会走默认的处理器!api

mavContainer.setRequestHandled(true)  必定要!

 

标识请求是否已经在该方法内完成处理mvc

在RequestMappingHandlerAdapter.invokeHandlerMethod执行过程当中,在处理完输出对象后, 会调用getModelAndView子过程经过“mavContainer.isRequestHandled()”来断定返回一个ModelAndeView对象。
app

正确的逻辑应该返回null;若返回了ModelAndView对象,但内部属性View为空也无法解析。
ide

DispatcherServlet.doDispatch -> DispatcherServlet.processDispatchResult -> DispatcherServlet.render -> InternalResourceView(AbstractView).render 解析过程输出异常 :spring-boot

2019-12-12 17:42:00.613 [http-nio-8023-exec-9] WARN  org.springframework.web.servlet.PageNotFound -- No mapping found for HTTP request with URI [/api/api/query] in DispatcherServlet with name 'dispatcherServlet'

postMan响应结果:
post

自定义实现

参数及返回结果处理spa

import javax.servlet.http.HttpServletResponse;

import org.springframework.core.MethodParameter;
import org.springframework.web.bind.support.WebDataBinderFactory;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.HandlerMethodReturnValueHandler;
import org.springframework.web.method.support.ModelAndViewContainer;

import com.utrusts.adapter.dto.guarantee.Person;

public class SessionArgumentsReturnValRelover
		implements HandlerMethodArgumentResolver, HandlerMethodReturnValueHandler {
	@Override
	public boolean supportsParameter(MethodParameter parameter) {
		return parameter.hasParameterAnnotation(Session.class) && parameter.getParameterType().equals(String.class);
	}

	@Override
	public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
			NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
		return "test";
	}

	@Override
	public boolean supportsReturnType(MethodParameter returnType) {
		return returnType.getParameterType() == Person.class;
	}

	@Override
	public void handleReturnValue(Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer,
			NativeWebRequest webRequest) throws Exception {
		mavContainer.setRequestHandled(true); // 设置请求已经被处理的标识
		HttpServletResponse response = webRequest.getNativeResponse(HttpServletResponse.class);
		response.setContentType("text/plain;charset=utf-8");
		Person person = (Person) returnValue;
		response.getWriter().write("通过HandlerMethodReturnValueHandler输出的person:" + person);
	}

}

spring-boot方式注册自定义分解器

@Configuration
public class MyConfigurer extends WebMvcConfigurationSupport {
	SessionArgumentsReturnValRelover relover = new SessionArgumentsReturnValRelover();

	@Override
	protected void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
		argumentResolvers.add(relover);
	}

	@Override
	protected void addReturnValueHandlers(List<HandlerMethodReturnValueHandler> returnValueHandlers) {
		returnValueHandlers.add(relover);
	}
}

使用时要注意的是: 使用自定义实现后,须要去除controller方法上的@ResponseBody注解(或类上的@RestController 注解换为 @Controller),否则由于自定义的优先级比较低,仍是会走默认的处理器。

import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import com.utrusts.adapter.aop.Session;
import com.utrusts.adapter.dto.common.query.QueryApplyResultReq;
import com.utrusts.adapter.dto.guarantee.Person;

import lombok.extern.slf4j.Slf4j;
//@RestController
@Controller
@RequestMapping("/api")
public class QueryController {

	@PostMapping("/query")
	public Person query(@RequestBody QueryApplyResultReq queryReq, @Session String user) {
		Person person = new Person();
		person.setName(user);
		return person ;
	}
}

postMan响应结果:

相关文章
相关标签/搜索