SpringMVC

SpringMVC:是基于spring的一个框架, 实际上就是spring的一个模块, 专门是做web开发的。
理解是servlet的一个升级

   web开发底层是servlet , 框架是在servlet基础上面加入一些功能,让你做web开发方便。

SpringMVC就是一个Spring。 Spring是容器,ioc能够管理对象,使用, @Component, @Repository, @Service, @Controller
SpringMVC能够创建对象, 放入到容器中(SpringMVC容器), springmvc容器中放的是控制器对象,

我们要做的是 使用@Contorller创建控制器对象, 把对象放入到springmvc容器中, 把创建的对象作为控制器使用
这个控制器对象能接收用户的请求, 显示处理结果,就当做是一个servlet使用。

使用@Controller注解创建的是一个普通类的对象, 不是Servlet。 springmvc赋予了控制器对象一些额外的功能。

web开发底层是servlet, springmvc中有一个对象是Servlet :DispatcherServlet(中央调度器)
DispatcherServlet: 负责接收用户的所有请求, 用户把请求给了DispatherServlet, 之后DispatcherServlet把请求转发给
我们的Controller对象, 最后是Controller对象处理请求。

index.jsp—–DispatcherServlet(Servlet)—-转发,分配给—Controller对象(@Controller注解创建的对象)
main.jsp MainController
addUser.jsp UserController

SpringMVC核心 DispatcherServlet

DispatcherServlet处理流程

和其他Servlet一样他也是通过Tomcat服务器创建的需要在web.xml文件中配置这个Servlet类的只有这样Tomcat服务器才知道什么时候去创建这个指定的Servlet

DispatcherServlet主要负责在tomcat启动的一开始 创建一个Springmvc容器放入ServletContext中, DispatcherServlet初始化时会读取.xml文件,创建容器和里面的类的实例 比如组件扫描器配置后 @Controller注解所指的类的对象

在整个 Spring MVC 框架中,DispatcherServlet 处于核心位置,它负责协调和组织不同组件完成请求处理并返回响应工作。DispatcherServlet 是 SpringMVC统一的入口,所有的请求都通过它。DispatcherServlet 是前端控制器,配置在web.xml文件中,Servlet依自已定义的具体规则拦截匹配的请求,分发到目标Controller来处理。 初始化 DispatcherServlet时,该框架在web应用程序WEB-INF目录中寻找一个名为[servlet-名称]-servlet.xml的文件,并在那里定义相关的Beans,重写在全局中定义的任何Beans。在看DispatcherServlet 类之前,我们先来看一下请求处理的大致流程:

  1. Tomcat 启动,(前提是在<servlet中配置了标签 他会告诉tomcat在它启动时实例化该Servlet)对 DispatcherServlet 进行实例化,然后调用它的 init() 进行初始化,在这个初始化过程中完成了:对 web.xml 中初始化参数的加载;建立 WebApplicationContext(SpringMVC的IOC容器);进行组件的初始化;

    DispatcherServlet的初始化会执行init()方法.DispatcherServlet在inti()中{
    //创建SpringMVC的IOC容器,读取配置文件
    WebApplicationContext ctx = new ClassPathXmlApplicationContext("springmvc.xml");
    //把容器对象放到ServletContext中(全局作用域)
    getServletContext().getAttribute(key,ctx);

    }
  2. 客户端发出请求,由 Tomcat 接收到这个请求,如果匹配 DispatcherServlet 在 web.xml中配置的映射路径,Tomcat 就将请求转交给 DispatcherServlet 处理;

  3. DispatcherServlet 从容器中取出所有 HandlerMapping 实例(每个实例对应一个 HandlerMapping接口的实现类)并遍历,每个 HandlerMapping 会根据请求信息,通过自己实现类中的方式去找到处理该请求的 Handler(执行程序,如 Controller 中的方法),并且将这个 Handler 与一堆 HandlerInterceptor (拦截器)封装成一个 HandlerExecutionChain 对象,一旦有一个 HandlerMapping 可以找到 Handler则退出循环;

  4. DispatcherServlet 取出 HandlerAdapter 组件,根据已经找到的 Handler,再从所有HandlerAdapter 中找到可以处理该 Handler 的 HandlerAdapter 对象;

  5. 执行 HandlerExecutionChain 中所有拦截器的 preHandler(),然后再利用 HandlerAdapter 执行 Handler ,执行完成得到 ModelAndView,再依次调用拦截器的 postHandler();

  6. 利用 ViewResolver 将 ModelAndView 或是 Exception (可解析成 ModelAndView)解析成View,然后 View 会调用 render() 再根据 ModelAndView 中的数据渲染出页面;

  7. 最后再依次调用拦截器的 afterCompletion(),这一次请求就结束了。


SpringMVC配置文件

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">

<!--声明,注册springmvc的核心对象DispatcherServlet
需要在tomcat服务器启动后,创建DispatcherServlet对象的实例
为什么要创建DispatcherServlet对象的实例呢?
因为DispatcherServlet在他创建的过程中会同时创建springmvc容器对象
读取springmvc的配置文件,把这个配置文件中的对象创建好,当用户发起请求时就可以直接直接使用对象了

servlet的初始化会执行init()方法.DispatcherServlet在inti()中{
//创建容器,读取配置文件
WebApplicationContext ctx = new ClassPathXmlApplicationContext("springmvc.xml");
//把容器对象放到ServletContext中
getServletContext().getAttribute(key,ctx);

}

-->
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>

<!--自定义springmvc读取的配置文件的位置-->
<init-param>
<!--springmvc读取的配置文件的位置的属性-->
<param-name>contextConfigLocation</param-name>
<!--指定配置文件的位置-->
<param-value>classpath:springmvc.xml</param-value>
</init-param>



