SpringMVC

第一章 SpringMVC概述

1.1 SpringMVC简介

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

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

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

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

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

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

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

1.2 SpringMVC优点

1.基于MVC架构。功能明确,解耦合。
2.轻量、简单、易学。
3.作为Spring框架的一部分,能够使用IoC、AOP,能够方便的整合其他框架。
4.Spring强化注解的使用。方便灵活。

1.3 第一个SpringMVC程序

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的核心方法, 所有的请求都在这个方法中完成的。

1.pom.xml的配置(添加依赖)
spring-webmvc依赖,添加后间接添加Spring依赖

2.注册中央调度器
在web.xml中注册一个servlet:DispatcherServlet,是HttpServlet的子类,称为中央调度器,也被称作前端控制器(front controller)。
通常情况下可以设置contextConfigLocation这个初始化参数来修改这一默认规则,在指定目录下寻找配置文件。
自定义配置文件路径为classpath:springmvc.xml,就在resources目录下创建此文件,以后1.3.6进行配置。

<?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()方法。DispatcherServletinit(){
        //创建容器,读取配置文件
        webApplicationcontext ctx = new ClassPath×mlApplicationContext ("springmvc.xml");
        //把容器对象放入到servletcontext中
        getservletcontext( ) .setAttribute(key,ctx);
     }

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

    <init-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:springmvc.xml</param-value>
    </init-param>
    <!-- 在tomcat启动后,创建servlet对象
     load-on-startup:表示tomcat启动后创建对象的顺序。它的值是整数,数值越小,
     tomcat创建对象的时间越早。大于等于0的整数。-->
    <load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
    <servlet-name>springmvc</servlet-name>
    <url-pattern>*.do</url-pattern>
</servlet-mapping>

</web-app>

3.创建请求页面
index.jsp:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    <p>第一个springmvc项目</p>
    <p><a href="${pageContext.request.contextPath}/some.do">发生some.do的请求</a> </p>
    <p><a href="${pageContext.request.contextPath}/other.do">发生other.do的请求</a> </p>
</body>
</html>

4.创建处理器
在类上添加@Controller注解,这个类就成了控制器、处理器,称之为后端控制器:banck controller
在类中的方法上添加@RequestMapping注解。使用@RequestMapping修饰的方法叫做处理器方法或控制器方法,用来处理请求,相当于sevlet中的service方法。

返回值:ModelAndView
Model:显示给用户的数据,
View:视图,如jsp等

package com.smb.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;

/**
 * @Controller :创建处理器对象,对象放在springmvc容器中。
 * 位置:在类的上面
 * 和spring中讲的@service ,@Component
 */
@Controller
public class MyController {
    /*处理用户提交的请求,springmvc中是使用方法来处理的。
    方法是自定义的,可以有多种返回值,多种参数,方法名称自定义*/

    /**
     * 准备使用dosome方法处理some.do请求。
     * @RequestMapping:
     *        请求映射,作用是把一个请求地址和一个方法绑定在一起。一个请求指定一个方法处理。
     *      属性:1. value是一个string,表示请求的uri地址的( some.do )。
     *          value的值必须是唯一的,不能重复。在使用时,推荐地址以“"
     *      位置:1.在方法的上面,常用的。
     *          2.在类的上面
     * 说明:使用RequestMapping修饰的方法叫做处理器方法或者控制器方法。
     * 使用@RequestMapping修饰的方法可以处理请求的,类似servlet中的doGet,doPost
     *
     * 返回值:ModelAndView 表示本次请求的处理结果
     *  Model:数据,请求处理完成后,要显示给用户的数据
     *  view:视图,比如jsp等等。
     */
    @RequestMapping(value = {"/some.do","/first.do"})
    public ModelAndView doSome(){
        //处理some.do请求了。相当于service调用处理完成了。
        ModelAndView mv = new ModelAndView();
        //添加数据 框架在请求的最后把数据放入到request作用域。
        mv.addObject("msg","欢迎使用springmvc做web开发");
        mv.addObject("fun","执行的是doSome方法");

        //指定视图,指定视图的完整路径
        //框架对视图执行的forward操作,request.getRequestDispather ("/show.jsp") . forward(..)
        //mv.setViewName("/show.jsp");

        //mv.setViewName("/WEB-INF/view/show.jsp");
        //mv.setViewName("/WEB-INF/view/other.jsp");

        //当配置了视图解析器后,可以使用逻辑名称(文件名),指定视图
        //框架会使用视图解析器的前缀+逻辑名称+后缀组成完成路径,这里就是字符连接操作
        // /WEB-INF/view/ + show + .jsp
        mv.setViewName("show");
        //返回mv
        return mv;
    }

    @RequestMapping(value = {"/other.do","/second.do"})
    public ModelAndView doOther(){
        ModelAndView mv = new ModelAndView();
        mv.addObject("msg","欢迎使用springmvc做web开发");
        mv.addObject("fun","执行的是doOther方法");
        mv.setViewName("other");
        return mv;
    }
}

5.声明组件扫描器
springmvc.xml配置文件

<!--声明组件扫描器-->
<context:component-scan base-package="com.smb.controller"/>

6.定义目标页面

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    <h3>/WEB-INF/view/show.jsp从request作用域获取数据</h3><br>
    <h3>msg数据:${msg}</h3><br>
    <h3>fun数据:${fun}</h3>
