SSM--SpringMVC

115 阅读13分钟

SpringMvc

note.youdao.com/noteshare?i…

Spring MVC是由Spring官方提供的基于MVC设计理念的web框架

图片.png

图片.png

一、SpringMVC概述

1.1 SpringMVC优势

  • 严格遵守了MVC分层思想
  • 采用了松耦合、插件式结构;相比较于我们封装的BaseServlet以及其他的一些MVC框架来说更灵活、更具扩展性
  • SpringMVC是基于Spring的扩展、提供了一套完善的MVC注解
  • SpringMVC在数据绑定、视图解析都提供了多种处理方式,可灵活配置
  • SpringMVC对RESTful URL设计方法提供了良好的支持

1.2 SpringMVC本质工作

  • 接收并解析请求
  • 处理请求
  • 数据渲染、响应请求

二、SpringMVC框架部署

2.1 基于Maven创建一个Web工程

图片.png

图片.png

图片.png

图片.png

图片.png

2.2 添加SpringMVC依赖

  • spring-context
  • spring-aspects
  • spring-jdbc
  • spring-web
  • spring-webmvc
  • spring-junit
<dependencies>  
<dependency>  
<groupId>org.springframework</groupId>  
<artifactId>spring-context</artifactId>  
<version>6.0.9</version>  
</dependency>  
<dependency>  
<groupId>org.springframework</groupId>  
<artifactId>spring-aspects</artifactId>  
<version>6.0.9</version>  
</dependency>  
<dependency>  
<groupId>org.springframework</groupId>  
<artifactId>spring-jdbc</artifactId>  
<version>6.0.9</version>  
</dependency>  
<!-- https://mvnrepository.com/artifact/org.springframework/spring-test -->  
<dependency>  
<groupId>org.springframework</groupId>  
<artifactId>spring-test</artifactId>  
<version>6.0.9</version>  
<scope>test</scope>  
</dependency>  
<!-- https://mvnrepository.com/artifact/org.springframework/spring-web -->  
<dependency>  
<groupId>org.springframework</groupId>  
<artifactId>spring-web</artifactId>  
<version>6.0.9</version>  
</dependency>  
<!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->  
<dependency>  
<groupId>org.springframework</groupId>  
<artifactId>spring-webmvc</artifactId>  
<version>6.0.9</version>  
</dependency>  
</dependencies>

2.3 创建SpringMVC配置文件

  • 在resource目录下创建名为spring-servlet.xml 文件
  • 添加MVC命名空间

spring-servlet.xml配置

<?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" 
       xmlns:aop="http://www.springframework.org/schema/aop" 
       xmlns:mvc="http://www.springframework.org/schema/mvc" 
       xsi:schemaLocation=" http://www.springframework.org/schema/beans 
                           http://www.springframework.org/schema/beans/spring-beans.xsd 
                           http://www.springframework.org/schema/context 
                           http://www.springframework.org/schema/context/spring-context.xsd 
                           http://www.springframework.org/schema/aop 
                           http://www.springframework.org/schema/aop/spring-aop.xsd 
                           http://www.springframework.org/schema/mvc 
                           http://www.springframework.org/schema/mvc/spring-mvc.xsd"> 
    <!-- 声明使用注解配置--> 
    <context:annotation-config/> 
    <!-- 声明Spring工厂注解的扫描范围--> 
    <context:component-scan base-package="com.liguoqing"/> 
    <!-- 声明mvc使用注解驱动-->
    <mvc:annotation-driven/> 
</beans>

2.4 在web.xml中配置SpringMVC的前端控制器

SpringMVC提供了一个名为DispatcherServlet的类(SpringMVC前端控制器),用于拦截用户请求交由SpringMVC处理

