springMvc概念
springMvc请求流程
springMvc组件详解
springMvc常用注解
springMvc拦截器
springMvc异常处理
一、springMvc概念
springMvc是基于servlet的web框架,其简化了web程序的开发
二、springMvc请求流程
在阅读时不妨可以带着几个问题阅读:
1.我们通常在浏览器输入的接口怎么由DispatcherServlet调到具体的Handler的(就是我们自己开发的Controller类)
2.编写Controller的形式有哪几种?
springMvc重要组件:
之所以先说这几个组件,是因为只要了解了这几个组件后你便可以对springMvc请求流程有个大致的清晰认识了。(Handler就是我们写的Controller)
HandlerMapping
HandlerAdapter
ViewResolver
View
HandlerExceptionResolver
HandlerInterceptor
DisPatcher作为一个主流程入口,看一下DispatcherServlet结构
DispatcherServlet为了简洁,省去了很多方法跟属性
public class DispatcherServlet extends FrameworkServlet {
//定义了默认策略名字
private static final String DEFAULT_STRATEGIES_PATH = "DispatcherServlet.properties";
private static final Properties defaultStrategies;
static {
//从Properties文件中加载默认策略实现
ClassPathResource resource = new ClassPathResource(DEFAULT_STRATEGIES_PATH, DispatcherServlet.class);
defaultStrategies = PropertiesLoaderUtils.loadProperties(resource);
}
private List<HandlerMapping> handlerMappings;
private List<HandlerAdapter> handlerAdapters;
private List<HandlerExceptionResolver> handlerExceptionResolvers;
private List<ViewResolver> viewResolvers;
//初始化策略
protected void initStrategies(ApplicationContext context) {
initMultipartResolver(context);
initLocaleResolver(context);
initThemeResolver(context);
initHandlerMappings(context);
initHandlerAdapters(context);
initHandlerExceptionResolvers(context);
initRequestToViewNameTranslator(context);
initViewResolvers(context);
initFlashMapManager(context);
}
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
try {
ModelAndView mv = null;
Exception dispatchException = null;
try {
//检查是否文件上传
processedRequest = checkMultipart(request);
multipartRequestParsed = (processedRequest != request);
//通过HandlerMapping 获取Handler(返回的是HandlerExecutionChain)
/**public class HandlerExecutionChain {
//HandlerExecutionChain封装了Handler(就是我们编写的Controller)跟interceptors
private final Object handler;
private HandlerInterceptor[] interceptors;
**/
HandlerExecutionChain mappedHandler = getHandler(processedRequest);
//获取的Handler是Object类型,需要通过HandlerAdapter获取Handler真实类型
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
// Process last-modified header, if supported by the handler.
//调用Handlerinterceptor PreHandle(前置拦截器),返回false则停止执行
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
// 调用真实handler逻辑并返回ModelAndView
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
//将ModelAndView返回值DispatcherServlet后
applyDefaultViewName(processedRequest, mv);
//调用Handlerinterceptor PostHandle(后置拦截器)
mappedHandler.applyPostHandle(processedRequest, response, mv);
}
catch (Exception ex) {
dispatchException = ex;
}
catch (Throwable err) {
// As of 4.3, we're processing Errors thrown from handler methods as well,
// making them available for @ExceptionHandler methods and other scenarios.
dispatchException = new NestedServletException("Handler dispatch failed", err);
}
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
}
catch (Exception ex) {
triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
}
catch (Throwable err) {
triggerAfterCompletion(processedRequest, response, mappedHandler,
new NestedServletException("Handler processing failed", err));
}
finally {
if (asyncManager.isConcurrentHandlingStarted()) {
// Instead of postHandle and afterCompletion
if (mappedHandler != null) {
//调用Handlerinterceptor afterCompletion
mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
}
}
else {
// Clean up any resources used by a multipart request.
if (multipartRequestParsed) {
cleanupMultipart(processedRequest);
}
}
}
}}
通过上面的DispatcherServlet大概分析可以得知几个组件的作用:
HandlerMapping:
根据请求url地址得到具体Handler(Controller)
HandlerAdapter
根据Handler得到Handler适配器
ViewResolver
试图仓库:根据ViewName得到View
View
具体解析视图
HandlerExceptionResolver
异常捕捕捉器
HandlerInterceptor
拦截器
三、springMvc处理流程图解:(引用他人流程图)
简略图:
四、各组件详解:
1.HandlerMapping
HandlerMapping方法:
HandlerMapping子类:
从上图看一看出常用的Mapping有三类:SimpleUrlHandlerMapping、BeanNameUrlHandlerMapping、RequestMappingHandlerMapping。
RequestMappingHandlerMapping就是我们最长使用的方式基于注解@RequestMapping方式的url映射。
SimpleUrlHandlerMapping 基于手动配置 url 与control 映射
<bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="mappings">
<props>
<prop key="/hello">helloController</prop>
</props>
</property>
</bean>
<bean id="helloController" class="com.ckd.controller.HelloController"/>
-----------------------------------------------------------------------------------------------------------------------
import org.springframework.web.servlet.mvc.Controller;
public class HelloController implements Controller {
@Override
public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
ModelAndView mv = new ModelAndView("index");
mv.addObject("hello","world");
return mv;
}
}
BeanNameUrlHandlerMapping是配置IOC bean时id以"/"开头与Controller的映射
<bean id="/beanname" class="com.ckd.controller.BeanNameController"/>
//需要继承HttpRequestHandler 此时可以把/beanname映射到handleRequest方法上
public class BeanNameControl implements HttpRequestHandler {
@Override
public void handleRequest(HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException {
request.getRequestDispatcher("/WEB-INF/page/userView.jsp").forward(request, response);
}
}
通过DisPatcherServlet.getHandler()获得Handler的类型时Object,此时无法调用,因此需要HandlerAdapter根据Handler获取具体的适配器
2.HandlerAdapter
springmvc采用适配器的模式适配调用Handler,根据handler不同调用不同的适配器,Handler与HandlerAdapter对用关系如下:
Handler类别 | 对应适配器 | 描述 |
---|---|---|
Controller | SimpleControllerHandlerAdapter | 标准控制器,返回ModelAndView |
HttpRequestHandler | HttpRequestHandlerAdapter | 业务自行处理 请求,不需要通过modelAndView 转到视图 |
Servlet | SimpleServletHandlerAdapter | 基于标准的servlet 处理 |
HandlerMethod | RequestMappingHandlerAdapter | 基于@requestMapping对应方法处理 |
基于Servlet演示
<bean class="org.springframework.web.servlet.handler.SimpleServletHandlerAdapter"/>
<bean id="/helloservlet" class="com.ckd.controller.HelloServlet"/>
----------------------------------------------------------------------------------------------------------------------------
public class HelloServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.getWriter().println("hello Servlet");
}
}
HelloServlet注册IOC容器中时,会由BeanNameUrlHandlerMapping找到对应的Handler,由SimpleServletHandlerAdapter找到对应的适配器,调用业务逻辑Controller,并返回ModelAndView。
3.ViewResolver View
DispatcherServlet#getHandlerAdapter().handle()后返回ModelAndView,
调用resolveViewName() 去viewResolvers试图列表中查找对应的View并返回View.交由View解析生成html并返回
4.HandlerExceptionResolver
该组件用于指示 当出现异常时 mvc 该如何处理。 dispatcherServlet 会调用org.springframework.web.servlet.DispatcherServlet#processHandlerException() 方法,遍历 handlerExceptionResolvers 处理异常,处理完成之后返回errorView 跳转到异常视图。
- [ ] 演示自定义异常捕捉
<bean class="com.ckd.controller.ExceptionHandlerSample"/>
public class ExceptionHandlerSample implements HandlerExceptionResolver {
@Override
public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
return new ModelAndView("error");
}
}
5.HandlerInterceptor
- [ ] 演示HandlerInterceptor
<mvc:interceptors>
<mvc:interceptor>
<!-- 拦截所有的请求,这个必须写在前面-->
<mvc:mapping path="/**" />
<bean class="com.ckd.controller.SimpleHandlerInterceptor" />
</mvc:interceptor>
</mvc:interceptors>
-----------------------------------------------------------------------------------------------------------------------------------------
public class SimpleHandlerInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("preHandle");
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("postHandle");
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("afterCompletion");
}
}
其实现机制是基于 HandlerExecutionChain 分别在 doDispatch 方法中执行以下方法:
- preHandle :业务处理前执行
- postHandle:业务处理后(异常则不执行)
- afterCompletion:视图处理后
具体逻辑源码参见:org.springframework.web.servlet.DispatcherServlet#doDispatch 方法。