淘先锋技术网

首页 1 2 3 4 5 6 7

Servlet API参数解析原理

springMVC除了给我们参数位值传输一些简单注解(@PathVariable,@RequesrHeader,@MedelAttibute,@RequestParam,@MatrixVariable,@CookieValue,@RequestBody)能参数解析外。我们方法位值也允许传入一些Servlet API(WebRequest,ServetRequest,MultipartRequest,HttpSession,javax.servlet.http.PushBuilder,Principal,ImputStream,Reader,HttpMethod,Locale,TimeZone,Zoneld)作为参数,

比如我们写个RequestController.java

@Controller  //普通的Controller,它只是我们的一个控制器
public class RequestController {
    //如果是控制器我们默认方法的返回时进行页面跳转的

    @GetMapping("/goto")
    public String goToPage(HttpServletRequest request){
        request.setAttribute("msg","成功了");
        request.setAttribute("code",200);
        return "forward:/success"; //转发到    /success请求
    }
}

里面有一个/goto方法,传入了原生的request对象。request.setAttribute("msg","成功了");我们打上断点Debug一下,我们来看一下我们的request对象是用哪个参数解析器来进行处理的;我们发送localhost:8080/goto请求:一路step over来到我们WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);,Resume Program(F9)到我们执行方法的Object returnValue = invokeforRequest(webRequest,mavContainer,providedArgs);(获取我们的参数值)steo into 拿到我们所有参数(MethodParamrter[] parameters = getMethodParameters();)然后拿到我们所有参数,拿到我们的第一个参数(parameter.initParameterNameDiscovery(this.parameterNameDiscoverer);)我们接下来看resolvers supports parameter(if(!resolvers.supportsParameter(parameter)))接下来就要看我们这些解析器能不能解析我这个类型(com.huihu.boot.controller.goToPage(javax.servlrt.http.Servlet.http.HttpServletRequest))的参数,这个类型的参数能够明显看到这个参数是HttpServletRequest,我们看它能不能解析(step into):

我们这所有的参数解析器挨个遍历断点打到(for(HadlerMethodArgumentResolver resolver : this.argumentResolvers)中的if(resolver.supportParameter(parameter)))遍历的第一个

是叫RequestParamMethodArgumentRequest,放行到ServletRequestMethodArgumentResolver支持。

拿到这个解析器(HandlerMethodArrgumentResolver resolver = getArgumentResolver(parameter);)调用解析(if(resolver == null))它怎么把原生的Request传过来

HandlerMethodArgumentResolverComposite.java里有一个方法public Object resolveArgument(MethodParameter parameter,@Nullable ModelAndViewContainer mavCon...,

NativeWebRequest webRequest,...)throws Exception{

}的一个形参webRequest相当于把Requestresponse原生的这俩个东西全部组合放到了这个对象里面(NativeWebRequest webRequest)然后解析参数的时候,我们现在想要拿到原生的Request对象(Class<?> paramType = paramter.getParameterType();)它就在这判断(if(WebRequest.class.isAssignableFrom(paramType)))对象类型(paramType)是不是WebRequest,我们不是,而我们是ServletRequest就对了(if(ServletRequest.class.isAssignableFrom(paramType)))然后他给我们解析step into(他把webRequest(return resolveNativeRequest(webRequest,paramType))传进来)也就是webRequest把我们这个原生的request请求拿到(T nativeRequest = webRequest.getNativeRequest(requiredType);)然后把原生的request请求往回一返(return nativeRequest;)就行了


WebRequest,ServetRequest,MultipartRequest,HttpSession,javax.servlet.http.PushBuilder,Principal,ImputStream,Reader,HttpMethod,Locale,TimeZone,Zoneld

ServletRequestMethodArgumentResolver以上的部分参数

其他的一些参数大家自己来找相应的解析器就行了

@Override
	public boolean supportsParameter(MethodParameter parameter) {
		Class<?> paramType = parameter.getParameterType();
		return (WebRequest.class.isAssignableFrom(paramType) ||
				ServletRequest.class.isAssignableFrom(paramType) ||
				MultipartRequest.class.isAssignableFrom(paramType) ||
				HttpSession.class.isAssignableFrom(paramType) ||
				(pushBuilder != null && pushBuilder.isAssignableFrom(paramType)) ||
				(Principal.class.isAssignableFrom(paramType) && !parameter.hasParameterAnnotations()) ||
				InputStream.class.isAssignableFrom(paramType) ||
				Reader.class.isAssignableFrom(paramType) ||
				HttpMethod.class == paramType ||
				Locale.class == paramType ||
				TimeZone.class == paramType ||
				ZoneId.class == paramType);
	}