webapp/WEB-INF/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"> 
<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:spring-servlet.xml</param-value> 
</init-param> 
<load-on-startup>1</load-on-startup>
</servlet> 
<servlet-mapping> 
<servlet-name>SpringMVC</servlet-name> 
<url-pattern>/</url-pattern> 
</servlet-mapping>
<!-- /* 拦截所有的HTTP请求,包括.jsp的请求,都做为控制器类的请求路径来处理--> 
<!-- / 拦截所有的HTTP请求,但不包括.jsp的请求,但不会放行静态资源请求,html/js/css/图片--> 
</web-app>
<dependency>  
<groupId>javax.servlet</groupId>  
<artifactId>javax.servlet-api</artifactId>  
<version>4.0.1</version>  
</dependency>

三、SpringMVC框架使用

在SpringMVC中,我们把接收用户请求,处理用户请求的类称之为Controller(控制器)

3.1 创建控制器

  • 创建一个名为 com.liguoqing.controllers 的包(包需要在Spring注解扫描的范围内)
  • 创建一个类(无需做任何的继承和实现)
  • 在类上添加 @Controller 注解声明此类为SpringMVC的控制器
  • 在类上添加 @RequestMapping("/url") 声明此控制器类的请求url
@Controller  
@RequestMapping("/book")  
public class BookController {  
}
  • bean类
package com.xie.bean;

public class Book {
    private int bookId;
    private String bookName;
    private String bookAuthor;
    private double bookPrice;

    public Book(int bookId, String bookName, String bookAuthor, double bookPrice) {
        this.bookId = bookId;
        this.bookName = bookName;
        this.bookAuthor = bookAuthor;
        this.bookPrice = bookPrice;
    }

    public Book() {
    }

    @Override
    public String toString() {
        return "Book{" +
                "bookId=" + bookId +
                ", bookName='" + bookName + ''' +
                ", bookAuthor='" + bookAuthor + ''' +
                ", bookPrice=" + bookPrice +
                '}';
    }

    public int getBookId() {
        return bookId;
    }

    public void setBookId(int bookId) {
        this.bookId = bookId;
    }

    public String getBookName() {
        return bookName;
    }

    public void setBookName(String bookName) {
        this.bookName = bookName;
    }

    public String getBookAuthor() {
        return bookAuthor;
    }

    public void setBookAuthor(String bookAuthor) {
        this.bookAuthor = bookAuthor;
    }

    public double getBookPrice() {
        return bookPrice;
    }

    public void setBookPrice(double bookPrice) {
        this.bookPrice = bookPrice;
    }
}

3.2 在控制器类中定义处理请求的方法

  • 在一个控制器类中可以定义多个方法处理不同的请求
  • 在每个方法上添加 @RequestMapping("/url") 用于声明当前方法请求的url
@Controller  
@RequestMapping("/book")  
  
public class BookController {  
@RequestMapping("/add")  
public void add(){  
  
}  
@RequestMapping("/list")  
public void list(){  
  
}  
}

3.3 静态资源配置

静态资源:就是项目中的HTML、CSS、JS、图片等

3.3.1 /* 和 / 区别

<!-- /* 拦截所有的HTTP请求,包括.jsp的请求,都做为控制器类的请求路径来处理--> 
<!-- / 拦截所有的HTTP请求,但不包括.jsp的请求,但不会放行静态资源请求(html/js/css/图片)--> 
<servlet-mapping>
    <servlet-name>SpringMVC</servlet-name> 
    <url-pattern>/</url-pattern>
</servlet-mapping>

3.3.2 静态资源放行配置

  • 在springMVC的配置文件中,添加如下静态资源放行的配置

spring-servlet.xml

<!--放行资源-->  
<mvc:resources mapping="/css/**" location="/css/"/>  
<mvc:resources mapping="/pages/**" location="/pages/"/>  
<mvc:resources mapping="/imgs/**" location="/imgs/"/>  
<mvc:resources mapping="/js/**" location="/js/"/>

3.4 前端提交数据到控制器

图片.png

3.4.1 表单提交

  • 创建前端页面(book-add.jsp)
    表单提交:输入框需要提供name属性,springMVC控制器是通过name属性取值的
<!DOCTYPE html>  
<html lang="en">  
<head>  
<meta charset="UTF-8">  
<title>Title</title>  
</head>  
<body>  
<h3>添加图书</h3>  
<form action="book/add" method="post">  
<p>图书名称:<input type="text"></p>  
<p>图书作者:<input type="text"></p>  
<p>图书价格:<input type="text"></p>  
<p><input type="submit" value="提交"></p>  
</form>  
</body>  
</html>

3.4.2 URL提交

URL提交:

<%--超链接提交--%>
<a href="book/add?bookName=Java">URL提交</a>

3.4.3 AJAX提交

AJAX提交:请求行、请求头、请求体都可以用来传值

<h3>AJAX提交</h3>  
<input type="button" value="ajax提交"/>  
<script type="text/javascript" src="js/jquery-3.4.1.min.js"></script>  
<script type="text/javascript">  
$("#btn1").click(function (){  
var obj ={};  
obj.bookName="Java";  
obj.bookAuthor="张三";  
obj.bookPrice=3.33;  
$.ajax({  
url:"book/add",  
type:"post",  
headers:{  
  
},  
contentType:"application/json",  
data:obj,  
success:function (res){  
console.log(res);  
}  
});  
});  
</script>

3.5 控制器中接收前端提交的数据

3.5.1 请求行传值

  • 表单提交 method="get"
  • URL提交
  • $.ajax请求的url传值
$.ajax({
url:这里拼接url,把参数放url就是请求行传值, 
type:"post",
headers:{
},
contentType:"application/json", 
data:obj, 
success:function (res){
    console.log(res); 
    }
});
  • $.post()/$.get()中的{}传值

@RequestParam 注解用于接收请求行传递的数据

  • 前端提交数据
<h3>表单提交</h3>
<form action="book/add" method="get">
    <p>图书名称:<input type="text" name="name"></p>
    <p>图书作者:<input type="text" name="author"></p>
    <p>图书价格:<input type="text" name="price"></p>
    <p><input type="submit" value="提交"></p>
</form>
  • 控制器接收数据
package com.liguoqing.controllers;
import org.springframework.stereotype.Controller; 
import org.springframework.web.bind.annotation.RequestMapping; 
import org.springframework.web.bind.annotation.RequestParam;
@Controller 
@RequestMapping("/book") 
public class BookController {
// <form action="book/add" method="post"> 
// <p>图书名称:<input type="text" name="name"></p>
// <p>图书作者:<input type="text" name="author"></p> 
// <p>图书价格:<input type="text" name="price"></p> 
// <p><input type="submit" value="提交"></p>
// </form> 
/*接收请求行数据*/ 
@RequestMapping("/add")
public void add(@RequestParam("name") String a, 
                @RequestParam("author") String b,
                @RequestParam("price") double c){
    System.out.println("~~~~~book add"); 
    System.out.println(a); 
    System.out.println(b);
    System.out.println(c); 
    }
}