<!--默认tomcat启动后不创建Servlet对象 只有接收到请求才会创建对象
为了能够在tomcat启动后,创建Servlet对象 load-on-startup:表示tomcat启动后创建对象的顺序
,他的值时整数,数值越小,tomcat创建对象的时间越早,大于等于零的整数
-->
<load-on-startup>1</load-on-startup>

</servlet>
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<!--
使用框架的时候,url-pattern可以使用两种值
1.使用扩展名,语法*.xxx,xxx是自定义扩展名.常用方式 *.do,*.action,*.mvc等
表示以xxx结尾的请求都由<servlet-name>对应的servlet处理
http://localhost:8088/myweb/web.do

2.使用"/" 与一般servlet使用无差 即拦截所有请求
-->
<url-pattern>*.do</url-pattern>
</servlet-mapping>

</web-app>
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">

<!--配置组件扫描器 配合扫描组件的@Controller和其中的@RequestMapping-->
<context:component-scan base-package="com.dyw.controller"/>
<!--配置视图解析器 原理就是字符串的拼接-->
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/page/"/>
<property name="suffix" value=".jsp"/>
</bean>
</beans>

这是SpringMVC-config.xml;


SpringMVC请求处理过程

springmvc请求的处理流程

1)发起some.do
2)tomcat(web.xml–url-pattern知道 *.do的请求给DispatcherServlet)
3)DispatcherServlet(根据springmvc.xml配置知道 some.do—doSome())
4)DispatcherServlet把some.do转发个MyController.doSome()方法
5)框架执行doSome()把得到ModelAndView进行处理, 转发到show.jsp

img

上面的过程简化的方式

some.do—DispatcherServlet—MyController

springmvc执行过程源代码分析

  1. tomcat启动,创建容器的过程
    通过load-on-start标签指定的1,创建DisaptcherServlet对象,
    DisaptcherServlet它的父类是继承HttpServlet的, 它是一个serlvet, 在被创建时,会执行init()方法。
    在init()方法中
    //创建容器,读取配置文件
    WebApplicationContext ctx = new ClassPathXmlApplicationContext(“springmvc.xml”);
    //把容器对象放入到ServletContext中
    getServletContext().setAttribute(key, ctx);

上面创建容器作用: 创建@controller注解所在的类的对象, 创建MyController对象,
这个对象放入到 springmvc的容器中, 容器是map , 类似 map.put(“myController”,MyController对象)

2.请求的处理过程
1)执行servlet的service()
protected void service(HttpServletRequest request, HttpServletResponse response)

protected void doService(HttpServletRequest request, HttpServletResponse response)
DispatcherServlet.doDispatch(request, response){

调用MyController的.doSome()方法
}

doDispatch:springmvc中DispatcherServlet的核心方法, 所有的请求都在这个方法中完成的。


SpringMVC中的注解

@Controller(控制器)

@Controller:创建处理器对象,对象放在springmvc容器中.
位置:类的上面
和spring中讲的@service和@Component一样

能处理请求的都是控制器(处理器):MyController能处理请,叫做后端控制器(back controller)

@RequestMapping

表示当前方法为处理器方法。该方法要对 value 属性所指定的 URI进行处理与响应。被注解的方法的方法名可以随意。

@RequestMapping:请求映射:作用是把一个请求地址和一个方法绑定在一起.
一个请求指定一个方法处理
属性: 1.value是一个String,表示请求的uri地址的(some.do). 可以使用数组表示多个请求路径都有这个方法处理
2.value的值必须是唯一的,不能重复. 再使用时推荐地址以”/“开头

位置:1.在方法上面,常用的
        2.在类上面

说明:使用RequestMapping修饰的方法叫做处理器方法或者控制器方法
使用@RequestMapping修饰的方法可以处理请求的,类似与Servlet中的doGet() or doPost()

可以在@RequestMapping指定请求的方法

>@RequestMapping(value = "/some.do",method = RequestMethod.GET)

RequestMethod.GET、RequestMethod.POST

​ 如果不设置就是任意请求方法都能处理不会报405错

请求传参

处理器方法的参数

处理器方法可以包含以下四类参数,这些参数会在系统调用时由系统自动赋值,即程序员可在方法内直接使用。
➢ HttpServletRequest
➢ HttpServletResponse
➢ HttpSession
➢ 请求中所携带的请求参数

方式一 直接在方法中写入与前端页面同样名称的参数(同名匹配规则)

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<form method="post" action="/springmvc_03/doSome.do">
姓名:<input type="text" name="name" />
年龄:<input type="text" name="age"/>
<input type="submit" value="提交">
</form>
</body>
</html>
@Controller
public class MyController {
@RequestMapping(value = "/doSome.do", method = RequestMethod.POST)
public ModelAndView doSome(String name,Integer age){
ModelAndView mv = new ModelAndView();
mv.addObject("name",name);
mv.addObject("age",age);

System.out.println("姓名:"+name);
System.out.println("年龄:"+Integer.valueOf(age));
mv.setViewName("show");
return mv;
}
}

方式二 使用@RequestParam(“前台参数名”) 注入

防止前台名称与后台名称不一致导致出错 同时也防止同名匹配规则与前台的耦合 利于更好的分离开发

@RequestMapping(value = "/doSome.do", method = RequestMethod.POST)
public ModelAndView doSome(@RequestParam("name") String sname, @RequestParam("age") Integer sage){
ModelAndView mv = new ModelAndView();
mv.addObject("name",sname);
mv.addObject("age",sage);

System.out.println("姓名:"+sname);
System.out.println("年龄:"+Integer.valueOf(sage));
mv.setViewName("show");
return mv;
}

