Loading

SpringMVC

1 SpringMVC概述

1.1 SpringMVC是什么?

  • SpringMVC是一种基于的实现MVC设计模式的请求驱动类型的轻量级web框架,属于Spring FrameWork的后续产品,已经融合在Spring Web Flow里面。Spring框架提供了构建web应用程序的全功能MVC模块。使用Spring可插入MVC架构,从而在使用Spring进行web开发的时候,可以选择使用Spring的SpringMVC框架或集成其他的Web开发框架。
  • SpringMVC已经成为目前最主流的MVC框架之一,并且随着Spring3.0的发布,全面超越了Struts2,成为最优秀的MVC框架,没有之一。
  • SpringMVC通过一套注解,让一个简单的Java类成为处理请求的控制器,而无须实现任何接口,同时它还支持RESTful编程风格的请求。

1.2 关于MVC和三层架构

1.2.1 三层架构

  • 我们的开发架构一般都是基于两种开发模式:一种是C/S架构,也就是客户端/服务器模式,另一种是B/S架构,也就是浏览器/服务器模式。在JavaEE开发中,几乎全部是基于B/S架构的开发。那么在B/S架构中,系统标准的三层架构包括:表现层、业务层、持久层。三层架构在我们的实际开发中使用的非常多。

  • 三层架构中,每一层都各司其职。

    • 表现层:

      • 就是我们常说的web层。它负责接收客户端的请求,同时向客户端响应结果,通常客户端使用HTTP协议请求web层,web层需要接收HTTP请求,完成HTTP的响应。
      • 表现层包括展示层和控制层:控制层负责接收请求,展示层负责结果的展示。
      • 表现层依赖业务层,接收到客户端请求一般会调用业务层进行业务处理,并将处理结果响应给客户端。
      • 表现层的设计一般都是使用MVC模型(MVC是表现层的设计模型,和其他层没有关系)。
    • 业务层:

      • 就是我们常说的service层。它负责业务的逻辑处理,和我们开发项目的需求息息相关。web层依赖业务层,但是业务层不依赖web层。
      • 业务层在业务处理可能会依赖持久层,如果要对数据持久化需要保证事务的一致性(也就是说事务应该放到业务层来控制)。
    • 持久层:

      • 就是我们常说的dao层。负责数据持久化,包括数据层级数据库和数据访问层,数据库是对数据进行持久化的载体,数据访问层是业务层和持久层交互的接口,业务层需要通过数据访问层将数据持久化到数据库中。通俗的讲,持久层就是和数据库交互,对数据库表进行CRUD的。

1.2.2 MVC模型

  • MVC全名是Model View Controller,是模型(Model)-视图(View)-控制器(Controller)的缩写,是一种用于设计创建web应用程序表现层的模式。
  • MVC中的每个部分各司其职:
    • Model(模型):
      • 就是我们常说的数据模型。一般用于封装数据。
    • View(视图):
      • 通常指的就是我们的JSP页面或HTML页面等。一般用于展示数据。
      • 视图时依据模型数据创建的。
    • Controller(控制器):
      • 是应用程序中处理用户交互的部分。一般用于处理程序逻辑。

2 SpringMVC的入门

2.1 入门案例

  • 目录结构:

SpringMVC入门

  • 导入相关jar包的Maven坐标:
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>5.2.7.RELEASE</version>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-aspects</artifactId>
    <version>5.2.7.RELEASE</version>
</dependency>
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid</artifactId>
    <version>1.1.23</version>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-jdbc</artifactId>
    <version>5.2.7.RELEASE</version>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-web</artifactId>
    <version>5.2.7.RELEASE</version>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-webmvc</artifactId>
    <version>5.2.7.RELEASE</version>
</dependency>
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>8.0.19</version>
</dependency>
<dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.13</version>
    <scope>test</scope>
</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.1</version>
    <scope>provided</scope>
</dependency>
  • 在web.xml文件中配置前端控制器:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xmlns="http://java.sun.com/xml/ns/javaee"
         xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
         id="WebApp_ID" version="2.5">


    <!-- 配置SpringMVC的前端控制器,拦截所有请求  -->
    <servlet>
        <servlet-name>dispatcherServlet</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <!-- 加载SpringMVC的配置文件 -->
        <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>
    </servlet-mapping>
</web-app>
  • HelloController.java
package com.sunxiaping.web;

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


@Controller
public class HelloController {


    @RequestMapping(value = "/hello")
    public String hello(){

        System.out.println("==========HelloController.hello============");

        return "success";
    }
}
  • 新建springmvc.xml
<?xml version="1.0" encoding="UTF-8"?>
<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="http://www.springframework.org/schema/beans"
       xmlns:tx="http://www.springframework.org/schema/tx"
       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/tx
        http://www.springframework.org/schema/tx/spring-tx.xsd 
        http://www.springframework.org/schema/mvc 
        https://www.springframework.org/schema/mvc/spring-mvc.xsd">

    <!-- 开启组件扫描 -->
    <context:component-scan base-package="com.sunxiaping" 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 name="suffix" value=".jsp"/>
    </bean>

    <!-- 配置SpringMVC的注解驱动 -->
    <mvc:annotation-driven/>

</beans>
  • 在webapps目录下新建index.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>SpringMVC的入门</title>
</head>
<body>

    <a href="${pageContext.request.contextPath}/hello">访问SpringMVC的入门</a>

</body>
</html>
  • 在webapps/WEB-INF目录下新建views目录以及success.jsp:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    成功
</body>
</html>

2.2 入门案例中涉及到的组件

2.2.1 DispatcherServlet:前端控制器

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

2.2.2 HandlerMapping:处理器映射器

  • HandlerMapping负责根据用户请求找到Handler(也可以成为处理器,控制器),SpringMVC提供了不同的映射器实现不同的映射方式,例如:配置文件方式、实现接口方式和注解方式等。

2.2.3 Handler:处理器

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

2.2.4 HandlerAdapter:处理器适配器

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

2.2.5 ViewResolver:视图解析器

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

2.2.6 View:视图

  • SpringMVC框架提供了很多的View视图类型的支持,包括:jstlView、freemarkerView、pdfView等。我们常见的视图就是JSP。
  • 一般情况下需要通过页面标签或页面模板技术将模型数据通过页面展示给用户,需要由程序员根据业务需求开发具体的页面。

