一文学会SpringMVC,SpringMVC最简单的入门教程(万字好文)

第一章 SpringMVC概述

1.1 SpringMVC基本说明

SpringMVC是基于spring的,是spring中的一个模块,做web开发用的。springmvc叫做spring web mvc,说明他是spring的核心技术,做web开发,springmvc内部是使用mvc框架模式。

SpringMVC是一个容器,管理对象的,使用IoC核心技术。

SpringMVC管理界面层中的控制器对象。

SpringMVC底层也是Servlet,以Servlet为核心,接收请求,处理请求。显示处理结果给用户。

处理用户的请求:

用户发起请求—SpringMVC—Spring—MyBatis—Mysql数据库

1.2 SpringMVC中的核心Servlet – DispatcherServlet

DispatcherServlet是框架中的一个Servlet对象。负责接收请求,响应处理结果。

DispatcherServlet他的父类是HttpServlet

DispatcherServlet也叫做前端控制器(front controller)

SpringMVC是管理控制器对象,原来没有SpringMVC之前使用Servlet作为控制器对象使用。现在通过SpringMVC容器创建一种叫做控制器的对象,代替Servlet行使控制器的功能。

例子:

需求:用户发起一个请求,springmvc接收请求,显示请求的处理结果

servlet的实现方式:
    jsp发起请求---servlet---jsp显示结果

步骤:
1.新建web应用
2.加入web依赖
    spring-webmvc依赖(springmvc框架依赖),servlet依赖

3.声明springmvc核心对象DispatcherServlet
    1) DispatcherServlet是一个Servlet对象
    2) DispatcherServlet叫做前端控制器(front controller)
    3) DispatcherServlet作用:
        1.在servlet的init()方法中,创建springmvc中的容器对象
        2.作为servlet,接收请求

4.创建一个jsp,发起请求

5.创建一个普通的类,作为控制器使用(代替之前的servlet)
    1) 在类的上面加入@Controller注解
    2) 在类中定义方法,方法的上面加入@RequestMapping注解
       方法处理请求的,相当于servlet的doGet,doPost

6.创建作为结果的jsp页面

7.创建springmvc的配置文件(spring的配置文件一样)
    1) 声明组件扫描器,指定@Controller注解所在的包
    2) 声明视图解析器对象

pom.xml文件:



<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0modelVersion>

  <groupId>org.examplegroupId>
  <artifactId>SpringMVC-01artifactId>
  <version>1.0-SNAPSHOTversion>
  <packaging>warpackaging>

  <name>SpringMVC-01 Maven Webappname>
  
  <url>http://www.example.comurl>

  <properties>
    <project.build.sourceEncoding>UTF-8project.build.sourceEncoding>
    <maven.compiler.source>10maven.compiler.source>
    <maven.compiler.target>10maven.compiler.target>
  properties>

  <dependencies>
    <dependency>
      <groupId>junitgroupId>
      <artifactId>junitartifactId>
      <version>4.11version>
      <scope>testscope>
    dependency>

    <dependency>
      <groupId>org.springframeworkgroupId>
      <artifactId>spring-webmvcartifactId>
      <version>5.3.4version>
    dependency>

    <dependency>
      <groupId>javax.servletgroupId>
      <artifactId>javax.servlet-apiartifactId>
      <version>4.0.1version>
    dependency>
  dependencies>

  <build>
    <finalName>SpringMVC-01finalName>
    <pluginManagement>
      <plugins>
        <plugin>
          <artifactId>maven-clean-pluginartifactId>
          <version>3.1.0version>
        plugin>
        
        <plugin>
          <artifactId>maven-resources-pluginartifactId>
          <version>3.0.2version>
        plugin>
        <plugin>
          <artifactId>maven-compiler-pluginartifactId>
          <version>3.8.0version>
        plugin>
        <plugin>
          <artifactId>maven-surefire-pluginartifactId>
          <version>2.22.1version>
        plugin>
        <plugin>
          <artifactId>maven-war-pluginartifactId>
          <version>3.2.2version>
        plugin>
        <plugin>
          <artifactId>maven-install-pluginartifactId>
          <version>2.5.2version>
        plugin>
        <plugin>
          <artifactId>maven-deploy-pluginartifactId>
          <version>2.8.2version>
        plugin>
      plugins>
    pluginManagement>
  build>
project>