注意:

如果控制器方法中接收数据的参数名与请求行传值的key是一致的,则@RequestParam注解可以省略

@RequestMapping("/add")
public void add(String name, String author, double price){ 
System.out.println("~~~~~book add"); 
System.out.println(name);
System.out.println(author);
System.out.println(price); }

3.5.2 请求头传值

  • $.ajax 封装请求头数据
$.ajax({ 
    url:"book/add",
    type:"post", 
    headers:{ 这里请求头传值 }, 
    contentType:"application/json", 
    data:obj, 
    success:function (res){
    console.log(res);
    }
});

演示代码:(这里的请求头里如果写中文暂时是有问题的)

@RequestHeader 用于接收请求头传递的数据

@RequestMapping("/list")
public void list(@RequestHeader("token") String token){ 
    System.out.println(token); 
    System.out.println("~~~~~book list");
}
----------------------------------------------------------------- 

<h3>AJAX提交</h3>
<input type="button" value="ajax提交" id="btn1"/>
<script type="text/javascript" src="js/jquery-3.4.1.min.js"></script>
<script type="text/javascript">
    $("#btn1").click(function (){
        $.ajax({
            url:"book/list",
            type:"post",
            headers:{
                token:"Eqeqeq"
            },
            success:function (res) {
                console.log(res);
            }
    });
    console.log("结束");
    });
</script>

3.5.3 请求体传值

  • $.ajax 封装请求体数据
$.ajax({
    url:"book/add",
    type:"post",
    headers:{ 这里请求头传值 },
    contentType:"application/json",
    data:{ 
    这里放请求体数据
    }, 
    success:function (res){
        console.log(res);
        } });

@RequestBody 注解用于接收请求体传递的数据

  • 前端
<h3>AJAX提交</h3>
<input type="button" value="ajax提交" id="btn1">
<script type="text/javascript" src="js/jquery-3.4.1.min.js"></script>
<script type="text/javascript">
    $("#btn1").click(function (){
        console.log("进入方法");
        var obj ={};
        obj.bookName="Java";
        obj.bookAuthor="张三";
        obj.bookPrice=3.33;
        console.log("obj");
        $.ajax({
            url:"book/update",
            type:"post",
            contentType:"application/json",
            data:JSON.stringify(obj),
            success:function (res) {
                console.log(res);
            }
    });
    console.log("结束");
    })
  • 导入依赖
<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind -->
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.15.1</version>
</dependency>
  • 测试
@RequestMapping("/update")
public void update(@RequestBody Book book){
    //    servlet的处理方式使用request的输入流接收请求体数据
    System.out.println(".....book update");
        System.out.println(book);
    }

3.6 控制器响应前端请求

3.6.1 控制器响应同步请求

同步请求:form , 超链接

  • 处理同步请求的方法的返回类型定义为String或者ModelAndView,以实现页面的跳转

    • 返回类型为String:
  • 新建一个jsp(tips.jsp)

    <h3>表单提交</h3>
    <form action="book/add" method="get">
        <p>图书名称:<input type="text" name="name"></p>
        <p>图书作者:<input type="text" name="author"></p>
        <p>图书价格:<input type="text" name="price"></p>
        <p><input type="submit" value="提交"></p>
    </form>
    
    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <html>
    <head>
        <title>Title</title>
    </head>
    <body>
    <h1>跳转成功</h1>
    </body>
    </html>
    
    • 转发
    @RequestMapping("/add")
    public String add(
            @RequestParam("name") String a,
            @RequestParam("author") String b,
            @RequestParam("price") double c){
    
        System.out.println(".....book add");
        return "/tips.jsp";
    }
    
    • 重定向
    @RequestMapping("/add")
    public String add(
            @RequestParam("name") String a,
            @RequestParam("author") String b,
            @RequestParam("price") double c){
    
        System.out.println(".....book add");
        return "redirect:/tips.jsp";
    }
    
  • 返回类型为ModelAndView

    • 转发
    @RequestMapping("/add")
    public ModelAndView add(
            @RequestParam("name") String a,
            @RequestParam("author") String b,
            @RequestParam("price") double c){
        System.out.println(".....book add");
        ModelAndView modelAndView = new ModelAndView("/tips.jsp");
        return modelAndView;
    }
    
    • 重定向
    @RequestMapping("/add")
    public ModelAndView add(
            @RequestParam("name") String a,
            @RequestParam("author") String b,
            @RequestParam("price") double c){
        System.out.println(".....book add");
        ModelAndView modelAndView = new ModelAndView("redirect:/tips.jsp");
        return modelAndView;
    }
    

3.6.2 控制器响应异步请求

异步请求:ajax请求

1. 使用response中的输出流进行响应
  • 控制器方法的返回类型为void
  • 控制器方法添加HttpServletResponse response 参数
  • 在方法中通过response 获取输出流,使用流响应ajax请求