</body>
</html>

7.创建视图解析器
在当前项目中存在一个问题:用户可以通过地址栏直接访问show.jsp。
为了保护show.jsp的访问权限,可以将它放在WEB-INF目录或子目录下(WEB-INF)对用户来说是不可见的。
这样修改控制器中ModelAndView的ViewName到show。jsp的实际路径就可以解决这个问题。
SpringMVC可以简化setViewName参数冗长的字符串,通过配置视图解析器来实现。

例如,将show.jsp放在WEB-INF/view下:

配置视图解析器(springmvc.xml):

<!--声明 springmvc框架中的视图解析器,帮助开发人员设置视图文件的路径-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
    <!--前缀:视图文件的路径-->
    <property name="prefix" value="/WEB-INF/view/"/>

    <!--后缀:视图文件的扩展名-->
    <property name="suffix" value=".jsp"/>
</bean>

在控制器的doSome方法中,mv.setViewName(“/show.jsp”);写成mv.setViewName(“show”);

第二章 SpringMV注解式开发

2.1 @RequestMapping定义请求规则

@RequestMapping在控制器类上面的使用:
其value属性是此类中每个方法对应的请求路径(也就是 @RequestMapping注解的value属性值)的开头公共部分。

method属性指定请求方法
属性值是枚举类型RequestMethod,常用值RequestMethod.GET和RequestMethod.POST
当未指定请求方式时,无论哪种请求都会成功;
当请求方式与指定方式不匹配时,报错:405 Request method is not supported。

/**
 * @RequestMapping:
 *  value :所有请求地址的公共部分,叫做模块名称
 *  位置:放在类的上面
 */
@Controller
@RequestMapping(value = "/user")
public class MyController {
    /**
     *@RequestMapping :请求映射
     *      属性: method ,表示请求的方式。它的值RequestMethod类枚举值。
     *              例如表示get请求方式,RequestMethod.GET
     *              post方式,RequestMethod.Post
     */

    //指定some.do使用get请求方式
    @RequestMapping(value = "/some.do",method = RequestMethod.GET)
    public ModelAndView doSome(){
        ModelAndView mv = new ModelAndView();
        mv.addObject("msg","欢迎使用springmvc做web开发");
        mv.addObject("fun","执行的是doSome方法");
        mv.setViewName("show");
        return mv;
    }

    //指定other.do使用post请求方式
    @RequestMapping(value = "/other.do",method = RequestMethod.POST)
    public ModelAndView doOther(){
        ModelAndView mv = new ModelAndView();
        mv.addObject("msg","欢迎使用springmvc做web开发");
        mv.addObject("fun","执行的是doOther方法");
        mv.setViewName("other");
        return mv;
    }
}

2.2 处理器方法的参数

方法1.在控制器方法中添加形式参数HttpServletRequest、HttpServletResponse、HttpSession。
方法2.逐个接收请求参数:控制器方法中添加与参数名相同的形式参数即可。此参数可以直接使用。
注意:这种方式要求接受的参数(字符串)可以转化成形式参数类型,否则会报状态码为400的错误。
例如如果一个代表年龄参数没有值,则交给服务器的是一个空字符串"",此时就无法转化成int类型。
当请求参数名与处理器方法的形参名不同时,无法接收到参数。此时使用\@RequestParam注解解决这一问题。此注解添加在控制器方法的形参参数类型前,并给出value属性的值为此形参对应的请求参数名(字符串类型),例如请求参数是username,形参名是name:public ModelAndView doSome(@RequestParam(“username” String name, Integer age)){…}
@RequestParam注解还有一个属性required,其默认值为true,这样如果发送请求时未携带参数,就会报状态码为400的错误。可以手动设为false,表示发送的请求可以不携带此参数。
注意不携带此参数不等同于携带此参数但没有值。例如在表单中,即使没有填写某项参数就提交了,但请求依然会携带这个参数(只要此标签有name属性),只是值为空字符串而已。
方法3:使用对象接收参数:创建一个java类,其中包含与请求参数同名的属性,并进行封装。然后将控制器方法的形参换成此类型。在方法内部使用getter获取参数。
在请求发送到控制器时,框架会自动调用控制器方法参数类型的无参构造器,并使用setter赋值。

package com.smb.controller;

import com.smb.vo.Student;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

@Controller
public class MyController {

    /*   逐个接收请求参数:
        要求:处理器(控制器)方法的形参名和请求中参数名必须一致。
             同名的请求参数赋值给同名的形参
        框架接收请求参数
        1.使用request对象接收请求参数
            string strName = request.getParameter( "name");
            string strAge = request.getparameter("age");
        2. springmvc框架通过DispatcherServlet调用Mycontroller的doSome()方法
            调用方法时,按名称对应,把接收的参数赋值给形参
            dosome(strName, Integer.valueof(strAge))
            框架会提供类型转换的功能,能把string转为 int ,Long , float , double等类型。
        400
    */

    @RequestMapping(value = "/receivceproperty.do")
    public ModelAndView doSome(String name,Integer age){
        ModelAndView mv = new ModelAndView();
        mv.addObject("myname",name);
        mv.addObject("myage",age);
        mv.setViewName("show");
        return mv;
    }