web.xml文件:


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

  

  <servlet>
    <servlet-name>springmvcservlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServletservlet-class>
    
    <init-param>
      <param-name>contextConfigLocationparam-name>
      <param-value>classpath:springmvc-servlet.xmlparam-value>
    init-param>
    
    <load-on-startup>1load-on-startup>
  servlet>
  <servlet-mapping>
    <servlet-name>springmvcservlet-name>
    
    <url-pattern>*.dourl-pattern>
  servlet-mapping>
web-app>

springmvc-servlet.xml文件:


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

    
    <context:component-scan base-package="com.lu.controller">context:component-scan>

    
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        
        <property name="prefix" value="/WEB-INF/view/">property>
        
        <property name="suffix" value=".jsp">property>
    bean>
beans>

Controller类:

package com.lu.controller;

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

/**
 * @Controller:创建控制器对象
 *  控制器:叫做后端控制器(back controller),自定义的类处理请求的
 *  位置:在类的上面,表示创建此类的对象,对象放在springmvc的容器中
 * */
@Controller
public class MyController {

    //定义方法,处理请求。public void doGet(){}

    /**
     * springmvc框架,使用控制器类中的方法,处理请求
     * 方法的特点:
     * 1. 方法的形参,表示请求中的参数
     * 2.方法的返回值,表示本次请求的处理结果
     *
     *
     * @RequestMapping:请求映射
     *      属性:value 请求中的url地址,唯一值,以 "/" 开头
     *      位置:1.在方法的上面(必须) 2.在类定义的上面(可选)
     *      作用:把指定的请求,交给指定的方法处理,等同于url-pattern
     *
     * 返回值ModelAndView:表示本次请求的处理结果(数据和视图)
     *      Model:表示数据
     *      View:表示视图
     * */

    @RequestMapping(value = {"/some.do","/first.do"})
    public ModelAndView doSome() { //doGet()
        //使用这个方法处理请求。能处理请求的方法叫做控制器方法
        //调用service对象,处理请求,返回数据
        ModelAndView mv = new ModelAndView();
        //添加数据
        mv.addObject("msg","处理了some.do请求");
        mv.addObject("fun","执行了doSome方法");

        //指定视图,setViewName("视图的完整路径")
        //mv.setViewName("/show.jsp");
        //mv.setViewName("/WEB-INF/view/show.jsp");

        //当配置了视图解析器,使用文件名称作为视图名使用,叫做视图逻辑名称
        //使用了逻辑名称,框架使用配置文件中视图解析器的前缀和后缀,拼接为完整视图路径
        //    /WEB-INF/view/ + show + .jsp
        mv.setViewName("show");
        //返回结果
        return mv;
    }

    /**
     * 当框架调用完doSome()方法后,得到返回中ModelAndView
     * 框架会在后续的处理逻辑值,处理mv对象里面的数据和视图
     * 对数据执行 request.setAttribute("msg","处理了some.do请求"); 把数据放入到request作用域
     * 对视图执行forward转发操作。等同于request.getRuestDispather("/show.jsp").forward(..)
     * */



    @RequestMapping(value = {"/other.do","/test/second.do"})
    public ModelAndView doOther() { //doGet()

        ModelAndView mv = new ModelAndView();

        mv.addObject("msg","处理了other.do请求");
        mv.addObject("fun","执行了doOther方法");

        mv.setViewName("other");

        return mv;
    }
}

1.3 SpringMVC请求的处理过程

简单的处理过程:

用户发起请求some.do—>tomcat接收了请求—>DispatcherServlet—>分配MyController(doSome() 返回mv对象)—>mv显示给用户

省略tomcat

用户some.do-------->DispatcherServlet-------->MyController

如果使用servlet处理请求

用户发起请求----------->没有其他对象-------------->Servlet

1.4 复习

用户发起some.do----DispatcherServlet(Servlet接收请求)-----转发给MyController


public class DispatcherServlet extends HttpServlet() {
	public void service(HttpServletRequest request,HttpServletResponse response) {
		if("some.do".equals(request.getURL())){
            //从容器中获取MyController
            MyController c = ctx.getBean("some");
            c.doSome();
        }else if("other.do".equals(request.getURL())){
            OtherController c = ctx.getBean("other");
            c.doOther();
        }	
	}
}

1.5 web开发中配置文件的说明

1.web.xml 部署描述符文件,给服务器(tomcat)

​ 作用:服务器在启动的时候,读取web.xml。根据文件中的声明去创建各种对象

​ 根据文件中的声明,知道 请求和servlet等对象的关系

2.框架的配置文件,springmvc的配置文件

​ 作用:声明框架创建的各种对象,主要是创建Controller对象

配置文件的加载顺序和声明