@RequestMapping("/update")
public void update(@RequestBody Book book, HttpServletResponse response) throws IOException {
    response.setContentType("text/plain");
    response.setContentType("application/json");
    System.out.println(".....book update");
    System.out.println("请求头传递:"+book);
    String s = new ObjectMapper().writeValueAsString(book);
    response.setCharacterEncoding("utf-8");
    PrintWriter out = response.getWriter();
    out.println(s);
    out.flush();
    out.close();
}
<h3>AJAX提交</h3>
<input type="button" value="ajax提交" id="btn1"/>
<script type="text/javascript" src="js/jquery-3.4.1.min.js"></script>
<script type="text/javascript">
    $("#btn1").click(function (){
        console.log("进入方法");
        var obj ={};
        obj.bookName="Java";
        obj.bookAuthor="张三";
        obj.bookPrice=3.33;
        console.log("obj");
        $.ajax({
            url:"book/update",
            type:"post",
            headers:{
                token:"Eqeqeq"
            },
            contentType: "application/json;charset=UTF-8",
            data:JSON.stringify(obj),
            dataType: "json",
            success: function(response) {
                console.log(response);
                alert("请求成功!")
            },
            // error: 设置请求失败后的回调函数
            error: function() {
                alert("请求失败!请稍后再试!");
            },
            success:function (res) {
                console.log(res);
            }
    });
    console.log("结束");
    });
</script>
2. 直接在控制器方法返回响应的对象
  • 控制器方法的返回类型设置为响应给ajax请求的对象类型
  • 在控制器方法前添加一个 @ResponseBody 注解,将返回的对象转换成JSON格式返回给ajax请求
  • 如果一个控制器类中的所有方法都是响应ajax请求,则可以直接在控制器类前添加 @ResponseBody 注解
@RequestMapping("/update2")
@ResponseBody
public List<Book> update2(@RequestBody Book book, HttpServletResponse response) throws IOException {
    //    servlet的处理方式使用request的输入流接收请求体数据
    System.out.println(".....book update2");
    System.out.println("直接在控制器方法返回响应的对象");
    List<Book> books=new ArrayList<Book>();
    books.add(new Book(1,"java","老张",22));
    books.add(new Book(2,"C语言","老李",82));
    System.out.println(books);
    return books;
}

3.6.3 控制器响应数据传递(同步请求)

3.6.3.1 返回类型是String
方法一:Model

对于同步请求的转发响应,我们可以传递参数到转发的页面

  • 返回类型为String:

    • 1:在控制器方法中定义一个Model类型的参数
    • 2:在return页面之前,向model中添加键值对,添加的键值对就会被传递到转发的页面
    @RequestMapping("/add2")
    public String add2(
            @RequestParam("name") String a,
            @RequestParam("author") String b,
            @RequestParam("price") double c,
            Model model){
        model.addAttribute("key1","key2");
        model.addAttribute("book",new Book(1,"java","老张",22));
        System.out.println(".....book2 add");
        return "/tips.jsp";
    }
    
    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <html>
    <head>
        <title>Title</title>
    </head>
    <body>
    <h3>表单提交</h3>
    <form action="book/add3" method="get">
        <p>图书名称:<input type="text" name="name"></p>
        <p>图书作者:<input type="text" name="author"></p>
        <p>图书价格:<input type="text" name="price"></p>
        <p><input type="submit" value="提交"></p>
    </form>
    
    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <html>
    <head>
        <title>跳转页面</title>
    </head>
    <body>
    <h1>恭喜跳转成功</h1>
    <hr>
    ${key1}
    <hr>
    ${book.bookName}
    </body>
    </html>
    

    图片.png

方法二:request
@RequestMapping("/add4")
public String add4(String name, String author, double price, HttpServletRequest request){
    request.setAttribute("key1","key2");
    request.setAttribute("book",new Book(1,"java","老张",22));
    System.out.println(".....book2 add");
    return "/tips.jsp";
}
3.6.3.2 返回类型是ModelAndview
@RequestMapping("/add5")
public ModelAndView add5(String name, String author, double price){
    ModelAndView modelAndView = new ModelAndView("/tips.jsp");
    modelAndView.addObject("key1","value1");
    modelAndView.addObject("book",new Book(1,"java","老张",22));
    return modelAndView;
}

3.7 解决中文乱码问题

3.7.1 前端代码

  • JSP页面
    • <%@ page contentType="text/html;charset=UTF-8" language="java" pageEncoding="UTF-8" %>
  • HTML页面
    • <meta charset="UTF-8">

3.7.2 服务器编码

  • tomcat/conf/ 图片.png 图片.png

3.7.3 设置SpringMVC的编码方式

  • 在web.xml中配置SpringMVC编码过滤器的编码方式
    <filter>
        <filter-name>EncodingFilter</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>forceEncoding</param-name>
            <param-value>true</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>EncodingFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
    

四、SpringMVC的请求处理流程

4.1 请求处理流程

SpringMVC 通过前端控制器(DispatcherServlet)拦截并处理用户请求的

图片.png

