一、SpringMVC的基本概念

1.1 三层架构和MVC

1.1.1 三层架构

  1. 表现层

    • SpringMVC
  2. 业务层

    • Spring
  3. 持久层

    • MyBatis

1.1.2 MVC模型

  1. Model 模型:

    • 数据模型。通常用于封装数据。
  2. View 视图:

    • jsp或html,展示数据。
  3. Controller 控制器:

    • 应用程序中处理用户交互的部分,处理程序逻辑的。

1.2 SpringMVC概述

1.2.1 SpringMVC是什么

  • SpringMVC是一种基于Java的实现MVC设计模型的请求驱动类型的轻量级Web框架,属于Spring Frame的后续产品。
  • 通过一套注解,让一个Java类成为处理请求的控制器,而无需实现任何借口,支持RESTful编程等个的请求。

1.2.2 SpringMVC在三层架构的位置

1.2.3 SpringMVC的优势

  1. 清晰的角色划分

    1. 前端控制器:DispatcherService
    2. 请求到处理器映射:HandlerMapping
    3. 处理器适配器:HandlerAdapter
    4. 视图解析器:ViewResolver
    5. 处理器或页面控制器:Controller
    6. 验证器:Validator
    7. 命令对象:Command
    8. 表单对象:Form Object
  2. 分工明确,容易扩展。
  3. 和Spring无缝集成
  4. 可定制
  5. 功能强大的数据验证、格式化、绑定机制
  6. 利用Spring提供的Mock对象能够非常简单的web层单元测试
  7. 强大的JSP标签库。
  8. RESTful风格的支持。

1.2.4 SpringMVC和Struts2的优劣分析

  1. 共同点:

    1. 都是表现层框架,都是基于MVC模型编写的
    2. 底层都离不开ServletAPI
    3. 处理请求的机制都是一个核心控制器
  2. 区别:

    1. SpringMVC的入口是Servlet,Struts2是Filter
    2. SpringMVC是基于方法设计的,而Struts2是基于类,Struts2每次都会创建一个动作类,所以SpringMVC会稍微比Struts2快一点。
    3. SpringMVC使用更加简洁,同时还支持JSR303,处理ajax的请求更方便
    4. Struts2 的OGNL 表达式使页面的开发效率相比Spring MVC 更高些,但执行效率并没有比JSTL提升,尤其是struts2的表单标签,远没有html执行效率高。

二、SpringMVC的快速入门

2.1 入门案例

2.1.1 使用Maven创建web工程

2.1.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>com.ruki</groupId>
  <artifactId>springmvc_day01_01_start</artifactId>
  <version>1.0-SNAPSHOT</version>
  <packaging>war</packaging>

  <name>springmvc_day01_01_start 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的版本 -->
    <spring.version>5.1.7.RELEASE</spring.version>
  </properties>

  <dependencies>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>${spring.version}</version>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-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>

  <build>
    <finalName>springmvc_day01_01_start</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>
      </plugins>
    </pluginManagement>
  </build>
</project>

2.1.3 配置核心控制器

  • org.springframework.web.servlet.DispatcherServlet
    <!-- 核心控制器 -->
    <servlet>
    <servlet-name>dispatcherServlet</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <!-- 初始化时加载配置文件-->
    <init-param>
      <param-name>contextConfigLocation</param-name>
      <param-value>classpath:springmvc.xml</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
  </servlet>
  <servlet-mapping>
    <servlet-name>dispatcherServlet</servlet-name>
    <url-pattern>/</url-pattern>
  </servlet-mapping>

2.1.4 创建的主配置文件

  • springmvc.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:mvc="http://www.springframework.org/schema/mvc"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="
        http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd
        http://www.springframework.org/schema/mvc
        http://www.springframework.org/schema/mvc/spring-mvc.xsd">
    <!-- 开启注解扫描 -->
    <context:component-scan base-package="com.ruki"></context:component-scan>

    <!-- 视图解析器对象 -->
    <bean id="internalResourceViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/pages/"></property>
        <property name="suffix" value=".jsp"></property>
    </bean>

    <!-- 配置自定义日期转换器-->
    <bean id="convertorService" class="org.springframework.context.support.ConversionServiceFactoryBean">
        <property name="converters">
            <set>
                <bean class="com.ruki.utils.StringToDate"></bean>
            </set>
        </property>
    </bean>

    <!-- 开启SpringMVC框架注解的支持-->
    <mvc:annotation-driven conversion-service="convertorService"></mvc:annotation-driven>
</beans>