1.tomcat服务器启动,读取web,xml,根据web.xml文件中的说明,创建对象


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

  <servlet>
    <servlet-name>springmvcservlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServletservlet-class>
    <init-param>
      <param-name>contextConfigLocationparam-name>
      <param-value>classpath:springmvc-servlet.xmlparam-value>
    init-param>
    <load-on-startup>1load-on-startup>
  servlet>

  <servlet-mapping>
    <servlet-name>springmvcservlet-name>
    <url-pattern>*.dourl-pattern>
  servlet-mapping>


web-app>

创建DispatcherServlet他的对象,会执行init()方法。在init()方法中会执行springmvc容器对象创建

WebApplicationContext ctx = new ClassPathXmlApplicationContext(“classpath:springmvc.xml”)

2.springmvc框架,new ClassPathXmlApplicationContext() 读取springmvc的配置文件


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

    <context:component-scan base-package="com.lu.controller">context:component-scan>

    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/view/">property>
        <property name="suffix" value=".jsp">property>
    bean>
beans>

使用组件扫描器base-package=“com.lu.controller”,遍历controller包中的所有类

MyController类,找到这个类中的@Controller,@RequestMapping注解,就能创建MyController对象。

知道some.do请求时执行doSome()方法、

3.用户发起请求some.do----DispatcherServlet

DispatcherServlet里面有WebApplicationContext,WebApplicationContext里面有MyController对象

请求some.do,DispatcherServlet就知道时MyController处理的

第二章 SpringMVC注解式开发

2.1 @RequestMapping注解的使用

属性:value 请求的url地址

位置:

  1. 在方法的上面,必须的
  2. 在类的上面作为模块名称

先看Controller类

package com.lu.controller;

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

@Controller
public class MyController {

    @RequestMapping(value = {"/test/some.do","/test/first.do"})
    public ModelAndView doSome() {
        System.out.println("执行了MyController的doSome()方法");

        ModelAndView mv = new ModelAndView();
        mv.addObject("msg","处理了some.do请求");
        mv.addObject("fun","执行了doSome方法");

        mv.setViewName("show");

        return mv;
    }

    @RequestMapping(value = {"/test/other.do","/test/second.do"})
    public ModelAndView doOther() {
        System.out.println("执行了MyController的doOther()方法");

        ModelAndView mv = new ModelAndView();
        mv.addObject("msg","处理了other.do请求");
        mv.addObject("fun","执行了doOther方法");

        mv.setViewName("other");

        return mv;
    }
}

配置tomcat后我们访问地址,是下面这两行

https://localhost:8443/test/some.do

https://localhost:8443/test/second.do

我们可以把@RequestMapping放在类的上面

package com.lu.controller;

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


@Controller
@RequestMapping("/test")
public class MyController {

    @RequestMapping(value = {"/some.do","/first.do"})
    public ModelAndView doSome() {
        System.out.println("执行了MyController的doSome()方法");

        ModelAndView mv = new ModelAndView();
        mv.addObject("msg","处理了some.do请求");
        mv.addObject("fun","执行了doSome方法");

        mv.setViewName("show");

        return mv;
    }

    @RequestMapping(value = {"/other.do","/second.do"})
    public ModelAndView doOther() {
        System.out.println("执行了MyController的doOther()方法");

        ModelAndView mv = new ModelAndView();
        mv.addObject("msg","处理了other.do请求");
        mv.addObject("fun","执行了doOther方法");

        mv.setViewName("other");

        return mv;
    }
}

属性method请求的方式,使用RequestMethod类的枚举,表示请求方式

//请求方式不一样,错误码是 405
//指定some.do使用get请求方式
@RequestMapping(value = "/some.do", method = RequestMethod.GET)
public ModelAndView doSome() {}

2.2 接收请求中的参数

对应HttpServletRequest,HttpServletResponse,HttpSession 只需要在控制器方法的形参列表中定义就可以了。框架会给参数赋值,在控制器方法内部可以直接使用request,reponse,session参数。

400:http status,表示客户端异常,主要是发生在用户提交参数过程中。

接收请求中的参数:逐个接收;对象接收

2.2.1 逐个接收

逐个接收:请求中的参数名和控制器方法的形参名一样,按照名称

逐个接收请求参数

姓名:
年龄:
@RequestMapping(value = "receive_property.do")
public ModelAndView doPropertyParam(String name, Integer age) {
    System.out.println("执行了MyController的doPropertyParam方法,name:" + name + " age:" + age);
    ModelAndView mv = new ModelAndView();
    mv.addObject("myname",name);
    mv.addObject("myage",age);
    mv.setViewName("show");

    return mv;
}