图片.png

  • ①前端发送请求被前端控制器DispatcherServlet拦截
  • ②前端控制器调用处理器映射器HandlerMapping对请求URL进行解析,解析之后返回调用给前端控制器
  • ③前端控制器调用处理器适配器数处理调用链
  • ④处理器适配器基于反射通过适配器设计模式完成处理器(控制器)的调用处理用户请求
  • ⑤处理器适配器将控制器返回的视图和数据信息封装成ModelAndViewll响应给前端控制器
  • ⑥前端控制器调用视图解析器ViewResolver对ModelAndViewi进行解析,将解析结果(视图资源和数据)响应给前端控制器
  • ⑦前端控制器调用视图vⅵw组件将数据进行渲染,将渲染结果(静态视图)响应给前端控制器
  • ⑧前端控制器响应用户请求

4.2 SpringMVC核心组件

  • DispatcherServlet 前端控制器,总控制器
    • 作用:接收请求,协同各组件工作,响应请求
  • HandlerMapping 处理器映射
    • 作用:负责根据用户请求的URL找到对应的Handler
    • 可以自定义配置 SpirngMVC提供多个处理器映射的实现,可以根据需要进行配置
  • HandlerAdapter 处理器适配器
    • 作用:根据HandlerMapping 解析用户请求后产生的调用链,通过适配器模式完成Handler的调用
  • Handler 处理器/控制器
    • 由工程师根据业务的需求进行开发
    • 作用:处理请求
  • ModelAndView 视图模型
    • 作用:用于封装处理器返回的数据以及响应的视图
    • ModelAndView = Model + View
  • ViewResolver 视图解析器
    • 作用:对ModelAndView进行解析
    • 可以自定义配置 SpirngMVC提供多个视图解析器的实现,可以根据需要进行配置
  • View 视图
    • 作用:完成数据渲染

4.3 处理器映射器

不同的处理器映射器对URL处理的方式也不相同,使用对应的处理器映射器之后,我们的前端请求规则也需要发生相应的变化

SpringMVC提供的处理器映射器:
1:BeanNameUrlHandlerMappering:根据控制器的Id访问控制器 (首字母小写)
2:SimpleUrlHandlerMapping 根据控制器配置的URL访问(默认)

配置处理器映射器:

  • 在SpringMVC的配置文件中通过Bean标签声明处理器映射器
    <bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"></bean>
    
    默认首字母小写,就不用写 @RequestMapping了
  • 配置 BeanNameUrlHandlerMapping
    <bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
        <property name="mappings">
            <props>
                <prop key="/book">bookController</prop>
            </props>
        </property>
    </bean>
    
    相当于
    @RequestMapping("/book")
    
    所以就默认不配,直接使用注解

4.4 视图解析器

SpringMVC提供了多个视图解析器:
1:UrlBasedViewResolver
2:InternalResourceViewResolver

  • UrlBasedViewResolver 需要依赖 jstl 包

    • 添加JSTL的依赖

    pom.xml

    <!-- https://mvnrepository.com/artifact/javax.servlet/jstl -->
    <dependency>
        <groupId>javax.servlet</groupId>
        <artifactId>jstl</artifactId>
        <version>1.2</version>
    </dependency>
    

    配置

    <bean id="viewResolver" class="org.springframework.web.servlet.view.UrlBasedViewResolver">
        <property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>
        <property name="prefix" value="/"/>
        <property name="suffix" value=".jsp"/>
    </bean>
    

    prefix:前缀
    suffix:后缀
    如果配置了这个

    图片.png

  • InternalResourceViewResolver

    <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/"/>
        <property name="suffix" value=".jsp"/>
    </bean>
    

五、 使用对象接收数据在控制器方法中

实体类

public class Book {
    private int bookId;
    private String bookName;
    private String bookAuthor;
    private double bookPrice;
     private Date publishTime;


    public Book() {
    }

    public Book(int bookId, String bookName, String bookAuthor, double bookPrice, Date publishTime) {
        this.bookId = bookId;
        this.bookName = bookName;
        this.bookAuthor = bookAuthor;
        this.bookPrice = bookPrice;
        this.publishTime = publishTime;
    }
    public Book(int bookId, String bookName, String bookAuthor, double bookPrice) {
        this.bookId = bookId;
        this.bookName = bookName;
        this.bookAuthor = bookAuthor;
        this.bookPrice = bookPrice;
    }

    public int getBookId() {
        return bookId;
    }

    public void setBookId(int bookId) {
        this.bookId = bookId;
    }

    public String getBookName() {
        return bookName;
    }

    public void setBookName(String bookName) {
        this.bookName = bookName;
    }

    public String getBookAuthor() {
        return bookAuthor;
    }

    public void setBookAuthor(String bookAuthor) {
        this.bookAuthor = bookAuthor;
    }

    public double getBookPrice() {
        return bookPrice;
    }

    public void setBookPrice(double bookPrice) {
        this.bookPrice = bookPrice;
    }

    public Date getPublishTime() {
        return publishTime;
    }

    public void setPublishTime(Date publishTime) {
        this.publishTime = publishTime;
    }
}

book-add.jsp

<h3>表单提交</h3>
<form action="test/add" method="get">
    <p>图书名称:<input type="text" name="bookName"></p>
    <p>图书作者:<input type="text" name="bookAuthor"></p>
    <p>图书价格:<input type="text" name="bookPrice"></p>
    <p>出版时间:<input type="text" name="date"></p>
    <p><input type="submit" value="提交"></p>