2.2.7 mvc:annotation-drivern标签

  • 在SpringMVC的各个组件中,处理器映射器、处理器适配器和视图解析器称为SpringMVC的三大组件。
  • 使用<mvc:annotation-drivern/>自动加载RequestMappingHandlerMapping(处理器映射器)和RequestMappingHandlerAdapter(处理器适配器),可以在SpringMVC的配置文件中使用<mvc:annotation-drivern/>替代处理器映射器和处理器适配器的配置。

2.3 @RequestMapping注解

2.3.1 概述和应用示例

  • 作用:用于建立请求URL和处理请求方法之间的对应关系。
  • 源码:
package org.springframework.web.bind.annotation;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

import org.springframework.core.annotation.AliasFor;

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Mapping
public @interface RequestMapping {

	String name() default "";

	@AliasFor("path")
	String[] value() default {};

	@AliasFor("value")
	String[] path() default {};

	RequestMethod[] method() default {};

	String[] params() default {};

	String[] headers() default {};

	String[] consumes() default {};

	String[] produces() default {};

}
  • 出现位置:

    • 写在方法上:表示和请求的URL进行绑定。
    • 写在类上:表示将请求的URL进行窄化处理,可以让URL变成模块化的形式。
  • 属性:

    • value:用于指定访问URL和执行方法之间的对应关系,它和path属性的作用是一样的。
    • method:用来限定请求的方式。
    • params(不常用):用于指定限制请求参数的条件。它支持简单的表达式,要求请求参数的key和value必须和配置的一模一样。
    //表示请求参数中必须有accountName
    @RequestMapping(value = "findAccount", method = {RequestMethod.GET},params = {"accountName"})
    
    //表示请求参数中必须有money,但是money的参数值不能是100
    @RequestMapping(value = "findAccount", method = {RequestMethod.GET},params = {"money!=100"})
    
    • headers(不常用):用于指定限制请求消息头的条件。
  • 示例:@RequestMapping注解中的method属性

package com.sunxiaping.web;

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

/**
 * @author <a href="mailto:1900919313@qq.com">weiwei.xu</a>
 * @version 1.0
 */
@Controller
public class AccountController {

    /**
     * method = {RequestMethod.POST} 指定请求的类型是POST类型
     *
     * @return
     */
    @RequestMapping(value = "saveAccount", method = {RequestMethod.POST})
    public String saveAccount() {
        System.out.println("保存账户信息");
        return "success";
    }

    /**
     * method = {RequestMethod.GET} 指定请求的类型是GET类型
     *
     * @return
     */
    @RequestMapping(value = "findAccount", method = {RequestMethod.GET},headers = {"content-type=text/*"})
    public String findAccount() {
        return "success";
    }
}

3 请求参数的绑定

3.1 绑定说明

3.1.1 绑定的机制

  • 我们知道,表单中的请求参数都是基于key=value的形式的。

  • SpringMVC绑定请求参数的过程是把表单提交请求参数,作为控制器中方法参数进行绑定的。

  • 示例:

  • index.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>SpringMVC的入门</title>
</head>
<body>
	
    <a href="${pageContext.request.contextPath}/account/findAccount?id=1">请求参数的绑定</a>

</body>
</html>
  • AccountController.java
package com.sunxiaping.web;

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

/**
 * @author <a href="mailto:1900919313@qq.com">weiwei.xu</a>
 * @version 1.0
 */
@Controller
@RequestMapping(value = "/account")
public class AccountController {

    @RequestMapping(value = "/findAccount", method = {RequestMethod.GET})
    public String findAccount(Integer id) {
        System.out.println("id = " + id);
        return "success";
    }
    
}

3.1.2 支持的数据类型

  • 基本类型参数:包括基本数据类型和String类型。

  • POJO类型参数:包括实体类以及关联的实体类。

  • 数组和集合类型参数:包括List结构和Map结构的集合,也包括数组。

  • ServletAPI对象作为请求参数。

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

3.1.3 使用要求

  • 如果是基本数据类型或String类型:要求参数名称必须和控制器中方法的形参名称保持一致(严格区分大小写)。
  • 如果是POJO类型或其关联对象:要求表单中参数名称和POJO类的属性名称保持一致,并且控制器方法的参数类型是POJO类型。
  • 如果是集合类型,有两种方式:
    • 如果给List集合中的元素赋值,使用元素的索引(下标)。
    • 如果给Map集合中的元素赋值,使用元素的键值对。
  • 如果是ServletAPI对象:要求方法的参数只能是HttpServletRequestHttpServletResponseHttpSessionjava.security.PrincipalLocaleInputStreamOutputStreamReaderWriter

3.1.3.1 请求参数是基本数据类型或String类型

  • index.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>SpringMVC的入门</title>
</head>
<body>

    <a href="${pageContext.request.contextPath}/account/findAccount?id=1">请求参数的绑定</a>

</body>
</html>
  • AccountController.java
package com.sunxiaping.web;

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

/**
 * @author <a href="mailto:1900919313@qq.com">weiwei.xu</a>
 * @version 1.0
 */
@Controller
@RequestMapping(value = "/account")
public class AccountController {

    @RequestMapping(value = "/findAccount", method = {RequestMethod.GET})
    public String findAccount(Integer id) {
        System.out.println("id = " + id);
        return "success";
    }

}

3.3.3.2 请求参数是POJO类型

  • Account.java
index.jsppackage com.sunxiaping.domain;

import java.io.Serializable;

/**
 * @author <a href="mailto:1900919313@qq.com">weiwei.xu</a>
 * @version 1.0
 */
public class Account implements Serializable {

    private String name;

    private Double money;

    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{" +
                "name='" + name + '\'' +
                ", money=" + money +
                '}';
    }
}
  • index.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>SpringMVC的入门</title>
</head>
<body>

    <form action="${pageContext.request.contextPath}/account/saveAccount" method="post">
        账户名称:<input type="text" name="name" value=""/><br/>
        账户余额:<input type="text" name="money" value=""/><br/>
        <input type="submit" value="提交"/>
    </form>

</body>
</html>
  • AccountController.java
package com.sunxiaping.web;