接收参数的问题:

  1. 参数最好使用包装类型。例如Integer,能够接收空值情况,接收的是null
  2. 框架可以使用String到int,long,float,double等类型的转换
  3. post请求中有乱码的问题,可以使用字符集过滤器

CharacterEncodingFilter使用:


<filter>
  <filter-name>encodingfilter-name>
  <filter-class>org.springframework.web.filter.CharacterEncodingFilterfilter-class>
  
  <init-param>
    
    <param-name>encodingparam-name>
    <param-value>utf-8param-value>
  init-param>

  <init-param>
    
    <param-name>forceRequestEncodingparam-name>
    <param-value>trueparam-value>
  init-param>

  <init-param>
    
    <param-name>forceResponseEncodingparam-name>
    <param-value>trueparam-value>
  init-param>
filter>

<filter-mapping>
  <filter-name>encodingfilter-name>
  
  <url-pattern>/*url-pattern>
filter-mapping>

2.2.3 请求中参数名和形参名不一致,使用@RequestParam

/**
 * 逐个接收请求参数:请求中参数名和形参名不一致
 * @RequestParam:解决名称不一样的问题
 *          属性:value 请求中的参数名称
 *               required:boolean类型的,默认是true
 *                        true:请求中必须有此参数,没有报错
 *          位置:在形参定义的前面
 * */
@RequestMapping(value = "receive_param.do")
public ModelAndView doReceiveParam(@RequestParam(value = "rname",required = false) String name,
                                   @RequestParam("rage") Integer age) {}

2.2.4 对象接收

对象接收:在控制器方法的形参是Java对象,使用Java对象的属性接收请求中的参数值

要求:Java对象的属性名和请求中参数名一致。

例子:

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

/**
     * 使用对象接收请求中的参数
     * 要求:参数名和Java对象的属性名一样
     *      Java类需要有一个无参数构造方法,属性有set方法
     *
     * 框架的处理:
     *  1.调用Student的无参数构造方法,创建对象
     *  2.调用对象set方法,同名的参数,调用对应的set方法
     *    参数是name,调用setName(参数名)
     * */
    @RequestMapping("receive_object.do")
    public ModelAndView doReceiveObject(Student student) {
        System.out.println("MyController的方法doReceiveObject=" + student);
        ModelAndView mv = new ModelAndView();

        mv.addObject("myname",student.getName());
        mv.addObject("myage",student.getAge());
        mv.addObject("myid",student.getId());

        mv.setViewName("show");

        return mv;
    }

2.3 控制器方法的返回值

控制器方法的返回值表示本次请求的处理结果,返回值有ModelAndView,String,void,Object

请求的处理结果包含:数据和视图

2.3.1 ModelAndView 数据和视图

请求的结果有数据和视图,使用ModelAndView最方便

数据:存放request作用域

视图:执行forward转发操作

2.3.2 String视图

框架对应的返回值是String,执行的是forward转发操作

视图可以表示为完整视图路径,或者视图的逻辑名称

@Controller
public class MyController {
    /**
     * 控制器方法返回String,表示逻辑名称。需要项目中配置视图解析器
     *
     */
    @RequestMapping("return-string-view.do")
    public String doReturnStringView1(String name, Integer age) {
        System.out.println("执行了MyController的doReturnStringView1方法 name=" + name + ",age=" + age);

        //返回结果,forward,转发到show.jsp
        return "show";
    }
}

2.3.3 void 没有数据和视图

void:没有数据和视图,可以使用HttpServletResponse对象输出数据,相应ajax请求

/**
 * 控制器方法返回是void,相应ajax请求。使用HttpServletResponse输出数据
 * */
@RequestMapping("/return-void-ajax.do")
public void returnVoidAjax(HttpServletResponse response, String name, Integer age) throws IOException {
    System.out.println("处理void返回类型,name=" + name + ",age=" + age);

    //调用service得到结果对象
    Student student = new Student();

    student.setName(name + "同学");
    student.setAge(age);

    //把对象转为json
    ObjectMapper om = new ObjectMapper();
    String json = om.writeValueAsString(student);
    System.out.println("服务器段对象转为的json===" + json);

    //输出Json,相应ajax
    response.setContentType("application/json;charset=utf-8");

    PrintWriter pw = response.getWriter();
    pw.write(json);
    pw.flush();
    pw.close();
}
<%--
  Created by IntelliJ IDEA.
  User: Administrator
  Date: 2022/7/22
  Time: 11:08
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>


    请求方式
    



    

