一、SpringMVC的基本概念
1.1 三层架构和MVC
1.1.1 三层架构
表现层
- SpringMVC
业务层
- Spring
持久层
- MyBatis
1.1.2 MVC模型
Model 模型:
- 数据模型。通常用于封装数据。
View 视图:
- jsp或html,展示数据。
Controller 控制器:
- 应用程序中处理用户交互的部分,处理程序逻辑的。
1.2 SpringMVC概述
1.2.1 SpringMVC是什么
- SpringMVC是一种基于Java的实现MVC设计模型的请求驱动类型的轻量级Web框架,属于Spring Frame的后续产品。
- 通过一套注解,让一个Java类成为处理请求的控制器,而无需实现任何借口,支持
RESTful
编程等个的请求。
1.2.2 SpringMVC在三层架构的位置
1.2.3 SpringMVC的优势
清晰的角色划分
- 前端控制器:
DispatcherService
- 请求到处理器映射:
HandlerMapping
- 处理器适配器:
HandlerAdapter
- 视图解析器:
ViewResolver
- 处理器或页面控制器:
Controller
- 验证器:
Validator
- 命令对象:
Command
- 表单对象:
Form Object
- 前端控制器:
- 分工明确,容易扩展。
- 和Spring无缝集成
- 可定制
- 功能强大的数据验证、格式化、绑定机制
- 利用Spring提供的Mock对象能够非常简单的web层单元测试
- 强大的JSP标签库。
RESTful
风格的支持。
1.2.4 SpringMVC和Struts2的优劣分析
共同点:
- 都是表现层框架,都是基于MVC模型编写的
- 底层都离不开ServletAPI
- 处理请求的机制都是一个核心控制器
区别:
- SpringMVC的入口是Servlet,Struts2是Filter
- SpringMVC是基于方法设计的,而Struts2是基于类,Struts2每次都会创建一个动作类,所以SpringMVC会稍微比Struts2快一点。
- SpringMVC使用更加简洁,同时还支持JSR303,处理ajax的请求更方便
- 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 支持的数据类型
基本类型数据:参数名称必须和控制器中方法的形参名称保持一致。(严格区分大小写)
- 基本类型
String
POJO类型参数:表单中参数名称和POJO类的属性名称保持一致。并且控制器方法的参数类型是POJO类型。
- 实体类和关联的实体类
数组和集合类型的参数:集合类型的请求参数必须在POJO中。在表单中请求参数名称要和POJO中集合属性名称相同。
List
:使用下标。list[0].uname
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
请求方式会报错。如果取值为false
,get
请求得到是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的一个重要标志。
- 例如:请求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"; } }