import com.sunxiaping.domain.Account;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

/**
 * @author <a href="mailto:1900919313@qq.com">weiwei.xu</a>
 * @version 1.0
 */
@Controller
@RequestMapping(value = "/account")
public class AccountController {

    /**
     * 保存账户信息
     *
     * @param account
     * @return
     */
    @RequestMapping(value = "/saveAccount", method = {RequestMethod.POST})
    public String saveAccount(Account account) {

        System.out.println("account = " + account);

        return "success";
    }

}

3.3.3.3 请求参数是POJO关联对象类型

  • Address.java
package com.sunxiaping.domain;

import java.io.Serializable;

/**
 * @author <a href="mailto:1900919313@qq.com">weiwei.xu</a>
 * @version 1.0
 */
public class Address implements Serializable {

    private String name;

    public String getName() {
        return name;
    }

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

    @Override
    public String toString() {
        return "Address{" +
                "name='" + name + '\'' +
                '}';
    }
}
  • Account.java
package com.sunxiaping.domain;

import java.io.Serializable;

/**
 * @author <a href="mailto:1900919313@qq.com">weiwei.xu</a>
 * @version 1.0
 */
public class Account implements Serializable {

    private String name;

    private Double money;

    private Address address;

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

    public Address getAddress() {
        return address;
    }

    public void setAddress(Address address) {
        this.address = address;
    }

    @Override
    public String toString() {
        return "Account{" +
                "name='" + name + '\'' +
                ", money=" + money +
                ", address=" + address +
                '}';
    }
}
  • index.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>SpringMVC的入门</title>
</head>
<body>

    <form action="${pageContext.request.contextPath}/account/saveAccount" method="post">
        账户名称:<input type="text" name="name" value=""/><br/>
        账户余额:<input type="text" name="money" value=""/><br/>
        账户的地址:<input type="text" name="address.name" value=""/><br/>
        <input type="submit" value="提交"/>
    </form>

</body>
</html>
  • AccountController.java
package com.sunxiaping.web;

import com.sunxiaping.domain.Account;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

/**
 * @author <a href="mailto:1900919313@qq.com">weiwei.xu</a>
 * @version 1.0
 */
@Controller
@RequestMapping(value = "/account")
public class AccountController {

    /**
     * 保存账户信息
     *
     * @param account
     * @return
     */
    @RequestMapping(value = "/saveAccount", method = {RequestMethod.POST})
    public String saveAccount(Account account) {

        System.out.println("account = " + account);

        return "success";
    }

}

3.3.3.4 POST请求参数的乱码问题

  • 在web.xml中配置一个过滤器
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xmlns="http://java.sun.com/xml/ns/javaee"
         xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
         id="WebApp_ID" version="2.5">

    <!-- 配置编码过滤器 -->
    <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>

    <!-- 配置SpringMVC的前端控制器,拦截所有请求  -->
    <servlet>
        <servlet-name>dispatcherServlet</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <!-- 加载SpringMVC的配置文件 -->
        <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>
    </servlet-mapping>
</web-app>
  • 在springmvc.xml中放开静态资源的拦截:
<?xml version="1.0" encoding="UTF-8"?>
<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="http://www.springframework.org/schema/beans"
       xmlns:tx="http://www.springframework.org/schema/tx"
       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/tx
        http://www.springframework.org/schema/tx/spring-tx.xsd
        http://www.springframework.org/schema/mvc
        https://www.springframework.org/schema/mvc/spring-mvc.xsd">

    <!-- 开启组件扫描 -->
    <context:component-scan base-package="com.sunxiaping" 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 name="suffix" value=".jsp"/>
    </bean>


    <!-- 配置SpringMVC的注解驱动 -->
    <mvc:annotation-driven/>

    <!-- 设置静态资源不过滤 -->
    <mvc:resources mapping="/css/" location="/css/**"/>
    <mvc:resources mapping="/img/" location="/img/**"/>
    <mvc:resources mapping="/js/" location="/js/**"/>

</beans>

3.3.3.5 请求参数是List集合类型

  • Address.java
package com.sunxiaping.domain;

import java.io.Serializable;

/**
 * @author <a href="mailto:1900919313@qq.com">weiwei.xu</a>
 * @version 1.0
 */
public class Address implements Serializable {

    /**
     * 地址名称
     */
    private String name;

    public String getName() {
        return name;
    }

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

    @Override
    public String toString() {
        return "Address{" +
                "name='" + name + '\'' +
                '}';
    }
}
  • Account.java
package com.sunxiaping.domain;

import java.io.Serializable;

/**
 * @author <a href="mailto:1900919313@qq.com">weiwei.xu</a>
 * @version 1.0
 */
public class Account implements Serializable {

    /**
     * 账户名称
     */
    private String name;

    /**
     * 账户余额
     */
    private Double money;

    private Address address;

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

    public Address getAddress() {
        return address;
    }

    public void setAddress(Address address) {
        this.address = address;
    }

    @Override
    public String toString() {
        return "Account{" +
                "name='" + name + '\'' +
                ", money=" + money +
                ", address=" + address +
                '}';
    }
}
  • User.java
package com.sunxiaping.domain;

import java.io.Serializable;
import java.util.List;

/**
 * @author <a href="mailto:1900919313@qq.com">weiwei.xu</a>
 * @version 1.0
 */
public class User implements Serializable {

    private String username;

    private String password;

    private Integer age;

    private List<Account> accountList;

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public List<Account> getAccountList() {
        return accountList;
    }

    public void setAccountList(List<Account> accountList) {
        this.accountList = accountList;
    }

    @Override
    public String toString() {
        return "User{" +
                "username='" + username + '\'' +
                ", password='" + password + '\'' +
                ", age=" + age +
                ", accountList=" + accountList +
                '}';
    }
}
  • index.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>请求参数的绑定</title>
</head>
<body>

    <form action="${pageContext.request.contextPath}/user/saveUser" method="post">
        用户名称:<input type="text" name="username" value=""/><br/>
        用户密码:<input type="password" name="password" value=""/><br/>
        年龄:<input type="text" name="age" value=""/><br/>

        账户1的名称:<input type="text" name="accountList[0].name" value=""/><br/>
        账户1的余额:<input type="text" name="accountList[0].money" value=""/><br/>

        账户2的名称:<input type="text" name="accountList[1].name" value=""/><br/>
        账户2的余额:<input type="text" name="accountList[1].money" value=""/><br/>

        <input type="submit" value="提交"/>
    </form>

</body>
</html>
  • UserController.java
package com.sunxiaping.web;

import com.sunxiaping.domain.User;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import java.io.Serializable;

/**
 * @author <a href="mailto:1900919313@qq.com">weiwei.xu</a>
 * @version 1.0
 */
@Controller
@RequestMapping(value = "/user")
public class UserController implements Serializable {


    /**
     * 增加用户信息
     *
     * @param user
     * @return
     */
    @RequestMapping(value = "/saveUser", method = RequestMethod.POST)
    public String saveUser(User user) {

        System.out.println("user = " + user);

        return "success";
    }

}

3.3.3.6 请求参数是Map集合类型

  • Address.java
package com.sunxiaping.domain;

import java.io.Serializable;

/**
 * @author <a href="mailto:1900919313@qq.com">weiwei.xu</a>
 * @version 1.0
 */
public class Address implements Serializable {

    /**
     * 地址名称
     */
    private String name;

    public String getName() {
        return name;
    }

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

    @Override
    public String toString() {
        return "Address{" +
                "name='" + name + '\'' +
                '}';
    }
}
  • Account.java
package com.sunxiaping.domain;

import java.io.Serializable;

/**
 * @author <a href="mailto:1900919313@qq.com">weiwei.xu</a>
 * @version 1.0
 */
public class Account implements Serializable {

    /**
     * 账户名称
     */
    private String name;

    /**
     * 账户余额
     */
    private Double money;

    private Address address;

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

    public Address getAddress() {
        return address;
    }

    public void setAddress(Address address) {
        this.address = address;
    }

    @Override
    public String toString() {
        return "Account{" +
                "name='" + name + '\'' +
                ", money=" + money +
                ", address=" + address +
                '}';
    }
}
  • User.java
package com.sunxiaping.domain;

import java.io.Serializable;
import java.util.Map;

/**
 * @author <a href="mailto:1900919313@qq.com">weiwei.xu</a>
 * @version 1.0
 */
public class User implements Serializable {

    private String username;

    private String password;

    private Integer age;

    private Map<String,Account> accountMap;


    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public Map<String, Account> getAccountMap() {
        return accountMap;
    }

    public void setAccountMap(Map<String, Account> accountMap) {
        this.accountMap = accountMap;
    }

    @Override
    public String toString() {
        return "User{" +
                "username='" + username + '\'' +
                ", password='" + password + '\'' +
                ", age=" + age +
                ", accountMap=" + accountMap +
                '}';
    }
}
  • index.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>请求参数的绑定</title>
</head>
<body>

    <form action="${pageContext.request.contextPath}/user/saveUser" method="post">
        用户名称:<input type="text" name="username" value=""/><br/>
        用户密码:<input type="password" name="password" value=""/><br/>
        年龄:<input type="text" name="age" value=""/><br/>

        账户1的名称:<input type="text" name="accountMap.one.name" value=""/><br/>
        账户1的余额:<input type="text" name="accountMap['one'].money" value=""/><br/>

        账户2的名称:<input type="text" name="accountMap['two'].name" value=""/><br/>
        账户2的余额:<input type="text" name="accountMap['two'].money" value=""/><br/>

        <input type="submit" value="提交"/>
    </form>

</body>
</html>
  • UserController.java
package com.sunxiaping.web;

import com.sunxiaping.domain.User;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import java.io.Serializable;

/**
 * @author <a href="mailto:1900919313@qq.com">weiwei.xu</a>
 * @version 1.0
 */
@Controller
@RequestMapping(value = "/user")
public class UserController implements Serializable {


    /**
     * 增加用户信息
     *
     * @param user
     * @return
     */
    @RequestMapping(value = "/saveUser", method = RequestMethod.POST)
    public String saveUser(User user) {

        System.out.println("user = " + user);

        return "success";
    }

}

3.2 特殊情况

3.2.1 概述

  • SpringMVC其实只能处理String类型、String的数组类型、字节输入流类型。是因为SpringMVC是基于Servlet,而Servlet可以通过如下的方法获取请求参数值。
String parameter = request.getParameter("");
String[] parameterValues = request.getParameterValues("");
ServletInputStream inputStream = request.getInputStream();
  • 对于String-->Date或Date-->String,只能通过自定义类型转换器。

3.2.2 自定义类型转换器应用示例

  • 示例:
  • StringToDateConverter.java
package com.sunxiaping.converter;

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

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

/**
 * 字符串转Date类型的转换器
 *
 * @author <a href="mailto:1900919313@qq.com">weiwei.xu</a>
 * @version 1.0
 */
public class StringToDateConverter implements Converter<String, Date> {
    /**
     * 把字符串转换成日期对象
     *
     * @param source
     * @return
     */
    @Override
    public Date convert(String source) {
        if (StringUtils.isEmpty(source)) {
            throw new NullPointerException("请传入参数");
        }
        DateFormat df = new SimpleDateFormat("yyyy-MM-dd");

        try {
            return df.parse(source);
        } catch (ParseException e) {
            throw new RuntimeException("类型转换错误");
        }
    }
}
  • 在SpringMVC的配置文件中配置自定义类型转换器:
<?xml version="1.0" encoding="UTF-8"?>
<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="http://www.springframework.org/schema/beans"
       xmlns:tx="http://www.springframework.org/schema/tx"
       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/tx
        http://www.springframework.org/schema/tx/spring-tx.xsd
        http://www.springframework.org/schema/mvc
        https://www.springframework.org/schema/mvc/spring-mvc.xsd">

    <!-- 开启组件扫描 -->
    <context:component-scan base-package="com.sunxiaping" 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 name="suffix" value=".jsp"/>
    </bean>

    <!-- 配置自定义类型转换器 -->
    <bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
        <property name="converters">
            <set>
                <bean class="com.sunxiaping.converter.StringToDateConverter"></bean>
            </set>
        </property>
    </bean>

    <!-- 配置SpringMVC的注解驱动 -->
    <mvc:annotation-driven conversion-service="conversionService"/>
    
