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
ServletRequestMethodArgumentResolver
和ServletResponseMethodArgumentResolver
處理了自動綁定HttpServletRequest和HttpServletResponseRequestParamMapMethodArgumentResolver
處理了@RequestParam
RequestHeaderMapMethodArgumentResolver
處理了@RequestHeader
PathVariableMapMethodArgumentResolver
處理了@PathVariable
ModelAttributeMethodProcessor
處理了@ModelAttribute
RequestResponseBodyMethodProcessor(實際處理類AutoWrapperRequestResponseBodyMethodProcessor)
處理了@RequestBody 。同時也繼承: org.springframework.web.method.support.HandlerMethodReturnValueHandler 用來處理 @ResponseBody
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
因此: 使用自定義實現後,須要去除controller方法上的@ResponseBody
註解(或類上的@RestController 註解換爲 @Controller),否則由於自定義的優先級比較低,仍是會走默認的處理器!api
標識請求是否已經在該方法內完成處理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響應結果: