SSM学习笔记之SpringMVC

0x00 概述

本文主要涉及SpringMVC知识:SpringMVC部署,SpringMVC框架,请求流程,请求定制(日期和文件处理),统一异常处理,拦截流程。

 

0x01 BaseServlet

什么是Servelet

Servlet功能模块化--封装BaseServlet

BaseServlet可以让一个Servlet处理多种不同的请求,不同的请求调用Servlet的不同方法;

随着项目需求复杂化,基于BaseServlet已经无法满足项目管理和开发的需求,这时候就需要引入web开发框架了;

 

0x02 SpringMVC概述

/**

Spring MVC是由Spring官方提供的基于MVC设计理念的web框架
Spring MVC是基于Servlet封装的用于实现MVC控制的框架,实现前端和服务端的交互。

**/

2.1 SpringMVC的优势

/**

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

**/

2.2 SpringMVC本质工作

/**

1. 接收并解析请求
2. 处理请求
3. 数据渲染,相应请求

**/

 

0x03 SpringMVC框架部署

3.1 基于Maven创建一个Web工程

 

 

3.2 添加SpringMVC依赖

/**

spring-context
spring-aspects
spring-jdbc
spring-web
spring-webmvc
spring-junit

**/
<?xml version="1.0" encoding="UTF-8"?>
<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.0</modelVersion>

    <groupId>com.springMVCDemo</groupId>
    <artifactId>springmvc-demo2</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>war</packaging>

    <properties>
            <spring.version>5.2.13.RELEASE</spring.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aspects</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-web</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>${spring.version}</version>
        </dependency>
    </dependencies>


</project>

 

 3.3 创建SpringMVC配置文件

/**

在resource目录下创建名为spring-servlet.xml文件

添加MVC命名空间

**/
<?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.springMVCDemo"/>
    <!--    声明mvc使用注解驱动-->
    <mvc:annotation-driven/>

</beans>

 

 3.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>

  

0x04 SpringMVC框架使用

4.1 控制器Controller

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

4.1.1 创建控制器

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

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

@Controller
@RequestMapping("/book")
public class BookController {
} 

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

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

4.1.3 访问

  • http://localhost:8081/springmvc_demo22_war_exploded/book/add
  • http://localhost:8081/springmvc_demo22_war_exploded/book/list

4.2 静态资源配置

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

4.2.1 /* 和 / 区别

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

 4.2.2 静态资源放行配置

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

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.springMVCDemo"/>
    <!--    声明mvc使用注解驱动-->
    <mvc:annotation-driven/>

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

</beans>

 

4.3 前端提交数据到控制器

4.3.1 表单提交

表单提交:输入框需要提供name属性,springMVC控制器是通过name属性取值的

<%--
  Created by IntelliJ IDEA.
  User: LT2
  Date: 2022/3/05
  Time: 21:33
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <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>

4.3.2 URL提交

URL提交: <a href="book/add?bookName=java">url提交</a>

4.3.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>

 

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

4.4.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="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>
  •  控制器接收的数据
package com.springMVCDemo.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是一致的,则@RequetParam注解可以省略 

@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);
}

 4.4.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 (){
        console.log("进入方法");
        var obj ={};
        obj.bookName="Java";
        obj.bookAuthor="张三";
        obj.bookPrice=3.33;
        console.log("obj");
        $.ajax({
            url:"book/list",
            type:"post",
            headers:{
                token:"Eqeqeq"
            },
            // contentType:"application/json",
            // data:obj,
            success:function (res){
                console.log(res);
            }
        });
        console.log("结束");
    });
</script>

4.4.3 请求体传值

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

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

  • 前端
<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="pytone";
        obj.bookAuthor="woshinidie";
        obj.bookPrice=3.33;
        console.log("obj");
        $.ajax({
            url:"book/update",
            type:"post",
            // headers:{
            //     token:"Eqeqeq"
            // },
            contentType:"application/json",
            data: JSON.stringify(obj), //data的值为json格式字符串, contentType:"application/json"
            success:function (res){
                console.log(res);
            }
        });
        console.log("结束");
    });
</script>

@RequestBody将前端请求的JSON格式数据转换为Java对象,依赖jackson包

  • 导入jackson的依赖
<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind -->
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.13.0</version>
</dependency>
  • 控制器
    @RequestMapping("/update")
    public void update(@RequestBody Book book){
        System.out.println("~~~~~book update");
        try{
            System.out.println(book);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    ----------------------------------
//    @RequestMapping("/update")
//    public void update(HttpServletRequest request){
//        System.out.println("~~~~~book update");
//        try{
////           Servlet的处理方法: 使用request 的输入流接收请求体数据
//            ServletInputStream is = request.getInputStream();
//            StringBuffer stringBuffer = new StringBuffer();
//            byte[] bs = new byte[100];
//            int len = -1;
//            while ((len = is.read(bs)) != -1){
//                String s = new String(bs,0,len);
//                stringBuffer.append(s);
//            }
//            System.out.println(stringBuffer.toString());
//
//        } catch (IOException e) {
//            e.printStackTrace();
//        }
//    }

 

4.5 控制器响应前端请求

4.5.1 控制器响应同步请求

同步请求: from,超链接

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

转发

@RequestMapping("/add")
public String 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);

    //如何挑战到指定的页面呢?
    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");
    System.out.println(a);
    System.out.println(b);
    System.out.println(c);

    //如何挑战到指定的页面呢?
    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");
    System.out.println(a);
    System.out.println(b);
    System.out.println(c);
    //如何挑战到指定的页面呢?
    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");
    System.out.println(a);
    System.out.println(b);
    System.out.println(c);
    //如何挑战到指定的页面呢?
    ModelAndView modelAndView = new ModelAndView("redirect/tips.jsp");
    return modelAndView;
}

4.5.2 控制器应异步请求

异步请求:ajax请求

使用response中的输出流进行响应

/**

控制器方法的返回类型为void
控制器方法添加HttpServletResponse response 参数
在方法中通过response 获取输出流,使用流响应ajax请求

**/
@RequestMapping("/update")
public void update(@RequestBody Book book, HttpServletResponse response){
    System.out.println("~~~~~book update");
    try{
        System.out.println(book);

        //使用ObjectMapper将对象转换成json格式字符串
        String s = new ObjectMapper().writeValueAsString(book);

        response.setCharacterEncoding("utf-8");
        response.setContentType("application/json");
        PrintWriter out = response.getWriter();
        out.println();
        out.close();

    } catch (Exception e) {
        e.printStackTrace();
    }
}

直接在控制器方法返回相应的对象

  • 控制器方法的返回类型设置为响应给ajax请求的对象类型
  • 在控制器方法前添加一个@ResponseBody注解,将返回的对象转换成json格式返回给ajax请求
  • 如果一个控制器类中的所有方法都是响应ajax请求,则可以直接在控制器类前添加@ResponseBody注解
@RequestMapping("/update")
@ResponseBody
public List<Book> update(){
    System.out.println("~~~~~book update");

    ArrayList<Book> books = new ArrayList<Book>();
    books.add(new Book(1,"我朝","嘿嘿",2.33));
    books.add(new Book(2,"到店","顶顶",2.33));
    return books;

}

 4.5.3 控制器响应同步请求的数据传递

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

  • 返回类型为String:
//1:在控制器方法中定义一个Model类型的参数
//2:在return页面之前,向model中添加键值对,添加的键值对就会被传递到转发的页面
@RequestMapping("/add1")
public String add1(@RequestParam("name") String a,
                        @RequestParam("author") String b,
                        @RequestParam("price") double c,
                        Model model){
    model.addAttribute("key1","value1");
    model.addAttribute("key1",new Book(1,"Java","老张",2.33));
    return "/tips.jsp";

}

//除了使用Model对象传值外还可以直接使用HttpServletRequest对象
@RequestMapping("/add1")
public String add1(@RequestParam("name") String a,
                        @RequestParam("author") String b,
                        @RequestParam("price") double c,
                        HttpServletRequest request){
    request.addAttribute("key1","value1");
    request.addAttribute("key1",new Book(1,"Java","老张",2.33));
    return "/tips.jsp";

}
  • 返回类型为ModelAndView
@RequestMapping("/add2")
public ModelAndView add2(@RequestParam("name") String a,
                        @RequestParam("author") String b,
                        @RequestParam("price") double c){
    System.out.println("~~~~~book add");
    ModelAndView modelAndView = new ModelAndView("/tips.jsp");
    modelAndView.addObject("key1","value");
    modelAndView.addObject("key2",new Book(1,"Java","老张",2.35));
    return modelAndView;
}

 