控制器方法返回String-逻辑视图名称

姓名:
年龄:


2.3.4 Object

返回Student表示数据,还有视图。

所以控制器方法返回对象Object,用来相应Ajax请求

返回对象Object,可以是List,Student,Map,String,Integer…这些都是数据,Ajax请求需要的就是数据。在Ajax请求中,一般需要从服务器返回的是json格式的数据,经常要处理Java 对象到json的转换。而且还需要输出数据响应Ajax请求。框架提供了处理Java对象到json转换,还有数据输出工作

2.3.4.1 HttpMessageConverter 消息转换器

HttpMessageConverter接口,作用:

  1. 实现请求的数据转为Java对象
  2. 把控制器方法返回的对象转为json,xml,text,二进制等不同格式的数据

public interface HttpMessageConverter<T> {

   /**
	作用:检查clazz这个类型的对象,能否转为mediaType所表示的数据格式
		 如果能转为mediaType表示的类型,返回true,返回true调用read()
    */
   boolean canRead(Class<?> clazz, @Nullable MediaType mediaType);
   
   /**
    作用:接收请求中的数据,把数据转为clazz表示的对象
    */
   T read(Class<? extends T> clazz, HttpInputMessage inputMessage)
         throws IOException, HttpMessageNotReadableException;
    
   /**
	作用:检查clazz这种数据类型,能否转为mediaType表示的数据格式
    */
   boolean canWrite(Class<?> clazz, @Nullable MediaType mediaType);
   /**
	作用:把t对象,按照contentType说明的格式,把对象转为Json或者xml
    */
   void write(T t, @Nullable MediaType contentType, HttpOutputMessage outputMessage)
         throws IOException, HttpMessageNotWritableException;

}

MediaType:媒体类型,表示互联网中数据的格式。例如 application/json;text/html;image/gif

HttpMessageConverter接口的实现类:
1.MappingJackson2HttpMessageConverter	使用jackson工具库中的ObjectMapper把Java对象转换为json数据格式
2.StringHttpMessageConverter	把字符串类型的数据,进行格式转换和编码

怎么使用实现类:

框架根据控制器方法的返回类型,自动查找使用的实现类。

@RequestMapping("/receiver-object.do")
public Student doReceiveObject(String name, Integer age) {
    System.out.println("doReceiveObject方法执行了");
    
    Student student = new Student();
    student.setName("lisi");
    student.setAge(21);
    student.setId(1001);
    
    return student;
}

默认情况下:springmvc使用了HttpMessageConverter接口的4个实现类。包括StringHttpMessageConverter

需要在springmvc的配置文件中,加入注解驱动的标签 mvc:annotation-driven,加入这个标签后,springmvc项目启动后,会创建HttpMessageConverter接口的7个实现类对象,包括StringHttpMessageConverter和Mappingjackson2HttpMessageConverter.

2.3.4.2 @ResponseBody

@ResponseBody注解的作用,就是把student转换后的json通过HttpServletResponse对象输出给浏览器

//输出Json,相应ajax
response.setContentType("application/json;charset=utf-8");

PrintWriter pw = response.getWriter();
pw.write(json);
pw.flush();
pw.close();

@ResponseBody注解的作用就是上面的代码的实现

2.3.4.3 控制器方法返回对象转为json的步骤

  1. pom.xml文件加入jackson依赖,springmvc框架,默认处理json就是使用jackson
  2. springmvc的配置文件中,加入注解驱动的标签 mvc:annotation-driven
  3. 在控制器方法的上面加入@ResponseBody注解,表示返回值数据,输出到浏览器

2.4 静态资源处理

访问地址:

当web.xml中DispathcerServlet的url-pattern是*.do

http://localhost:8080/index.jsp tomcat

http://localhost:8080/js/jquery-3.6.0.min.js tomcat

http://localhost:8080/images/book02.jpg tomcat

http://localhost:8080/html/test.html tomcat

http://localhost:8080/some.do DispathcerServlet(SpringMVC框架)

2.4.1 tomcat的default servlet

tomcat安装目录/conf/web.xml

<servlet>
	<servlet-name>defaultservlet-name>
	<servlet-class>org.apache.catalina.servlets.DefaultServletservlet-class>
	<init-param>
		<param-name>debugparam-name>
		<param-value>0param-value>
	init-param>
	<init-param>
        <param-name>listingsparam-name>
        <param-value>falseparam-value>
    init-param>
    <load-on-startup>1load-on-startup>
servlet>