    /**
     * 注意:
     *  在提交请求参数时,get请求方式中文没有乱码。
     *  使用post方式提交请求,中文有乱码,需要使用过滤器处理乱码的问题。
     *
     * 过滤器可以自定义,也可使用框架中提供的过滤器characterEncodingFilter
     */


    /**
     *请求中参数名和处理器方法的形参名不一样
     * @RequestParam: 解决请求中参数名形参名不一样的问题
     *      属性:1. value请求中的参数名称
     *           2.required是一个boolean,默认是true
     *              true :表示请求中以须包含此参数。
     *      位置:在处理器方法的形参定义的前面
     */
    @RequestMapping(value = "/receivcePara.do")
    public ModelAndView receivceParam(@RequestParam(value = "rname",required = false) String name,
                                      @RequestParam(value = "rage",required = false) Integer age){
        System.out.println("name="+name+","+"age="+age);
        ModelAndView mv = new ModelAndView();
        mv.addObject("myname",name);
        mv.addObject("myage",age);
        mv.setViewName("show");
        return mv;
    }

    /**
     *处理器方法形参是java对象,这个对象的属性名和请求中参数名一样的
     * 框架会创建形参的java对象,给属性赋值。请求中的参数是name,框架会调用setName()
     *
     */
    @RequestMapping(value = "/receivceObject.do")
    public ModelAndView receivceObject(Student myStudent){
        System.out.println("name="+myStudent.getName()+","+"age="+myStudent.getAge());
        ModelAndView mv = new ModelAndView();
        mv.addObject("myname",myStudent.getName());
        mv.addObject("myage",myStudent.getAge());
        mv.addObject("mystudent",myStudent);
        mv.setViewName("show");
        return mv;
    }

}

解决请求参数包含中文的乱码问题。
get请求方式没有乱码,post请求方式有乱码。
web.xml中设置过滤器

<!--注册声明过滤器,解决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>
    <!--强制请求对象( HttpservletRequest)使用encoding编码的值-->
    <init-param>
        <param-name>forceRequestEncoding</param-name>
        <param-value>true</param-value>
    </init-param>
    <!--强制应答对象( HttpservletResponse)使用encoding编码的值-->
    <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>

2.3 处理器方法的返回值

在这里插入图片描述

2.3.1 返回ModelAndView

有数据和视图,对视图执行forward

2.3.2 返回String