@RequestParam 注解细节:

该注解有三个变量:**valuerequireddefaultvalue**

value :指定 name 属性的名称是什么,value 属性都可以默认不写

required :是否必须要有该参数,可以设置为【true】或者【false】防止出现空指针异常

defaultvalue :设置默认值

方式三 使用模型传参(使用对象)

@RequestMapping(value = "/doSome.do", method = RequestMethod.POST)
public ModelAndView doSome(People people){
ModelAndView mv = new ModelAndView();
mv.addObject("name",people.getName());
mv.addObject("age",people.getAge());

System.out.println("姓名:"+people.getName());
System.out.println("年龄:"+people.getAge());
mv.setViewName("show");
return mv;
}

使用模型传参 要求参数的形参名要和对象的属性名一样, 框架会调用模型类的构造方法 创建一个模型 在调用模型的set方法完成注入

优点:可以避免方法参数过多而引起的参数过长,乱而不方便查看,而且可以隐藏信息

注意 :

中文乱码问题

这种问题主要出现在POST请求中 对于这种问题如果我们没写一个方法都去写一个setCharacterEncoding的话会 程序会出现很多冗余。

解决方案:使用过滤器 通过配置 Spring MVC 字符编码过滤器来解决POST请求传参乱码问题

**注意:**最好将该过滤器注册在其它过滤器之前。因为过滤器的执行是按照其注册顺序进行的。

在web.xml中配置这样一段