2.1.5 编写控制器并使用注解配置

package com.ruki.controller;

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

//控制器类
@Controller
@RequestMapping("/user")
public class HelloController {
    @RequestMapping(path = "/hello")
    public String sayHello(){
        System.out.println("Hello StringMVC");
        return "success";
    }
}

2.2 入门案例请求处理流程图

2.3 组件介绍

2.3.1 DispatcherServlet:前端控制器

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

2.3.2 HandlerMapping:处理器映射器

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

2.3.3 Handler:处理器

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

2.3.4 HandlerAdapter:处理器适配器

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

2.3.5 View Resolver视图解析器

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

2.3.6 View:视图

  • 一般情况下需要通过页面标签或页面模版技术将模型数据通过页面展示给用户,需要由程序员根据业务需求开发具体的页面。

2.3.7 mvc:annotation-driven 说明

  • 在SpringMVC的各个组件中,处理器映射器、处理器适配器、视图解析器称为SpringMVC的三大组件。 使用<mvc:annotation-driven>自动加载RequestMappingHandlerMapping(处理映射器)和RequestMappingHandlerAdapter(处理适配器),可用在SpringMVC.xml配置文件中使用<mvc:annotation-driven>替代注解处理器和适配器的配置。
  • 简而言之,<font color="red"><u>处理映射器</u><u>处理适配器</u>不需要再配置了,<u>视图解析器</u>还需要配置</font>

2.4 RequestMapping注解

2.4.1 使用说明

  • 作用:建立请求URL和处理请求方法之间的关系
  • 出现位置:

    • 类上:第一级访问目录
    • 方法上:第二级访问目录
  • 属性:

    • value:指定请求的URL。作用与path一致
    • method:指定请求的方式
    • params:指定限制请求参数的条件。请求参数的key和value必须和配置的一样

三、请求参数的绑定

3.1 绑定说明

3.1.1 绑定机制(自动绑定)

  • <a href="account/findAccount?accountId=10">查询账户</a>

    /** 
    * 查询账户 
    * @return 
    */ 
    @RequestMapping("/findAccount") 
    public String findAccount(Integer accountId) { 
        System.out.println("查询了账户。。。。"+accountId); 
        return "success"; 
    }

3.1.2 支持的数据类型

  1. 基本类型数据:参数名称必须和控制器中方法的形参名称保持一致。(严格区分大小写)

    1. 基本类型
    2. String
  2. POJO类型参数:表单中参数名称和POJO类的属性名称保持一致。并且控制器方法的参数类型是POJO类型。

    1. 实体类和关联的实体类
  3. 数组和集合类型的参数:集合类型的请求参数必须在POJO中。在表单中请求参数名称要和POJO中集合属性名称相同。

    1. List:使用下标。list[0].uname
    2. Map:使用键值对。map['one'].uname
        <form action="param/testParam" method="post">
            姓名:<input type="text" name="username"><br>
            密码:<input type="text" name="password"><br>
            金额:<input type="text" name="money"><br>
    
            用户名:<input type="text" name="list[0].uname"><br>
            年龄:<input type="text" name="list[0].uage"><br>
    
            用户名:<input type="text" name="map['one'].uname"><br>
            年龄:<input type="text" name="map['one'].uage"><br>
            <input type="submit" value="注册"><br>
        </form>

3.2 自定义转换器

  • 需求:1999-11-11类型的日期能够被识别

3.2.1 创建工具类 StringToDate

package com.ruki.utils;

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

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

public class StringToDate implements Converter<String, Date> {

    @Override
    public Date convert(String source) {
        DateFormat df = new SimpleDateFormat("yyyy-MM-dd");
        try {
            return df.parse(source);
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return null;
    }
}

3.2.2 在springmvc.xml中进行配置

    <!-- 配置自定义日期转换器-->
    <bean id="convertorService" class="org.springframework.context.support.ConversionServiceFactoryBean">
        <property name="converters">
            <set>
                <bean class="com.ruki.utils.StringToDate"></bean>
            </set>
        </property>
    </bean>

3.2.3 开启引用自定义类型转换器(也在spring.xml中)

    <!-- 开启SpringMVC框架注解的支持-->
    <mvc:annotation-driven conversion-service="convertorService"></mvc:annotation-driven>

3.2.4 测试

  • 控制器代码
    @RequestMapping("/stringToDate")
    public String stringToDate(User user){
        System.out.println(user);
        return "success";
    }

3.3 使用原生ServletAPI作为参数

  • jsp