<servlet-mapping>
    <servlet-name>defaultservlet-name>
    <url-pattern>/url-pattern>
servlet-mapping>


default叫做默认servlet,作用:
1.它提供静态资源的处理
2.它处理所有未映射到其他请求的请求处理

2.4.2 中央调度器设置 “/”

http://localhost:8080/index.jsp tomcat 成功访问

http://localhost:8080/js/jquery-3.6.0.min.js 404 没有对应的控制器对象

http://localhost:8080/images/book02.jpg 404 没有对应的控制器对象

http://localhost:8080/html/test.html 404 没有对应的控制器对象

http://localhost:8080/some.do 200 MyController

404是因为没有对应的控制器对象

使用"/",导致中央调度器成为了默认的default servlet,

需要处理静态资源和其他的未映射的请求,默认中央调度器没有处理静态资源的控制器对象,所以静态资源都是404,some.do这个请求有MyController对象,所以能访问。

如果项目中,中央调度器设置了"/",动态资源能访问,静态资源不能访问,需要处理静态资源的访问工作。

2.4.3 第一种方式处理静态资源

在springmvc的配置文件中加入:mvc:default-servlet-handler/标签 ,springmvc框架会在项目运行时,加入DefaultServletHttpRequestHandler对象,让这个对象处理静态资源访问


<mvc:default-servlet-handler/>


<mvc:annotation-driven>mvc:annotation-driven>

2.4.4 第二种方式处理静态资源

在springmvc配置文件中加入一个 mvc:resources 标签,框架会创建ResourceHttpRequestHandler控制器对象,使用这个对象处理静态资源的访问。不依赖tomcat


<mvc:annotation-driven>mvc:annotation-driven>





<mvc:resources mapping="/static/**" location="/static/">mvc:resources>

第三章 SpringMVC核心技术

3.1 转发和重定向

forward:/视图完整路径

redirect:/视图完整路径

package com.lu.controller;

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

@Controller
public class MyController {

    /**
     * 控制器方法返回是ModelAndView实现转发forward
     * 语法:mv.setViewName("forward:视图完整路径")
     * */
    @RequestMapping(value = "/doForward.do",method = RequestMethod.GET)
    public ModelAndView doForward() {
        System.out.println("执行了doForward方法");
        ModelAndView mv = new ModelAndView();

        mv.addObject("msg","处理了doForward请求");
        mv.addObject("fun","执行了doForward方法");
        //显示使用forward指定转发操作
        mv.setViewName("forward:/WEB-INF/view/show.jsp");

        return mv;
    }


    /**
     * 当控制器方法返回ModelAndView实现重定向
     * 语法: mv.setViewName("redirect:视图完整路径")
     * redirect特点:不和视图解析器一起工作,就当作项目中没有视图解析器
     *
     * 框架提供的重定向的功能:
     * 1.框架可以实现两次请求之间的数据传递,把第一个请求中的Model俩面简单类型的数据,转为字符串,附加到目标页面的后面,做get参数传递
     *   可以在目标页面中获取参数值使用
     *
     * 2.在目标页面中,可以使用 ${param.参数名} 获取参数的值
     * */
    @RequestMapping("doRedirect.do")
    public ModelAndView doRedirect(String name, Integer age) {
        System.out.println("执行了doRedirect方法,name=" + name + ",age=" + age);

        ModelAndView mv = new ModelAndView();
        mv.addObject("myname",name);
        mv.addObject("myage",age);

        mv.setViewName("redirect:/other.jsp");
        //http://localhost:8080/other.jsp?myname=%E5%BC%A0%E4%B8%89&myage=23

        return mv;
    }
}

3.2 异常处理

框架使用的是集中的异常处理。把各个Controller中抛出的异常集中到一个地方处理。处理异常的叫做异常处理。

框架中使用两个注解完成异常的集中处理。这样每个controller不用单独处理异常了。注解是:

  1. @ExceptionHandler:放在方法的上面,表示此方法可以处理某个类型的异常。当异常发生时,执行这个方法

  2. @ControllerAdvice:放在类的上面,表示这个类中有异常的处理方法,相当于aop中的@Aspect

    @ControllerAdvice看作是 控制器增强,就是给Controller类增加异常(切面)的处理功能

package com.lu.controller;

import com.lu.exception.AgeException;
import com.lu.exception.MyUserException;
import com.lu.exception.NameException;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.ModelAndView;

@Controller
public class MyController {