</form>

testController

@Controller
@RequestMapping("/test")
public class TestController {
    //    表单提交的多个数据,在控制器方法中使用对象接收,但是提交的数据的key必须要与对象的属性名一致
    @RequestMapping("add")
    public String addBook(Book book){
        System.out.println(book.getBookName());
        return "tips";
    }
}

六、SpringMVC自定义日期转换器

如果前端需要输入日期数据,在控制器中转换成Date对象,SpringMVC要求前端输入的日期格式必须为yyyy/MM/DD

如果甲方要求日期格式必须为指定的格式,而这个指定格式SpringMVC不接受,该如何处理呢?

  • 自定义日期转换器:

6.1 创建自定义日期转换器

  1. 创建一个类实现Converter接口,泛型指定从什么类型转换为什么类型
  2. 实现Converter准换方法
public class MyDateConverter implements Converter<String, Date> {
    SimpleDateFormat simpleFormatter=new SimpleDateFormat("yyyy年MM月dd日");
    public Date convert(String s){
        Date date = null;
        try {
            date = simpleFormatter.parse(s);
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return date;
    }

}

6.2 配置自定义转换器

<!-- 声明mvc使用注解驱动-->
<mvc:annotation-driven conversion-service="converterFactory"/>

<bean id="converterFactory" class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
    <property name="converters">
        <set>
            <bean class="com.xie.utils.MyDateConverter"></bean>
        </set>
    </property>
</bean>

注意:要想要其他的格式,就可以多配置几个

七、文件上传

7.1 SpringMVC框架部署

  • 基于Maven创建web工程
  • 添加SpringMVC所需的依赖
    • Spring-context aspects jdbc test web webmvc jackson
  • 创建SpringMVC配置文件
  • 在web.xml中配置SpringMVC的前端控制器
  • 在web.xml中配置SpringMVC的编码过滤器
  • 配置静态资源处理策略
<dependencies>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-aspects</artifactId>
        <version>5.3.29</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>5.3.29</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-jdbc</artifactId>
        <version>5.3.29</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-test</artifactId>
        <version>5.3.29</version>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-webmvc</artifactId>
        <version>5.3.29</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-web</artifactId>
        <version>5.3.29</version>
    </dependency>
    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-databind</artifactId>
        <version>2.15.1</version>
    </dependency>
   
<?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"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xsi:schemaLocation="http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context.xsd
       http://www.springframework.org/schema/aop
       http://www.springframework.org/schema/aop/spring-aop.xsd
       http://www.springframework.org/schema/mvc
       http://www.springframework.org/schema/mvc/spring-mvc.xsd
       http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd">
    <!-- 声明使用注解配置-->
    <context:annotation-config/>
    <!-- 声明Spring工厂注解的扫描范围-->
    <context:component-scan base-package="com.xie"/>
    <!-- 声明mvc使用注解驱动-->
    <mvc:annotation-driven />
<!--    配置静态资源处理策略-->
    <mvc:resources mapping="/js/**" location="/js/"/>

</beans>
<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:spring-servlet.xml</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
    <servlet-name>SpringMVC</servlet-name>
    <url-pattern>/</url-pattern>
</servlet-mapping>

<!--编码过滤器-->
<filter>
    <filter-name>EncodingFilter</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>forceEncoding</param-name>
        <param-value>true</param-value>
    </init-param>
</filter>
<filter-mapping>
    <filter-name>EncodingFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

7.2 案例:添加图书,同时提交图书的封面图片

7.2.1 前端提交文件

  • 准备工作
    • book-add.jsp
    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <html>
    <head>
        <title>Title</title>
    </head>
    <body>
    <h1>添加图书信息</h1>
    <form action="">
        <p>图书名称:<input type="text" name=""></p>
        <p>图书作者:<input type="text" name=""></p>
        <p>图书价格:<input type="text" name=""></p>
        <p>图书封面:<input type="file" name=""></p>
        <p><input type="submit" value="提交"></p>
    </form>
    </body>
    </html>
    
    • index.jsp
      <%@ page contentType="text/html;charset=UTF-8" language="java" %>
      <html>
      <head>
          <title>Title</title>
      </head>
      <body>
          <table width="100%" height="700">
              <tr>
                  <td width="200" style="border-right: cornflowerblue 2px solid;background: rgba(255,0,0,0.1)">
                      <ul>
                          <li><a href="book-add.jsp" target="mainFrame">添加图书</a></li>
                          <li><a href="">图书列表</a></li>
                      </ul>
                  </td>
                  <td>
                      <iframe name="mainFrame" width="100%" height="700" frameborder="0"></iframe>
                  </td>
              </tr>
          </table>
      </body>
      </html>
    
    • 新建包(controller)
    @Controller
    @RequestMapping("/book")
    public class BookController {
        @RequestMapping("/add")
        public String addBook(){
            System.out.println(".......add");
            return "/tips.jsp";
        }
    }
    