4.6 解决中文乱码问题

4.6.1 前端编码

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

4.6.2 服务器编码

  • tomcat/conf/server.xml
 <Connector port="8081" protocol="HTTP/1.1"
               connectionTimeout="20000"
               redirectPort="8443" URIEncoding="UTF-8"/>

4.6.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>

 

0x05 SpringMVC的请求处理流程

5.1 SpringMVC的请求处理流程

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

 

 

5.2 SpringMVC的核心组件

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

 

5.3 处理器映射器

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

SpringMVC提供的处理器映射器:

1. BeanNameUrlHandlerMappering 根据控制器的Id访问控制器

2. SimpleUrlHandlerMapping 根据控制器配置的URL访问(默认配置)

配置处理器映射器:

  • 在SpringMVC的配置文件中通过Bean标签声明处理器映射器
  • 配置BeanNameUrlHandlerMapping
<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"></bean>
  • 配置SimpleHandlerMapping
<bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
    <property name="mappings">
        <props>
        //这里也可以通过注解的方式在controller上进行配置@RequestMapping("/aaa")
            <prop key="/aaa">bookController</prop>
            <prop key="/bbb">studentController</prop>
        </props>
    </property>
</bean>

 

5.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>
    • 配置视图解析器

spring-servlet.xml

<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>
    • InternalResourceViewResolver
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
    <property name="prefix" value="/"/>
    <property name="suffix" value=".jsp"/>
</bean>

 

0x06 SpringMVC中的日期格式处理

6.1 在控制器中使用对象接收数据

  • 前端
<form action="test/add" method="post">
    <p>图书名称:<input type="text" name="bookId"></p>
    <p>图书作者:<input type="text" name="bookName"></p>
    <p>图书价格:<input type="text" name="bookPrice"></p>
    <p>图书出版时间:<input type="text" name="publish"></p>
    <p><input type="submit" value="提交"></p>
</form>
  • 后端
package com.springMVCDemo.beans;

import java.util.Date;

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

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

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

    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 getPublish() {
        return publish;
    }

    public void setPublish(Date publish) {
        this.publish = publish;
    }

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

    public Book() {
    }
}
--------------------------
package com.springMVCDemo.controllers;

import com.springMVCDemo.beans.Book;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

import java.util.Date;

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

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

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

 

6.2 日期格式处理

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

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

自定义日期转换器:

6.2.1 创建自定义日期转换器

package com.springMVCDemo.utils;

import org.springframework.core.convert.converter.Converter;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

/*
* 1:创建一个类实现Converter接口,泛型指定从什么类型转换为什么类型
* 2:实现Converter准换方法
* */
public class MyDateConverter implements Converter<String,Date> {

    SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日");

    public Date convert(String s) {
        Date date = null;
        try {
            date = sdf.parse(s);
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return date;
    }
}

 6.2.2 配置自定义转换器

<?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.springMVCDemo"/>
    --------------------------------------------------------------------------------
    <!--    声明mvc使用注解驱动-->
    <mvc:annotation-driven conversion-service="converterFactory"/>
------------------------------------------------------------------------

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

<!--HandlerMapping-->
<!--    <bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"></bean>-->

<!--    <bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">-->
<!--        <property name="mappings">-->
<!--            <props>-->
<!--                <prop key="/aaa">bookController</prop>-->
<!--                <prop key="/bbb">studentController</prop>-->
<!--            </props>-->
<!--        </property>-->
<!--    </bean>-->


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

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

-----------------------------------------------------------
<!--自定义转换器-->
    <bean id="converterFactory" class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
        <property name="converters">
            <set>
<!--                //这里可以配置多个-->
                <bean class="com.liguoqing.utils.MyDateConverter"/>
            </set>
        </property>
    </bean>
----------------------------------------------

</beans>
//自己定义一个转换类
//MyDateConverter.class
package com.springMVCDemo.utils;

import org.springframework.core.convert.converter.Converter;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

/*
* 1:创建一个类实现Converter接口,泛型指定从什么类型转换为什么类型
* 2:实现Converter准换方法
* */
public class MyDateConverter implements Converter<String,Date> {

    SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日");

    public Date convert(String s) {
        Date date = null;
        try {
            date = sdf.parse(s);
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return date;
    }
}

 

0x07 SpringMVC中的文件上传和下载

7.1 SpringMVC框架部署