</beans>
  • User.java
package com.sunxiaping.domain;

import java.io.Serializable;
import java.util.Date;

/**
 * @author <a href="mailto:1900919313@qq.com">weiwei.xu</a>
 * @version 1.0
 */
public class User implements Serializable {

    private String username;

    private String password;

    private Integer age;

    private Date birthday;

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public Date getBirthday() {
        return birthday;
    }

    public void setBirthday(Date birthday) {
        this.birthday = birthday;
    }

    @Override
    public String toString() {
        return "User{" +
                "username='" + username + '\'' +
                ", password='" + password + '\'' +
                ", age=" + age +
                ", birthday=" + birthday +
                '}';
    }
}
  • index.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>请求参数的绑定</title>
</head>
<body>

    <form action="${pageContext.request.contextPath}/user/saveUser" method="post">
        用户名称:<input type="text" name="username" value=""/><br/>
        用户密码:<input type="password" name="password" value=""/><br/>
        年龄:<input type="text" name="age" value=""/><br/>
        生日:<input type="text" name="birthday" value=""/><br/>

        <input type="submit" value="提交"/>
    </form>

</body>
</html>
  • UserController.java
package com.sunxiaping.web;

import com.sunxiaping.domain.User;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import javax.servlet.http.HttpServletRequest;
import java.io.Serializable;

/**
 * @author <a href="mailto:1900919313@qq.com">weiwei.xu</a>
 * @version 1.0
 */
@Controller
@RequestMapping(value = "/user")
public class UserController implements Serializable {


    /**
     * 增加用户信息
     *
     * @param user
     * @return
     */
    @RequestMapping(value = "/saveUser", method = RequestMethod.POST)
    public String saveUser(User user, HttpServletRequest request) {

        System.out.println("user = " + user);

        return "success";
    }

}

4 常用注解

4.1 @RequestParam注解

4.1.1 概述

  • 作用:把请求中指定名称的参数赋值给控制器中方法的形参。
  • 属性:
    • value:请求参数中的名称。
    • required:请求参数中是否必须提供此参数。默认值:true,表示必须提供,如果不提供将报错。

4.1.2 应用示例

  • 示例:
  • index.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>常用注解</title>
</head>
<body>

   <a href="${pageContext.request.contextPath}/user/test?name=aaa">@RequestParam注解</a>

</body>
</html>
  • UerController.java
package com.sunxiaping.web;

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

import java.io.Serializable;

/**
 * @author <a href="mailto:1900919313@qq.com">weiwei.xu</a>
 * @version 1.0
 */
@Controller
@RequestMapping(value = "/user")
public class UserController implements Serializable {


    @RequestMapping(value = "/test", method = RequestMethod.GET)
    public String test(@RequestParam(value = "name", required = false) String username) {
        System.out.println("username = " + username);
        return "success";
    }
}

4.2 @RequestBody注解

4.2.1 概述

  • 作用:

    • 用于获取请求体的内容。直接使用得到的是key=value&key=value的结构的数据。
    • 不能用于GET方式。
    • @RequestBody注解一般用于将前端传递过来的JSON数据封装到后台定义的VO中。
  • 属性:

    • required:是否必须有请求体。默认值:true,当值为true的时候,GET请求方式会报错;当值为false的时候,GET请求方式得到的是null。

4.2.2 应用示例

  • 示例:
  • index.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>常用注解</title>
</head>
<body>

    <form action="${pageContext.request.contextPath}/user/saveUser" method="post">
        用户名称:<input type="text" name="username" value=""/><br/>
        用户密码:<input type="password" name="password" value=""/><br/>
        年龄:<input type="text" name="age" value=""/><br/>

        <input type="submit" value="提交"/>
    </form>

</body>
</html>
  • UserController.java
package com.sunxiaping.web;

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

import java.io.Serializable;

/**
 * @author <a href="mailto:1900919313@qq.com">weiwei.xu</a>
 * @version 1.0
 */
@Controller
@RequestMapping(value = "/user")
public class UserController implements Serializable {

    /**
     * 增加用户信息
     *
     * @param user
     * @return
     */
    @RequestMapping(value = "/saveUser", method = RequestMethod.POST)
    public String saveUser(@RequestBody String user) {

        System.out.println("user = " + user);

        return "success";
    }

}

4.3 @PathVariable注解

4.3.1 概述

  • 作用:
    • 用于绑定URL中的占位符。例如:URL中/delete/{id},这个{id}就是URL的占位符。
    • URL支持占位符是在Spring3.0之后加入的,是SpringMVC支持RESTful风格URL的一个重要标志。
  • 属性:
    • value:用于指定URL中占位符的名称。
    • required:是否必须提供占位符。

4.3.2 应用示例

  • 示例:
  • index.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>常用注解</title>
</head>
<body>

    <a href="${pageContext.request.contextPath}/user/delete/1">删除用户信息</a>

</body>
</html>
  • UserController.java
package com.sunxiaping.web;

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

import java.io.Serializable;

/**
 * @author <a href="mailto:1900919313@qq.com">weiwei.xu</a>
 * @version 1.0
 */
@Controller
@RequestMapping(value = "/user")
public class UserController implements Serializable {


    @RequestMapping(value = "/delete/{id}")
    public String delete(@PathVariable(value = "id") Integer id) {
        System.out.println("id = " + id);
        return "success";
    }

}

4.4 @RequestHeader注解(不常用)

4.4.1 概述

  • 作用:获取请求头的信息。

4.4.2 应用示例

  • 示例:
  • index.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>常用注解</title>
</head>
<body>

    <a href="${pageContext.request.contextPath}/user/testRequestHeader">testRequestHeader</a>

</body>
</html>
  • UserController.java
package com.sunxiaping.web;

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

import java.io.Serializable;

/**
 * @author <a href="mailto:1900919313@qq.com">weiwei.xu</a>
 * @version 1.0
 */
@Controller
@RequestMapping(value = "/user")
public class UserController implements Serializable {
    
    @RequestMapping(value = "/testRequestHeader")
    public String testRequestHeader(@RequestHeader(value = "Accept-Encoding") String encoding) {
        System.out.println("encoding = " + encoding);
        return "success";
    }

}

4.5 @CookieValue注解(不常用)