    • 新建tips.jsp
  • 表单提交方式必须为post
  • 表单 enctype属性 设置为 multipart/form-data
<h1>添加图书信息</h1>
<form action="book/add" method="post" enctype="multipart/form-data">
    <p>图书名称:<input type="text" name="bookName"></p>
    <p>图书作者:<input type="text" name="bookAuthor"></p>
    <p>图书价格:<input type="text" name="bookPrice"></p>
    <p>图书封面:<input type="file" name="bookFile"></p>
    <p><input type="submit" value="提交"></p>
</form>
</body>
</html>

7.2.2 控制器接收数据和文件

SpringMVC处理上传文件需要借助CommonsMultipartResolver文件解析器

clipboard.png

  • 添加依赖:commons-io commons-fileupload
<!-- https://mvnrepository.com/artifact/commons-io/commons-io -->
<dependency>
    <groupId>commons-io</groupId>
    <artifactId>commons-io</artifactId>
    <version>2.12.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/commons-fileupload/commons-fileupload -->
<dependency>
    <groupId>commons-fileupload</groupId>
    <artifactId>commons-fileupload</artifactId>
    <version>1.5</version>
</dependency>
  • 在spring-servlet.xml中配置文件解析器
<!--    配置文件解析器-->
    <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
        <property name="maxUploadSize" value="10240000"/>
        <property name="maxInMemorySize" value="102400"/>
        <property name="defaultEncoding" value="utf-8"/>
    </bean>
  • 控制器接收文件
    • 在处理文件上传的方法中定义一个 MultipartFile 类型的对象,就可以接收图片了
    @Controller
    @RequestMapping("/book")
    public class BookController {
        @RequestMapping("/add")
        public String addBook(Book book, MultipartFile bookImages){
            System.out.println(".......add");
            System.out.println(bookImages);
            return "/tips.jsp";
        }
    }
    
    注意:bookImages要和book-add.jsp里的名字一样
    @Controller
    @RequestMapping("/book")
    public class BookController {
        @RequestMapping("/add")
        public String addBook(Book book, MultipartFile bookImages){
            System.out.println(".......add");
    //        bookImages表示上传的图片
            String originalFilename=bookImages.getOriginalFilename();
    
            System.out.println(originalFilename);//会得到上传的图片的名字
            return "/tips.jsp";
        }
    }
    
  • 文件上传
<dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>javax.servlet-api</artifactId>
    <version>4.0.1</version>
</dependency>
@Controller
@RequestMapping("/book")
public class BookController {
    @RequestMapping("/add")
    public String addBook(Book book, MultipartFile bookImages, HttpServletRequest request) throws IOException {
        System.out.println(".......add");
//        bookImages表示上传的图片
//        1.截取上传文件的后缀名,生成新的文件名
        String originalFilename=bookImages.getOriginalFilename();
        String ext=originalFilename.substring(originalFilename.lastIndexOf("."));//.jpg
        String fileName=System.currentTimeMillis()+ext;
        // 2:获取images目录在服务器的路径
        String dir=request.getServletContext().getRealPath("images");
        String savePath=dir+"/"+fileName;

//        3.保存文件
        bookImages.transferTo(new File(savePath));
//        4。将图片的访问路径设置为book对象
        book.setBookImg("images/"+fileName);
//        5. 调用service保存book到数据库

        System.out.println(originalFilename);//会得到上传的图片的名字
        return "/tips.jsp";
    }
}

7.3 文件下载

clipboard.png

7.3.1 文件下载-显示

  • book-add.jsp
<h1>添加图书信息</h1>
<form action="book/add" method="post" enctype="multipart/form-data">
    <p>图书名称:<input type="text" name="bookName"></p>
    <p>图书作者:<input type="text" name="bookAuthor"></p>
    <p>图书价格:<input type="text" name="bookPrice"></p>
    <p>图书封面:<input type="file" name="bookImages"></p>
    <p><input type="submit" value="提交"></p>
</form>
  • index.jsp
<table width="100%" height="700">
    <tr>
        <td width="200" style="border-right: cornflowerblue 2px solid;background: rgba(255,0,0,0.1)">
            <ul>
                <li><a href="book-add.jsp" target="mainFrame">上传图片</a></li>
                <li><a href="list.jsp" target="mainFrame">文件列表</a></li>
            </ul>
        </td>
        <td>
            <iframe name="mainFrame" width="100%" height="700" frameborder="0"></iframe>
        </td>
    </tr>
</table>
  • list.jsp
<h4>文件列表</h4>
 <script type="text/javascript" src="js/jquery-3.4.1.min.js"></script>
<script type="text/javascript">
    $.get("book/list",function (res){
        console.log(res)
    },"json",)
</script>
  • Controller
    @RequestMapping("/list")
    @ResponseBody
    public String[] listImages(HttpServletRequest request ){
//        1.从images目录下获取所有的图片信息
        String dir = request.getServletContext().getRealPath("images");
        File imgDri=new File(dir);
        String[] fileNames = imgDri.list();
        return fileNames;
    }
<html>
<head>
    <title>list</title>
</head>
<body>

<%--    最新版本的BootStrap核心CSS文件--%>
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-GLhlTQ8iRABdZLl6O3oVMWSktQOp6b7In1Zl3/Jr59b6EGGoI1aFkw7cmDA6j6gD" crossorigin="anonymous">
<%--  最新的BootStrap核心JavaScript文件--%>
    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/js/bootstrap.min.js" integrity="sha384-ep+dxp/oz2RKF89ALMPGc7Z89QFa32C8Uv1A3TcEK8sMzXVysblLA3+eJWTzPJzT" crossorigin="anonymous"></script>
<h4>文件列表</h4>
    <div class="row" id="container">