  • 基于Maven创建web工程
  • 添加SpringMVC所需的依赖
    • Spring-context
    • aspects
    • jdbc
    • test
    • web
    • webmvc
    • jackson
  • 创建SpringMVC配置文件
  • 在web.xml中配置SpringMVC的前端控制器
  • 在web.xml中配置SpringMVC的编码过滤器
  • 配置静态资源处理策略

 

7.2 文件上传

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

7.2.1 前端提交文件

表单提交方式必须为post

表单enctype属性,设置为multipart/form-data

<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="ImgFile"></p>
    <p>提交:<input type="submit" name="提交"></p>
</form>

 7.2.2 控制器接收数据和文件

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

  •  添加依赖:
    • commons-io
    • commons-fileupload
<!-- https://mvnrepository.com/artifact/commons-io/commons-io -->
<dependency>
    <groupId>commons-io</groupId>
    <artifactId>commons-io</artifactId>
    <version>2.4</version>
</dependency>

<!-- https://mvnrepository.com/artifact/commons-fileupload/commons-fileupload -->
<dependency>
    <groupId>commons-fileupload</groupId>
    <artifactId>commons-fileupload</artifactId>
    <version>1.3.1</version>
</dependency>
  • 在spring-servlet.xml中配置文件解析器
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
    <!--一些属性,自己百度-->
    <property name="maxUploadSize" value="10240000"/>
    <property name="maxInMemorySize" value="10240"/>
    <property name="defaultEncoding" value="utf-8"/>
</bean>
  • 在控制器接收文件
    • 在处理文件上传的方法中定义一个MultipartFile类型的对象,就可以接收图片了
package com.springMVCDemo.controller;

import com.springMVCDemo.beans.Book;
import org.springframework.http.HttpRequest;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.IOException; 

@Controller
@RequestMapping("/book")
public class BookController {

    @RequestMapping("/add")
    public String addBook(Book book, MultipartFile ImgFile, HttpServletRequest request) throws IOException {
        System.out.println("~~~~addBook");
        System.out.println(book);
        System.out.println(ImgFile);
        //ImgFile表示上传的图片
        //1:截取上传文件的后缀名,生成新的文件名
        String originalFilename = ImgFile.getOriginalFilename();
        String ext = originalFilename.substring( originalFilename.lastIndexOf(".") );// .jpg
        String filename = System.currentTimeMillis()+ext;

        //2:获取imgs目录在服务器的路径
        String dir = request.getServletContext().getRealPath("imgs");
        String savePath = dir + "/" + filename;//存储路径(C:/asd/ad/asdf/img.jpg)

        //3:保存文件
        ImgFile.transferTo(new File(savePath));

        //4:将图片的访问路径设置到对象
        book.setBookImg("imgs/"+ filename);

        //5:调用service保存book到数据库

        return "/tips.jsp";
    }

}

 

7.3 文件下载

7.3.1 文件下载流程

@RequestMapping("/list")
@ResponseBody
public String[] listImgs(HttpServletRequest request){
    //1:从imgs目录下获取所有的图片信息
    String dir = request.getServletContext().getRealPath("imgs");
    File imgDir = new File(dir);
    String[] filenames = imgDir.list();
    return filenames;
} 

7.3.2 实现文件下载

 

0x08 SpringMVC中的统一异常处理

在我们的应用系统运行的过程中,可能由于运行环境,用户操作,资源不足等各个方面的原因导致系统出现异常

(HTTP状态异常,Java异常Exception);如果系统出现了异常,这些异常将会通过浏览器呈现给用户,而这种异常的显示是没有必要的,

因此我们可以在服务器进行特定的处理--当系统出现异常之后,呈现给用户一个统一的可读的提示页面

8.1 HTTP异常状态统一处理

HTTP Status 404

  • 创建一个用于异常提示的页面: 404.jsp
  • 在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.NullPointerException</exception-type>
    <location>/err.jsp</location>
</error-page>

 8.2.2 SpringMVC处理

  • 使用异常处理类进行统一处理

 

0x09 SpringMVC的拦截器

9.1 拦截器介绍

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

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

 

9.2 自定义拦截器

 9.2.1 创建拦截器

 9.2.2 配置拦截器

 

9.3 拦截器链

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

 

posted @ 2022-03-12 17:53  时光飞逝,逝者如斯  阅读(48)  评论(0编辑  收藏  举报