运行流程
- 用户发送请求至前置控制器DispatcherServlet
- DispatcherServlet收到请求调用HandlerMapping处理器映射器。
- 处理器映射器根据请求url找到具体的处理器,生成处理器对象及处理器拦截器(如果有则生成)一并返回给DispatcherServlet。
- DispatcherServlet通过HandlerAdapter处理器适配器调用处理器
- 执行处理器/后端控制器Controller
- Controller执行完成返回ModelAndView
- HandlerAdapter将controller执行结果ModelAndView返回给DispatcherServlet
- DispatcherServlet将ModelAndView传给视图解析器ViewReslover
- ViewReslover解析后返回具体View
- DispatcherServlet对View进行渲染视图(即将模型数据填充至视图中)。
- DispatcherServlet响应用户。
从上面可以看出,DispatcherServlet有接收请求,响应结果,转发等作用。有了DispatcherServlet之后,可以减少组件之间的耦合度。
九大组件
HandlerMapping
处理器映射器:根据请求url找到具体的处理器,生成处理器对象及处理器拦截器(如果有则生成)一并返回给DispatcherServlet
HandlerAdapter
适配器。因为SpringMVC中的Handler可以是任意的形式,但是Servlet需要的处理方法的结构却是固定的,都是以request和response为参数的方法。HandlerAdapter的作用就是让固定的Servlet处理方法调用Handler(Controller)来进行处理。
有篇文章总结的很好:Handler是用来干活的工具;HandlerMapping用于根据需要干的活找到相应的工具;HandlerAdapter是使用工具干活的人。
HandlerExceptionResolver
异常处理:自定义异常处理类继承此类或其子类,实现resolveException方法。如下:
@Component
public class GlobalExceptionResolver implements HandlerExceptionResolver {
...
/**
* 针对请求处理异常
*/
@Override
public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler,
Exception ex) {
boolean isHttpApi = isHttpApi(handler);
HandleResult result = handleException(ex);
if (isReturnReponseBody(handler) || isHttpApi) {
if(isHttpApi){
result = apiHandleException(ex);
}
ModelAndView modelAndView = new ModelAndView();
//处理异常
response.setContentType("application/json;charset=UTF-8");
byte[] bytes = JSON.toJSONBytes(Result.fail(result.getCode(), result.getMessage()), SerializerFeature.DisableCircularReferenceDetect, SerializerFeature.WriteMapNullValue);
try {
response.getOutputStream().write(bytes);
response.getOutputStream().flush();
} catch (IOException e) {
log.error("打印错误信息出错!", e);
}
modelAndView.clear();
return modelAndView;
}else {
Map<String, String> model = Maps.newHashMap();
model.put("code", result.getCode());
model.put("message", result.getMessage());
return new ModelAndView("500", model);
}
}
...
}
ViewResolver
视图解析器:当Controller将请求处理结果放入到ModelAndView中以后,DispatcherServlet会根据ModelAndView选择合适的视图进行渲染。ViewResolver接口有众多实现类,根据viewName创建合适类型的View实现。配置如下:
<bean class="org.Springframework.web.servlet.view.InternalResourceViewResolve">
<property name="prefix" value="/WEB-INF/views/" />
<property name="suffix" value=".jsp" />
</bean>
RequestToViewNameTranslator
当Controller处理器方法没有返回一个View对象或逻辑视图名称,并且在该方法中没有直接往response的输出流里面写数据的时候,Spring就会采用约定好的方式提供一个逻辑视图名称。可通过实现接口org.Springframework.web.servlet.RequestToViewNameTranslator接口的getViewName方法来实现。
LocaleResolver
国际化配置
- Spring的国际化配置三种方式
- 基于URL参数的配置:通过URL参数来控制国际化
- 页面:
<a href="myTest.jsp?locale=zh_CN">简体中文</a>
- 配置文件:
<bean id="localeResolver" class="org.Springframework.web.servlet.i18n.AcceptHeaderLocaleResolver"/>
- 页面:
- 基于session的配置:通过检验用户会话中预置的属性来解析区域,最常用的是根据用户本次会话过程中的语言设定决定语言种类,如果该会话不存在,它会根据accept-language HTTP头部确定默认区域。配置
<bean id="localeResolver" class="org.Springframework.web.servlet.i18n.SessionLocaleResolver"/>
- 基于Cookie的国际化配置:用于通过浏览器的cookie设置取得Locale对象,这种策略在应用程序不支持会话或者状态必须保存在客户端时有用。
<bean id="localeResolver" class="org.Springframework.web.servlet.i18n.CookieLocaleResolver"/>
- 基于URL参数的配置:通过URL参数来控制国际化
ThemeResolver
解析主题。一个主题就是一组静态资源(比如样式表、图片等),它们可以影响应用程序的视觉效果。
- SpringMVC中跟主题相关的类
- ThemeResolver:主题解析器
- ThemeSource:主题资源
- Theme:主题接口
- ThemeChangeInterceptor:根据用户请求来改变主题(需要在handlerMapping中配置拦截器
<property name="interceptors"><list><ref local="themeChangeInterceptor" /></list></property>
)
- ThemeResolver子类
- AbstractThemeResolver:SessionThemeResolver和FixedThemeResolver继承的抽象类
- SessionThemeResolver:用户的主题保存在HTTP session中
- CookieThemeResolver:用于实现用户所选的主题,以cookie的形式存放在客户端的机器上
- FixedThemeResolver:用于选择一个固定的主题
MultipartResolver
MultipartResolver 用于处理文件上传,当收到请求时 DispatcherServlet 的 checkMultipart() 方法会调用 MultipartResolver 的 isMultipart() 方法判断请求中是否包含文件。如果请求数据中包含文件,则调用 MultipartResolver 的 resolveMultipart() 方法对请求的数据进行解析,然后将文件数据解析成 MultipartFile 并封装在 MultipartHttpServletRequest (继承了 HttpServletRequest) 对象中,最后传递给 Controller.
- MultipartResolver子类
- CommonsMultipartResolver:使用 commons Fileupload来处理 multipart请求,所以在使用时,必须要引入相应的jar包。而像SpringBoot是不支持CommonsMultipartResolver
- StandardServletMultipartResolver:基于Servlet3.0来处理multipart请求的,所以不需要引用其他jar包,从Tomcat7.0.x的版本开始就支持 Servlet 3.0了