4.5.1 概述

  • 作用:获取Cookie的值。

4.5.2 应用示例

  • 示例:
  • index.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>常用注解</title>
</head>
<body>

    <a href="${pageContext.request.contextPath}/user/testCookieValue">testCookieValue</a>

</body>
</html>
  • UserController.java
package com.sunxiaping.web;

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

import java.io.Serializable;

/**
 * @author <a href="mailto:1900919313@qq.com">weiwei.xu</a>
 * @version 1.0
 */
@Controller
@RequestMapping(value = "/user")
public class UserController implements Serializable {

    @RequestMapping(value = "/testCookieValue")
    public String testCookieValue(@CookieValue(value = "JSESSIONID") String jSessionId) {
        System.out.println("jSessionId = " + jSessionId);
        return "success";
    }
}

4.6 @ModelAttribute注解

4.6.1 概述

  • 作用:
    • 该注解是SpringMVC4.3版本以后新加入的,它可以用来修饰方法和参数。
    • 如果该注解修饰方法,表示当前方法会在控控制器的方法执行之前,先执行。它可以修饰没有返回值的方法,也可以修饰有返回值的方法。
    • 如果该注解修饰参数,获取指定的数据给参数赋值。
  • 属性:
    • value:用于获取数据的key。key可以是POJO的属性名称,也可以是map结构的key。
  • 应用场景:
    • 当表单提交的数据不是完整的实体类数据的时候,保证没有提交数据的字段使用的是数据库对象原来的数据。
    • 例如:我们在编辑一个用户的时候,用户有一个创建信息的字段,该字段的值是不允许被修改的。在提交表单的时候肯定没有此字段的内容,一旦更新会把该字段内容设置为null,此时就可以使用此注解解决此类问题。

4.6.2 应用示例

  • 示例:
  • User.java
package com.sunxiaping.domain;

import java.io.Serializable;

/**
 * @author <a href="mailto:1900919313@qq.com">weiwei.xu</a>
 * @version 1.0
 */
public class User implements Serializable {

    /**
     * 主键
     */
    private Integer id;

    /**
     * 账号 不能修改
     */
    private String username;

    /**
     * 密码
     */
    private String password;

    /**
     * 昵称
     */
    private String nickname;

    public Integer getId() {
        return id;
    }

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

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public String getNickname() {
        return nickname;
    }

    public void setNickname(String nickname) {
        this.nickname = nickname;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", username='" + username + '\'' +
                ", password='" + password + '\'' +
                ", nickname='" + nickname + '\'' +
                '}';
    }
}
  • index.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>常用注解</title>
</head>
<body>

    <form action="${pageContext.request.contextPath}/user/updateUser" method="post">
        用户主键:<input type="text" name="id" value="1"/><br/>
        用户昵称:<input type="text" name="nickname" value=""/><br/>
        用户密码:<input type="password" name="password" value=""/><br/>
        <input type="submit" value="提交"/>
    </form>

</body>
</html>
  • UserController.java
package com.sunxiaping.web;

import com.sunxiaping.domain.User;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import java.io.Serializable;

/**
 * @author <a href="mailto:1900919313@qq.com">weiwei.xu</a>
 * @version 1.0
 */
@Controller
@RequestMapping(value = "/user")
public class UserController implements Serializable {


    @ModelAttribute(value = "user")
    public User findById(Integer id) {
        User user = new User();
        user.setId(id);
        user.setUsername("admin");
        user.setPassword("123456");
        user.setNickname("管理员");
        return user;
    }

    @RequestMapping(value = "/updateUser", method = RequestMethod.POST)
    public String updateUser(User user) {

        System.out.println("user = " + user);

        return "success";
    }
}

5 响应数据和结果视图

5.1 返回值分类

5.1.1 字符串

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

  • 示例:

package com.sunxiaping.web;

import com.sunxiaping.domain.User;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import java.io.Serializable;

/**
 * @author <a href="mailto:1900919313@qq.com">weiwei.xu</a>
 * @version 1.0
 */
@Controller
@RequestMapping(value = "/user")
public class UserController implements Serializable {


    /**
     * 指定逻辑视图名,经过视图解析器解析为JSP的物理路径 /WEB-INF/views/success.jsp
     *
     * @param user
     * @return
     */
    @RequestMapping(value = "/updateUser", method = RequestMethod.POST)
    public String updateUser(User user) {

        System.out.println("user = " + user);

        return "success";
    }
}

5.1.2 void

  • 当方法的返回值是voide类型的时候,SpringMVC会把方法名作为前缀,到指定的位置查找JSP。

  • 示例:

  • index.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>返回值类型</title>
</head>
<body>

    <a href="${pageContext.request.contextPath}/user/testVoid">testVoid</a>

</body>
</html>
  • UerController.java
package com.sunxiaping.web;

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

import java.io.Serializable;

/**
 * @author <a href="mailto:1900919313@qq.com">weiwei.xu</a>
 * @version 1.0
 */
@Controller
@RequestMapping(value = "/user")
public class UserController implements Serializable {


    /**
     * 当方法返回时void的时候,SpringMVC会把方法名作为前缀,到指定的位置查找JSP
     */
    @RequestMapping(value = "/testVoid")
    public void testVoid() {

        System.out.println("返回的类型是void");

    }
}

方法的返回值是void类型

5.1.3 ModelAndView

  • ModelAndView是SpringMVC为我们提供的一个对象,该对象也可以用作控制器方法的返回值。

  • 示例:

  • index.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>

    <a href="${pageContext.request.contextPath}/user/testModelAndView">testModelAndView</a>

</body>
</html>
  • UserController.java
package com.sunxiaping.web;

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

import java.io.Serializable;

/**
 * @author <a href="mailto:1900919313@qq.com">weiwei.xu</a>
 * @version 1.0
 * 2020-07-26 6:32
 */
@Controller
@RequestMapping(value = "/user")
public class UserController implements Serializable {


    @RequestMapping(value = "/testModelAndView",method = RequestMethod.GET)
    public ModelAndView testModelAndView(){
        ModelAndView modelAndView = new ModelAndView();
        modelAndView.setViewName("success");
        modelAndView.addObject("helloWorld", "你好,世界");
        return modelAndView;
    }
}
  • success.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    success   ${helloWorld}
