spingmvc 的requestmappling方法如何动态修改返回值类型
业务场景:
客户端请求服务端(两个公司的不同系统之间的请求,类似于http接口),请求中参数异常就直接给客户端提示,请求正常,服务端控制跳转到自己系统的页面,执行剩余逻辑。
springmvc 的requestmapping 方法,分两种,一种是带有responsebody注解的(ajax操作),一种是没有(做请求跳转)
springmvc 提供了一个 标签(
<mvc:annotation-driven><mvc:return-value-handlers><bean/></mvc:return-value-handlers></mvc:annotation-driven>
),用来注册返回值类型的,我们可以自己定义返回值类型(例如:定义User),
接下来可以了解下生命周期,启动的时候把把自定义的方法返回值类型注册,然后放到一个list里面,
requestmapping方法被调用的时候,先执行方法体,然后会根据方法的实际返回类型,到list中去找,
如果这个返回值类型没有,并且是responsebody方法则转换成json,返回页面,如果不是responsebody则抛出返回类型不支持的异常,要实现我们的需求,就要从这里侵入源码,
前面定义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;
}
//无聊时,瞎研究,可能没有实战意义,特定场景会用上,又不对的麻烦指出