2.1 Spring MVC 简介
Spring MVC 是一种将业务、视图、数据分离的设计模式。它不仅出现在 Java 后端开发中,在前端开发中也经常使用这种设计模式。Spring MVC 提供了高度可配置的 Web 框架和多种视图解决方案,并且提供了基于 Servlet 的接口,可以灵活地处理请求。
2.1.1 Spring MVC 的工作流程
Spring MVC 框架主要由核心 Servlet(DispatcherServlet)、处理器映射(Handler-Mapping)、控制器(Controller)、视图解析器(ViewResolver)、模型(Model)及视图(View)等几部分组成,其主要的工作流程如图 2.1 所示。
图 2.1 Spring MVC 的工作流程图
从图 2.1 中可以看到,Spring MVC 框架的主要工作流程可以分为以下几步:
(1)在浏览器中输入 URL 地址后,所有的请求都被 DispatcherServlet 拦截。
(2)DispatcherServlet 通过 HandlerMapping 解析 URL 地址,找到匹配的能处理该请求的 Controller,然后请求被 Controller 处理。
(3)Controller 通过调用具体的业务逻辑,返回 ModelAndView。
(4)DispatcherServlet 通过 ViewResolver(视图解析器),组装 Model 数据与对应的视图,如某个 JSP 页面等。
(5)将视图结果展现在浏览器页面上。
Spring MVC 框架提供了很多重要的接口,用于完成一个 HTTP 请求的处理,主要的接口如表 2.1 所示。
表 2.1 Spring MVC 框架的主要接口
2.1.2 DispatcherServlet 类
DispatcherServlet 类是 Servlet 的一种实现,置于 Controller 前,对所有的请求提供统一的处理逻辑。DispatcherServlet 类需要提前声明,可以采用 Java 配置或 web.xml 方式进行声明。它通过请求映射、视图解析及统一异常处理等 Spring 配置发现真正的请求处理组件,从而完成对请求的处理。
DispatcherServlet 类处理请求的步骤如下:
(1)DispatcherServlet 类将 WebApplicationContext 绑定到请求中,WebApplication-Context 会持有 Controller、ViewResolver、HandlerMapping、Service 及 Repository 等。
(2)HandlerMapping 通过匹配规则授权给一个 Handler 来处理具体的逻辑,此处的 Handler 是一个处理链,整个处理过程会通过拦截器(Interceptor)和控制器(Controller)等来处理。
(3)返回 Model 数据并渲染视图。
DispatcherServlet 类通过 web.xml 方式可以声明,代码如下:
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http:// xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd" version="4.0"> <context-param> <param-name>contextConfigLocation</param-name> <param-value>/WEB-INF/dispatcher-servlet.xml</param-value> </context-param> <listener> <listener-class>org.springframework.web.context.Context LoaderListener</listener-class> </listener> <servlet> <servlet-name>dispatcher</servlet-name> <servlet-class>org.springframework.web.servlet.Dispatcher Servlet</servlet-class> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>dispatcher</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> </web-app>
DispatcherServlet 类也可以通过实现 WebApplicationInitializer 接口来声明。以下是摘自 Spring 官网的一段示例代码:
public class MyWebApplicationInitializer implements WebApplication Initializer { @Override public void onStartup(ServletContext servletCxt) { //加载 Spring Web 应用上下文 AnnotationConfigWebApplicationContext ac = new Annotation ConfigWebApplicationContext(); ac.register(AppConfig.class); ac.refresh(); //创建 DispatcherServlet DispatcherServlet servlet = new DispatcherServlet(ac); //注册 DispatcherServlet ServletRegistration.Dynamic registration = servletCxt. addServlet("app", servlet); registration.setLoadOnStartup(1); registration.addMapping("/app/*"); } }
2.1.3 HandlerInterceptor 拦截器
为了实现一些特殊功能,如在请求处理之前进行用户校验或日志记录等,Spring MVC 提供了灵活的处理方式,即定义拦截器。自定义拦截器实现 HandlerInterceptor 接口,然后实现对应的抽象方法,这样可以做一些预处理或请求之后的处理。Handler-Interceptor 接口提供了 3 个方法:
- preHandle(HttpServletRequest request, HttpServletResponse response, Object handler):默认返回 true。该方法是在处理器执行之前调用,通过返回 true 或 false,判断是否继续执行后面的处理链。返回 true 表示继续向后执行,返回 false 表示中断后续处理。
- postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView):该方法是在处理器处理请求之后及解析视图之前调用,可以通过该方法对请求后的模型和视图进行修改。
- afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex):该方法是在处理器处理完请求之后,即视图渲染结束后执行。
下面展示一个简单的 Interceptor 登录拦截器的例子:
//自定义拦截器 public class LogInterceptor implements HandlerInterceptor { //处理器处理请求之后且视图渲染结束执行 @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { System.out.println("afterCompletion 方法是在处理器处理完请求之 后,即视图渲染结束后执行"); } //处理器处理请求之后,即解析视图之前调用 @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { System.out.println("postHandle 方法是在处理器处理请求之后解析视图之前调用"); } //处理器处理请求之前执行 @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { System.out.println("preHandle 方法是在处理器执行之前调用"); return true; } }
如果想让 Interceptor 生效,还需要声明一下,代码如下:
<mvc:interceptors> <!--配置一个全局拦截器,拦截所有请求 --> <bean class="com.cn.springmvc.LogInterceptor" /> </mvc:interceptors>
注意:postHandle() 方法很少与 @ResponseBody 和 ResponseEntity 配合使用,因为 @ResponseBody 和 ResponseEntity 已经提交了响应,无法再修改。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论