表示视图,只完成页面跳转工作。这个字符串可以是完整路径或逻辑名称(需要配置视图解析器

@Controller
public class MyController {
    /**
     * 处理器方法返回string--表示逻辑视图名称,需要配置视图解析器
     */
    @RequestMapping(value = "/returnString-view.do")
    public String doReturnView(HttpServletRequest request, String name, Integer age) {
        System.out.println("name=" + name + "," + "age=" + age);
        request.setAttribute("myname", name);
        request.setAttribute("myage", age);

        //show :逻辑视图名称,项目中配置了视图解析器
        // 框架对视图执行forward转发操作
        return "show";
    }

    //处理器方法返回string ,表示完整视图路径,此时不能配置视图解析器
    @RequestMapping(value = "/returnString-view2.do")
    public String doReturnView2(HttpServletRequest request, String name, Integer age) {
        System.out.println("name=" + name + "," + "age=" + age);
        request.setAttribute("myname", name);
        request.setAttribute("myage", age);

        //show :逻辑视图名称,项目中不能配置视图解析器
        // 框架对视图执行forward转发操作
        return "WEB-INF/view/show.jsp";
    }
}

2.3.3 返回void(了解)

不能表示数据,也不能表示视图。
一般的使用场景:处理AJAX请求。
通过HttpServletResponse输出数据。
1.创建项目,添加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

2.创建页面发送ajax请求:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
    <script type="text/javascript" src="js/jquery-3.6.0.js"></script>
    <script type="text/javascript">
        $(function () {
            $("button").click(function () {
                $.ajax({
                    //url:"returnVoid-ajax.do",
                    //url:"returnStudentJsonArray.do",
                    url:"returnStringData.do",
                    data:{
                        name:"zhangsan",
                        age:20
                    },
                    type:"post",
                    //dataType:"json",
                    success:function (resp) {
                        //[{"name":"zhangsan","age":21},{"name":"lisi","age":20}]
                        /*$.each(resp,function (i,n) {
                            alert(n.name+"   "+n.age);
                        })*/
                        alert("返回的是文本数据:"+resp)
                    }
                })
            })
        })
    </script>
</head>
<body>
    <button id="btn">发起ajax请求</button>
</body>
</html>

3.在控制器中处理并响应请求

//处理器方法返回void ,响应ajax请求
//手工实现ajax,json数据:代码有重复的 1.java对象转为json 2.通过HttpServle tResponse输出json数据
@RequestMapping(value = "/returnVoid-ajax.do")
public void doReturnVoidAjax(HttpServletResponse response, String name, Integer age) throws IOException {
    System.out.println("name=" + name + "," + "age=" + age);
    //处理ajax,使用json做数据的格式
    // service调用完成了,使用student表示处理结果
    Student student = new Student();
    student.setName(name);
    student.setAge(age);

    String json = "";
    //把结果的对象转为json格式的数据
    if (student != null) {
        ObjectMapper om = new ObjectMapper();
        json = om.writeValueAsString(student);
        System.out.println("student转换的json===" + json);
    }

    //输出数据,响应ajax的请求
    response.setContentType("application/json;charset=utf-8");
    PrintWriter out = response.getWriter();
    out.print(json);
    out.flush();
    out.close();
}

2.3.4 返回Object

在上面2.3.3的示例中,控制器方法的第二、三部分 代码(将结果对象转化为json格式的数据和输出数据)在许多方法中重复使用。只不过需要转化的数据类型不同。为了减少代码复用,这一部分由框架完成
1.添加jackson依赖。
2.添加注解驱动。(约束文件的地址是以mvc结尾) <mvc:annotation-driven/>

这一步的目的是完成数据类型的转换,例如2.3.3中的Object转换成json使用的是MappingJackson2HttpMessageConvener类。还有其他七个类,它们都实现了MessageConvener接口,由于不同的数据格式转换。
3.在控制器方法中添加注解@ResponseBody,将数据通过response对象返回。

返回值类型也可以是一个List集合,这样框架会自动将结果数据转化成json数组。顺序与List添加元素顺序相同。
当返回值类型是String的控制器方法添加了ResponseBody注解,此字符串不会作为视图处理,而是结果数据。如果包含中文,会出现乱码,在RequestMapping中添加属性produces=“text/plain;charset=utf-8”

@Controller
public class MyController {
    /**
     * 处理器方法返回一个student,通过框架转为json,响应ajax请求
     * @ResponseBody:
     *  作用:把处理器方法返回对象转为json后,通过 HttpServletResponse输出给浏览器。
     *  位置:方法的定义上面。和其它注解没有顺序的关系。
     *
     *  返回对象框架的处理流程:
     * 1.框架会把返回student类型,调用框架中的ArrayList<HttpMessageConverter>集合中每个类的canWrite()方法
     *    检查哪个HttpMessageConverter接口的实现类能处理Student类型的数据--MappingJackson2HttpMessageConverter
     *
     * 2.框架会调用实现类的write() ,MappingJackson2HttpMessageConverter的write()方法
     *    把李四同学的Student对象转为json ,调用Jackson的ObjectMapper实现转为json
     *
     *  3.框架会调用@ResponseBody把2的结果数据输出到浏览器,ajax请求处理完成
     */

    @RequestMapping(value = "/returnStudentJson.do")
    @ResponseBody
    public Student doStudentJsonObject(String name, Integer age)  {
        //service调用完成了,使用student表示处理结果
        Student student = new Student();
        student.setName("lisi");
        student.setAge(20);
        return student;
    }

    /**
     * 处理器方法返回List<student>
     */
    @RequestMapping(value = "/returnStudentJsonArray.do")
    @ResponseBody
    public List<Student> doStudentJsonObjectArray(String name, Integer age)  {
        List<Student> list=new ArrayList<>();
        //service调用完成了,使用student表示处理结果
        Student student1 = new Student();
        student1.setName("lisi");
        student1.setAge(20);
        Student student2 = new Student();
        student2.setName("zhangsan");
        student2.setAge(21);
        list.add(student2);
        list.add(student1);
        return list;
    }
    /**
     * 处理器方法返回的是string , String表示数据的,不是视图。
     * 区分返回值string是数据,还是视图,看有没有@ResponseBody注解
     * 如果有@ResponseBody注解,返回string就是数据,反之就是视图
     *
     * 默认使用text/plain;charset=ISO-8859-1”作为contentType,导致中文有乱码,
     * 解决方案;给RequestMapping增加一个属性 produces,使用这个属性指定新的contentType.
     */

    @RequestMapping(value = "/returnStringData.do",produces = "text/plain;charset=utf-8")
    @ResponseBody
    public String doStringData(String name,Integer age){
        return "Hello SpringMVC返回对象,表示数据";
    }
}

2.4 解读标签

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

<servlet>
    <servlet-name>springmvc</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:springmvc.xml</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
    <servlet-name>springmvc</servlet-name>

    <!--
        使用框架的时候,url-pattern可以使用两种值
        1,使用扩展名方式,语法*.xxx , xxx是自定义的扩展名。常用的方式 *. do
            不能使用*.jsp
            http:/ /localhost:8080/myweb/some.do
            http:/ /localhost:808o/myweb/other.do
        2.使用斜杠“/"
            当你的项目中使用了/,它会替代tomcat中的default
            导致所有的静态资源都给DispatcherServlet处理,默认情况下DispatcherServlet没有处理静态资源的能力。
            没有控制器对象能处理静态资源的访问。所以静态资源(html , js ,图片 ,css)都是404.

            动态资源some.do是可以访问,因为我们程序中有MyController控制器对象,能处理some. do请求。

    -->

    <!--<url-pattern>*.do</url-pattern>-->
    <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).

1.处理静态资源
2.处理未映射到其它servlet的请求。

在SpringMVC中,中央调度器处理各种请求,因此需要写各种url-patrern,如果只写/会很方便。但是会造成静态资源无法访问。

在中央调度器的url-pattern使用 / ,如何解决静态资源无法访问的问题?
方法一:

在springmvc.xml配置文件中添加:

<!-- default-servlet-handler和CRequestMapping注解有冲突,需要加入annotation-driven 解决问题 -->

<!--第一种处理静态资源的方式:
    需要在springmvc配置文件加入<mvc :default-servlet-handler>
    原理是︰加入这个标签后,框架会创健控制器对象DefaultServletHttpRequestHandler(类似我们自己创建的MyController )
    DefaultServletHttpRequestHandler这个对象可以把接收的请求转发给 tomcat的default这个servlet。