<!--配置过滤器-->
<filter>
<filter-name>CharacterEncodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<!--设置编码格式-->
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
<init-param>
<!--强制请求的编码为utf-8-->
<param-name>forceRequestEncoding</param-name>
<param-value>true</param-value>
</init-param>
<init-param>
<!--强制响应的编码为utf-8-->
<param-name>forceResponseEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>CharacterEncodingFilter</filter-name>
<!--对所有请求路径都修改编码-->
<url-pattern>/*</url-pattern>
</filter-mapping>

控制器回显数据

Controller处理器中的方法返回值为String就代表 视图名 一般用在同步请求

方式一:使用 Spring MVC 所提供的 ModelAndView 对象

​ 在使用他之前需要创建一个show.jsp 用来充当视图 前面的演示中也是使用的这样的方式

index.jsp


<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<form method="post" action="/springmvc_03/doSome.do">
姓名:<input type="text" name="name" />
年龄:<input type="text" name="age"/>
<input type="submit" value="提交">
</form>
</body>
</html>

MyController

@Controller
public class MyController {
@RequestMapping(value = "/doSome.do", method = RequestMethod.POST)
public ModelAndView doSome(People people){
ModelAndView mv = new ModelAndView();
mv.addObject("name",people.getName());
mv.addObject("age",people.getAge());

System.out.println("姓名:"+people.getName());
System.out.println("年龄:"+people.getAge());
mv.setViewName("show");
return mv;
}
}

show.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<h3>${name}</h3>
<h3>${age}</h3>
</body>
</html>

结果如图:

image-20220109182433561

image-20220109182513274

方式二 使用 Model 对象

在 Spring MVC 中,我们通常都是使用这样的方式来绑定数据

index.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<a href="/springmvc_04/some.do">test1-Model方式回显数据</a>
</body>
</html>

MyController.java

@Controller
public class MyController {
@RequestMapping("/some.do")
public String doSome(Model model){
model.addAttribute("msg","这是使用Model方式回显数据");
return "show";
}
}

返回值就是一个就是一个jsp资源可以使用完整路径 也可以使用视图解析器简化

show.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<h3>${msg}</h3>
</body>
</html>

运行结果:

image-20220109194719801

方式三 使用 @ModelAttribute 注解:

单独创建一个方法model用于在一开始向Model中添加数据

MyController.java

@Controller
public class MyController {
@ModelAttribute
public void model(Model model){
model.addAttribute("msg","这是方式三使用@ModelAttribute");
}
@RequestMapping("/some.do")
public String doSome(){
return "show";
}
}

这样写就会在访问控制器方法 handleRequest() 时,会首先调用 model() 方法将 message 添加进页面参数中去,在视图中可以直接调用,但是这样写会导致该控制器所有的方法都会首先调用 model() 方法,但同样的也很方便,因为可以加入各种各样的数据。

方式四:使用void(了解)

对于处理器方法返回 void 的应用场景,AJAX 响应.

若处理器对请求处理后,无需跳转到其它任何资源,此时可以让处理器方法返回 void。

例如,对于 AJAX 的异步请求的响应。

方式五:使用Object

主要用于响应Ajax请求

处理器方法也可以返回 Object 对象。这个 Object 可以是 Integer,String,自定义对象,Map,List 等。但返回的对象不是作为逻辑视图出现的,而是作为直接在页面显示的数据出现的。

返回对象,需要使用@ResponseBody 注解,将转换后的 JSON 数据放入到响应体中。

环境搭建:

由于返回 Object 数据,一般都是将数据转化为了 JSON 对象后传递给浏览器页面的。而这个由 Object 转换为 JSON,是由 Jackson 工具完成的。所以需要导入 Jackson 的相关 Jar 包。所以需要在maven的pom.xml中添加jackson相关依赖

<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.9.0</version>
</dependency>

<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.0</version>
</dependency>

声明注解驱动:

将 Object 数据转化为 JSON 数据,需要由消息转换器 HttpMessageConverter 完成。而转换器的开启,需要由mvc:annotation-driven/来完成。(注意:一定时路径带有mvc的)

SpringMVC 使用消息转换器实现请求数据和对象,处理器方法返回对象和响应输出之间的自动转换

当 Spring 容器进行初始化过程中,在mvc:annotation-driven/处创建注解驱动时,默认创建了七个 HttpMessageConverter 对象。也就是说,我们注册mvc:annotation-driven/,就是为了让容器为我们创建 HttpMessageConverter 对象。(对应七个转换不同类型的对象)

没有加入注解驱动标签时的状态
org.springframework.http.converter.ByteArrayHttpMessageConverter
org.springframework.http.converter.StringHttpMessageConverter
org.springframework.http.converter.xml.SourceHttpMessageConverter
org.springframework.http.converter.support.AllEncompassingFormHttpMessageConverter

加入注解驱动标签时的状态
org.springframework.http.converter.ByteArrayHttpMessageConverter
org.springframework.http.converter.StringHttpMessageConverter
org.springframework.http.converter.ResourceHttpMessageConverter
org.springframework.http.converter.ResourceRegionHttpMessageConverter
org.springframework.http.converter.xml.SourceHttpMessageConverter
org.springframework.http.converter.support.AllEncompassingFormHttpMessageConverter
org.springframework.http.converter.xml.Jaxb2RootElementHttpMessageConverter
org.springframework.http.converter.json.MappingJackson2HttpMessageConverter

HttpMessageConverter 接口 : HttpMessageConverter是 Spring3.0 新添加的一个接口,负责将请求信息转换为一个对象(类型为 T),将对象(类型为 T)输出为响应信息

HttpMessageConverter接口定义的方法:

  1. boolean canRead(Class<?> clazz,MediaType mediaType): 指定转换器可以读取的对象类型,即转 换 器 是 否 可 将 请 求 信 息 转 换 为 clazz 类 型 的 对 象 , 同 时 指 定 支 持 MIME 类 型(text/html,applaiction/json 等)

  2. **boolean canWrite(Class<?> clazz,MediaType mediaType):**指定转换器是否可将 clazz 类型的对象写到响应流中,响应流支持的媒体类型在 MediaType 中定义。
    LIst getSupportMediaTypes():该转换器支持的媒体类型

  3. T read(Class<? extends T> clazz,HttpInputMessage inputMessage):将请求信息流转换为 T 类型的对象。

  4. **void write(T t,MediaType contnetType,HttpOutputMessgae outputMessage):**将 T 类型的对象写到响应流中,同时指定相应的媒体类型为 contentType

加入注解驱动mvc:annotation-driven/后适配器类的 messageConverters 属性值

18868114-5a5b24aab0a648c9

18868114-0248cc96bbce4592

返回自定义类型对象

返回自定义类型对象时,不能以对象的形式直接返回给客户端浏览器,而是将对象转换为 JSON 格式的数据发送给浏览器的。

在处理器方法上使用@ResponseBody即可使得返回值可以以数据的形式响应

@RequestMapping(value = "myajax.do")
@ResponseBody
public Student doStudentJson(){
//创建Student对象
//返回Student对象
}

返回其他对象也同样可以按照这个方法


客户端跳转(重定向)

序言

​ 框架的底层会在我们使用@Controller方法时, 在指定视图名称和Model后,帮助我们将Modl封装到request请求域中,然后自动调用**request.getRequestDispatcher(“地址”).forward(request, response);**也就是请求转发. 也就是说 这些都是服务端的跳转

​ 在学习servlet中我们可知 请求转发是一次请求 用法为request.getRequestDispatcher(“xx.jsp”).forward()

重定向是两次转发:response.sendRedirect(“xxx.jsp”)

​ 在SpringMVC框架中把原来 Servlet 中的请求转发和重定向操作进行了封装。现在可以使用简单的方式实现转发和重定向。

服务端跳转

​ 前面对框架的介绍时我说过SpringMVC框架在你指定视图名称之后是自动帮你转发到视图资源上的(来让其获得Model中的资源).

​ 也可以手动指定只需要在前方加入”forward”即可

**方式一:**以ModelAndView对象的方式返回

@RequestMapping(...)
public ModelAndView doSome(){
ModelAndView mv= new ModelAndView();

mv.set("forward:/...jsp");
return mv;
}

**方式二:**以String方式返回

@RequestMapping(...)
public String doSome(){
return "forward:/...jsp";
}

**方式三:**以ModelAndView初始化的方式 且 以ModelAndView对象的方式返回

@RequestMapping(...)
public ModelAndView doSome(){
ModelAndView mv= new ModelAndView("forward:/...jsp");
return mv;
}

如何进行客户端跳转?

注意: ModeAndView的构造方法

/**
* 当没有模型数据要公开时,方便的构造函数。也可以与 {@code addObject} 结合使用。 @param viewName 要渲染的视图名 称,由 DispatcherServlet 的 ViewResolver 解析 @see addObject

即可以在创建ModelAndView对象时 没有设置返回的ViewName时 可以指定视图路径
*/
public ModelAndView(String viewName) {
this.view = viewName;
}

**方式一:**MyController.java

@Controller
public class MyController {
@RequestMapping("/jump")
public ModelAndView jump() {
ModelAndView mav = new ModelAndView("redirect:/jump.jsp");
return mav;
}
}

可以在创建 ModelAndView对象时指定重定向的资源(html、jsp、controller、servlet等)路径

格式为 ModelAndView mav = new ModelAndView(“redirect:/资源路径”); 相当于服务器又发了一次请求但这个不能使用视图解析器 因为这是浏览器发来的另一次请求

方式二:

@RequestMapping("/jump")
public ModelAndView jump() {
ModelAndView mav = new ModelAndView();
mav.setViewName("redirect:/jump.jsp");
return mav;
}

方式三:

@RequestMapping("/jump")
public String jump() {
return "redirect:/jump.jsp";
}

注意