    <a href="param/testServlet">获取原生APItestServlet</a><br>
  • 控制器

    @RequestMapping("/testServlet")
    public String testServlet(HttpServletRequest request, HttpServletResponse response){
      System.out.println(request);
      System.out.println(request.getSession());
      System.out.println(request.getSession().getServletContext());
      return "success";
    }

四、常用注解

4.1 RequestParam

  • 作用:把请求中指定名称的参数给控制器中的形参赋值
  • 属性:

    • value:请求参数中的名称。
    • required:请求参数中是否必须提供此参数。默认值:true。表示必须提供,如果不提供将报错。

4.1.1 举例

  • jsp

    <a href="param/testRequestParam?username=张三">RequestParam注解</a><br>
  • 控制器

    @RequestMapping("/testRequestParam")
    public String testRequestParam(@RequestParam(name="username") String name){
      System.out.println(name);
      return "success";
    }

4.2 RequestBody

  • 作用:用于获取请求体内容。直接使用得到是key=value&key=value...结构的数据,<font color="red">json的String形式</font>。 get请求方式不适用。
  • 属性:

    • required:是否必须有请求体。默认值是:true。当取值为true时,get请求方式会报错。如果取值为falseget请求得到是null

4.2.1 举例

  • jsp

    <a href="springmvc/useRequestBody?body=test">requestBody注解get请求</a>
  • 控制器

    @RequestMapping("/useRequestBody") 
    public String useRequestBody(@RequestBody(required=false) String body){ 
        System.out.println(body); 
        return "success"; 
    }

4.3 PathVariable

  • 作用: 用于绑定url中的占位符。

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

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

4.3.1 举例

  • jsp

    <a href="param/testPathVariable/10">PathVariable注解</a><br>
  • 控制器

    @RequestMapping("/testPathVariable/{id}")
    public String testPathVariable(@PathVariable(name="id") String id){
      System.out.println(id);
      return "success";
    }

4.4 RequestHeader

  • 作用: 用于获取请求消息头。
  • 属性:

    • value:提供消息头名称
    • required:是否必须有此消息头

4.4.1 举例

  • jsp

    <a href="param/testRequestHeader">RequestHeader注解</a><br>
  • 控制器

    @RequestMapping("/testRequestHeader")
    public String testRequestHeader(@RequestHeader("Accept") String header){
      System.out.println(header);
      return "success";
    }

4.5 CookieValue

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

    • value:指定cookie的名称。
    • required:是否必须有此cookie

4.5.1 举例

  • jsp

    <a href="springmvc/useCookieValue">CookieValue注解</a>
  • 控制器

    @RequestMapping("/useCookieValue") 
    public String useCookieValue(@CookieValue(value="JSESSIONID",required=false) String cookieValue){ 
        System.out.println(cookieValue); 
        return "success"; 
    } 

4.6 ModelAttribute

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

    • 出现在方法上,表示当前方法会在控制器的方法执行之前,先执行。它可以修饰没有返回值的方法,也可以修饰有具体返回值的方法。
    • 出现在参数上,获取指定的数据给参数赋值。
  • 属性:

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

4.6.1 举例

4.6.1.1 有返回值,基于POJO

  • jsp

    <a href="springmvc/testModelAttribute?username=test">测试modelattribute</a>
  • 控制器

    /** 
    * 被ModelAttribute修饰的方法 
    * @param user 
    */ 
    @ModelAttribute 
    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"; 
    }

4.6.1.2 无返回值,基于Map

  • jsp

    <a href="springmvc/testModelAttribute?username=test">测试modelattribute</a>
  • 控制器

    /** 
    * 被ModelAttribute修饰的方法 
    * @param user 
    */ 
    @ModelAttribute 
    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"; 
    }

4.7 SessionAttribute

  • 作用: 用于多次执行控制器方法间的参数共享。
  • 属性:

    • value:用于指定存入的属性名称
    • type:用于指定存入的数据类型

4.7.1 举例

  • jsp

    <a href="springmvc/testPut">存入SessionAttribute</a> <hr/> 
    <a href="springmvc/testGet">取出SessionAttribute</a> <hr/> 
    <a href="springmvc/testClean">清除SessionAttribute</a>
  • 控制器

    @Controller("sessionAttributeController")
    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("age")); 
            return "success"; 
        } 
        
        @RequestMapping("/testClean") 
        public String complete(SessionStatus sessionStatus){ 
            sessionStatus.setComplete(); 
            return "success"; 
        } 
    } 
Last modification:September 28th, 2019 at 05:28 pm