    </div>



    <script type="text/javascript" src="js/jquery-3.4.1.min.js"></script>
<script type="text/javascript">
    $.get("book/list",function (res){
        for (var i=0;i<res.length;i++){
            var fn=res[i];
            var htmlStr="<div class='col-lg-2 col-md-3 col-sm-4 col-xs-6'><div class='thumbnail'><img src='images/"+fn+"' alt=''><div class='caption'><p><a href='' class='btn btn-primary' role='button'>下载</a></p></div></div></div>";
            $("#container").append(htmlStr);
        }
    },"json",)
</script>
</body>
</html>

7.3.2 文件下载-实现

var htmlStr="<div class='col-lg-2 col-md-3 col-sm-4 col-xs-6'><div class='thumbnail'><img src='images/"+fn+"' alt=''><div class='caption'><p><a href='book/download?fname="+fn+"' class='btn btn-primary' role='button'>下载</a></p></div></div></div>";
    @RequestMapping("/download")
    public void downloadImg(String fname, HttpServletRequest request, HttpServletResponse response) throws Exception {
//  从images目录找到当前文件
        String dir = request.getServletContext().getRealPath("images");
        String filePath=dir+"/"+fname;
        FileInputStream fileInputStream = new FileInputStream(filePath);
        response.setContentType("application/exe");
        response.addHeader("content-Disposition","attachment;filename="+fname);
        IOUtils.copy(fileInputStream,response.getOutputStream());
    }

八、统一异常处理

在我们的应用系统运行的过程中,可能由于运行环境,用户操作,资源不足等各方面的原因导致系统出现异常(HTTP状态异常、Java异常Exception);如果系统出现了异常,这些异常将会通过浏览器呈现给用户,而这种异常的显示是没有必要的,因此我们可以在服务器进行特定的处理——当系统出现异常之后,呈现给用户一个统一的,可读的提示页面。

8.1 HTTP状态异常

HTTP Status 404 ;访问地址有误

HTTP Status 500是服务器有误或者网络异常

  • 创建一个用于异常提示的页面:404.jsp
<html>
<head>
    <title>404</title>
</head>
<body>
<h3>您的访问地址有误,请检查。。。。</h3>
</body>
</html>
  • 在web.xml中进行配置
<error-page>
    <error-code>404</error-code>
    <location>/404.jsp</location>
</error-page>

8.2 Java代码异常的统一处理

8.2.1基于Servlet-api的处理

  • 创建异常提示页面:err.jsp
  • 在web.xml中进行配置
<error-page>
    <exception-type>java.lang.NumberFormatException</exception-type>
    <location>/error.jsp</location>
</error-page>

8.2.2 SpringMVC处理

  • 使用异常处理类进行统一处理
@ControllerAdvice
public class MyExceptionHandler {
    //空指针异常
    @ExceptionHandler(NullPointerException.class)
    public String nullHandle(){
        return "/error1.jsp";
    }
    //数据格式化异常
    @ExceptionHandler(NumberFormatException.class)
    public String formatHandler(){
        return "/error.jsp";
    }
    
}

九、拦截器

9.1 拦截器介绍

SpringMVC提供的拦截器就类似与Servlet-api中的过滤器,可以对控制器的请求进行拦截实现相关的预处理和后处理。

  • 过滤器
    • 是Servlet规范的一部分,所有web项目都可以使用
    • 过滤器在web.xml配置(可以使用注解),能够拦截所有web请求
  • 拦截器
    • 是SpringMVC框架的实现,只有在SpringMVC框架中才能使用
    • 拦截器在SpringMVC配置文件进行配置,不会拦截SpringMVC放行的资源(js/html/css..)

图片.png

图片.png

9.2 自定义拦截器

9.2.1 创建拦截器

public class MyInterceptor1 implements HandlerInterceptor {


    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("。。。。。。预处理");

        return false;//是否放行
    }

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

9.2.2 配置拦截器

<mvc:interceptors>
    <mvc:interceptor>
        <mvc:mapping path="/book/query"/>
        <mvc:mapping path="/student/**"/>
        <mvc:exclude-mapping path="/student/add"/>
        <bean class="com.xie.utils.MyInterceptor1"/>
    </mvc:interceptor>
</mvc:interceptors>

图片.png


public class MyInterceptor1 implements HandlerInterceptor {


    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("。。。。。。预处理");
        Enumeration<String> keys = request.getParameterNames();
        while(keys.hasMoreElements()){
            String key=keys.nextElement();
            if("bookId".equals(key)){
                return true;
            }
        }
        response.setStatus(400);
       return false;

    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        modelAndView.addObject("tips","这是通过拦截器的后处理器添加的数据");
        System.out.println("。。。。。。后处理");
    }
}

9.3 拦截器链

将多个拦截器按照一定的顺序构成一个拦截器链

再加一个拦截器并配置

图片.png

这是拦截器1的配置在前面的时候,要是拦截器2在前面,则是“2112”

图片.png