spingmvc 的requestmappling方法如何動態修改返回值類型web
業務場景:ajax
客戶端請求服務端(兩個公司的不一樣系統之間的請求,相似於http接口),請求中參數異常就直接給客戶端提示,請求正常,服務端控制跳轉到本身系統的頁面,執行剩餘邏輯。spring
springmvc 的requestmapping 方法,分兩種,一種是帶有responsebody註解的(ajax操做),一種是沒有(作請求跳轉)json
springmvc 提供了一個 標籤(mvc
<mvc:annotation-driven><mvc:return-value-handlers><bean/></mvc:return-value-handlers></mvc:annotation-driven>app
),用來註冊返回值類型的,咱們能夠本身定義返回值類型(例如:定義User),異步
接下來能夠了解下生命週期,啓動的時候把把自定義的方法返回值類型註冊,而後放到一個list裏面,ide
requestmapping方法被調用的時候,先執行方法體,而後會根據方法的實際返回類型,到list中去找,this
若是這個返回值類型沒有,而且是responsebody方法則轉換成json,返回頁面,若是不是responsebody則拋出返回類型不支持的異常,要實現咱們的需求,就要從這裏侵入源碼,url
前面定義user 假設有兩個屬性,一個url(地址挑轉),一個code(表示給客戶端返回錯誤碼)
源碼中, org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(
ServletWebRequest webRequest,
ModelAndViewContainer mavContainer, Object... providedArgs
)throws Exception
//調用requestmapping 方法
Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);
//執行完requestmapping 方法,returnValue 就是返回的類型
setResponseStatus(webRequest);
if (returnValue == null) {
if (isRequestNotModified(webRequest) || hasResponseStatus() || mavContainer.isRequestHandled()) {
mavContainer.setRequestHandled(true);
return;
}
}
else if (StringUtils.hasText(this.responseReason)) {
mavContainer.setRequestHandled(true);
return;
}
mavContainer.setRequestHandled(false);
try {
//這裏重點,這個方法就是去匹配註冊返回值類型
this.returnValueHandlers.handleReturnValue(
returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
}
catch (Exception ex) {
if (logger.isTraceEnabled()) {
logger.trace(getReturnValueHandlingErrorMessage("Error handling return value", returnValue), ex);
}
throw ex;
}
}
//匹配返回值類型執行的方法
org.springframework.web.method.support.HandlerMethodReturnValueHandlerComposite.handleReturnValue(Object returnValue, MethodParameter returnType,
ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {
//看方法名就知道,匹配返回值類型
HandlerMethodReturnValueHandler handler = selectHandler(returnValue, returnType);
if (handler == null) {
throw new IllegalArgumentException("Unknown return value type: " + returnType.getParameterType().getName());
}
//相似於渲染
handler.handleReturnValue(returnValue, returnType, mavContainer, webRequest);
}
//Object value 若是是對象,那確定就去匹配 json的返回值類型,若是是字符串那就去匹配跳轉請求的試圖,因此在這裏提早對這個對象坐判斷,而後在封裝成原有的請求就能夠實現需求
private HandlerMethodReturnValueHandler selectHandler(Object value, MethodParameter returnType) {
//這裏用來判斷異步的,能夠研究下
boolean isAsyncValue = isAsyncReturnValue(value, returnType);
//匹配本身返回值類型
for (HandlerMethodReturnValueHandler handler : this.returnValueHandlers) {
if (isAsyncValue && !(handler instanceof AsyncHandlerMethodReturnValueHandler)) {
continue;
}
if (handler.supportsReturnType(returnType)) {
//找到對應的返回值類型,
//能夠從這裏侵入(改源碼),
// 沒有responbody註解返回
//org.springframework.web.method.annotation.ModelAttributeMethodProcessor@618b340e
//有responbody註解返回
//org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor@5cff5f93
return handler;
}
}
return null;
}
//無聊時,瞎研究,可能沒有實戰意義,特定場景會用上,又不對的麻煩指出