0%

javaSpring学习(五)——SpringMVC

Spring MVC

MVC 是模型(Model)、视图(View)、控制器(Controller)的简写,其核心思想是通过将业务逻辑、数据、显示分离来组织代码。

img

网上有很多人说 MVC 不是设计模式,只是软件设计规范,我个人更倾向于 MVC 同样是众多设计模式中的一种。**java-design-patterns** 项目中就有关于 MVC 的相关介绍。

img

想要真正理解 Spring MVC,我们先来看看 Model 1 和 Model 2 这两个没有 Spring MVC 的时代。

Model 1 时代

很多学 Java 后端比较晚的朋友可能并没有接触过 Model 1 时代下的 JavaWeb 应用开发。在 Model1 模式下,整个 Web 应用几乎全部用 JSP 页面组成,只用少量的 JavaBean 来处理数据库连接、访问等操作。

这个模式下 JSP 即是控制层(Controller)又是表现层(View)。显而易见,这种模式存在很多问题。比如控制逻辑和表现逻辑混杂在一起,导致代码重用率极低;再比如前端和后端相互依赖,难以进行测试维护并且开发效率极低。

mvc-mode1

Model 2 时代

学过 Servlet 并做过相关 Demo 的朋友应该了解“Java Bean(Model)+ JSP(View)+Servlet(Controller) ”这种开发模式,这就是早期的 JavaWeb MVC 开发模式。

  • Model:系统涉及的数据,也就是 dao 和 bean。
  • View:展示模型中的数据,只是用来展示。
  • Controller:处理用户请求都发送给 ,返回数据给 JSP 并展示给用户。

img

Model2 模式下还存在很多问题,Model2 的抽象和封装程度还远远不够,使用 Model2 进行开发时不可避免地会重复造轮子,这就大大降低了程序的可维护性和复用性。

于是,很多 JavaWeb 开发相关的 MVC 框架应运而生比如 Struts2,但是 Struts2 比较笨重。

Spring MVC 时代

随着 Spring 轻量级开发框架的流行,Spring 生态圈出现了 Spring MVC 框架, Spring MVC 是当前最优秀的 MVC 框架。相比于 Struts2 , Spring MVC 使用更加简单和方便,开发效率更高,并且 Spring MVC 运行速度更快。

MVC 是一种设计模式,Spring MVC 是一款很优秀的 MVC 框架。Spring MVC 可以帮助我们进行更简洁的 Web 层的开发,并且它天生与 Spring 框架集成。Spring MVC 下我们一般把后端项目分为 Service 层(处理业务)、Dao 层(数据库操作)、Entity 层(实体类)、Controller 层(控制层,返回数据给前台页面)。

SpringMVC 工作原理

Spring MVC 原理如下图所示:

SpringMVC 工作原理的图解我没有自己画,直接图省事在网上找了一个非常清晰直观的,原出处不明。

img

流程说明(重要):

  1. 客户端(浏览器)发送请求,直接请求到 DispatcherServlet
  2. DispatcherServlet 根据请求信息调用 HandlerMapping处理器映射器,解析请求对应的 Handler
  3. 解析到对应的 Handler(也就是我们平常说的 Controller 控制器)
  4. 处理器映射器找到具体的处理器(可以根据xml配置、注解进行查找),生成处理器对象及处理器拦截器(如果有则生成)一并返回给DispatcherServlet
  5. DispatcherServlet调用HandlerAdapter处理器适配器。
  6. HandlerAdapter 会根据 Handler来调用真正的处理器开处理请求,并处理相应的业务逻辑。
  7. 处理器处理完业务后,会返回一个 ModelAndView 对象,Model 是返回的数据对象,View 是个逻辑上的 View
  8. HandlerAdaptercontroller执行结果ModelAndView返回给DispatcherServlet
  9. DispatcherServletModelAndView传给ViewReslover视图解析器。
  10. ViewResolver 会根据逻辑 View 查找实际的 View
  11. DispaterServlet 把返回的 Model 传给 View(视图渲染)。
  12. View 返回给请求者(浏览器)

请求 —> DispatcherServlet(前端控制器)—> 调用HandlerMapping(处理器映射器)—> DispatcherServlet调用 HandlerAdapter(处理器适配器)—> 适配调用具体的Controller —> 返回ModelAndView —> 传给ViewReslover视图解析器 —> 解析后返回具体View —> 根据View进行渲染视图响应用户.

