SpringMVC学习笔记记录

0 、概述

服务器端分成三层架构。

三层架构

一、环境搭建

1.1 Maven环境的创建

  1. 导入坐标依赖

    <!-- 版本锁定 -->
    <spring.version>5.0.2.RELEASE</spring.version>
    <!-- 配置依赖 -->
    <dependencies>
        <!-- spring IOC -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <!-- spring web -->
        <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>javax.servlet</groupId>
            <artifactId>servlet-api</artifactId>
            <version>2.5</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>javax.servlet.jsp</groupId>
            <artifactId>jsp-api</artifactId>
            <version>2.0</version>
            <scope>provided</scope>
        </dependency>
    </dependencies>
    
  2. 配置核心的控制器(类似servlet类 – dispatcherServlet)

    <!DOCTYPE web-app PUBLIC
     "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
     "http://java.sun.com/dtd/web-app_2_3.dtd" >
    
    <web-app>
      <display-name>Archetype Created Web Application</display-name>
      <servlet>
        <servlet-name>dispatcherServlet</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
      </servlet>
      
      <servlet-mapping>
        <servlet-name>dispatcherServlet</servlet-name>
        <url-pattern>/</url-pattern>
      </servlet-mapping>
    </web-app>
    

<url-pattern>/</url-pattern>时,默认就是拦截所有路径连静态资源也不能访问。但是Controller中配置@RequestMapping的路径是不会被拦截的,配置了@RequestMapping就相当于在web.xml中注<servlet>

1.2 第一个执行程序

1.2.1 引入SpringMVC配置文件

resources下新建springMVC.XML配置文件:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:mvc="http://www.springframework.org/schema/mvc"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd
       http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
</beans>
1.2.2 编写控制器
// 控制器
@Controller
public class HelloController {
    
    @RequestMapping("/hello") // 请求的资源路径
    public String sayHello() {
        System.out.println("Hello SpringMVC");
        return "success"; // 需要跳转的页面,默认jsp文件名
    }
}
  1. 控制器类配置@Controller注解,表明是控制器。
  2. 在具体的方法上配置@RequestMapping注解,参数即为访问时的资源路径
  3. return中的字符串,方法执行完需要跳转的页面
1.2.3 完善springMVC.xml配置文件
  1. 控制器中加入注解,那么就需要配置需要扫描的包;
  2. 配置文件解析器,创建IOC容器对象,由Tomcat负责调用;
  3. 配置spring开启注解MVC的支持
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:mvc="http://www.springframework.org/schema/mvc"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd
       http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">

    <!-- 配置spring创建容器时要扫描的包 -->
    <context:component-scan base-package="cn.lizhi"></context:component-scan>
    <!-- 配置视图解析器 Ioc容器对象,由tomcat调用-->
    <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <!-- 文件具体所在的目录 -->
        <property name="prefix" value="/WEB-INF/pages/"></property>
        <!-- 文件解析的类型(后缀名) -->
        <property name="suffix" value=".jsp"></property>
    </bean>

    <!-- 配置spring开启注解mvc的支持 -->
    <mvc:annotation-driven></mvc:annotation-driven>
</beans>

WEB-INF目录下的内容是对客户端不可见,只对服务端可见,即客户端不能直接对其进行访问。

1.2.4 完善web.xml配置文件

由于上方的springMVC.XML配置文件时在resources目录下的,我们启动的是web项目,就需要将该配置文件加载进Tomcat服务器进行读取。

即:配置Servlet的初始化参数,读取springMVC的配置文件,创建spring容器,用于加载配置文件。

MVC配置文件加载成功,那么其中的扫描就能够成功,继而将控制器中的类加载成对象。

<!DOCTYPE web-app PUBLIC
 "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
 "http://java.sun.com/dtd/web-app_2_3.dtd" >

<web-app>
  <display-name>Archetype Created Web Application</display-name>
  <servlet>
    <servlet-name>dispatcherServlet</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <!-- 配置Servlet的初始化参数,读取springMVC的配置文件,创建spring容器,用于加载配置文件
          MVC配置文件加载成功,那么其中的扫描就成功,继而到控制器中类加载成对象
    -->
    <init-param>
      <param-name>contextConfigLocation</param-name>
      <param-value>classpath:springMVC.xml</param-value>
    </init-param>
    <!-- 服务器在启动时,就加载资源
 		 配置servlet的对象的创建时间点:应用加载时创建。-->
    <load-on-startup>1</load-on-startup>
  </servlet>
  <servlet-mapping>
    <servlet-name>dispatcherServlet</servlet-name>
    <!-- 配置资源路径/表明所有的资源皆可被访问到 -->
    <url-pattern>/</url-pattern>
    <!-- 表明只有hello的资源路径可以被访问到
      <url-pattern>/hello</url-pattern>
    -->
  </servlet-mapping>
</web-app>

二、Spring MVC 详解

2.1 执行过程及组件分析

