HiddenHttpMethodFilter源码分析:
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)throws ServletException, IOException {
//获取表单上_method带来的值(delete/put)
String paramValue = request.getParameter(this.methodParam);
//判断如果表单是一个post而且_method有值
if ("POST".equals(request.getMethod()) && StringUtils.hasLength(paramValue)) {
//转为PUT、DELETE
String method = paramValue.toUpperCase(Locale.ENGLISH);
//重写了request.getMethod()
HttpServletRequest wrapper = new HttpMethodRequestWrapper(request, method);
//wrapper.getMethod()==PUT
filterChain.doFilter(wrapper, response);
}
else {
//直接放行
filterChain.doFilter(request, response);
}
}
* 关系:
* Map,Model,ModelMap 最终都是BindingAwareModelMap在工作
* 相当于给BindingAwareModelMap中保存的东西都会被放在请求域中
*
* Map(interface(jdk)) Model(interface(spring))
* || //
* || //
* \/ //
* ModelMap(class) //
* \\ //
* \\ //
* ExtendedModelMap
* ||
* \/
* BindingAwareModelMap
DispatcherServlet执行过程源码分析:
前端控制器DispatcherServlet的架构:
doDispatch()详细细节:
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
HttpServletRequest processedRequest = request;
HandlerExecutionChain mappedHandler = null;
boolean multipartRequestParsed = false;
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
try {
ModelAndView mv = null;
Exception dispatchException = null;
try {
// 1、检查是否文件上传请求
processedRequest = checkMultipart(request);
multipartRequestParsed = processedRequest != request;
// Determine handler for the current request.
// 2、根据当前的请求地址找到哪个类能来处理
mappedHandler = getHandler(processedRequest);
// 3、如果没有找到哪个处理器(控制器)能处理这个请求就404,或者抛异常
if (mappedHandler == null || mappedHandler.getHandler() == null) {
noHandlerFound(processedRequest, response); //抛异常
return;
}
// Determine handler adapter for the current request.
// 4、拿到能执行这个类的所有方法的适配器
// (反射工具AnnotationMethodHandlerAdapter)
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
// Process last-modified header, if supported by the handler.
String method = request.getMethod();
boolean isGet = "GET".equals(method);
if (isGet || "HEAD".equals(method)) {
long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
if (logger.isDebugEnabled()) {
String requestUri = urlPathHelper.getRequestUri(request);
logger.debug("Last-Modified value for [" + requestUri + "] is: " + lastModified);
}
if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
return;
}
}
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
try {
// Actually invoke the handler.处理(控制)器的方法被调用
// 控制器(Controller),处理器(Handler)
// 5、适配器来执行目标方法,将目标方法执行完成后的返回值作为视图名
// 设置保存到ModelAndView中
// 目标方法无论怎么写,最终适配器执行完成以后都会将执行后的信息封装成ModelAndView
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
}
finally {
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
}
// 如果没有视图名设置一个默认的视图名
applyDefaultViewName(request, mv);
mappedHandler.applyPostHandle(processedRequest, response, mv);
}
catch (Exception ex) {
dispatchException = ex;
}
// 转发到目标页面
// 6、根据方法最终执行完成后封装的ModelAndView;转发到对应页面,而且ModelAndView中的数据可以从请求域中获取
// processedRequest:封住后的请求对象
// response:相应对象
// mappedHandler:处理器
// mv:ModelAndView
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
}
catch (Exception ex) {
triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
}
catch (Error err) {
triggerAfterCompletionWithError(processedRequest, response, mappedHandler, err);
}
finally {
if (asyncManager.isConcurrentHandlingStarted()) {
// Instead of postHandle and afterCompletion
mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
return;
}
// Clean up any resources used by a multipart request.
if (multipartRequestParsed) {
cleanupMultipart(processedRequest);
}
}
}
总结:
1)、所有请求过来DispatcherServlet收到请求
2)、调用doDispatch()方法进行处理
1)、getHandler(): 根据当前请求地址找到能处理这个请求的目标处理器类(处理器)
根据当前请求在HandlerMapping中找到这个请求的映射信息,获取到目标处理器类
2)、getHandlerAdapter(): 根据当前处理器类获取到能执行这个处理器方法的适配器
根据当前处理器类,找到当前类的HandlerAdapter(适配器)
3)、使用刚才获取到的适配器(AnnotationMethodHandlerAdapter)执行目标方法
4)、目标方法执行后会返回一个ModelAndView对象
5)、根据ModelAndView的信息转发到具体的页面,并可以在请求域中取出ModelAndView模型中的数据