SpringMVC总结
一、spring MVC的工作内容
将URL映射到Java类或者方法
封装用户提交的数据
处理请求,调用相关的业务层,并封装响应的数据
将要响应的数据进行渲染
二、SpringMVC的优点和特点
与spring无缝集成(IOC、AOP)
约定优于配置
性能比Struts2好
设计中的角色或者职责划分明确
Restful
JUnit测试
异常处理
本地化、国际化
数据验证、类型转化等
拦截器
使用的人和公司比较多
简单、便捷、易学
springMVC处理请求的流程
springMVC基于请求驱动,所有设计都围绕一个中央servlet展开,它负责将请求分发给各个处理器(页面控制器、Controller),下图展示了springMVC处理请求的流程,图中的Front Controller(前端控制器)正是springMVC的DispatcherServlet;Controller称为处理器或应用控制器,由它来处理具体的请求,返回数据模型;View Template为具体视图,用于展示数据,响应请求.
具体处理请求步骤:
用户发送请求,被前端拦截器拦截,前端控制器根据请求的信息选择相应的页面控制器,并将请求委托给此页面控制器来处理。
页面控制器接收到请求后,首先收集并绑定请求参数到一个命令对象(表单对象)中,并进行验证转换等操作,然后将命令对象委托给业务对象处理,最后返回一个modelAndView对象。
前端控制器根据返回的视图名,选择相应的视图进行渲染,并将模型数据传入到视图中以便展示。
前端控制器将响应的结果返回给用户。
至此,整个请求流程结束,当然还有一些细节的问题,需要我们了解,比如:前端控制器如何选择页面控制器,前端控制器如果根据页面控制器的返回选择相应的视图进行渲染,等等。带着这些问题,我们将springMVC处理请求的流程图转换为架构图讨论一下。
先上一段代码:
/**
* Process the actual dispatching to the handler.
* <p>The handler will be obtained by applying the servlet's HandlerMappings in order.
* The HandlerAdapter will be obtained by querying the servlet's installed HandlerAdapters
* to find the first that supports the handler class.
* <p>All HTTP methods are handled by this method. It's up to HandlerAdapters or handlers
* themselves to decide which methods are acceptable.
* @param request current HTTP request
* @param response current HTTP response
* @throws Exception in case of any kind of processing failure
*/
/**
* 处理实际的请求分发到处理器.
* 要获得具体的Handler, 需要先使用servlet的HandlerMappings.
* 要获得HandlerAdpter, 需要先在servlet加载的各HandlerAdapter中查找, 找到第一个支持此Handler的Adapter.
* 所有的HTTP方法都通过这个方法来处理的. 这个方法中, 由HandlerAdapter或Handler自己来决定哪些方法可以被调用.
* @param request current HTTP request
* @param response current HTTP response
* @throws Exception in case of any kind of processing failure
*/
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 {
// 检查请求是否为multipart(文件上传)
processedRequest = checkMultipart(request);
multipartRequestParsed = (processedRequest != request);
// Determine handler for the current request.
// 图中2,3两步, 通过HandlerMappsing映射, 获取处理请求的Handler
mappedHandler = getHandler(processedRequest);
if (mappedHandler == null || mappedHandler.getHandler() == null) {
noHandlerFound(processedRequest, response);
return;
}
// Determine handler adapter for the current request.
// 图中步骤4, 将Handler包装成Adapter
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()) {
logger.debug("Last-Modified value for [" + getRequestUri(request) + "] is: " + lastModified);
}
if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
return;
}
}
// 前置拦截器
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
// Actually invoke the handler.
// 图中5,6,7步骤, 由HandlerAdapter调用真正的处理器处理请求, 并返回ModelAndView对象
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
applyDefaultViewName(processedRequest, mv);
// 后置拦截器
mappedHandler.applyPostHandle(processedRequest, response, mv);
}
catch (Exception ex) {
dispatchException = ex;
}
// 图中8,9,10,11步骤, 处理Handler的处理结果, 这个结果可能是一个ModelAndView对象, 还可能是一个异常
// 第8,9步, 由viewResolver解析视图
// viewResolver.resolveViewName(viewName, locale)
// 第10, 11步, 传入Model, 并渲染视图
// view.render(mv.getModelInternal(), request, response);
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
if (mappedHandler != null) {
// 完成时拦截器
mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
}
}
else {
// Clean up any resources used by a multipart request.
if (multipartRequestParsed) {
cleanupMultipart(processedRequest);
}
}
}
}
步骤①, DispatcherServlet作为前端控制器, 统一的请求接收点, 控制全局的请求流程. 接收到用户请求, 自己不做处理, 而是将请求委托给其他的处理器进行处理.
步骤②③, DispatcherServlet通过HandlerMapping(处理映射器), 将请求映射为一个HandlerExecutionChain对象, 其中包括了页面控制器和对其配置的拦截器.
步骤④, DispatcherServlet通过获得的Handler(处理器, 页面控制器, Controller), 查找一个合适的HandlerAdapter(处理器适配器), 通过这个HandlerAdapter调用Handler实际处理请求的方法.
步骤⑤, 提取请求中的模型数据, 调用Handler实际处理请求的方法. 在调用方法时, 填充参数过程中, spring会根据配置做一些工作, 如: 数据转换, 数据格式化, 数据验证等.
步骤⑥⑦, Handler执行完成后, 将返回一个ModelAndView对象给DispatherServlet. ModelAndView对象中包含逻辑视图名或逻辑视图名和模型.
步骤⑧, 根据ModelAndView对象选择一个合适的ViewResolver(视图解析器).
步骤⑨, ViewResolver将ModelAndView中的逻辑视图名解释成View对象. ViewResolver也是接口, 同样采用了策略模式, 这样就很容易切换其他的视图类型.
步骤⑩⑪, 渲染视图时, 将Model数据传入视图中, 这里的Model数据是一个Map, 容易与各种视图类型相结合.
步骤⑫, 最后, 由DispatcherServlet将最终的响应结果返回给用户.
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。