-->
<mvc:default-servlet-handler/>

其原理是创建DefaultServletHttpRequestHandler对象,类似于控制器,它能将静态资源请求转发给tomcat的defaultServlet。(requestDispatcher.forward)
方法二:
在springmvc.xml配置文件中添加:

 <!--第二种处理静态资源的方式
     mvc: resources加入后框架会创建 ResourceHttpRequestHandler这个处理器对象。
     让这个对象处理静态资源的访问,不依赖tomcat服务器。
     mapping:访问静态资源的uri地址,使用通配符**
     location:静态资源在你的项目中的目录位置。
 -->
   <mvc:resources mapping="/images/**" location="/images/"/>
   <mvc:resources mapping="/html/**" location="/html/"/>
   <mvc:resources mapping="/js/**" location="/js/"/>

   <!-- mvc:resources和@RequestMapping有一定的冲突-->
   <mvc:annotation-driven/>

   <!--使用一个配置语句,指定多种静态资源的访问-->
   <mvc:resources mapping="/static/**" location="/static/"/>

2.5 参考地址

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

地址分类:
 1.绝对地址 , 带有协议名称的是绝对地址,  http://www.baidu.com , ftp://202.122.23.1
 2.相对地址, 没有协议开头的, 例如 user/some.do  , /user/some.do
              相对地址不能独立使用,必须有一个参考地址。 通过参考地址+相对地址本身才能指定资源。

				  张三同学, 1班有张三, 2班也有张三

 3.参考地址
    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 组成访问地址
        
<%--获取基础路径--%>
<%
    String basePath = request.getScheme() + "://" +
            request.getServerName() + ":" + request.getServerPort() +
            request.getContextPath() + "/";
%>
<base href="<%=basePath%>">




   2)在你的页面中的,访问地址加 "/"
      访问的是: 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>

第三章 SSM整合开发

在这里插入图片描述在这里插入图片描述

1.建立数据库,创建Maven项目,并添加依赖(pom.xml)

2.配置 web.xml

(1)注册中央调度器DispatcherServlet
 目的:
  1.创建springmvc容器对象,才能创建controller类对象。
  2.创建的是servlet ,才能接受用户的请求。

(2)注册spring的监听器:ContextLoaderListener
 目的:创建spring的容器对象,才能创建service,dao等对象

(3)注册字符集过滤器,解决post请求乱码的问题

  <!--注册中央调度器-->
  <servlet>
    <servlet-name>springmvc</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
      <param-name>contextConfigLocation</param-name>
      <param-value>classpath:conf/dispatcherServlet.xml</param-value>
    </init-param>

    <load-on-startup>1</load-on-startup>
  </servlet>
  <servlet-mapping>
    <servlet-name>springmvc</servlet-name>
    <url-pattern>*.do</url-pattern>
    <!--<url-pattern>/</url-pattern>-->
  </servlet-mapping>
  
  <!--注册spring的监听器-->
  <context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>classpath:conf/applicationContext.xml</param-value>
  </context-param>
  <listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
  </listener>

  <!--注册字符集过滤器,解决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>
    <!--强制请求对象( HttpservletRequest)使用encoding编码的值-->
    <init-param>
      <param-name>forceRequestEncoding</param-name>
      <param-value>true</param-value>
    </init-param>
    <!--强制应答对象( HttpservletResponse)使用encoding编码的值-->
    <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>

3.创建包,组织程序的结构。

Controller包, service ,dao ,实体类包名创建好
在这里插入图片描述

4. 编写配置文件

(1)Jdbc 属性配置文件 jdbc.properties

jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/jdbcStudy?useUnicode=true&characterEncoding=utf8&useSSL=true
jdbc.username=root
jdbc.password=123456
jdbc.max=20

(2)Spring 配置文件 applicationContext.xml

<!--spring配置文件:声明service , dao ,工具类等对象-->

<!--声明数据源,连接数据库-->
<context:property-placeholder location="classpath:conf/jdbc.properties"/>
<!--声明数据源DataSource,作用是连接数据库的-->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"
      init-method="init" destroy-method="close">
    <property name="url" value="${jdbc.url}"/>
    <property name="username" value="${jdbc.username}"/>
    <property name="password" value="${jdbc.password}"/>
</bean>

<!--SqlSessionFactoryBean创建SqlSessionFactory-->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
    <property name="dataSource" ref="dataSource"/>
    <property name="configLocation" value="classpath:conf/mybatis.xml"/>
</bean>

<!--声明mybatis的扫描器,创建dao对象-->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
    <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
    <property name="basePackage" value="com.smb.dao"/>
</bean>

<!--声明service的注解@Service所在的包名位置-->
<context:component-scan base-package="com.smb.service"/>

<!--事务配置:注解的配置, aspectj的配置-->

(3)Springmvc 配置文件:springmvc.xml

<!--springmvc配置文件,声明controller和其它web相关的对象-->

<!--组件扫描器-->
<context:component-scan base-package="com.smb.controller"/>

<!--声明视图解析器-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
    <property name="prefix" value="/WEB-INF/jsp/"/>
    <property name="suffix" value=".jsp"/>
</bean>