    @RequestMapping("some.do")
    public ModelAndView doSome(String name, Integer age) throws MyUserException {
        System.out.println("执行了doSome方法,name=" + name + ",age=" + age);

        //抛出异常
        if(!"zs".equals(name)) {
            throw new NameException("姓名不正确");
        }

        if(age == null || age.intValue() > 80) {
            throw new AgeException("年龄太大了");
        }

        ModelAndView mv = new ModelAndView();
        mv.addObject("myname",name);
        mv.addObject("myage",age);

        mv.setViewName("show");

        return mv;
    }
}

3.3 拦截器

拦截器:是springmvc框架中的一种对象,需要实现接口HandlerInterceptor,拦截用户的请求,拦截到controller的请求

作用:拦截用户的请求,可以预先对请求做处理,根据处理结果,决定是否执行controller,也可以把多个controller中共用的功能定义到拦截器。

特点:

  1. 拦截器可以分为系统拦截器和自定义拦截器
  2. 一个项目可以有多个拦截器,0或者多个自定义拦截器
  3. 拦截器侧重拦截用户的请求
  4. 拦截器是在请求处理之前先执行的

拦截器的定义:

  1. 创建类实现拦截器接口HandlerInterceptor,实现接口中的方法(3个)
  2. 在springmvc配置文件中,声明拦截器对象,并指定拦截的url地址

3.3.1 第一个拦截器

package com.lu.handler;

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

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

/**
 * 拦截器
 * */
public class MyInterceptor implements HandlerInterceptor {
    /**
     * preHandle:预先处理请求的方法。总的开关
     * 参数:
     *      Object handler:被拦截的控制器对象(MyController)
     * 返回值:boolean
     *  true:请求是正确的,可以被controller处理的
     *      ====MyInterceptor拦截器的preHandle====
     *      执行了MyController的doSome方法
     *      ====MyInterceptor拦截器的postHandle====
     *      ====MyInterceptor拦截器的afterCompletion====
     *  false:请求不能被处理,控制器方法不会执行。请求到此截止。
     *  	====MyInterceptor拦截器的preHandle====
     *
     * 特点:
     *  1.预处理方法他的执行时间;在控制器方法之前执行的
     *  2.可以对请求做处理,可以做登录的检查,权限的判断,统计数据等等。
     *  3.决定请求是否执行
     * */
    @Override
    public boolean preHandle(HttpServletRequest request,
                             HttpServletResponse response,
                             Object handler) throws Exception {
        System.out.println("====MyInterceptor拦截器的preHandle====");
        return true;
    }

    /**
     * postHandle:后处理发方法
     * 参数:
     *      Object handler:被拦截的控制器对象(MyController)
     *      ModelAndView mv:控制器方法的返回值(请求的执行结果)
     *
     * 特点:
     *  1.在控制器方法之后执行的
     *  2.能获取到控制器方法的执行结果,可以修改原来的执行结果(可以修改数据,也可以修改视图)
     *  3.可以做对请求的二次处理
     *
     * */
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("====MyInterceptor拦截器的postHandle====");
    }

    /**
     * afterComletion:最后执行的方法
     * 参数:
     *      Object handler:被拦截的控制器对象(MyController)
     *      Exception ex:异常对象
     *
     * 特点:
     *      1.在请求处理完成后执行的,请求处理完成的标志是视图处理完成,对视图执行forward操作后
     *      2.可以做程序最后要做的工作,释放内存,清理临时变量
     *
     *      3.方法的执行条件:
     *          1)当前的拦截器preHandle()方法必须执行
     *          2)preHandle()必须返回true
     *
     * */
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("====MyInterceptor拦截器的afterCompletion====");
    }
}

配置文件:

<mvc:interceptors>
    
    <mvc:interceptor>
        
        <mvc:mapping path="/**"/>
        <bean class="com.lu.handler.MyInterceptor">bean>
    mvc:interceptor>
mvc:interceptors>

当你的preHndle返回true,执行结果:

====MyInterceptor拦截器的preHandle====
执行了MyController的doSome方法
====MyInterceptor拦截器的postHandle====
====MyInterceptor拦截器的afterCompletion====

请求的执行顺序:用户some.do---preHandle---doSome---postHandle---afterComletion

当preHandle返回false,执行结果:

====MyInterceptor拦截器的preHandle====

三个方法的使用:

package com.lu.handler;

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

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

/**
 * 拦截器
 * */