Spring与SpringMVC父子容器的区别和联系

  1. Spring 与SpringMVC 两个都是容器,存在父子关系(包含和被包含的关系)
  2. Spring容器中存放着mapper代理对象,service对象,SpringMVC存放着Controller对象。子容器SpringMVC中可以访问父容器中的对象。但父容器Spring不能访问子容器SpringMVC的对象(存在领域作用域的原因,子容器可以访问父容器中的成员,而子容器的成员则只能被自己使用)。如:Service对象可以在Controller层中注入,反之则不行。
  3. Spring容器导入的properties配置文件,只能在Spring容器中用而在SpringMVC容器中不能读取到。 需要在SpringMVC 的配置文件中重新进行导入properties文件,并且同样在父容器Spring中不能被使用,导入后使用@Value(“${key}”)在java类中进行读取。

SpringMVC拦截器

常见应用场景

  1. 日志记录:记录请求信息的日志,以便进行信息监控、信息统计、计算PV(Page View)等
  2. 权限检查:如登录检测,进入处理器检测检测是否登录,如果没有直接返回到登录页面
  3. 性能监控:有时候系统在某段时间莫名其妙的慢,可以通过拦截器在进入处理器之前记录开始时间,在处理完后记录结束时间,从而得到该请求的处理时间(如果有反向代理,如apache可以自动记录)
  4. 通用行为:读取cookie得到用户信息并将用户对象放入请求,从而方便后续流程使用,还有如提取Locale、Theme信息等,只要是多个处理器都需要的即可使用拦截器实现。
  5. OpenSessionInView:如Hibernate,在进入处理器打开Session,在完成后关闭Session。

拦截器接口

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public interface HandlerInterceptor {  
/**
* 预处理回调方法,实现处理器的预处理(如登录检查),第三个参数为响应的处理器(如我们上一章的Controller实现)
* 返回值:true表示继续流程(如调用下一个拦截器或处理器);
* false表示流程中断(如登录检查失败),不会继续调用其他的拦截器或处理器,此时我们需要通过response来产生响应
*/
boolean preHandle(
HttpServletRequest request, HttpServletResponse response,
Object handler)
throws Exception;
/**
* 后处理回调方法,实现处理器的后处理(但在渲染视图之前),此时我们可以通过modelAndView(模型和视图对象)对模型数据进行处理或对视图进行处理,modelAndView也可能为null。
*/
void postHandle(
HttpServletRequest request, HttpServletResponse response,
Object handler, ModelAndView modelAndView)
throws Exception;
/**
* 整个请求处理完毕回调方法,即在视图渲染完毕时回调,如性能监控中我们可以在此记录结束时间并输出消耗时间 ,
* 还可以进行一些资源清理,类似于try-catch-finally中的finally,但仅调用处理器执行链中preHandle返回true的拦截器的afterCompletion。
*/
void afterCompletion(
HttpServletRequest request, HttpServletResponse response,
Object handler, Exception ex)
throws Exception;
}

拦截器和过滤器什么区别

Spring的拦截器与Servlet的过滤器Filter有很多相似之处,比如两者都是AOP编程思想的体现,都能实现权限检查、日志记录等,不同的是:

  1. 使用范围不同:Filter是Servlet规范规定的,只能用于Web程序中,而拦截器既可以用于Web程序,也可以用于Application、Swing程序中
  2. 规范不同:Filter是Servlet规范中定义的,是Servlet容器支持的。而拦截器是在Spring容器内的,是Spring框架支持的
  3. 使用的资源不同:拦截器是一个Spring的组件,归Spring管理,配置在Spring文件中,因此能使用Spring里的任何资源、对象,例如Service对象、数据源、事务管理等,通过IoC注入到拦截器即可,而Filter则不能
  4. 深度不同:Filter只在Servlet前后起作用。而拦截器能够深入到方法前后、异常抛出前后等,因此拦截器的使用具有更大的弹性。所以在Spring架构的程序中,要优先使用拦截器。
  5. 实现原理不同:拦截器是基于动态代理来实现的,而过滤器是基于函数回调来实现的。
  6. 作用域不同:拦截器只对Action起作用,过滤器可以对所有请求起作用。
  7. 调用次序不同:在action的生命周期中,拦截器可以多次被调用,而过滤器只能在容器初始化时被调用一次。

参考

参考文章