</body>
</html>

5.2 转发和重定向

5.2.1 使用原生Servlet API实现转发和重定向

  • 示例:使用原生Servlet API实现转发
  • index.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>返回值类型</title>
</head>
<body>

    <a href="${pageContext.request.contextPath}/user/testVoid">testVoid</a>

</body>
</html>
  • UserController.java
package com.sunxiaping.web;

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

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.Serializable;

/**
 * @author <a href="mailto:1900919313@qq.com">weiwei.xu</a>
 * @version 1.0
 */
@Controller
@RequestMapping(value = "/user")
public class UserController implements Serializable {


    /**
     * 使用原生Servlet API实现转发
     */
    @RequestMapping(value = "/testVoid")
    public void testVoid(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

        System.out.println("返回的类型是void");

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

    }
    
}
  • 示例:使用原生Servlet API实现重定向
  • index.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>返回值类型</title>
</head>
<body>

    <a href="${pageContext.request.contextPath}/user/testVoid">testVoid</a>

</body>
</html>
  • UserController.java
package com.sunxiaping.web;

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

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.Serializable;

/**
 * @author <a href="mailto:1900919313@qq.com">weiwei.xu</a>
 * @version 1.0
 */
@Controller
@RequestMapping(value = "/user")
public class UserController implements Serializable {


    /**
     * 使用原生Servlet API实现转发
     */
    @RequestMapping(value = "/testVoid")
    public void testVoid(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

        System.out.println("返回的类型是void");

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

}

5.2.2 SpringMVC的请求转发和重定向

  • 一般情况下,控制器方法返回字符串类型的值会被当成逻辑视图名处理。

  • 如果返回的字符串中带有forward:redirect:前缀,SpringMVC会对它们进行特殊处理,将forward:redirect:当成指示符,其后的字符串作为URL来处理。

  • 示例:

  • index.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>

    <a href="${pageContext.request.contextPath}/user/test">test</a>

</body>
</html>
  • UserController.java
package com.sunxiaping.web;

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

import java.io.Serializable;

/**
 * @author <a href="mailto:1900919313@qq.com">weiwei.xu</a>
 * @version 1.0
 * 2020-07-26 6:32
 */
@Controller
@RequestMapping(value = "/user")
public class UserController implements Serializable {

    @GetMapping(value = "/test")
    public String test(){
        return "forward:/WEB-INF/views/success.jsp";
    }

}

5.3 @ResponseBody注解响应JSON数据

  • @ResponseBody注解用于将Controller方法的返回对象,通过HttpMessageConverter接口转换为指定格式的数据如JSON、XML等,通过Response响应给客户端。

  • 示例:

  • 导入jackson的jar包的Maven坐标:

<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.9.8</version>
</dependency>
  • 在springmvc.xml中需要配置<mvc:annotation-drivern/>:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns="http://www.springframework.org/schema/beans"
       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/mvc
        https://www.springframework.org/schema/mvc/spring-mvc.xsd">

    <!-- 开启组件扫描 -->
    <context:component-scan base-package="com.sunxiaping" 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 name="suffix" value=".jsp"/>
    </bean>


    <!-- 配置SpringMVC的注解驱动 -->
    <mvc:annotation-driven/>

</beans>
  • index.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>

    <a href="${pageContext.request.contextPath}/user/findAll">findAll</a>

</body>
</html>
  • User.java
package com.sunxiaping.domain;

import java.io.Serializable;

/**
 * @author <a href="mailto:1900919313@qq.com">weiwei.xu</a>
 * @version 1.0
 * 2020-07-26 12:59
 */
public class User implements Serializable {

    private String username;

    private String password;

    public User() {
    }

    public User(String username, String password) {
        this.username = username;
        this.password = password;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    @Override
    public String toString() {
        return "User{" +
                "username='" + username + '\'' +
                ", password='" + password + '\'' +
                '}';
    }
}
  • UserController.java
package com.sunxiaping.web;

import com.sunxiaping.domain.User;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;

/**
 * @author <a href="mailto:1900919313@qq.com">weiwei.xu</a>
 * @version 1.0
 * 2020-07-26 6:32
 */
@Controller
@RequestMapping(value = "/user")
public class UserController implements Serializable {


    @GetMapping(value = "/findAll")
    @ResponseBody
    public List<User> findAll() {
        List<User> userList = new ArrayList<>();
        userList.add(new User("abc", "123"));
        userList.add(new User("bcd", "456"));
        return userList;
    }

}

6 文件上传

6.1 文件上传的前提条件

  • form表单的enctype的取值必须是multipart/form-data
  • method属性取值必须是POST
  • 提供一个文件选择域 <input type="file"/>

6.2 应用示例

  • 示例:
  • 导入commons-fileupload相关jar包的Maven坐标:
<dependency>
    <groupId>commons-fileupload</groupId>
    <artifactId>commons-fileupload</artifactId>
    <version>1.4</version>
</dependency>
  • 在springmvc.xml中配置CommonsMultipartResolver
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns="http://www.springframework.org/schema/beans"
       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/mvc
        https://www.springframework.org/schema/mvc/spring-mvc.xsd">

    <!-- 开启组件扫描 -->
    <context:component-scan base-package="com.sunxiaping" 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 name="suffix" value=".jsp"/>
    </bean>

    <!-- 需要配置CommonsMultipartResolver -->
    <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
        <property name="defaultEncoding" value="utf-8"/>
        <property name="maxUploadSize" value="#{1024*1024}"/>
    </bean>


    <!-- 配置SpringMVC的注解驱动 -->
    <mvc:annotation-driven/>

</beans>
  • index.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>

    <form action="${pageContext.request.contextPath}/springmvc/fileUpload" enctype="multipart/form-data" method="post">
        上传文件<input type="file" name="file"/><br/>
        <input type="submit" value="提交"/>
    </form>

</body>
</html>
  • FileUploadController.java
package com.sunxiaping.web;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.multipart.MultipartFile;

/**
 * @author <a href="mailto:1900919313@qq.com">weiwei.xu</a>
 * @version 1.0
 * 2020-07-26 14:06
 */
@Controller
@RequestMapping(value = "/springmvc")
public class FileUploadController {