<!--加入注解驱动-->
<mvc:annotation-driven/>
<!-- 1.响应ajax请求,返回json
2.解决静态资源访问问题。-->

(4)mybatis.xml

<!--settings :控制mybatis全局行为
   <settings>
       &lt;!&ndash;设置mybatis输出日志&ndash;&gt;
       <setting name="logImpl" value="STDOUT_LOGGING"/>
   </settings>-->

   <!--设置别名-->
   <typeAliases>
       <!--name:实体类所在的包名(不是实体类的包名也可以)-->
       <package name="com.smb.domain"/>
   </typeAliases>

   <!-- sql mapper(sql映射文件)的位置-->
   <mappers>
       <!--name :是包名,这个包中的所有mapper.xml一次都能加载
           使用package的要求:
           1.mapper文件名称和dao接口名必须完全一致,包括大小写
           2.mapper文件和dao接口必须在同一目录
       -->
       <package name="com.smb.dao"/>
   </mappers>

5.写代码,实体类,dao接口和mapper文件,service和实现类

(1)实体类Student

public class Student {
    private Integer id;
    private String name;
    private Integer age;
	//set和get方法
}

(2) Dao 接口和 sql mapper文件

public interface StudentDao {
    int insertStudent(Student student);
    List<Student> selectStudents();
}
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.smb.dao.StudentDao">
    <select id="selectStudents" resultType="Student">
        select id,name,age from student order by id asc;
    </select>
    <insert id="insertStudent">
        insert into student(name,age) values(#{name},#{age})
    </insert>
</mapper>

(3) Service 接口和实现类

public interface StudentService {
    int addStudent(Student student);
    List<Student> findStudents();
}
@Service
public class StudentServiceImpl implements StudentService {
    //引用类型自动注入@Autowired,@Resource
    @Resource
    private StudentDao studentDao;

    @Override
    public int addStudent(Student student) {
        int nums = studentDao.insertStudent(student);
        return nums;
    }

    @Override
    public List<Student> findStudents() {
        List<Student> students = studentDao.selectStudents();
        return students;
    }
}

(4) 处理器定义 StudentController

@Controller
@RequestMapping("/student")
public class StudentController {

    @Resource
    private StudentService service;

    //注册学生
    @RequestMapping("/addStudent.do")
    public ModelAndView addStudent(Student student){
        ModelAndView mv=new ModelAndView();
        String tips="注册失败";
        //调用service处理student
        int nums = service.addStudent(student);
        if(nums>0){
            //注册成功
            tips="学生【"+student.getName()+"】注册成功";
        }

        //添加数据
        mv.addObject("tisps",tips);

        //指定结果页面
        mv.setViewName("result");
        return mv;
    }

    //处理查询,响应ajax
    @RequestMapping("/queryStudent.do")
    @ResponseBody
    public List<Student> queryStudent(){
        List<Student> students = service.findStudents();
        return students;
    }
}

6.写jsp页面

(1) 定义视图-首页文件— index.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%
    String basePath = request.getScheme() + "://" +
            request.getServerName() + ":" + request.getServerPort() +
            request.getContextPath() + "/";
%>
<html>
<head>
    <title>功能入口</title>
    <base href="<%=basePath%>">
</head>
<body>
    <div align="center">
        <p>SSM整合</p>
        <img src="images/1.png">
        <table>
            <tr>
                <td><a href="addStudent.jsp">注册学生</a> </td>
            </tr>
            <tr>
                <td><a href="listStudent.jsp">浏览学生</a> </td>
            </tr>
        </table>
    </div>
</body>
</html>

(2)注册学生页面 — addStudent.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%
    String basePath = request.getScheme() + "://" +
            request.getServerName() + ":" + request.getServerPort() +
            request.getContextPath() + "/";
%>
<html>
<head>
    <title>注册学生</title>
    <base href="<%=basePath%>">
</head>
<body>
    <div align="center">
        <form action="student/addStudent.do" method="post">
            <table>
                <tr>
                    <td>姓名:</td>
                    <td><input type="text" name="name"></td>
                </tr>
                <tr>
                    <td>年龄:</td>
                    <td><input type="text" name="age"></td>
                </tr>
                <tr>
                    <td>&nbsp;&nbsp;&nbsp;&nbsp;</td>
                    <td><input type="submit" value="注册学生"></td>
                </tr>
            </table>
        </form>
    </div>
</body>
</html>

(3) 浏览学生页面 — listStudent.jsp
页面表格

<head>
    <title>查询学生ajax</title>
    <base href="<%=basePath%>">
    <script type="text/javascript" src="js/jquery-3.6.0.js"></script>
    <script type="text/javascript">
        $(function () {
            //在当前页面dom对象加载后,执行loadStudentData ( )
            loadStudentData();
            $("#btnLoader").click(function () {
                loadStudentData();
            })
        })

        function loadStudentData() {
            $.ajax({
                url:"student/queryStudent.do",
                type:"get",
                dataType:"json",
                success:function (data) {
                    //清除旧的数据
                    $("#info").html("");
                    //添加新的数据
                    $.each(data,function (i,n) {
                        $("#info").append("<tr>")
                            .append("<td>"+n.id+"</td>")
                            .append("<td>"+n.name+"</td>")
                            .append("<td>"+n.age+"</td>")
                            .append("</tr>")
                    })
                }
            })
        }
    </script>
</head>
<body>
    <div align="center">
        <table>
            <thead>
                <tr>
                    <td>学号</td>
                    <td>姓名</td>
                    <td>年龄</td>
                </tr>
            </thead>
            <tbody id="info">

            </tbody>
        </table>
        <input type="button" id="btnLoader" value="查询数据">
    </div>

</body>

js 发起 ajax

(4)注册学生结果页面

<body>
    result.jsp 结果页面,注册结果:${tisps}
</body>

第四章 SpringMVC核心技术

4.1 请求转发与重定向

4.1.1 请求转发

特点: 不与视图解析器一同使用
用途: 可以转发至视图解析器指定的资源以外的资源。
moduleAndView对象.setViewName(“forward:转发目标完整路径”);
//forward是关键字

@Controller
public class MyController {
    /**
     * 处理器方法返回ModelAndView,实现转发forward
     * 语法: setViewName( "forward:视图文件完整路徭")
     * forward特点:不和视图解析器一同使用,就当项目中没有视图解析器
     */
    @RequestMapping(value = "/doForward.do")
    public ModelAndView doSome(){
        ModelAndView mv = new ModelAndView();
        mv.addObject("msg","欢迎使用springmvc做web开发");
        mv.addObject("fun","执行的是doSome方法");
        //显示转发
        mv.setViewName("forward:/WEB-INF/view/show.jsp");
        return mv;
    }
}

4.1.2 重定向

**特点:**不与视图解析器一同使用。本质是两次访问,不能访问WEB-INF目录下的资源
传参:
由于是两次不同的请求,因此不能通过getAttribute获得参数。当我们向ModelAndView对象添加数据(addObject方法)以后,这些数据会在发送第二次请求时以get方式呈现在url后(?参数名=参数值&…)
moduleAndView对象.setViewName(“redirect:转发目标完整路径”);
//redirect是关键字

* 框架对重定向的操作:
* 1.框架会把Model中的简单类型的数据,转为string使用,作为hello.jsp的get请求参数使用。
*      目的是在doRedirect.do和 hello.jsp两次请求之间传递数据
* 2.在目标hello.jsp页面可以使用参数集合对象${param}获取请求参数值
*      ${param.myname}
*
* 3.重定向不能访问/wEB-INF资源

@RequestMapping(value = "/doRedirect.do")
public ModelAndView doOther(String name,Integer age){
   ModelAndView mv = new ModelAndView();
   mv.addObject("myname",name);
   mv.addObject("myage",age);
   //重定向
   mv.setViewName("redirect:/show.jsp");
   return mv;
}

show.jsp
<h3>myname数据:${param.myname}</h3><br>
<h3>myage数据:${param.myage}</h3>
<h3>取参数数据:<%=request.getParameter("myname")%></h3>

4.2 异常处理

SpringMVC处理异常使用的是AOP的思想,其目的是将异常处理的代码与业务代码分开,达到解耦合的目的。
1.创建自定义的异常
自定义的异常类需要继承java.lang.Exception,并至少给出无参构造器和带有String参数的构造器。

public class MyUserException extends Exception{

    public MyUserException() {
    }

    public MyUserException(String message) {
        super(message);
    }
}

2.在Controller中向上抛出这些异常

@Controller
public class MyController {
    @RequestMapping(value = "/some.do")
    public ModelAndView doOther(String name,Integer age) throws MyUserException {
        ModelAndView mv = new ModelAndView();
        //根据请求参数抛出异常
        if(!"zs".equals(name)){
            throw new NameException("姓名不正确!!!");
        }
        if(age==null||age>80){
            throw new AgeException("年龄不正确!!!");
        }
        mv.addObject("myname",name);
        mv.addObject("myage",age);
        //重定向
        mv.setViewName("show");
        return mv;
    }
}

3.创建异常处理的切面类
在类前添加注解:@controllerAdvice
在类中给出异常处理的切面方法。这些方法的定义规则与第二章中控制器方法的定义规则相同,还可以添加一个形参Exception表示要处理的异常对象。在方法前添加注解:@ExceptionHandler 其value属性类型是Class,表示要处理的异常类型(value=异常类名.class)。如果没有value属性,则此方法用来处理未指定的异常类型。

/**
 * @controllerAdvice :控制器增强(也就是说给控制器类增加功能--异常处理功能)
 *                      位置:在类的上面。
 * 特点:必须让框架知道这个注解所在的包名,需要在springmvc配置文件声明组件扫描器。
 * 指定@ControllerAdvice所在的包名
 */
@ControllerAdvice
public class GlobalExceptionHandler {
    //定义方法,处理发生的异常

    /*
        处理异常的方法和控制器方法的定义一样,可以有多个参数,
        可以有ModelAndView,string,void,对象类型的返回值

        形参:Exception ,表示Controller中抛出的异常对象。
        通过形参可以获取发生的异常信息。

        @ExceptionHandler(异常的class):表示异常的类型,
        当发生此类型异常时,由当前方法处理
     */
    @ExceptionHandler(value = NameException.class)
    public ModelAndView doNameException(Exception exception){
        //处理NameException的异常
        /*
            异常发生处理逻辑:
            1.需要把异常记录下来,记录到数据库,日志文件。
            记录日志发生的时间,哪个方法发生的,异常错误内容。
            2.发送通知,把异常的信息通过邮件,短信﹐微信发送给相关人员。
            3.给用户友好的提示。
        */
        ModelAndView mv = new ModelAndView();
        mv.addObject("msg","姓名必须是zs,其他用户不能访问");
        mv.addObject("ex",exception);
        mv.setViewName("nameError");
        return mv;
    }
}

4.在springmvc配置文件中添加标签扫描器与注解驱动:

 <!--处理需要的两步-->
 <context:component-scan base-package="com.smb.handler"/>
 <mvc:annotation-driven/>

4.3 拦截器

4.3.1 一个拦截器的执行

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

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

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


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

1.定义类实现HandlerInterceptor接口
MyInterceptor类

package com.smb.handler;

import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Date;

//拦截器类:拦截用户的请求。
public class MyInterceptor implements HandlerInterceptor {
    private long btime=0;
    /**
     *preHandle叫做预处理方法。
     * 参数:
     *  object handler :被拦截的控制器对象
     * 返回值boolean
     *  特点∶
     *      1.方法在控制器方法(MyController的dosome )之前先执行的。
     *      用户的请求首先到达此方法
     *      2.在这个方法中可以获取请求的信息,验证请求是否符合要求。
     *      可以验证用户是否登录,验证用户是否有权限访问某个连接地址( url )。
     *      如果验证失败,可以截断请求,请求不能被处理。
     *      如果验证成功,可以放行请求,此时控制器方法才能执行。
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        btime=System.currentTimeMillis();
        System.out.println("拦截器的MyInterceptor的preHanded()");
        return true;
    }

    /**
     * postHandle:后处理方法。
     *  参数:
     *     object handler:被拦截的处理器对象MyController
     *     ModelAndView mv;处理器方法的返回值
     *     特点∶
     *         1.在处理器方法之后执行的( MyController. doSome() )
     *         2.能够获取到处理器方法的返回值NodelAndView,可以修改ModelAndView中的数据和视图,
     *         可以影响到最后的执行结果。
     *         3.主要是对原来的执行结果做二次修正﹐
     */

    @Override
    public void postHandle(HttpServletRequest request,
                           HttpServletResponse response,
                           Object handler, ModelAndView mv) throws Exception {
        System.out.println("拦截器的MyInterceptor的postHandle()");
        //对原来的dosome执行结果,需要调整。
        if (mv != null) {
            mv.addObject("mydate",new Date());
            mv.setViewName("other");
        }

    }

    /**
     * afterCompletion:最后执行的方法
     * 参数
     *  object handler:被拦截器的处理器对象
     *  Exception ex:程序中发生的异常
     * 特点:
     *  1.在请求处理完成后执行的。框架中规定是当你的视图处理完成后,对视图执行了forward。就认为请求处理完成。
     *  2.一般做资源回收工作的,程序请求过程中创建了一些对象,在这里可以删除,把占用的内存回收。
     */
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("拦截器的MyInterceptor的afterCompletion()");

        long etime=System.currentTimeMillis();
        System.out.println("计算从preHandle到请求处理完成的时间:"+(etime-btime));
    }
}