​ 1. 对于请求转发的页面,可以是WEB-INF中页面;而重定向的页面,是不能为WEB-INF中页的。因为重定向相当于用户再次发出一次请求,而用户是不能直接访问 WEB-INF 中资源的。


解读< url-pattern >

配置详解

(1) “*.xxx”

​ 以指定后缀结尾的请求都交由DispatcherServlet处理

(2) “/“

​ “/“将会 覆盖容器的default servlet, 凡是在web.xml文件中找不到匹配的URL,它们的访问请求都将交给该Servlet处理(静态资源也将会拦截). 所以web.xml没有配置其他特殊路径的servlet, 基本上 所有的请求都交由DispatcherServlet处理.但DispacherServlet是不能处理图片这样的静态资源的 但也有解决方法 但还是尽量让交给Tomcat去做

image-20220110145823608

(3)”/*”

'/*' 错误的配置,会拦截 *.jsp, *.jspx的请求, 使用这种配置最终要转发到一个JSP页面,仍然会由DispatcherServlet, 解析jsp地址, 不能根据jsp页面找到handler, 会报错

引入

发起的请求是由哪些服务器程序处理的。

http://localhost:8080/ch05_url_pattern/index.jsp :tomcat(jsp底层本质是Servlet)
http://localhost:8080/ch05_url_pattern/js/jquery-3.4.1.js : tomcat
http://localhost:8080/ch05_url_pattern/images/p1.jpg : tomcat
http://localhost:8080/ch05_url_pattern/html/test.html: tomcat
http://localhost:8080/ch05_url_pattern/some.do : DispatcherServlet(springmvc框架处理的)

tomcat本身能处理静态资源的访问, 像html, 图片, js文件都是静态资源

Tomcat的default

tomcat的web.xml文件有一个servlet 名称是 default , 在服务器启动时创建的。

<servlet>
<servlet-name>default</servlet-name>
<servlet-class>org.apache.catalina.servlets.DefaultServlet</servlet-class>
<init-param>
<param-name>debug</param-name>
<param-value>0</param-value>
</init-param>
<init-param>
<param-name>listings</param-name>
<param-value>false</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>/</url-pattern> 表示静态资源和未映射的请求都这个default处理
</servlet-mapping>

default这个servlet作用:

The default servlet for all web applications, that serves static
resources. It processes all requests that are not mapped to other
servlets with servlet mappings (defined either here or in your own
web.xml file).


所有 Web 应用程序的默认 servlet,提供静态服务
资源。它处理所有未映射到其他请求的请求
带有 servlet 映射的 servlet(在此处定义或在您自己的
web.xml 文件)。

  1. 处理静态资源(也就是说Tomcat服务器中的DefaultServlet会处理静态资源)
  2. 处理未映射到其它servlet的请求。

解决DisPatcherServlet 配置为”/“ 无法处理图片等静态资源的问题

的值并不是说写为/后,静态资源就无法访问了。经过一些配置后,该问题也是可以解决的。(.jsp还是可以访问的)

(1) 使用< mvc:default-servlet-handler />

​ 声 明 了 <mvc:default-servlet-handler /> 后 , springmvc 框 架 会 在 容 器 中 创 建DefaultServletHttpRequestHandler 处理器对象。它会像一个检查员,对进入 DispatcherServlet的 URL 进行筛查,如果发现是静态资源的请求,就将该请求转由 Web 应用服务器默认的Servlet 处理。一般的服务器都有默认的 Servlet。

​ 在 Tomcat 中,有一个专门用于处理静态资源访问的 Servlet 名叫 DefaultServlet。其为 default。可以处理各种静态资源访问请求。该 Servlet 注册在 Tomcat 服务器的 web.xml 中。在 Tomcat 安装目录/conf/web.xml。

img

​ 项目:url-pattern-2。在项目 url-pattern 基础上修改。

​ 只需要在 springmvc.xml 中添加< mvc:default-servlet-handler/>标签即可。

img

​ < mvc:default-servlet-handler/>表示使用 DefaultServletHttpRequestHandler 处理器对象。而该处理器调用了 Tomcat 的 DefaultServlet 来处理静态资源的访问请求。

当然了,要想使用<mvc: …/>标签,需要引入 mvc 约束

img

​ 该约束可从 Spring 帮助文档中搜索关键字 spring-mvc.xsd 即可获取:
docs/spring-framework-reference/htmlsingle/index.html

(2) 使用< mvc:resources/>(掌握)

项目:url-pattern-3。在项目 url-pattern 基础上修改。

​ 在 Spring3.0 版本后,Spring 定义了专门用于处理静态资源访问请求的处理器ResourceHttpRequestHandler。并且添加了**< mvc:resources/>**标签,专门用于解决静态资源无法访问问题。需要在 springmvc 配置文件中添加如下形式的配置:

img

​ location 表示静态资源(webapp-statics)所在目录。当然,目录不要使用/WEB-INF/及其子目录。

​ mapping 表 示 对 该 资 源 的 请 求 ( 以 /images/ 开 始 的 请 求 , 如 /image/beauty.jpg , /images/car.png 等)。注意,后面是两个星号**。

(3) 声明注解驱动

​ 解决动态资源和静态资源冲突的问题,在 springmvc 配置文件加入:

img

<!--为了解决静态资源和动态资源冲突的问题,可以加入 <mvc:annotation-driven/>-->
<mvc:annotation-driven/>
<!--方案一 调用Tomcat的默认Servlet去实现静态资源的请求 -->
<mvc:default-servlet-handler/>
<!--方案二 通过Springmvc框架去处理静态资源的请求 使用< mvc:resources/>且将静态资源放入webapp下的statics文件夹统一处理-->
<mvc:resources mapping="statics/**" location="/statics/"/>

总结:

  1. 使用”/“符合当今流行的REST风格

  2. 处理静态资源文件时应该将尽可能交给Tomcat服务器去做 可以通过配置< mvc:resources/>实现

  3. 我们在配置DisPatcherServlet时 应该尽可能将他的配置为”*.xxxx”的形式 减少DisPatcherServlet的处理压力 增强其功能


相对与绝对路径的问题

在jsp , html中使用的地址, 都是在前端页面中的地址,都是相对地址

地址分类:

  1. 绝对地址 , 带有协议名称的是绝对地址, http://www.baidu.com , ftp://202.122.23.1

  2. 相对地址, 没有协议开头的, 例如 user/some.do , /user/some.do
    相对地址不能独立使用,必须有一个参考地址。 通过参考地址+相对地址本身才能指定资源。

张三同学, 1班有张三, 2班也有张三
  1. 参考地址
    1. 在你的页面中的,访问地址不加 “/“
访问的是: http://localhost:8080/ch06_path/index.jsp
路径: http://localhost:8080/ch06_path/
资源: index.jsp

在index.jsp发起 user/some.do请求,访问地址变为 http://localhost:8080/ch06_path/user/some.do
当你的地址 没有斜杠开头,例如 user/some.do , 当你点击链接时, 访问地址是当前页面的地址
加上链接的地址。
http://localhost:8080/ch06_path/ + user/some.do

index.jsp 访问 user/some.do , 返回后现在的地址: http://localhost:8080/ch06_path/user/some.do

http://localhost:8080/ch06_path/user/some.do
路径: http://localhost:8080/ch06_path/user/
资源: some.do

在index.jsp 再访问 user/some.do ,就变为 http://localhost:8080/ch06_path/user/user/some.do

解决方案:
1.加入${pageContext.request.contextPath}
2.加入一个base标签, 是html语言中的标签。 表示当前页面中访问地址的基地址。
你的页面中所有 没有“/”开头的地址,都是以base标签中的地址为参考地址
使用base中的地址 + user/some.do 组成访问地址

问题

index.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<a href="user/some.do">带有不带斜杠的发起请求</a>
</body>
</html>

MyController.java

@Controller
public class MyController {
@RequestMapping("/user/some.do")
public ModelAndView doSome(){
ModelAndView mv = new ModelAndView();
mv.setViewName("/index.jsp");
return mv;
}
}

最后出现如下问题

解决方法

在你的页面中的,访问地址加 “/“
访问的是: http://localhost:8080/ch06_path/index.jsp
路径: http://localhost:8080/ch06_path/
资源: index.jsp

点击 /user/some.do, 访问地址变为 http://localhost:8080/user/some.do
参考地址是 你的服务器地址, 也就是 http://localhost:8080
如果你的资源不能访问: 加入${pageContext.request.contextPath}
<a href="${pageContext.request.contextPath}/user/some.do">发起user/some.do的get请求</a>

总结:

  1. 前端页面中href=””中最前方加入”/“表示为绝对地址 即除去域名端口后的地址包括(/项目名/资源路径)

  2. 前端页面中href=””中最前方不加入”/“表示为相对地址 即在(1)的基础上还去除了项目名(资源路径)

  3. 为了避免使用相对路径出现image-20220110155717000的错误可以使用绝对路径

    1. 使用在前面加入完整路径的方式(http://localhost:8088/项目名/资源路径)的方式
    2. 在jsp页面中使用${pageContext.request.contextPath}/
    3. 在jsp页面中使用的方式 他会在所有的请求路径之前加上base中的内容
    4. 但前三种始终是静态的 所以第四种为动态地获取 在jsp页面上方加入如下语句
    <%
    String basePath = request.getScheme()+"://"
    +request.getServerName()+":"+
    request.getServerPort()+
    request.getContextPath()+"/";
    %>

    再再base标签中配置<%=basePath%>即可 与第三种的区别在于 第四种可以动态获取前方的地址

    这些情况都是解决前端请求路径中不加入”/“问题的处理方法

    如果使用”/“就上项目名即可


SSM整合

整合思路

SSM 编程,即 SpringMVC + Spring + MyBatis 整合,是当前最为流行的 JavaEE 开发技术架构。其实 SSM 整合的实质,仅仅就是将 MyBatis整合入 Spring。因为 SpringMVC原本就是 Spring的一部分,不用专门整合。

**第一个容器:**SpringMVC容器,管理Controller控制器对象的.

**第二个容器:**Spring容器,管理Service,Dao,工具类对象的.

整合思路就是:

  1. 我们要将使用的对象交给合适的容器去创建、管理,把Controller还有web开发相关的对象交给SpringMVC容器,这些web用的对象写在SpringMVC配置文件中

  2. service,dao对象定义在Spring的配置文件中,让spring创建和创建这些对象

关键:由于SpringMVC容器时Spring容器的子容器,类似于java中的继承 子是可以访问父的内容的。也就是说springmvc容器中的对象可以访问spring容器中的对象。

SSM 整合的实现方式可分为两种:基于 XML 配置方式,基于注解方式。

搭建 SSM 开发环境

一:搭建SSM开发环境需要 再maven中添加如下依赖

  1. Servlet依赖 (J2EE WEB核心)

  2. JSP依赖

  3. SpringMVC依赖

  4. Spring依赖

  5. Mybatis依赖

  6. jackson依赖

  7. mysql依赖

  8. druid依赖

需要添加的依赖

<!--servlet-->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
</dependency>
<!--jsp-->
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>javax.servlet.jsp-api</artifactId>
<version>2.3.3</version>
<scope>provided</scope>
</dependency>
<!--springmvc-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.3.14</version>
</dependency>
<!--spring事务的依赖-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>5.3.14</version>
</dependency>
<!--事务相关的依赖-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.3.14</version>
</dependency>
<!--jackson工具包-->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.13.1</version>
</dependency>
<!-- spring-mybatis整合用到的依赖-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>2.0.6</version>
</dependency>
<!--mybatis依赖-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.9</version>
</dependency>
<!--mysql驱动依赖-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.27</version>
</dependency>
<!--druid连接池依赖-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.2.8</version>
</dependency>

build中需要添加的Resources

<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>false</filtering>
</resource>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>false</filtering>
</resource>
</resources>

二:编写web.xml

  1. 创建DispatcherServlet,
    1. 目的创建springmvc容器,才能船舰controller类对象
    2. 创建的时Servlet才能接收请求
<!--注册DispatcherServlet中央调度器-->
<servlet>
<servlet-name>DispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:conf/springmvc.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>DispatcherServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>

​ 配置中央调度器时需要注意,SpringMVC的配置文件名与其它 Spring配置文件名不相同。这样做的目的是 Spring 容器创建管理 Spring 配置文件中的 bean, SpringMVC 容器中负责视图层 bean 的初始。


  1. 创建spring的监听器:ContextLoaderListener
    1. 目的创建spring的容器对象,才能那个创建service,doo等对象.
<!--注册ContextLoadListener 监听器 用于初始化Spring容器的-->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:conf/spring.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

​ 注册 ServletContext 监听器的实现类 ContextLoaderListener,用于创建 Spring 容器及将创建好的 Spring 容器对象放入到 ServletContext 的作用域中。


  1. 注册字符集过滤器,解决post请求乱码问题
<!--注册请求字符集过滤器-->
<filter>
<filter-name>CharacterEncodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>utf-8</param-value>
</init-param>
<init-param>
<param-name>forceRequestEncoding</param-name>
<param-value>true</param-value>
</init-param>
<init-param>
<param-name>forceResponseEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>CharacterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>

​ 注册字符集过滤器,用于解决请求参数中携带中文时产生乱码问题。

**三:**创建包,Controller包,service,dao,实体类包

**四:**Spring、SpringMVC、Mybatis配置文件

  1. Spring配置文件
  2. SpringMVC配置文件
  3. Mybatis主配置文件
  4. 数据库的属性配置文件(.properties)

**五:**编写代码

  1. 写代码、dao接口、mapper配置文件
  2. Service和实现类、controller、实体类

六:写页面

项目执行流程

index.jsp–addStudent.jsp—student/addStudent.do( service的方法,调用dao的方法)–result.jsp


异常处理

异常处理:
springmvc框架采用的是统一,全局的异常处理。
把controller中的所有异常处理都集中到一个地方。 采用的是aop的思想。把业务逻辑和异常处理代码分开。解耦合。

SpringMVC 框架处理异常的常用方式:使用**@ExceptionHandler** 注解处理异常和**@ControllerAdvice**

@ExceptionHandler 注解

​ 使用注解@ExceptionHandler 可以将一个方法指定为异常处理方法。该注解只有一个可选属性 value,为一个 Class<?>数组,用于指定该注解的方法所要处理的异常类,即所要匹配的异常。

​ 对于异常处理注解的用法,也可以直接将异常处理方法注解于 Controller 之中。

注意:如果指定参数那么只处理参数中指定的异常,如果参数为空,则默认为方法参数列表中列出的任何异常

使用方法:

​ 定义在Controller类的方法上(一般不用在由@RequestMapping的方法上),在方法上面加入**@ExceptionHandler 注解**并且根据需求指定参数即可

@ExceptionHandler
public void doException(){

}

​ 不过,一般不这样使用,而是将异常处理方法专门定义在一个类中,作为全局的异常处理类. 这时需要使用注解**@ControllerAdvice**

@ControllerAdvice注解

​ 字面理解就是“控制器增强”,是给控制器对象增强功能的。使用@ControllerAdvice 修饰的类中可以使用**@ExceptionHandler**。

​ 当使用**@RequestMapping** 注解修饰的方法抛出异常时,会执行**@ControllerAdvice** 修饰的类中的异常处理方法。

@ControllerAdvice 是使用**@Component** 注解修饰的,可以< context:component-scan>扫描到@ControllerAdvice 所在的类路径(包名),创建对象。

使用方法:

定义在一个类的上面 然后里面的方法使用**@ExceptionHandler注解**, 表示异常处理方法

@ControllerAdvice
public class ExceptionController {
@ExceptionHandler
public void doException(){

}
}

SpringMVC.xml

使用@ControllerAdvice注解需要注册注解驱动
<!--声明组件扫描器-->
<context:component-scan base-package="com.dyw.Controller"/>
<context:component-scan base-package="com.dyw.Execp"/>
<!--注册注解驱动-->
<mvc:annotation-driven/>

拦截器

拦截器

​ SpringMVC 中的 Interceptor 拦截器是非常重要和相当有用的,它的主要作用是拦截指定的用户请求,并进行相应的预处理与后处理。其拦截的时间点在“处理器映射器根据用户提交的请求映射出了所要执行的处理器类,并且也找到了要执行该处理器类的处理器适配器,在处理器适配器执行处理器之前”。当然,在处理器映射器映射出所要执行的处理器类时,已经将拦截器与处理器组合为了一个处理器执行链,并返回给了中央调度器。

自定义拦截器

​ 自定义拦截器,需要实现 HandlerInterceptor 接口。而该接口中含有三个方法:

preHandle(request,response, Object handler):
该方法在处理器方法执行之前执行。其返回值为 boolean,若为 true,则紧接着会执行处理器方法,且会将 afterCompletion()方法放入到一个专门的方法栈中等待执行。

postHandle(request,response, Object handler,modelAndView):
该方法在处理器方法执行之后执行。处理器方法若最终未被执行,则该方法不会执行。由于该方法是在处理器方法执行完后执行,且该方法参数中包含 ModelAndView,所以该方法可以修改处理器方法的处理结果数据,且可以修改跳转方向。

afterCompletion(request,response, Object handler, Exception ex):
当 preHandle()方法返回 true 时,会将该方法放到专门的方法栈中,等到对请求进行响应的所有工作完成之后才执行该方法。即该方法是在中央调度器渲染(数据填充)了响应页面之后执行的,此时对 ModelAndView 再操作也对响应无济于事。

afterCompletion 最后执行的方法,清除资源,例如在 Controller 方法中加入数据

public class MyInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("执行MyInterceptor-------preHandle()");
return true;
}

@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("执行MyInterceptor-------postHandle()");
}

@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("执行MyInterceptor-------afterCompletion()");
}
}

拦截器中的方法与处理器方法的执行顺序如下:(会在请求到达处理器方法之前进行拦截的预处理,也会在处理器方法返回后响应前进行后处理)

18868114-b27c6ef989f87246

注册拦截器

需要在SpringMVC.xml配置文件中 注册拦截器

<!--注册拦截器-->
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/**"/>
<bean class="com.dyw.Interceptor.MyInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>

其中 < mvc:mapping/>用于指定当前所注册的拦截器可以拦截的请求路径,而/**表示拦截所有请求。

MyController.java

@Controller
public class MyController {
@RequestMapping("/some.do")
public ModelAndView doSome(String name, Integer age, HttpSession session){
System.out.println("执行MyController处理器方法");
ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject("myname",name);
modelAndView.addObject("myage",age);
modelAndView.setViewName("show");
session.setAttribute("atter","session中的数据");
return modelAndView;
}
}

执行结果:

image-20220110213638275

多个拦截器的执行

再创建一个拦截器 Myinterceptor2.java

public class MyInterceptor2 implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("123");
return true;
}

@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("124");
}

@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("125");
}
}

多个拦截器可以注册再一个< mvc:interceptors>< /mvc:interceptors>中

<!--注册多个拦截器-->
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/**"/>
<bean class="com.dyw.Interceptor.MyInterceptor"/>
</mvc:interceptor>
<mvc:interceptor>
<mvc:mapping path="/**"/>
<bean class="com.dyw.Interceptor.MyInterceptor2"/>
</mvc:interceptor>
</mvc:interceptors>

执行情况:

image-20220110214156717

可以推断出 一个请求的拦截会依次经过注册的拦截器 且拦截器的处理顺序与注册顺序有关

当有多个拦截器时,形成拦截器链。拦截器链的执行顺序,与其注册顺序一致。需要再次强调一点的是,当某一个拦截器的 preHandle()方法返回 true 并被执行到时,会向一个专门的方法栈中放入该拦截器的 afterCompletion()方法。

多个拦截器中方法与处理器方法的执行顺序如下:

img

问题:

我们将第一个拦截器的preHandle()方法返回值设为false

执行结果

image-20220110214845745

可以发现 后面的的Interceptor没有执行结合上图(多个拦截器执行情况图)可知 只要有一个 preHandle()方法返回 false,则上部的执行链将被断开,其后续的处理器方法与 postHandle()方法将无法执行。但,无论执行链执行情况怎样,只要方法栈中有方法,即执行链中只要有 preHandle()方法返回 true,就会执行方法栈中的afterCompletion()方法。最终都会给出响应。

用途

可以用作检查用户权限 当用户访问一个资源时可以通过注册拦截器的方式 去检测用户的权限、用户登录处理和记录日志

例如:只有经过登录的用户方可访问处理器,否则,将返回“无权访问”提示。

解惑:

拦截器与过滤器的区别:

  1. 过滤器是servlet中的对象, 拦截器是框架中的对象

  2. 过滤器实现Filter接口的对象, 拦截器是实现HandlerInterceptor

  3. 过滤器是用来设置request,response的参数,属性的,侧重对数据过滤的。
    拦截器是用来验证请求的,能截断请求。

  4. 过滤器是在拦截器之前先执行的。

  5. 过滤器是tomcat服务器创建的对象
    拦截器是springmvc容器中创建的对象

  6. 过滤器是一个执行时间点。
    拦截器有三个执行时间点

  7. 过滤器可以处理jsp,js,html等等
    拦截器是侧重拦截对Controller的对象。 如果你的请求不能被DispatcherServlet接收, 这个请求不会执行拦截器内容

  8. 拦截器拦截普通类方法执行,过滤器过滤servlet请求响应

总结

拦截器:

  1. 拦截器是springmvc中的一种,需要实现HandlerInterceptor接口。
  2. 拦截器和过滤器类似,功能方向侧重点不同。 过滤器是用来过滤器请求参数,设置编码字符集等工作。
    拦截器是拦截用户的请求,做请求做判断处理的。
  3. 拦截器是全局的,可以对多个Controller做拦截。 一个项目中可以有0个或多个拦截器, 他们在一起拦截用户的请求。
    拦截器常用在:用户登陆验证,权限验证,日志记录

拦截器的使用步骤:
1.定义类实现HandlerInterceptor接口
2.在springmvc配置文件中,声明拦截器, 让框架知道拦截器的存在。

拦截器的执行时间:
1)在请求处理之前, 也就是controller类中的方法执行之前先被拦截。
2)在控制器方法执行之后也会执行拦截器。
3)在请求处理完成后也会执行拦截器。

拦截器:看做是多个Controller中公用的功能,集中到拦截器统一处理。使用的aop的思想

END