    @PostMapping(value = "/fileUpload")
    public String fileUpload(MultipartFile file) {

        System.out.println(file);

        String originalFilename = file.getOriginalFilename();
        System.out.println("上传文件名 = " + originalFilename);

        String name = file.getName();
        System.out.println("input标签中name属性的值 = " + name);
        
        //可以通过transferTo方法复制文件
//        file.transferTo();

        return "success";
    }

}

7 拦截器

7.1 概述

  • SpringMVC可以使用拦截器对请求进行拦截处理,用户可以自定义拦截器来实现特定的功能。自定义的拦截器必须实现HandlerInterceptor接口。
package org.springframework.web.servlet;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.lang.Nullable;

public interface HandlerInterceptor {
    
    /**
     * 这个方法在业务处理器处理请求之前被调用,在该方法中可以对用户请求进行处理。
     * 如果程序员决定改拦截器对请求进行拦截处理之后还要调用其他的拦截器,或者业务处理器去进行处理,就返回true,否则返回false。
     *
     * @param request
     * @param response
     * @param handler
     * @return
     * @throws Exception
     */
    default boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        return true;
    }
    /**
     * 这个方法在业务处理器处理完请求后,但是DispatcherServlet向客户端返回响应前被调用
     *
     * @param request
     * @param response
     * @param handler
     * @param modelAndView
     * @throws Exception
     */
    default void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView) throws Exception {
    }
	 /**
     * 该方法在DispatcherServlet完全处理请求后被调用,通常用于一些资源清理的操作。
     *
     * @param request
     * @param response
     * @param handler
     * @param ex
     * @throws Exception
     */
    default void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception {
    }
}

7.2 应用示例

  • 示例:
  • SelfInterceptor.java
package com.sunxiaping.interceptor;


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

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

/**
 * @author <a href="mailto:1900919313@qq.com">weiwei.xu</a>
 * @version 1.0
 * 2020-07-26 18:04
 */
public class SelfInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("==========preHandle==============");
        return true;
    }

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

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("==========afterCompletion==============");
    }
}
  • SelfInterceptor2.java
package com.sunxiaping.interceptor;


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

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

/**
 * @author <a href="mailto:1900919313@qq.com">weiwei.xu</a>
 * @version 1.0
 * 2020-07-26 18:04
 */
public class SelfInterceptor2 implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("==========preHandle2==============");
        return true;
    }

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

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("==========afterCompletion2==============");
    }
}
  • 在springmvc.xml中配置拦截器
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns="http://www.springframework.org/schema/beans"
       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/mvc
        https://www.springframework.org/schema/mvc/spring-mvc.xsd">

    <!-- 开启组件扫描 -->
    <context:component-scan base-package="com.sunxiaping" 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 name="suffix" value=".jsp"/>
    </bean>

    <!-- 配置拦截器 -->
    <mvc:interceptors>
        <!-- 拦截所有的请求 -->
        <bean class="com.sunxiaping.interceptor.SelfInterceptor2"></bean>
        <mvc:interceptor>
            <!-- 拦截指定的请求-->
            <mvc:mapping path="/emps"/>
            <bean class="com.sunxiaping.interceptor.SelfInterceptor"/>
        </mvc:interceptor>
    </mvc:interceptors>


    <!-- 配置SpringMVC的注解驱动 -->
    <mvc:annotation-driven/>
</beans>

8 异常处理

8.1 概述

  • SpringMVC通过HandlerExceptionResolver处理程序的异常,包括Handler映射、数据绑定以及目标方法执行时发生的异常。
  • SpringMVC提供的HandlerExceptionResolver的实现类:

HandlerExceptionResolver的实现类

  • 如果在springmvc.xml中配置了<mvc:annotation-drivern>,那么DispatcherServlet默认装配的异常处理器是ExceptionHandlerExceptionResolver。
  • ExceptionHandlerExceptionResolver主要处理Handler中用@ExceptionHandler注解定义的方法。
  • @ExceptionHandler注解定义的方法优先级问题:如果发生的是NullPointerException,但是声明的异常有RuntimeException和Exception,此时会根据异常的最近继承关系找到继承深度最浅的哪个标注了@ExceptionHandler注解的方法,即标记了RuntimeException的方法。
  • ExceptionHandlerExceptionResolver内部找不到@ExceptionHandler注解,就会找@ControllerAdvice中的@ExceptionHandler注解标注的方法,如果还不找到,就将异常信息,发送给用户。

8.2 应用示例

  • 示例:
  • index.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>

    <a href="${pageContext.request.contextPath}/user/findAll">查询所有用户信息</a>

</body>
</html>
  • springmvc.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns="http://www.springframework.org/schema/beans"
       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/mvc
        https://www.springframework.org/schema/mvc/spring-mvc.xsd">

    <!-- 开启组件扫描 -->
    <context:component-scan base-package="com.sunxiaping"></context:component-scan>

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

    <!-- 配置SpringMVC的注解驱动 -->
    <mvc:annotation-driven/>

</beans>
  • UserController.java
package com.sunxiaping.web;

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

import java.io.Serializable;

/**
 * @author <a href="mailto:1900919313@qq.com">weiwei.xu</a>
 * @version 1.0
 * 2020-07-26 6:32
 */
@Controller
@RequestMapping(value = "/user")
public class UserController implements Serializable {


    @GetMapping(value = "/findAll")
    public String findAll() {
        System.out.println("查询所有用户信息");

        if (true) {
            throw new RuntimeException("aa");
        }

        return "success";
    }
}
  • UserControllerAdvice.java
package com.sunxiaping.web;

import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.servlet.ModelAndView;

/**
 * @author <a href="mailto:1900919313@qq.com">weiwei.xu</a>
 * @version 1.0
 * 2020-07-26 18:23
 */
@ControllerAdvice
public class UserControllerAdvice {

    @ExceptionHandler(RuntimeException.class)
    public ModelAndView resolverMathException(Exception ex) {
        ModelAndView mv = new ModelAndView();
        mv.setViewName("error");
        mv.addObject("msg", "出错啦");
        return mv;
    }
}
  • error.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    ${msg}
</body>
</html>
posted @ 2020-09-13 09:13  许大仙  阅读(361)  评论(0编辑  收藏  举报