2.在springmvc配置文件中,声明拦截器

<!--声明拦截器:拦截器可以有0个或多个-->
<mvc:interceptors>
    <mvc:interceptor>
        <!--指定拦截的请求uri地址(path)-->
        <mvc:mapping path="/**"/>
        <!--声明拦截器对象-->
        <bean class="com.smb.handler.MyInterceptor"/>
    </mvc:interceptor>
</mvc:interceptors>

4.3.2 多个拦截器的执行

多个拦截器:
第一个拦截器preHandle=true , 第二个拦截器preHandle=true 

111111-拦截器的MyInterceptor的preHandle()
22222-拦截器的MyInterceptor的preHandle()
=====执行MyController中的doSome方法=====
22222-拦截器的MyInterceptor的postHandle()
111111-拦截器的MyInterceptor的postHandle()
22222-拦截器的MyInterceptor的afterCompletion()
111111-拦截器的MyInterceptor的afterCompletion()

---------------------------------------------------
第一个拦截器preHandle=true , 第二个拦截器preHandle=false

111111-拦截器的MyInterceptor的preHandle()
22222-拦截器的MyInterceptor的preHandle()
111111-拦截器的MyInterceptor的afterCompletion()

----------------------------------------------------------
第一个拦截器preHandle=false , 第二个拦截器preHandle=true|false

111111-拦截器的MyInterceptor的preHandle()

在这里插入图片描述
拦截器和过滤器的区别

1.过滤器是servlet中的对象, 拦截器是框架中的对象
2.过滤器实现Filter接口的对象, 拦截器是实现HandlerInterceptor
3.过滤器是用来设置request,response的参数,属性的,侧重对数据过滤的。
拦截器是用来验证请求的,能截断请求。
4.过滤器是在拦截器之前先执行的。
5.过滤器是tomcat服务器创建的对象
拦截器是springmvc容器中创建的对象
6.过滤器是一个执行时间点。
拦截器有三个执行时间点
7.过滤器可以处理jsp,js,html等等
拦截器是侧重拦截对Controller的对象。 如果你的请求不能被DispatcherServlet接收, 这个请求不会执行拦截器内容
8.拦截器拦截普通类方法执行,过滤器过滤servlet请求响应

SpringMVC 执行流程(理解)

在这里插入图片描述

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值