public class MyInterceptor implements HandlerInterceptor {
    /**
     * preHandle:预先处理请求的方法。总的开关
     * 参数:
     *      Object handler:被拦截的控制器对象(MyController)
     * 返回值:boolean
     *  true:请求是正确的,可以被controller处理的
     *      ====MyInterceptor拦截器的preHandle====
     *      执行了MyController的doSome方法
     *      ====MyInterceptor拦截器的postHandle====
     *      ====MyInterceptor拦截器的afterCompletion====
     *  false:请求不能被处理,控制器方法不会执行。请求到此截止。
     *      ====MyInterceptor拦截器的preHandle====
     *
     * 特点:
     *  1.预处理方法他的执行时间;在控制器方法之前执行的
     *  2.可以对请求做处理,可以做登录的检查,权限的判断,统计数据等等。
     *  3.决定请求是否执行
     * */
    @Override
    public boolean preHandle(HttpServletRequest request,
                             HttpServletResponse response,
                             Object handler) throws Exception {
        System.out.println("====MyInterceptor拦截器的preHandle====");
        //request.getRequestDispatcher("/tips.jsp").forward(request,response);
        return true;
    }

    /**
     * postHandle:后处理发方法
     * 参数:
     *      Object handler:被拦截的控制器对象(MyController)
     *      ModelAndView mv:控制器方法的返回值(请求的执行结果)
     *
     * 特点:
     *  1.在控制器方法之后执行的
     *  2.能获取到控制器方法的执行结果,可以修改原来的执行结果(可以修改数据,也可以修改视图)
     *  3.可以做对请求的二次处理
     *
     * */
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView mv) throws Exception {
        System.out.println("====MyInterceptor拦截器的postHandle====");

        //对请求做二次的处理
        if(mv != null) {
            mv.addObject("mydate",new Date());
            mv.setViewName("other");
        }
    }

    /**
     * afterComletion:最后执行的方法
     * 参数:
     *      Object handler:被拦截的控制器对象(MyController)
     *      Exception ex:异常对象
     *
     * 特点:
     *      1.在请求处理完成后执行的,请求处理完成的标志是视图处理完成,对视图执行forward操作后
     *      2.可以做程序最后要做的工作,释放内存,清理临时变量
     *
     *      3.方法的执行条件:
     *          1)当前的拦截器preHandle()方法必须执行
     *          2)preHandle()必须返回true
     *
     * */
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("====MyInterceptor拦截器的afterCompletion====");

        //获取数据
        HttpSession session = request.getSession();
        Object attr = session.getAttribute("attr");
        System.out.println("attr == " + attr);

        //删除数据
        session.removeAttribute("attr");

        //确定数据是否删除
        attr = session.getAttribute("attr");
        System.out.println("删除后再次检查数据 === " + attr);
    }
}

3.3.2 多个拦截器

使用两个拦截器,主要看拦截器的执行顺序,以及哪个方法控制请求的执行

  1. 两个拦截器,第一个preHandle=true,第二个拦截器preHandle=true
====MyInterceptor拦截器的preHandle111====
====MyInterceptor拦截器的preHandle222====
执行了MyController的doSome方法
====MyInterceptor拦截器的postHandle222====
====MyInterceptor拦截器的postHandle111====
====MyInterceptor拦截器的afterCompletion222====
====MyInterceptor拦截器的afterCompletion111====

请求的执行顺序:

用户some.do—拦截器1的preHandle—拦截器2的preHandle—控制器doSome—拦截器2的postHandle—拦截器1的postHandle—拦截器2的afterComletion—拦截器1的afterComletion

2.两个拦截器,第一个拦截器preHnadle=true,第二个拦截器preHandle=false

====MyInterceptor拦截器的preHandle111====
====MyInterceptor拦截器的preHandle222====
====MyInterceptor拦截器的afterCompletion111====

3.两个拦截器,第一个拦截器preHnadle=false,第二个拦截器preHandle=true

====MyInterceptor拦截器的preHandle111====

3.3.3 拦截器和过滤器的对比

  1. 拦截器是springmvc框架中的对象。过滤器是servlet中的对象
  2. 拦截器对象是框架容器创建的,过滤器对象是tomcat创建的对象
  3. 拦截器是侧重对请求做判断的,处理的,可以截断请求,过滤器是侧重对request,response对象的属性,参数设置值的,例如request.setCharacterENcoding(“utf-8”)
  4. 拦截器的他执行时间有三个,控制器方法之前,之后,请求完成后,过滤器是在请求之前。
  5. 拦截器是拦截对controller,动态资源请求的,过滤器可以过滤所有请求动态的和静态的
  6. 拦截器和过滤器一起执行的,先执行的过滤器,后面是中央调度器,后面才是拦截器,再后面是控制器方法。

你可能感兴趣的:(springmvc,java,mvc)