2.1.1 执行过程
  1. 当启动Tomcat服务器的时候,因为配置了load-on-startup标签,所以会创建DispatcherServlet对象,就会加载springmvc.xml配置文件。这里是服务器启动,应用被加载。读取到web.xml中的配置创建spring容器并且初始化容器中的对象。
  2. springmvc.xml配置文件中开启了注解扫描,那么相应的controller对象(HelloController)对象就会被创建。
  3. index.jsp发送请求,请求会先到达DispatcherServlet核心控制器,根据配置@RequestMapping注解找到执行的具体方法。浏览器发送请求,被DispatcherServlet捕获,该Servlet并不处理请求,而是把请求转发出去。转发的路径是根据请求URL,匹配@RequestMapping中的内容。
  4. 根据执行方法的返回值,再根据配置的视图解析器,去指定的目录下查找指定名称的JSP文件。即:根据方法的返回值,借助InternalResourceViewResolver找到对应的结果视图。
  5. Tomcat服务器渲染页面,做出响应。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IfavgG6R-1617344854362)(https://s3.ax1x.com/2020/12/23/r6iFFs.png)]

2.1.2 组件分析
  1. DispatcherServlet:前端控制器

    用户请求到达前端控制器,它就相当于MVC模式中的cdispatcherServlet是整个流程控制的中心,由它调用其它组件处理用户的请求,dispatcherServlet的存在降低了组件之间的耦合性。

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iavVPVW8-1617344854369)(https://s3.ax1x.com/2020/12/23/r6iCwQ.png)]

  2. HandlerMapping:处理器映射器

    HandlderMapping负责根据用户请求找到Handler,即处理器,SpringMVC提供了不同的映射器实现不同的映射方式,例如:配置文件方式,实现接口方式,注解方式等。

  3. Handler:处理器

    它就是开发中编写的具体业务控制器。由DispatcherServlet把用户请求转发到Handler。由Handler对具体的用户请求进行处理。

  4. Handler:处理器适配器

    通过HandlerAdapter对处理器进行执行,这是适配器模式的应用,通过扩展适配器可以对更多类型的处理器进行执行。

  5. View Resolver:视图解析器

    View Resolver负责将处理结果生成View视图,View Resolver首先根据逻辑视图名解析成物理视图名即具体的页面地址,再生成View视图对象,最后对View进行渲染将处理结果通过页面展示给用户。

  6. View:视图

    将数据视图展示给客户端,即用户。

2.1.3 <mvc:annotation-driver>说明

SpringMVC的各个组件中,处理器映射器、处理器适配器、视图解析器成为SpringMVC的三大组件。使用<mvc:annotation-driver>自动加载RequestMappingHandlerMapping(处理器映射器)和RequestMappingHandlerAdapter(处理器适配器)。

2.2 常用注解说明

2.2.1 RequestMapping

作用:用于建立请求URL和处理请求方法之间的对应关系。

2.2.2 RequestParam

作用:把请求中指定名称的参数给控制器中的形参赋值。(适用于请求名称与属性名不相同的情况)

属性:

  • value:请求参数的名称。
  • required:请求参数中是否必须提供此参数。默认值:true。表示必须提供,如果不提供将报错。
@RequestMapping("/useRequestParam")
public String useRequestParam(@RequestParam("name")String username,@RequestParam(value="age",required=false)Integer age){
    System.out.println(username+","+age);
    return "success"; 
}
2.2.3 RequestBody

作用:用于获取请求体内容。直接使用得到是key=value&key=value...结构的数据。get请求方式不适用。

属性:

  • required:是否必须有请求体。默认值是:true。当取值是true时,get请求方式会报错。如果取值为falseget请求得到是null
@RequestMapping("/useRequestBody")
public String useRequestBody(@RequestBody(required=false) String body){
	System.out.println(body);
    return "success"; 
}
2.2.4 PathVariable

作用:用于绑定url中的占位符。例如:请求url/delete/{id},这个{id}就是url占位符。url支持占位符是spring3.0之后加入的。是springmvc支持rest风格URL的一个重要标志。

属性:

  • value:用于指定url中占位符名称。
  • required:是否必须提供占位符。

重点restful风格。

@RequestMapping("/usePathVariable/{id}")
public String usePathVariable(@PathVariable("id") Integer id){
    System.out.println(id);
    return "success"; 
}
2.2.5 RequestHeader

作用:用于获取请求消息头

属性:

  • value:提供消息头名称,用于指定获取消息头中的哪一部分。
  • required:是否必须有此消息头。
@RequestMapping("/useRequestHeader")
public String useRequestHeader(@RequestHeader(value="Accept-Language",
required=false)String requestHeader){
    System.out.println(requestHeader);
    return "success"; 
}

将请求头内容的信息封装到requestHeader参数中。

2.2.6 CookieValue

作用:用于把指定cookie名称的值传入控制器方法参数。

属性:

  • value:指定cookie的名称。键值对的形式,通过键来获取到它的值。
  • required:是否必须有cookie
@RequestMapping("/useCookieValue")
public String useCookieValue(@CookieValue(value="JSESSIONID",required=false) 
String cookieValue){
	System.out.println(cookieValue);
    return "success"; 
}
2.2.7 ModelAttribute

作用:该注解是SpringMVC4.3版本以后新加入的。它可以用于修饰方法和参数。

出现在方法上,表示当前方法会在控制器的方法执行之前,先执行。它可以修饰没有返回值的方法,也可以修饰有具体返回值的方法。

出现在参数上,获取指定的数据给参数赋值。

属性:

  • value:用于获取数据的keykey可以是POJO的属性名称,也可以是Map结构的key

应用场景:

当表单提交数据不是完整的实体类数据时,保证没有提交数据的字段使用数据库对象原来的数据。

例如:

当我们在编辑一个用户时,用户有一个创建信息字段,该字段的值是不允许被修改的。在提交表单数据时肯定没有此字段的内容,一旦更新会把该字段内容置为null,此时就可以使用此注解解决问题。

示例1:

@ModelAttributepublic 
public void showModel(User user) {
    System.out.println("执行了showModel方法"+user.getUsername());
}
/*** 
    接收请求的方法
* 	@param user* @return
*/
@RequestMapping("/testModelAttribute")
public String testModelAttribute(User user) {
    System.out.println("执行了控制器的方法"+user.getUsername());
    return "success"; 
}

即先执行showModel方法,再执行控制器中的方法testModelAttribute

2.2.7.1 ModelAttribute 修饰方法带返回值

需求:修改用户信息,要求用户密码不能修改

前端代码:

<form action="springmvc/updateUser" method="post">
    用户名称:<input type="text" name="username" ><br/>
    用户年龄:<input type="text" name="age" ><br/>
    <input type="submit" value="保存">
</form>
  1. 模拟查询数据库中用户信息
@ModelAttribute
public User showModel(String username) {
    //模拟去数据库查询
    User userByName = findUserByName(username);
    System.out.println("执行了 showModel 方法"+userByName);
    return userByName; 
}
  1. 模拟修改用户方法
@RequestMapping("/updateUser")
public String testModelAttribute(User user) {
    System.out.println("控制器中处理请求的方法:修改用户:"+user);
    return "success"; 
}
  1. 模拟去数据库查询
private User findUserByName(String username) {
    // 以下4句用来模拟数据库中的原有对象,即查询出来的对象
    User user = new User();
    user.setUsername(username);
    user.setAge(19);
    user.setPassword("123456");
    return user;
}

首先通过前端请求,获取username,而在showModel方法中参数,就是由前端请求的参数username。然后showModel方法体中通过数据库查询对象,再将对象进行返回。返回的对象是数据中的相对应的原有对象。(类似过滤器,后续在控制器中将需要修改的值,进行修改,不变的值,就不需要再次改动)。

2.2.7.2 ModelAttribute 修饰方法不带返回值

需求:修改用户信息,要求用户的密码不能修改

  1. 前端代码
<!-- 修改用户信息 --> 
<form action="springmvc/updateUser" method="post">
    用户名称:<input type="text" name="username" ><br/>
    用户年龄:<input type="text" name="age" ><br/>
    <input type="submit" value="保存">
</form>
  1. 查询数据库中用户信息-- 模拟去数据库查询
@ModelAttribute
public void showModel(String username,Map<String,User> map) {
    //模拟去数据库查询
    User user = findUserByName(username);
    System.out.println("执行了 showModel 方法"+user);
    map.put("abc",user);
}
  1. 模拟修改用户方法
@RequestMapping("/updateUser")
public String testModelAttribute(@ModelAttribute("abc")User user) {
    System.out.println("控制器中处理请求的方法:修改用户:"+user);
    return "success"; 
}
  1. 模拟去数据库查询
private User findUserByName(String username) {
    User user = new User();
    user.setUsername(username);
    user.setAge(19);
    user.setPassword("123456");
    return user; 
}

第二种不带返回值的方式更容易理解,即将原有的对象存放在map集合中,再通过注解,获取指定(根据map中的键)的数据给参数赋值。最后,将前端请求的参数对应的封装到这个参数中,就能够保证这个参数对象的所有属性都能够有值。

2.2.8 SessionAttributes

作用:用于多次执行控制器方法间的参数共享。只能作用在类对象(Class)上。

属性:

  • value:用于指定存入的属性名称
  • type:用于指定存入的数据类型
  1. 前端代码
<!-- SessionAttribute 注解的使用 --> 
<a href="springmvc/testPut">存入 SessionAttribute</a> <hr/>
<a href="springmvc/testGet">取出 SessionAttribute</a> <hr/>
<a href="springmvc/testClean">清除 SessionAttribute</a>
  1. 控制器中的代码
@Controller("sessionAttributeController")
@RequestMapping("/springmvc")
@SessionAttributes(value ={"username","password"},types={Integer.class})
public class SessionAttributeController {
    /**
    * 把数据存入 SessionAttribute
    * @param model
    * @return
    * Model 是 spring 提供的一个接口,该接口有一个实现类 ExtendedModelMap
    * 该类继承了 ModelMap,而 ModelMap 就是 LinkedHashMap 子类
    */
    @RequestMapping("/testPut") 
    public String testPut(Model model){ 
    model.addAttribute("username", "泰斯特"); 
    model.addAttribute("password","123456"); 
    model.addAttribute("age", 31); 
    //跳转之前将数据保存到 username、password 和 age 中,因为注解@SessionAttribute 中有这几个参数
    return "success"; 
    } 
    
    @RequestMapping("/testGet") 
    public String testGet(ModelMap model){ 
    System.out.println(model.get("username")+";"+model.get("password")+";"+model.get("a
    ge")); 
    return "success"; 
    } 
    
    @RequestMapping("/testClean") 
    public String complete(SessionStatus sessionStatus){ 
    sessionStatus.setComplete(); 
    return "success"; 
    } 
}

通过model对象进行值的存储操作,底层会将值存储在request域中。而又使用@SessionAttributes注解,具体有@SessionAttributes(value ={"username","password"},types={Integer.class})。此时通过values数组的指定 – usernamepassword,则表明model在存储操作时,不仅会将这两个的值存储在request域对象中,同时也会存储在session域对象中。

取值时,使用的model实现类 – ModelMap

删除时,使用SessionStatus

2.3 请求参数的绑定

前端向后端进行请求时,表单中请求参数都是基于key=value的。SpringMVC绑定请求参数的过程是通过把表单请求参数,作为控制器中方法参数进行绑定的。

2.3.1 支持的数据类型
  1. 基本数据类型

    • 基本数据类型
    • String类型
  2. POJO类型参数(实现序列化接口)

    • 实体类
    • 关联的实体类
  3. 数组和集合类型参数

    包括List结构和Map结构的集合(包括数组)

SpringMVC绑定请求参数是自动实现的,但是想要使用,必须遵循使用要求。

2.3.2 使用要求
  1. 基本数据类型或者是String类型:

要求我们的参数名称必须和控制器中方法的形参名称保持一致。(严格区分大小写)

  1. POJO类型或者及其关联对象

如果表单中参数名称和POJO类的属性名称保持一致。并且控制器方法的参数类型是POJO类型。

  1. 如果是集合类型

    • 第一种

      要求集合类型的请求参数必须在POJO中。在表单中请求参数名称要和POJO中集合属性名称相同。

      List集合中的元素赋值,使用下标。

      Map集合中的元素赋值,使用键值对。

    • 第二种

      接收的请求参数是json格式数据。需要借助一个注解实现。

  2. SpringMVC可以实现一些数据类型自动转换。其内置转换器全部都在:

    org.springframework.core.convert.support包下。

2.3.3 使用实例
2.3.3.1 POJO类型作为参数
  1. 实体类代码
public class Account implements Serializable {
	
    private Integer accountId;
    private String accountName;
    private Float money;
    private Address address;

    // getters and setters 方法
    
    // toString方法
}

以上是Account类。其中关联Address类:

package cn.lizhi.domain;

public class Address {

    private String provinceName;
    private String cityName;

	// getters and setters 方法
    
    // toString方法
}
  1. 前端代码
<form action="account/saveAccount" method="post">
    账户名称:<input type="text" name="name" ><br/>
    账户金额:<input type="text" name="money" ><br/>
    账户省份:<input type="text" name="address.provinceName" ><br/>
    账户城市:<input type="text" name="address.cityName" ><br/>
    <input type="submit" value="保存">
</form>

通过对象.属性的方式进行赋值。

  1. 控制器代码
@RequestMapping("/saveAccount")
public String saveAccount(Account account) {
    System.out.println("保存了账户。。。。"+account);
    return "success"; 
}
2.3.3.2 POJO类中包含集合类型参数
  1. 实体类 – User
package cn.lizhi.domain;
import java.util.Date;
import java.util.List;
import java.util.Map;

public class User {

    private String username;
    private String password;
    private Integer age;
    private Date date;
    private List<Account> accounts;
    private Map<String,Account> accountMap;

    // getter and setter
    
    @Override
    public String toString() {
        return "User{" +
                "username='" + username + '\'' +
                ", password='" + password + '\'' +
                ", age=" + age +
                ", date=" + date +
                ", accounts=" + accounts +
                ", accountMap=" + accountMap +
                '}';
    }
}
  1. 前端代码
<!-- POJO 类包含集合类型演示 -->
<form action="account/updateAccount" method="post">
    用户名称:<input type="text" name="username" ><br/>
    用户密码:<input type="password" name="password" ><br/>
    用户年龄:<input type="text" name="age" ><br/>
    账户 1 名称:<input type="text" name="accounts[0].name" ><br/>
    账户 1 金额:<input type="text" name="accounts[0].money" ><br/>
    账户 2 名称:<input type="text" name="accounts[1].name" ><br/>
    账户 2 金额:<input type="text" name="accounts[1].money" ><br/>
    账户 3 名称:<input type="text" name="accountMap['one'].name" ><br/>
    账户 3 金额:<input type="text" name="accountMap['one'].money" ><br/>
    账户 4 名称:<input type="text" name="accountMap['two'].name" ><br/>
    账户 4 金额:<input type="text" name="accountMap['two'].money" ><br/>
    <input type="submit" value="保存">
</form>

集合、列表赋值的方式。三要素:属性下标参数(属性)

  1. 控制器代码
@RequestMapping("/updateAccount")
public String updateAccount(User user) {
    System.out.println("更新了账户。。。。"+user);
    return "success"; 
}

2.4 请求参数乱码问题

tomcat8以后get请求方式,中文正常显示;post请求方式,中文会出现乱码问题。

在之前的serlvet学习中,对乱码解决的方式,是通过Filter过滤器。而现在SpringMVC提供好现有的类供我们使用。

首先post请求方式,在web.xml中配置一个过滤器。

  <!-- 配置解决中文乱码的过滤器 -->
  <filter>
    <filter-name>characterEncodingFilter</filter-name>
    <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
    <!--设置过滤器中的属性值-->
    <init-param>
      <param-name>encoding</param-name>
      <param-value>UTF-8</param-value>
    </init-param>
    <!-- 启动过滤器 -->
    <init-param>
      <param-name>encoding</param-name>
      <param-value>UTF-8</param-value>
    </init-param>
  </filter>
  <!-- 过滤所有请求 -->
  <filter-mapping>
    <filter-name>characterEncodingFilter</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>

如果想不过滤静态资源,在 Springmvc 的配置文件中可以配置,静态资源不过滤:

<!-- location 表示路径,mapping 表示文件,**表示该目录下的文件以及子目录的文件 -->
<mvc:resources location="/css/" mapping="/css/**"/>
<mvc:resources location="/images/" mapping="/images/**"/>
<mvc:resources location="/scripts/" mapping="/javascript/**"/>

get请求方式:

tomcatGETPOST请求处理方式是不同的,GET请求的编码问题,要改tomcatserver.xml配置文件,如下:

<Connector connectionTimeout="20000" port="8080"
protocol="HTTP/1.1" redirectPort="8443"/>
改为:
<Connector connectionTimeout="20000" port="8080"
protocol="HTTP/1.1" redirectPort="8443"
useBodyEncodingForURI="true"/>
<!-- 如果遇到 ajax 请求仍然乱码,请把:-->
useBodyEncodingForURI="true"改为 URIEncoding="UTF-8"

2.5 自定义类型转换器

例如,在前端输入日期格式时:

<!-- 特殊情况之:类型转换问题 --> 
<a href="account/deleteAccount?date=2018-01-01">根据日期删除账户</a>

可以看出,请求参数中,date=2018-01-01

当我们在后端接收到请求时:

@RequestMapping("/deleteAccount")
    public String deleteAccount(String date) {
    System.out.println("删除了账户:" + date);
    return "success";
}

输出:删除了账户:2018-01-01。如果当我们将接收参数的类型改为Date类型时:

@RequestMapping("/deleteAccount")
    public String deleteAccount(Date date) {
    System.out.println("删除了账户:" + date);
    return "success";
}

此时,前端再次请求时,会报400

下面便是我们自定义类型转化的方式:

首先,定义一个类,实现Convertet接口,该接口有两个泛型。

public interface Converter<S, T> {//S:表示接受的类型,T:表示目标类型
    /**
    * 实现类型转换的方法
    */
    @Nullable
    T convert(S source);
}

其中,S表示接受的类型,T表示目标类型。

其实现类:

public class StringToDate implements Converter<String, Date> {
    @Override
    public Date convert(String source) {

        if (source == null || source == "") {
            throw new RuntimeException("请输入日期");
        }

        SimpleDateFormat format = new SimpleDateFormat("yyyy-mm-dd");
        try {
            Date data = format.parse(source);
            return data;
        } catch (ParseException e) {
            throw new RuntimeException("请输入正确的日期格式");
        }

    }
}

其次,在Spring配置文件中配置类型转换器。

Spring配置类型转换器的机制是,将自定义的转换器注册到类型转换服务中去。

    <bean id="converterService" class="org.springframework.context.support.ConversionServiceFactoryBean">
        <!-- 给工厂注入一个新的类型转换器 -->
        <property name="converters">
            <array>
                <!-- 配置自定义类型转换器 -->
                <bean  class="cn.lizhi.utils.StringToDate"/>
            </array>
        </property>
    </bean>
    
    <!-- 配置spring开启注解mvc的支持 -->
    <mvc:annotation-driven conversion-service="converterService"></mvc:annotation-driven>

通过查看源码:

public class ConversionServiceFactoryBean implements FactoryBean<ConversionService>, InitializingBean {
    @Nullable
    private Set<?> converters;
    @Nullable
    private GenericConversionService conversionService;

    public ConversionServiceFactoryBean() {
    }

    public void setConverters(Set<?> converters) {
        this.converters = converters;
    }

    public void afterPropertiesSet() {
        this.conversionService = this.createConversionService();
        ConversionServiceFactory.registerConverters(this.converters, this.conversionService);
    }

    protected GenericConversionService createConversionService() {
        return new DefaultConversionService();
    }

    @Nullable
    public ConversionService getObject() {
        return this.conversionService;
    }

    public Class<? extends ConversionService> getObjectType() {
        return GenericConversionService.class;
    }

    public boolean isSingleton() {
        return true;
    }
}

其中converters是集合类型,并且有setter方法,通过上方的spring配置文件,给工厂注入一个新的类型转换器(不会覆盖原有的转换器)。

这样,在我们后面的使用中,便能够识别并对应转换成我们相应数据格式。

总之,实现转换器的方法以及对spring的配置,就是在原有的转换器集合中,再加入一种我们自己编写的转换器,以供我们使用。

2.6 响应数据

2.6.1 方法返回值的分类
2.6.1.1 String 类型

Controller方法返回字符串可以指定逻辑视图的名称,根据视图解析器为物理视图的地址。

即为前面所写的常规的返回值为String的方法,返回值为所需要跳转的物理视图的名称(即为跳转页面名称 -->地址)。

@RequestMapping(value="/hello") 
public String sayHello() { 
	System.out.println("Hello SpringMVC!!"); 
    // 跳转到XX页面 -- 跳转到success页面
    return "success";
}

模拟应用 – 模拟对数据库中的数据进行查询

  1. 前端代码

index.jsp页面

<!-- 模拟用户的修改 -->
<h3>修改用户</h3>
<a href="/user/initUpdate">模拟用户修改</a>

模拟update.jsp页面

<%@ page contentType="text/html;charset=UTF-8" language="java" isELIgnored="false" %>
<html>
<head>
    <title>首页</title>
</head>
<body>
<!-- 模拟用户的修改 -->
<h3>修改用户</h3>
<form action="/user/initUpdate" method="post">
    姓名:<input type="text" name="username" value="${user.username}"><br>
    密码:<input type="text" name="password" value="${user.password}"><br>
    金额:<input type="text" name="money" value="${user.money}"><br>
    <input type="submit" value="提交">
</form>
</body>
</html>
  1. 后端控制器代码
@Controller("userController")
@RequestMapping("/user")
public class UserController {
    @RequestMapping("/initUpdate")
    public String initUpdate(Model model) {
        // 模拟从数据库中查询数据
        User user = new User();
        user.setUsername("张三");
        user.setPassword("123456");
        user.setMoney(123d);
        model.addAttribute("user", user);
        return "update";
    }
}

返回值是update,即最后跳转到update页面。

2.6.1.2 void类型

如果控制器的方法返回值是void,在执行程序报404的异常,默认查找jsp页面没有找到。

Type Status Report
消息 /WEB-INF/pages/user/initUpdate.jsp
描述 源服务器未能找到目标资源的表示或者是不愿公开一个已经存在的资源表示。

从上面的错误信息可以看出,它会默认跳转到控制器中@RequestMapping("/example")initUpdate的页面。

SpringMVCServlet原始API可以作为控制器中方法的参数,即在controller方法形参上可以定义requestresponse,使用requestresponse指定相应结果。

  1. 使用request(即为存储转发)转向页面

    request.getRequestDispatcher("/WEB-INF/pages/success.jsp").forward(request, 
    response);
    

    在存储转发中不需要写虚拟目录,但这里的资源路径需要写webApp中的全路径,没有像前面只写一个success的原因是,前一种是交给了视图解析器进行管理;而这里没有用到视图解析器,是单纯由request进行实现,故需要写出资源的全路径。

  2. 使用response进行页面的重定向

    response.sendRedirect(request.getContextPath() + "/page.jsp");
    

    需要加上虚拟目录。

  3. 通过response指定响应结果,例如响应json数据:

    response.setCharacterEncoding("utf-8");
    response.setContentType("application/json;charset=utf-8");
    response.getWriter().write("json串");
    
2.6.1.3 关键字的转发或重定向

使用关键字进行转发或重定向时,Spring不会再通过视图解析器帮我们解析路径,需要我们自己手动配置。即就像上一小结中,资源路径需要写全。

  1. Forward转发

controller方法在提供了String类型的返回值之后,默认就是请求转发。当然,我们可以手动进行设置:

    @RequestMapping("/testForward")
    public String testForward() {
        System.out.println("test1方法执行了...");
        return "forward:/WEB-INF/pages/success.jsp";
    }

如果用了forward:,则路径必须写成实际视图url,不能写逻辑视图。

它相当于它相当于request.getRequestDispatcher("**url**").forward(request,response)。使用请求转发,既可以转发到jsp(到视图解析器中),也可以转发到其他的控制器方法。

  1. Redirect重定向

controller方法提供了一个String类型返回值之后,它需要在返回值里使用:redirect:

    @RequestMapping("/testRedirect")
    public String testRedirect() {
        System.out.println("testRedirect方法执行了...");
//        return "redirect:testForward"; // 重定向至另一个servlet地址
        return "redirect:/index.jsp"; // 重定向至jsp页面
    }

它相当于response.sendRedirect(url)。需要注意的是,如果是重定向到jsp页面,则jsp页面不能写在WEB-INF目录中,否则无法找到。

原因:
重定向是客户端的,而转发是服务端内部的。
重定向是让客户端去访问重定向的地址,而WEB-INF下的文件是不能通过外部访问的!

2.6.1.4 ResponseBody响应json数据

作用:该注解用于将Controller的方法返回的对象,通过HttpMessageConverter接口转换为指定格式的数据。如:jsonxml等,通过Response响应给客户端。

需求:使用@ResponseBody注解实现将controller方法返回对象转换为json响应给客户端。

前置:SpringMVC默认用MappingJacksonHttpMessageConverterjson数据进行转换,需要加入jackson的包。我们的项目中通过导入依赖的方法进行包的管理。

        <!-- 对json处理的包,即能够使用@ResponseBody -->
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.9.0</version>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-core</artifactId>
            <version>2.9.0</version>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-annotations</artifactId>
            <version>2.9.0</version>
        </dependency>

需要配置前端控制器不拦截静态资源。

DispatcherServlet会拦截到所有的资源,导致一个问题就是静态资源(img、css、js)也会被拦截到,从而
不能被使用。解决问题就是需要配置静态资源不进行拦截,在springmvc.xml配置文件添加如下配置:

<!-- 设置静态资源不过滤 -->
<mvc:resources location="/css/" mapping="/css/**"/> 
<!-- 样式 --> 
<mvc:resources location="/images/" mapping="/images/**"/>
<!-- 图片 --> 
<mvc:resources location="/js/" mapping="/js/**"/> <!-- javascript -->

其中,mvc:resources标签配置不过滤谁。

  • location元素表示webapp目录下的包下的所有文件.
  • mapping元素表示以/static开头的所有请求路径,如/static/a 或者/static/a/b.

客户端发送ajax的请求,传的是json字符串,后端把json字符串封装到user对象中。

响应:将对象转换成json字符串。

  1. 前端部分代码
    <input type="button" value="异步请求测试" id="testJson">
    <script>
        $(function () {
            $("#testJson").click(function () {
                $.ajax({
                    type: "post",
                    url: "${pageContext.request.contextPath}/user/testResponseBody",
                    contentType: "application/json;charset=utf-8", // 发送信息至服务器时内容编码类型
                    data: '{"username":"张三","password":"123","money":123}', // 发送的json数据
                    dataType: "json", // 服务器返回的数据类型 -- json
                    success: function (data) {
                        alert(data)
                    }
                });

            });
        })
    </script>
  1. 控制器中的代码
    @RequestMapping("/testResponseBody")
    public @ResponseBody User testResponseBody(@RequestBody User user) {
        System.out.println("异步请求:" + user);
        return user;
    }

在控制器中的代码,其中@RequestBody将前端发送的ajax请求的json格式数据封装成JavaBean@ResponseBody将后端返回值JavaBean对象,格式化成json数据类型返回给客户端,直接响应。

总结:首先通过@RequestBody获取请求体数据,将前端请求的json字符穿转换成JavaBean对象,最后使用@ResponseBody注解把JavaBean对面转换成Json字符串,直接响应。

2.6.1.5 ModelAndView对象

ModelAndView对象是Spring提供的一个对象,可以用来调整具体的JSP视图,即可以用作控制方法的返回值。该对象中有两个方法:

方法1:addObject

    public ModelAndView addObject(String attributeName, Object attributeValue) {
        this.getModelMap().addAttribute(attributeName, attributeValue);
        return this;
    }

添加模型到该对象中,通过上面的代码可以看出,和前面所讲的请求参数封装中用到的对象是同一个。即jsp页面中同样可以使用EL表达式从request域中获取值。

方法2:setViewName

public void setViewName(@Nullable String viewName) {
        this.view = viewName;
    }

用于设置逻辑视图名称,视图解析器会根据名称前往指定的视图。这也ModelAndViewModel最大的不同,它可以设置跳转的逻辑视图名称。

使用示例:

    @RequestMapping("/testModelAndView")
    public ModelAndView testModelAndView() {
        System.out.println("testModelAndView...");
        ModelAndView mv = new ModelAndView();
        mv.addObject("username", "张三");
        mv.setViewName("success");
        return mv;
    }
  1. 可以将对象存储到request域中。mv.addObject("key",value)
  2. 可以存储跳转到哪个页面中。mv.setViewName("success") – 选择视图解析器,进行解析。

前端代码:可以直接通过EL表达式进行值的获取,${username} --> 张三

ModelAndViewModel两者的不同:

  1. Model是每次请求中都存在的默认参数,利用其addAttribute()方法即可将服务器的值传递到jsp页面中;
  2. ModelAndView包含modelview两部分,使用时需要自己实例化,利用ModelMap用来传值,也可以设置view的名称。
  3. 总而言之,就是ModelAndView除了同Model一样包含存储的键值外,它还存储着跳转页面的名称地址,直接将ModelAndView对象整体作为返回值,其对象中存储的地址自动由SpringMVC进行视图解析。

2.7 SpringMVC实现文件上传

文件上传的前提:

  • form表单的enctype取值必须是:multipart/form-data。默认值是:application/x-www-form-urlencodedenctype:是表单请求正文的类型。
  • method属性取值必须是POST
  • 提供一个文件选择域<input type="file"/>

文件上传的原理:

当form 表单的enctype取值不是默认值后,request.getParameter()将失效。 
enctype=”application/x-www-form-urlencoded”时,form 表单的正文内容是:
key=value&key=value&key=value
当form 表单的enctype取值为Mutilpart/form-data时,请求正文内容就变成:
每一部分都是 MIME 类型描述的正文
-----------------------------7de1a433602ac 分界符
Content-Disposition: form-data; name="userName" 协议头
aaa 协议的正文
-----------------------------7de1a433602ac
Content-Disposition: form-data; name="file"; 
filename="C:\Users\zhy\Desktop\fileupload_demofile\b.txt"
Content-Type: text/plain 协议的类型(MIME 类型)
bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
-----------------------------7de1a433602ac--

使用Commons-fileupload组件实现文件上传,需要导入该组件相应的支撑jar包:

  • Commons-fileupload
  • Commons-io

Commons-io不属于文件上传组件的开发jar文件,但Commons-fileupload组件从1.1版本开始,它工作时需要commons-io包的支持。

导入依赖:

<!-- 文件上传依赖 -->
<dependency>
    <groupId>commons-fileupload</groupId>
    <artifactId>commons-fileupload</artifactId>
    <version>1.3.1</version>
</dependency>
<dependency>
    <groupId>commons-io</groupId>
    <artifactId>commons-io</artifactId>
    <version>2.4</version>
</dependency>

前端页面:

<form action="/user/testUpload" method="post" enctype="multipart/form-data">
    选择文件:<input type="file" name="upload"/><br>
    <input type="button" value="文件上传"/>
</form>

后端页面:

@RequestMapping("/testUpload")
public String testUpload(HttpServletRequest request) throws Exception {
    // 先获取到要上传的文件目录 - 即需要上传的目录设置成uploads
    String path = request.getSession().getServletContext().getRealPath("/uploads");
    // 创建File对象,用于向该路径下上传文件
    File file = new File(path);
    // 判断路径是否存在,若不存在则创建该路径
    if (!file.exists()) {
        file.mkdirs();
    }
    // 创建磁盘文件项工厂
    DiskFileItemFactory factory = new DiskFileItemFactory();
    ServletFileUpload fileUpload = new ServletFileUpload(factory);
    // 解析request对象
    List<FileItem> list = fileUpload.parseRequest(request);
    // 遍历
    for (FileItem fileItem : list) {
        // 判断文件项是普通字段,还是上传的文件
        if (fileItem.isFormField()) {
            continue;
        } else {
            // 上传文件
            // 获取到上传文件的名称
            String name = fileItem.getName();
            String uuid = UUID.randomUUID().toString().replaceAll("-", "").toUpperCase();
            // 将文件名唯一化
            name = uuid + "_" + name;
            // 上传文件
            fileItem.write(new File(file, name));
            // 删除临时文件
            fileItem.delete();

        }
    }
    return "success";
}

备注:request.getSession().getServletContext()获取servlet容器对象(最大的域对象),也可以理解为项目真正部署到tomcat时获得的tomcat(服务器)对象。因为session是服务器端对象。而request.getSession().getServletContext().getRealPath()用于获取指定目录在服务器端所真正部署的路径。

2.7.1 SpringMVC传统方式的文件上传

SpringMVC传统方式的文件上传,指的是我们上传的文件和访问的应用存在于同一台服务器上,并且上传完成以后,浏览器可能跳转。

SpringMVC框架提供了MultipartFile对象,该对象表示上传的文件,要求变量名称必须和表单file标签的name属性名称相同。

  1. 配置文件解析器
	<!-- 配置文件解析器对象,要求id名称必须是multipartResolver -->
    <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
        <!-- 配置文件最大上传的byte -->
        <property name="maxUploadSize" value="10485760"/>
    </bean>
  1. 控制器代码
    @RequestMapping("/testSpringMVCUpload")
    public String testSpringMVCUpload(HttpServletRequest request, MultipartFile upload) throws IOException { // 参数upload要和前端中的name属性相同
        System.out.println("SpringMVC方式的文件上传..");
        String path = request.getSession().getServletContext().getRealPath("/uploads");
        File file = new File(path);
        if (!file.exists()) {
            file.mkdirs();
        }

        // 获取到要上传文件的名称
        String filename = upload.getOriginalFilename();
        String uuid = UUID.randomUUID().toString().replaceAll("-", "").toUpperCase();
        filename = uuid + "_" + filename;
        // 上传文件
        upload.transferTo(new File(path,filename));
        return "success";
    }

SpringMVC文件上传的主要步骤图:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4LL5b6Qj-1617344854371)(https://s3.ax1x.com/2020/12/23/r6iPoj.png)]

首先前端请求,经过前端控制器将请求交给配置文件解析器,由相应的处理器进行处理。

2.7.2 SpringMVC跨服务器方式的文件上传

在实际开发中,我们可能会处理很多不同功能的服务器。例如:

  • 应用服务器:负责部署我们的应用
  • 数据库服务器:运行我们的数据库
  • 缓存和消息服务器:负责处理大并发访问的缓存和消息
  • 文件服务器:负责存储用户上传文件的服务器

即每个服务器负责每一个功能模块,而不是由一个服务器承担全部。分服务器处理的目的是让服务器各司其职,从而提高我们项目的运行效率。请求都由应用服务器进行处理转发,而需要的功能都分发到每个单独的服务器进行处理。见下图:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Bqv4NhP6-1617344854372)(https://s3.ax1x.com/2020/12/23/r6iSOS.png)]

现在模拟图片上传:

  1. 导入开发需要的Jar
       <!-- 跨服务器上传需要的依赖 -->
        <dependency>
            <groupId>com.sun.jersey</groupId>
            <artifactId>jersey-core</artifactId>
            <version>1.18.1</version>
        </dependency>
        <dependency>
            <groupId>com.sun.jersey</groupId>
            <artifactId>jersey-client</artifactId>
            <version>1.18.1</version>
        </dependency>
  1. 需要在图片服务器上的web.xml添加如下配置文件
  <servlet>
    <servlet-name>default</servlet-name>
    <servlet-class>org.apache.catalina.servlets.DefaultServlet</servlet-class>
    <init-param>
      <param-name>debug</param-name>
      <param-value>0</param-value>
    </init-param>
    <init-param>
      <param-name>listings</param-name>
      <param-value>false</param-value>
    </init-param>
    <init-param>
      <param-name>readonly</param-name>
      <param-value>false</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
  </servlet>

即:接收文件的目标服务器可以支持写入操作。

  1. 编写应用服务器端的控制器代码
    @RequestMapping("/testSpringMVCUpload2")
    public String testSpringMVCUpload2(MultipartFile upload) throws IOException {
        System.out.println("SpringMVC跨服务器上传...");
        // 定义图片服务器的请求路径
        String path = "http://localhost:8088/picture/uploads/";
        // 获取到上传文件的名称
        String filename = upload.getOriginalFilename();
        String uuid = UUID.randomUUID().toString().replaceAll("-", "").toUpperCase();
        filename = uuid + "_" + filename;
        // 向图片服务器上传文件
        // 创建客户端对象
        Client client = Client.create();
        // 连接图片服务器地址
        WebResource webResource = client.resource(path + filename);
        // 上传文件
        webResource.put(String.class,upload.getBytes());
        return "success";
    }

2.8 SpringMVC的异常处理

系统中的异常包括两类:预期异常和运行时异常RuntimeException,前者通过捕获异常从而获取异常信息,后者主要通过规范代码开发、测试通过手段减少运行时异常的发生。

系统的daoservicecontroller出现都通过throws Exception向上抛出,最后由SpringMVC前端控制器交由异常处理器进行异常处理。SpringMVC异常处理见下图:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3HMbCpyk-1617344854373)(https://s3.ax1x.com/2020/12/23/r6i9eg.png)]

控制器中捕获异常,从下向上抛出异常。

其目的是为了在出现异常的时候,跳到另外一个“友好”页面。模拟应用步骤:

  1. 自定义一个异常类。(继承Exception)

    package cn.lizhi.other;
    
    public class SysException extends Exception {
    
    	// 用于定义异常信息
        private String message;
    
        public SysException(String message) {
            this.message = message;
        }
    
        public SysException() {
        }
    
        @Override
        public String getMessage() {
            return message;
        }
    
        public void setMessage(String message) {
            this.message = message;
        }
    }
    
  2. 编写异常处理器类。

    public class SysExceptionResolver implements HandlerExceptionResolver {
        @Override
        public ModelAndView resolveException(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object handler, Exception ex) {
    
            // 异常信息打印
            ex.printStackTrace();
            SysException sysException = null;
            if (ex instanceof SysException) { // 如果抛出的是自定义异常则直接转换
                sysException = (SysException) ex;
            } else {
                //如果抛出的不是系统自定义异常则重新构造一个系统错误异常。
                sysException = new SysException("系统错误,请于管理员联系");
            }
    
            ModelAndView mv = new ModelAndView();
            mv.addObject("message", sysException.getMessage());
            mv.setViewName("error");
            return mv;
        }
    }
    

    即异常处理器,实现接口 HandlerExceptionResolver,其中ex参数表示接收到的异常对象。其中创建的ModelAndView用于存入异常信息,键值对;再设置跳转路径。

    这里我们可以通过判断不同的异常类型跳转到不同的页面显示。

  3. bean配置文件中配置异常处理器类。

    	<!-- 配置自定义异常处理器 -->
        <bean id="handlerExceptionResolver" class="cn.lizhi.other.SysExceptionResolver"/>
    
  4. 模拟出现异常

        @RequestMapping("testException")
        public String testException() {
            System.out.println("模拟异常处理器的处理方式");
            int i = 3 / 0;
            return "success";
        }
    

    页面出现结果 --> 系统错误,请于管理员联系

2.9 SpringMVC中的拦截器

Spring MVC 的处理器拦截器类似于 Servlet 开发中的过滤器 Filter,用于对处理器进行预处理和后处理。
用户可以自己定义一些拦截器来实现特定的功能。

谈到拦截器,还要向大家提一个词——拦截器链(Interceptor Chain)。拦截器链就是将拦截器按一定的顺
序联结成一条链。在访问被拦截的方法或字段时,拦截器链中的拦截器就会按其之前定义的顺序被调用。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0Un6zn4g-1617344854374)(https://s3.ax1x.com/2020/12/23/r6Pzy8.png)]

说到这里,可能大家脑海中有了一个疑问,这不是我们之前学的过滤器吗?是的它和过滤器是有几分相似,但
是也有区别,接下来我们就来说说他们的区别:

  • 过滤器是 servlet 规范中的一部分,任何 java web 工程都可以使用。

  • 拦截器是 SpringMVC 框架自己的,只有使用了 SpringMVC 框架的工程才能用。

  • 过滤器在 url-pattern 中配置了/*之后,可以对所有要访问的资源拦截。

  • 拦截器它是只会拦截访问的控制器方法,如果访问的是 jsphtml,css,image 或者 js 是不会进行拦
    截的。

  • 它也是 AOP 思想的具体应用。

  • 我们要想自定义拦截器, 要求必须实现:HandlerInterceptor 接口。

  • HandlerInterceptor拦截的是请求地址,所以针对请求地址做一些验证、预处理等操作比较合适。

2.9.1 自定义拦截器步骤
  1. 创建类,实现HandlerInterceptor接口,需要重写需要的方法

    public class MyInterceptor implements HandlerInterceptor {
    
        @Override
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
    
            System.out.println("拦截器执行了...前");
            return true;
        }
    
        @Override
        public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
            System.out.println("拦截器执行了...后");
        }
    
        @Override
        public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
            System.out.println("页面跳转完毕后...");
        }
    }
    
    • preHandler

      方法是在controller方法执行前,进行拦截的方法;返回结果为true表示放行,返回结果为false表示拦截(配合条件判断使用),因为提供了requestresponse参数,所以可以使用转发或者重定向直接跳转到指定的页面。

      调用:按拦截器定义顺序调用

      作用:如果决定该拦截器对请求进行拦截处理后还要调用其他的拦截器,或者是需要业务处理器进行处理,则返回true;如果不需要再调用其他的组件去处理请求,则返回false

    • postHandler

      后处理回调方法,实现处理器的后处理(但在渲染视图之前),此时我们可以通过modelAndView(模型和视图对象)对模型数据进行处理或对视图进行处理,modelAndView也可能为null

      按拦截器定义逆序调用;在拦截器链内所有拦截器返回成功后进行调用。

      作用:在业务处理器处理完请求后,但是DispatcherServlet向客户端返回响应前被调用,处理ModelAndView中的值。

    • afterCompletion

      调用顺序:按拦截器定义逆序调用

      调用时机:对拦截器链内所有拦截器内返回成功的拦截器才调用它的afterCompletion方法。

      作用:在业务处理器处理完请求后,但是DispathcerServlet向客户端返回响应前被调用。可以在该方法中进行一些资源清理的操作。

      view视图渲染完毕以后执行,不能再进行页面的跳转。

    一旦在preHandler方法中返回了false(等同于出现了异常),后续的拦截器和controller方法就都不会再执行,也不会再执行postHandler方法,只会倒叙执行afterCompletion方法。

拦截器只能拦截Controller中的方法。

  1. springmvc.xml配置文件中配置拦截器类

    <!-- 配置拦截器 -->
        <mvc:interceptors>
            <mvc:interceptor>
                <!-- 哪些方法进行拦截 -->
                <mvc:mapping path="/user/*"/>
                <!-- 哪些方法不进行拦截
                 <mvc:exclude-mapping path=""/>
                -->
                <!-- 注册拦截器对象 -->
                <bean id="myInterceptor" class="cn.lizhi.utils.MyInterceptor"/>
            </mvc:interceptor>
        </mvc:interceptors>
    

    可以配置多个拦截器,拦截器执行的顺序就是配置文件中注册的拦截器对象的顺序。

2.9.2 HandlerInterceptor接口中的方法总结
  1. preHandle方法是controller方法执行前拦截的方法

    1. 可以使用request或者response跳转到指定的页面

    2. return true放行,执行下一个拦截器,如果没有拦截器,执行controller中的方法。

    3. return false不放行,不会执行controller中的方法。

  2. postHandlecontroller方法执行后执行的方法,在JSP视图执行前。

    1. 可以使用request或者response跳转到指定的页面

    2. 如果指定了跳转的页面,那么controller方法跳转的页面将不会显示。

  3. postHandle方法是在JSP执行后执行

    1. request或者response不能再跳转页面了

三、SSM框架的整合

核心思想:通过Spring整合另外两个框架。

整合方式:配置文件加注解的方式。

整合的思路:

  • 搭建整合的环境
  • Spring的配置搭建完成
  • Spring整合SpringMVC框架
  • Spring整合Mybatis框架

3.1 环境搭建

  1. 数据库创建
create database ssm;
use ssm;
create table account(
	id INTEGER PRIMARY key auto_increment,
	name VARCHAR(32),
	money DOUBLE(7,2)
);
  1. pom.xml依赖导入
<?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>cn.lizhi</groupId>
    <artifactId>SpringMVC_03</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>war</packaging>

    <name>SpringMVC_03 Maven Webapp</name>
    <!-- FIXME change it to the project's website -->
    <url>http://www.example.com</url>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
        <spring.version>5.0.2.RELEASE</spring.version>
        <slf4j.version>1.6.6</slf4j.version>
        <log4j.version>1.2.12</log4j.version>
        <mysql.version>5.1.6</mysql.version>
        <mybatis.version>3.4.5</mybatis.version>
    </properties>

    <dependencies>
        <!-- spring -->
        <!-- 切入点表达式 -->
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.6.8</version>
        </dependency>
        <!-- springAOP  AOP核心功能,例如代理工厂等 -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aop</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <!-- springIOC -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</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>
        <!-- spring整合junit -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <!-- 事务控制 -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-tx</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <!-- SpringJDBC -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <!-- 单元测试 -->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>compile</scope>
        </dependency>
        <!-- mysql驱动 -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>${mysql.version}</version>
        </dependency>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>servlet-api</artifactId>
            <version>2.5</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>javax.servlet.jsp</groupId>
            <artifactId>jsp-api</artifactId>
            <version>2.0</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>jstl</groupId>
            <artifactId>jstl</artifactId>
            <version>1.2</version>
        </dependency>
        <!-- log start -->
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>${log4j.version}</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>${slf4j.version}</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-log4j12</artifactId>
            <version>${slf4j.version}</version>
        </dependency>
        <!-- log end -->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>${mybatis.version}</version>
        </dependency>
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis-spring</artifactId>
            <version>1.3.0</version>
        </dependency>
        <!-- 数据库连接池 -->
        <dependency>
            <groupId>c3p0</groupId>
            <artifactId>c3p0</artifactId>
            <version>0.9.1.2</version>
            <type>jar</type>
            <scope>compile</scope>
        </dependency>
    </dependencies>

    <build>
        <finalName>SpringMVC_03</finalName>
        <pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) -->
            <plugins>
                <plugin>
                    <artifactId>maven-clean-plugin</artifactId>
                    <version>3.1.0</version>
                </plugin>
                <!-- see http://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_war_packaging -->
                <plugin>
                    <artifactId>maven-resources-plugin</artifactId>
                    <version>3.0.2</version>
                </plugin>
                <plugin>
                    <artifactId>maven-compiler-plugin</artifactId>
                    <version>3.8.0</version>
                </plugin>
                <plugin>
                    <artifactId>maven-surefire-plugin</artifactId>
                    <version>2.22.1</version>
                </plugin>
                <plugin>
                    <artifactId>maven-war-plugin</artifactId>
                    <version>3.2.2</version>
                </plugin>
                <plugin>
                    <artifactId>maven-install-plugin</artifactId>
                    <version>2.5.2</version>
                </plugin>
                <plugin>
                    <artifactId>maven-deploy-plugin</artifactId>
                    <version>2.8.2</version>
                </plugin>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-compiler-plugin</artifactId>
                    <version>3.2</version>
                    <configuration>
                        <source>1.8</source>
                        <target>1.8</target>
                        <encoding>UTF-8</encoding>
                        <showWarnings>true</showWarnings>
                    </configuration>
                </plugin>
            </plugins>
        </pluginManagement>
    </build>
</project>
  1. 实体类编写
public class Account implements Serializable {

    private Integer id;
    private String name;
    private Double money;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Double getMoney() {
        return money;
    }

    public void setMoney(Double money) {
        this.money = money;
    }

    @Override
    public String toString() {
        return "Account{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", money=" + money +
                '}';
    }
}
  1. dao接口编写

由于我们是使用Mybatis框架,所以不需要编写其实现类,只需要写接口即可。

public interface AccountDao {

    public void saveAccount(Account account);

    public List<Account> findAll();
}
  1. 编写Service接口和实现类
public interface AccountService {

    public void saveAccount(Account account);

    public List<Account> findAll();
}

public class AccountServiceImpl implements AccountService {

    private AccountDao accountDao;

    @Override
    public void saveAccount(Account account) {
        System.out.println("对用户进行保存...");
        accountDao.saveAccount(account);

    }

    @Override
    public List<Account> findAll() {
        System.out.println("业务层:查询所有用户");
        List<Account> accounts = accountDao.findAll();
        return accounts;
    }
}

3.2 Spring框架代码的编写

3.2.1 搭建和测试Spring的开发环境
  1. 在项目中创建applicationContext.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:tx="http://www.springframework.org/schema/tx"
           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/tx http://www.springframework.org/schema/tx/spring-tx.xsd">
        <!-- 开启注解扫描,要扫描的是service层和dao层的注解,要忽略web层注解,因为web层(Controller层)让SpringMVC框架去管理 -->
        <context:component-scan base-package="cn.lizhi">
            <!-- 配置要忽略的注解 -->
            <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
        </context:component-scan>
    </beans>
    
  2. 编写测试方法,进行测试

        @Test
        public void testSpring() {
            // 获取Spring容器
            ApplicationContext ac = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
            AccountService accountService = ac.getBean("accountService", AccountService.class);
            accountService.findAll();
        }
    

3.3 Spring整合SpringMVC框架

  1. web.xml中配置DispatcherServlet前端控制器

    <!-- 配置前端控制器:服务器启动必须加载,需要加载springmvc.xml配置文件 -->
        <servlet>
            <servlet-name>dispatcherServlet</servlet-name>
            <servlet-class>org.springframework.web.servlet.DispatcherServlet
            </servlet-class>
            <!-- 配置初始化参数,创建完DispatcherServlet对象,加载springmvc.xml配置文件 -->
            <init-param>
                <param-name>contextConfigLocation</param-name>
                <param-value>classpath:springmvc.xml</param-value>
            </init-param> <!-- 服务器启动的时候,让DispatcherServlet对象创建 -->
            <load-on-startup>1</load-on-startup>
        </servlet>
        <servlet-mapping>
            <servlet-name>dispatcherServlet</servlet-name>
            <url-pattern>/</url-pattern>
        </servlet-mapping>
    
  2. web.xml中配置DispatcherServlet过滤器解决中文乱码

    	<!-- 配置解决中文乱码的过滤器 -->
        <filter>
            <filter-name>characterEncodingFilter</filter-name>
            <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
            <init-param>
                <param-name>encoding</param-name>
                <param-value>UTF-8</param-value>
            </init-param>
        </filter>
        <filter-mapping>
            <filter-name>characterEncodingFilter</filter-name>
            <url-pattern>/*</url-pattern>
        </filter-mapping>
    
  3. 创建SpringMVC.xml 的配置文件,编写配置文件

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans" xmlns:mvc="http://www.springframework.org/schema/mvc"
           xmlns:context="http://www.springframework.org/schema/context"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
           http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd
           http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
    
        <!-- 扫描Controller(web层)的注解,别的不扫描 -->
        <context:component-scan base-package="cn.lizhi">
            <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
        </context:component-scan>
        <!-- 配置视图解析器 -->
        <bean id="viewResolver"
              class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <!-- JSP文件所在的目录 -->
            <property name="prefix" value="/WEB-INF/pages/"/> <!-- 文件的后缀名 -->
            <property name="suffix" value=".jsp"/>
        </bean>
        <!-- 设置静态资源不过滤 -->
        <mvc:resources location="/css/" mapping="/css/**"/>
        <mvc:resources location="/images/" mapping="/images/**"/>
        <mvc:resources location="/js/" mapping="/js/**"/> <!-- 开启对SpringMVC注解的支持 -->
        <mvc:annotation-driven/>
    </beans>
    
  4. 测试SpringMVC的框架搭建是否成功

    1. 编写index.jsplist.jsp前端页面

      <!-- index页面 -->
      <a href="/account/findAll" >查询所有</a>
      <!-- list页面 -->
      <h3>查询所有</h3>
      
    2. 编写控制器方法

      @Controller("accountController")
      @RequestMapping("/account")
      public class AccountController {
          @RequestMapping("/findAll")
          public String findAll() {
              System.out.println("表面层:查询所有用户...");
              return "list";
          }
      }
      

      结果:查询所有

  5. Spring整合SpringMVC框架

    1. 目的:在Controller层中能成功调用service对象中的方法。

    2. 如果想在服务器启动的时候,获取到Spring的容器,那么就需要在项目启动的时候就去加载applicationContext.xml的配置文件。在web.xml中配置ContextLoaderListener监听器(该监听器只能加载WEB-INF目录下的applicationContext.xml的配置文件)。

      监听器的作用:监听器的作用是监听一些事件的发生从而进行一些操作,比如监听ServletContext,HttpSession的创建,销毁,从而执行一些初始化加载配置文件的操作,当Web容器启动后,Spring的监听器会启动监听,监听是否创建ServletContext的对象,如果发生了创建ServletContext对象这个事件(当web容器启动后一定会生成一个ServletContext对象,所以监听事件一定会发生),ContextLoaderListener类会实例化并且执行初始化方法,将Spring的配置文件中配置的bean注册到Spring容器中,监听的操作是读取WEB-INF/applicationContext.xml,但是我们可以在web.xml中配置多个需要读取的配置文件,如下方所示,读取完成后所有的配置文件中的bean都会注册到spring容器中。

      	<context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>
            /WEB-INF/config/application-context.xml
            /WEB-INF/config/cache-context.xml
            /WEB-INF/config/captcha-context.xml
            /WEB-INF/config/jeecms/jeecore-context.xml
            /WEB-INF/config/jeecms/jeecms-context.xml
            /WEB-INF/config/shiro-context.xml
            /WEB-INF/config/plug/**/*-context.xml
            /WEB-INF/config/quartz-task.xml
            /WEB-INF/config/zxw/zxw-context.xml
        </param-value>
      </context-param>
      

      web.xml中对监听器的配置:

       <!-- 配置Spring的监听器 -->
          <listener>
              <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
          </listener>
          <!-- 配置加载类路径的配置文件 -->
          <context-param>
              <param-name>contextConfigLocation</param-name>
              <param-value>classpath:applicationContext.xml</param-value>
          </context-param>
      
    3. Controller中注入service对象,调用service对象的方法进行测试

      @Controller("accountController")
      @RequestMapping("/account")
      public class AccountController {
      
          @Autowired
          private AccountService accountService;
      
          @RequestMapping("/findAll")
          public String findAll() {
              List<Account> accounts = accountService.findAll();
              System.out.println("表现层:查询所有用户...");
              return "list";
          }
      }
      

      输出结果:

      业务层:查询所有用户
      表现层:查询所有用户…

3.4 Spring整合Mybatis框架

3.4.1 搭建和测试MyBatis的环境
  1. web项目中编写SqlMapConfig.xml的配置文件,编写核心配置文件

    <?xml version="1.0" encoding="UTF-8"?> 
    <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
            "http://mybatis.org/dtd/mybatis-3-config.dtd">
    <configuration>
        <environments default="mysql">
            <environment id="mysql">
                <transactionManager type="JDBC"/>
                <dataSource type="POOLED">
                    <property name="driver" value="com.mysql.jdbc.Driver"/>
                    <property name="url" value="jdbc:mysql:///ssm?useUnicode=true&amp;characterEncoding=utf8"/>
                    <property name="username" value="root"/>
                    <property name="password" value="root"/>
                </dataSource>
            </environment>
        </environments> 
        <!-- 使用的是注解 -->
        <mappers> 
            <!-- <mapper class="cn.itcast.dao.AccountDao"/> --> 
            <!-- 该包下所有的dao接口都可以使用 -->
            <package name="cn.itcast.dao"/>
        </mappers>
    </configuration>
    
  2. AccountDao接口的方法上添加注解,编写SQL语句

    public interface AccountDao {
    
        @Insert("insert into account (name,money) values(#{name},#{money})")
        public void saveAccount(Account account);
    
        @Select("select * from account")
        public List<Account> findAll();
    }
    
  3. 编写测试方法

        @Test
        public void saveAccount() throws IOException {
            Account account = new Account();
            account.setName("小黑");
            account.setMoney(234d);
    
            // 加载配置文件
            InputStream is = Resources.getResourceAsStream("SqlMapConfig.xml");
            // 创建工厂
            SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
            SqlSessionFactory factory = builder.build(is);
            // 获取sqlSession对象
            SqlSession session = factory.openSession();
            // 常见代理对象
            AccountDao accountDao = session.getMapper(AccountDao.class);
            accountDao.saveAccount(account);
            // 提交事务
            session.commit();
            // 释放资源
            session.close();
            is.close();
        }
    
3.4.2 Spring整合MyBatis框架

目的:把SqlMapConfig.xml配置文件中的内容配置到applicationContext.xml配置文件中。由Spring为我们进行对象的管理。从上面的测试文件中,可以看出我们需要将工厂对象,session对象代理对象交由Spring容器进行管理。即:把Mybatis配置文件(SqlMapConfig.xml)中内容配置到spring配置文件中。

注意:

  • 当我们使用的是代理dao的模式,dao具体实现类由Mybatis使用代理方式创建,此时Mybatis配置文件不能删除。
  • 整合SpringMybatis时,Mybatis创建的Mapper.xml文件名必须和dao接口文件名一致。
  1. 配置文件
	<!-- 配置C3P0的连接池对象 -->
    <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql:///ssm?useUnicode=true&amp;characterEncoding=utf8"/>
        <property name="username" value="root"/>
        <property name="password" value="root"/>
    </bean> 
    <!-- 配置SqlSession的工厂 -->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource"/>
    </bean> 
    <!-- 配置扫描dao的包 -->
    <bean id="mapperScanner" class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="basePackage" value="cn.itcast.dao"/>
    </bean>

可以删除SqlSessionMap配置文件。

  1. dao接口加上注解@Repository
  2. service中注入dao对象,进行测试。
  3. 配置Spring框架声明式事务管理
  • 配置事务管理器

    	<!-- 配置Spring的声明式事务管理 -->
        <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
            <property name="dataSource" ref="dataSource"></property>
        </bean>
    
  • 配置事务通知

    	<!-- 配置事务的通知 -->
        <tx:advice id="txAdvice" transaction-manager="transactionManager">
            <tx:attributes>
                <tx:method name="*" propagation="REQUIRED" read-only="false"/>
                <tx:method name="find*" propagation="SUPPORTS" read-only="true"/>
            </tx:attributes>
        </tx:advice>
    
  • 配置AOP增强

        <!-- 配置 aop -->
        <aop:config>
            <!-- 配置切入点表达式 -->
            <aop:pointcut expression="execution(* cn.lizhi.service.impl.*.*(..))" id="pt1"/>
            <!-- 建立通知和切入点表达式的关系 -->
            <aop:advisor advice-ref="txAdvice" pointcut-ref="pt1"/>
        </aop:config>
    

4. 附常用配置文件

4.1 web.xml配置文件

<!DOCTYPE web-app PUBLIC
        "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
        "http://java.sun.com/dtd/web-app_2_3.dtd" >

<web-app>
    <display-name>Archetype Created Web Application</display-name>

    <!-- 配置前端控制器:服务器启动必须加载,需要加载springmvc.xml配置文件 -->
    <servlet>
        <servlet-name>dispatcherServlet</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <!-- 配置初始化参数,创建完DispatcherServlet对象,加载springmvc.xml配置文件 -->
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:springmvc.xml</param-value>
        </init-param> 
        <!-- 服务器启动的时候,让DispatcherServlet对象创建 -->
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>dispatcherServlet</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>

    <!-- 配置解决中文乱码的过滤器 -->
    <filter>
        <filter-name>characterEncodingFilter</filter-name>
        <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
        <init-param>
            <param-name>encoding</param-name>
            <param-value>UTF-8</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>characterEncodingFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

    <!-- 配置Spring的监听器 -->
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
    <!-- 配置加载类路径的配置文件 -->
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:applicationContext.xml</param-value>
    </context-param>

    <!-- 4、使用Rest风格的URI,将页面普通的post请求转为指定的delete或者put请求 -->
    <filter>
        <filter-name>HiddenHttpMethodFilter</filter-name>
        <filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>HiddenHttpMethodFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
    <filter>
        <filter-name>HttpPutFormContentFilter</filter-name>
        <filter-class>org.springframework.web.filter.HttpPutFormContentFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>HttpPutFormContentFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

</web-app>

4.2 pom.xml配置文件

<?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>cn.lizhi</groupId>
    <artifactId>SpringMVC_03</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>war</packaging>

    <name>SpringMVC_03 Maven Webapp</name>
    <!-- FIXME change it to the project's website -->
    <url>http://www.example.com</url>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
        <spring.version>5.0.2.RELEASE</spring.version>
        <slf4j.version>1.6.6</slf4j.version>
        <log4j.version>1.2.12</log4j.version>
        <mysql.version>5.1.6</mysql.version>
        <mybatis.version>3.4.5</mybatis.version>
    </properties>

    <dependencies>
        <!-- spring -->
        <!-- 切入点表达式 -->
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.6.8</version>
        </dependency>
        <!-- springAOP  AOP核心功能,例如代理工厂等 -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aop</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <!-- springIOC -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</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>
        <!-- spring整合junit -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <!-- 事务控制 -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-tx</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <!-- SpringJDBC -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <!-- 单元测试 -->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>compile</scope>
        </dependency>
        <!-- mysql驱动 -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>${mysql.version}</version>
        </dependency>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>3.0.1</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>javax.servlet.jsp</groupId>
            <artifactId>jsp-api</artifactId>
            <version>2.0</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>jstl</groupId>
            <artifactId>jstl</artifactId>
            <version>1.2</version>
        </dependency>
        <!-- log start -->
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>${log4j.version}</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>${slf4j.version}</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-log4j12</artifactId>
            <version>${slf4j.version}</version>
        </dependency>
        <!-- log end -->
        <!-- Mybatis -->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>${mybatis.version}</version>
        </dependency>
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis-spring</artifactId>
            <version>1.3.0</version>
        </dependency>
        <!-- 数据库连接池 -->
        <dependency>
            <groupId>c3p0</groupId>
            <artifactId>c3p0</artifactId>
            <version>0.9.1.2</version>
            <type>jar</type>
            <scope>compile</scope>
        </dependency>

        <!--引入pageHelper分页插件 -->
        <dependency>
            <groupId>com.github.pagehelper</groupId>
            <artifactId>pagehelper</artifactId>
            <version>5.0.0</version>
        </dependency>

        <!-- MBG -->
        <!-- https://mvnrepository.com/artifact/org.mybatis.generator/mybatis-generator-core -->
        <dependency>
            <groupId>org.mybatis.generator</groupId>
            <artifactId>mybatis-generator-core</artifactId>
            <version>1.3.5</version>
        </dependency>

        <!--JSR303数据校验支持;tomcat7及以上的服务器,
		tomcat7以下的服务器:el表达式。额外给服务器的lib包中替换新的标准的el
		-->
        <!-- https://mvnrepository.com/artifact/org.hibernate/hibernate-validator -->
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-validator</artifactId>
            <version>5.4.1.Final</version>
        </dependency>

        <!-- 对json处理的包,即能够使用@ResponseBody -->
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.9.0</version>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-core</artifactId>
            <version>2.9.0</version>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-annotations</artifactId>
            <version>2.9.0</version>
        </dependency>


    </dependencies>

    <build>
        <finalName>ssm_crud</finalName>
        <pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) -->
            <plugins>
                <plugin>
                    <artifactId>maven-clean-plugin</artifactId>
                    <version>3.1.0</version>
                </plugin>
                <!-- see http://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_war_packaging -->
                <plugin>
                    <artifactId>maven-resources-plugin</artifactId>
                    <version>3.0.2</version>
                </plugin>
                <plugin>
                    <artifactId>maven-compiler-plugin</artifactId>
                    <version>3.8.0</version>
                </plugin>
                <plugin>
                    <artifactId>maven-surefire-plugin</artifactId>
                    <version>2.22.1</version>
                </plugin>
                <plugin>
                    <artifactId>maven-war-plugin</artifactId>
                    <version>3.2.2</version>
                </plugin>
                <plugin>
                    <artifactId>maven-install-plugin</artifactId>
                    <version>2.5.2</version>
                </plugin>
                <plugin>
                    <artifactId>maven-deploy-plugin</artifactId>
                    <version>2.8.2</version>
                </plugin>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-compiler-plugin</artifactId>
                    <version>3.2</version>
                    <configuration>
                        <source>1.8</source>
                        <target>1.8</target>
                        <encoding>UTF-8</encoding>
                        <showWarnings>true</showWarnings>
                    </configuration>
                </plugin>
            </plugins>
        </pluginManagement>
    </build>
</project>

4.3 SpringMVC配置文件

<?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:mvc="http://www.springframework.org/schema/mvc"
       xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.3.xsd
		http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd">

    <!--SpringMVC的配置文件,包含网站跳转逻辑的控制,配置  -->
    <context:component-scan base-package="cn.lizhi" use-default-filters="false">
        <!--只扫描控制器。  -->
        <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
    </context:component-scan>

    <!--配置视图解析器,方便页面返回  -->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/views/"></property>
        <property name="suffix" value=".jsp"></property>
    </bean>

    <!--两个标准配置  -->
    <!-- 将springmvc不能处理的请求交给tomcat -->
    <mvc:default-servlet-handler/>
    <!-- 能支持springmvc更高级的一些功能,JSR303校验,快捷的ajax...映射动态请求 -->
    <mvc:annotation-driven/>

</beans>

4.4 Spring配置文件 – applicationContext.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:tx="http://www.springframework.org/schema/tx"
       xsi:schemaLocation="http://www.springframework.org/schema/aop 
        http://www.springframework.org/schema/aop/spring-aop-4.3.xsd
		http://www.springframework.org/schema/beans 
		http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
		http://www.springframework.org/schema/tx 
		http://www.springframework.org/schema/tx/spring-tx-4.3.xsd
		http://www.springframework.org/schema/context 
		http://www.springframework.org/schema/context/spring-context-4.3.xsd">

    <!-- 注解扫描,不扫描controller层,controller层交给SpringMVC进行管理 -->
    <context:component-scan base-package="cn.lizhi">
        <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller" />
    </context:component-scan>

    <!-- Spring的配置文件,这里主要配置和业务逻辑有关的 -->
    <!--=================== 数据源,事务控制,xxx ================-->
    <!-- 引入数据源配置文件 -->
    <context:property-placeholder location="classpath:dbconfig.properties" />
    <!-- 数据源配置 -->
    <bean id="pooledDataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <property name="jdbcUrl" value="${jdbc.jdbcUrl}"></property>
        <property name="driverClass" value="${jdbc.driverClass}"></property>
        <property name="user" value="${jdbc.user}"></property>
        <property name="password" value="${jdbc.password}"></property>
    </bean>

    <!--================== 配置和MyBatis的整合=============== -->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <!-- 指定mybatis全局配置文件的位置 -->
        <property name="configLocation" value="classpath:mybatis-config.xml"></property>
        <property name="dataSource" ref="pooledDataSource"></property>
        <!-- 指定mybatis,mapper文件的位置 -->
        <property name="mapperLocations" value="classpath:mapper/*.xml"></property>
    </bean>

    <!-- 配置扫描器,将mybatis接口的实现加入到ioc容器中 -->
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <!--扫描所有dao接口的实现,加入到ioc容器中 -->
        <property name="basePackage" value="cn.lizhi.dao"></property>
    </bean>

    <!-- 配置一个可以执行批量的sqlSession -->
    <bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
        <constructor-arg name="sqlSessionFactory" ref="sqlSessionFactory"></constructor-arg>
        <constructor-arg name="executorType" value="BATCH"></constructor-arg>
    </bean>
    <!--=============================================  -->

    <!-- ===============事务控制的配置 ================-->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <!--控制住数据源  -->
        <property name="dataSource" ref="pooledDataSource"></property>
    </bean>
    <!--开启基于注解的事务,使用xml配置形式的事务(必要主要的都是使用配置式)  -->
    <aop:config>
        <!-- 切入点表达式 -->
        <aop:pointcut expression="execution(* cn.lizhi.service..*(..))" id="txPoint"/>
        <!-- 配置事务增强 -->
        <aop:advisor advice-ref="txAdvice" pointcut-ref="txPoint"/>
    </aop:config>

    <!--配置事务增强,事务如何切入  -->
    <tx:advice id="txAdvice" transaction-manager="transactionManager">
        <tx:attributes>
            <!-- 所有方法都是事务方法 -->
            <tx:method name="*"/>
            <!--以get开始的所有方法  -->
            <tx:method name="get*" read-only="true"/>
        </tx:attributes>
    </tx:advice>

    <!-- Spring配置文件的核心点(数据源、与mybatis的整合,事务控制) -->
</beans>

4.5 Mybatis全局配置文件 – mybatis-config.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <settings>
        <setting name="mapUnderscoreToCamelCase" value="true"/>
    </settings>

    <typeAliases>
        <package name="cn.lizhi.bean"/>
    </typeAliases>

    <plugins>
        <plugin interceptor="com.github.pagehelper.PageInterceptor">
            <!--分页参数合理化  -->
            <property name="reasonable" value="true"/>
        </plugin>
    </plugins>
</configuration>

4.6 Mybatis逆向工程的配置文件 – mbg.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfiguration
        PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
        "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">

<generatorConfiguration>
    <context id="DB2Tables" targetRuntime="MyBatis3">
        <!-- 关闭注释 -->
        <commentGenerator>
            <property name="suppressAllComments" value="true" />
        </commentGenerator>
        
        <!-- 配置数据库连接 -->
        <jdbcConnection driverClass="com.mysql.jdbc.Driver"
                        connectionURL="jdbc:mysql://url:3306/ssm?useUnicode=true&amp;characterEncoding=utf8"
                        userId="username"
                        password="password">
        </jdbcConnection>

        <javaTypeResolver >
            <property name="forceBigDecimals" value="false" />
        </javaTypeResolver>

        <!-- 指定javaBean生成的位置 targetPackage为包的路径,targetProject为项目路径,即两个能够连接在一起 -->
        <javaModelGenerator targetPackage="cn.lizhi.bean" targetProject=".\src\main\java">
            <property name="enableSubPackages" value="true" />
            <property name="trimStrings" value="true" />
        </javaModelGenerator>

        <!-- 指定sql映射文件生成的位置 -->
        <sqlMapGenerator targetPackage="mapper"  targetProject="./src/main/resources">
            <property name="enableSubPackages" value="true" />
        </sqlMapGenerator>

        <!-- 指定dao接口生成的位置,mapper接口 -->
        <javaClientGenerator type="XMLMAPPER" targetPackage="cn.lizhi.dao"  targetProject="./src/main/java">
            <property name="enableSubPackages" value="true" />
        </javaClientGenerator>

        <!-- table指定每个表的生成策略 -->
        <table tableName="tbl_emp" domainObjectName="Employee"></table>
        <table tableName="tbl_dept" domainObjectName="Department"></table>

    </context>
</generatorConfiguration>

4.7 日志配置文件 – log4j.properties

# Set root category priority to INFO and its only appender to CONSOLE.
#log4j.rootCategory=INFO, CONSOLE            debug   info   warn error fatal
log4j.rootCategory=info, CONSOLE, LOGFILE

# Set the enterprise logger category to FATAL and its only appender to CONSOLE.
log4j.logger.org.apache.axis.enterprise=FATAL, CONSOLE

# CONSOLE is set to be a ConsoleAppender using a PatternLayout.
log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
log4j.appender.CONSOLE.layout.ConversionPattern=%d{ISO8601} %-6r [%15.15t] %-5p %30.30c %x - %m\n

# LOGFILE is set to be a File appender using a PatternLayout.
log4j.appender.LOGFILE=org.apache.log4j.FileAppender
log4j.appender.LOGFILE.File=axis.log
log4j.appender.LOGFILE.Append=true
log4j.appender.LOGFILE.layout=org.apache.log4j.PatternLayout
log4j.appender.LOGFILE.layout.ConversionPattern=%d{ISO8601} %-6r [%15.15t] %-5p %30.30c %x - %m\n

4.8 数据库连接池 – dbconfig.properties

jdbc.driverClass=com.mysql.jdbc.Driver
jdbc.jdbcUrl=jdbc:mysql://url:3306/ssm?useUnicode=true&characterEncoding=utf8
jdbc.user=username
jdbc.password=password
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值