SpringMVC
SpringMVC概述
- SpringMVC是在Spring框架内置的MVC的实现。
流程分析
-
首先用户发送请求——>
DispatcherServlet
,前端控制器收到请求后自己不进行处理,而是委托给其他的解析器进行处理,作为统一访问点,进行全局的流程控制; -
DispatcherServlet
——>HandlerMapping
,HandlerMapping
将会把请求映射为HandlerExecutionChain
对象(包含一个Handler处理器(页面控制器)对象、多个HandlerInterceptor
拦截器)对象,通过这种策略模式,很容易添加新的映射策略; -
DispatcherServlet
——>HandlerAdapter
,HandlerAdapter
将会把处理器包装为适配器,从而支持多种类型的处理器,即适配器设计模式的应用,从而很容易支持很多类型的处理器; -
HandlerAdapter
——>处理器功能处理方法的调用,HandlerAdapter
将会根据适配的结果调用真正的处理器的功能处理方法,完成功能处理;并返回一个ModelAndView
对象(包含模型数据、逻辑视图名); -
ModelAndView
的逻辑视图名——>ViewResolver
,ViewResolve
r将把逻辑视图名解析为具体的View
,通过这种策略模式,很容易更换其他视图技术; -
View
——>渲染,View
会根据传进来的Model模型数据进行渲染,此处的Model实际是一个Map数据结构,因此很容易支持其他视图技术; -
返回控制权给
DispatcherServlet
,由DispatcherServlet
返回响应给用户,到此一个流程结束。
MVC模型
- MVC全名是Model View Controller 模型视图控制器,每个部分各司其职。
Model
:数据模型,JavaBean的类,用来进行数据封装。View
:指JSP、HTML用来展示数据给用户Controller
:用来接收用户的请求,整个流程的控制器。用来进行数据校验等。
SpringMVC的入门案例
1. 创建WEB工程,引入开发jar包
<?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.yll</groupId>
<artifactId>SpringMvc01_start</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>war</packaging>
<name>SpringMvc01_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.version>5.0.2.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>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<finalName>SpringMvc01_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. 配置核心控制器(DispatcherServlet)
- 在
web.xml
配置文件中核心控制器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>
3. 编写springmvc.xml
的配置文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="com.yll"></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>
<!--开启Springmvc框架注解的支持-->
<mvc:annotation-driven></mvc:annotation-driven>
</beans>
4. 编写index.jsp
和HelloController
控制器类
index.jsp
<%--
Created by IntelliJ IDEA.
User: 10265
Date: 2020/2/9
Time: 13:55
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<h3>入门程序</h3>
<a href="user/hello">你点我啊~</a>
</body>
</html>
HelloController
/**
* 控制器类
* */
@Controller
@RequestMapping(path = "/user")
public class HelloController {
@RequestMapping(path="/hello")
public String sayHello(){
System.out.println("hello SpringMvc");
return "success";
}
}
5. 在WEB-INF目录下创建pages文件夹,编写success.jsp
的成功页面
<%--
Created by IntelliJ IDEA.
User: 10265
Date: 2020/2/9
Time: 14:08
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" isELIgnored="false" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<h3>入门成功了~</h3>
</body>
</html>
入门案例的执行过程分析
入门案例的执行流程
- 当启动Tomcat服务器的时候,因为配置了
load-on-startup
标签,所以会创建DispatcherServlet
对象, 就会加载springmvc.xml
配置文件 - 开启了注解扫描,那么
HelloController
对象就会被创建 - 从
index.jsp
发送请求,请求会先到达DispatcherServlet
核心控制器,根据配置@RequestMapping
注解 找到执行的具体方法 - 根据执行方法的返回值,再根据配置的视图解析器,去指定的目录下查找指定名称的JSP文件
- Tomcat服务器渲染页面,做出响应
RequestMapping注解
RequestMapping
注解的作用是建立请求URL和处理方法之间的对应关系RequestMapping
注解可以作用在方法和类上- 作用在类上:第一级的访问目录
- 作用在方法上:第二级的访问目录
- 细节:路径可以不编写 / 表示应用的根目录开始
- 细节:
${ pageContext.request.contextPath }
也可以省略不写,但是路径上不能写 /
RequestMapping
的属性path
指定请求路径的urlvalue
value属性和path属性是一样的method
指定该方法的请求方式params
指定限制请求参数的条件headers
发送的请求中必须包含的请求头
/***
* 超链接默认 get 方法
*/
@RequestMapping(value="/testResquestMapping",method = {RequestMethod.GET},params = {"username=ss"},headers = {"Accept"})
public String testResquestMapping(){
System.out.println("测试ResquestMapping");
return "success";
}
<a href="user/testResquestMapping?username=ss">requestMapping测试</a>
请求参数的绑定
- 请求参数的绑定说明
- 绑定机制
- 表单提交的数据都是k=v格式的 username=ss&password=52151
- SpringMVC的参数绑定过程是把表单提交的请求参数,作为控制器中方法的参数进行绑定的
- 要求:提交表单的name和参数的名称是相同的
- 支持的数据类型
- 基本数据类型和字符串类型
- 实体类型(JavaBean)
- 集合数据类型(List、map集合等)
- 绑定机制
- 基本数据类型和字符串类型
- 提交表单的name和参数的名称是相同的
- 区分大小写
- 实体类型(JavaBean)
- 提交表单的name和JavaBean中的属性名称需要一致
- 如果一个JavaBean类中包含其他的引用类型,那么表单的name属性需要编写成:对象.属性 例如: address.name
- 给集合属性数据封装
- JSP页面编写方式:list[0].属性
- 在控制器中使用原生的ServletAPI对象
- 只需要在控制器的方法参数定义
HttpServletRequest
和HttpServletResponse
对象
- 只需要在控制器的方法参数定义
@Controller
@RequestMapping("/param")
public class ParamController {
/**
* 请求参数绑定入门
* */
@RequestMapping("/testParam")
public String testParam(String username,String password){
System.out.println(username+": "+password);
System.out.println("执行了……");
return "success";
}
/**
* 请求参数绑定,把数据封装到javaBean的类中
* */
@RequestMapping("/saveAccount")
public String saveAccount(Account account){
System.out.println(account);
System.out.println("执行了……");
return "success";
}
/**
* Servlet原生api
* */
@RequestMapping("/testServlet")
public String testServlet(HttpServletRequest request, HttpServletResponse response){
System.out.println(request);
System.out.println(request.getSession());
System.out.println(request.getSession().getServletContext());
System.out.println(response);
System.out.println("执行了……");
return "success";
}
}
<%--
Created by IntelliJ IDEA.
User: 10265
Date: 2020/2/9
Time: 15:58
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<h3>请求参数绑定</h3>
<form action="param/testParam" method="get">
用户名:<input type="text" name="username">
密码:<input type="password" name="password">
<input type="submit" value="提交">
</form>
<%-- 把数据封装到Account类中--%>
<form action="param/saveAccount" method="post">
用户名:<input type="text" name="username"> <br>
密码:<input type="text" name="password"> <br>
金额:<input type="text" name="money"><br>
用户的姓名:<input type="text" name="user.uname">
用户年龄:<input type="text" name="user.age">
<input type="submit" value="提交">
</form>
<%-- 把数据封装到Account类中,类中存在list和map的集合--%>
<form action="param/saveAccount" 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">
用户年龄:<input type="text" name="list[0].age">
用户的姓名:<input type="text" name="map['one'].uname">
用户年龄:<input type="text" name="map['one'].age">
<input type="submit" value="提交">
</form>
<a href="param/testServlet">servlet原生api</a>
</body>
</html>
- 请求参数中文乱码的解决
- 在
web.xml
中配置Spring提供的过滤器类
- 在
<!--配置解决中文乱码的过滤器-->
<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>
- 自定义类型转换器
- 表单提交的任何数据类型全部都是字符串类型,但是后台定义
Integer
类型,数据也可以封装上,说明 Spring框架内部会默认进行数据类型转换。 - 如果想自定义数据类型转换,可以实现
Converter
的接口
- 表单提交的任何数据类型全部都是字符串类型,但是后台定义
- 自定义类型转换器
/**
* 把字符串转换成日期的转换器
*/
public class StringToDateConverter implements Converter<String, Date> {
@Override
public Date convert(String source) {
if(source == null) throw new RuntimeException("请您传入数据");
DateFormat df = new SimpleDateFormat("yyyy-mm-dd");
try {
//把字符串转成日期
return df.parse(source);
} catch (ParseException e) {
throw new RuntimeException("数据类型转换出错");
}
}
}
- 注册自定义类型转换器,在springmvc.xml配置文件中编写配置
<!--配置自定义类型转换器-->
<bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
<property name="converters">
<set>
<bean class="com.yll.utils.StringToDateConverter"></bean>
</set>
</property>
</bean>
<!--开启Springmvc框架注解的支持-->
<mvc:annotation-driven conversion-service="conversionService"></mvc:annotation-driven>
常用的注解
RequestParam注解
- 作用:把请求中的指定名称的参数传递给控制器中的形参赋值
- 属性
value
:请求参数中的名称required
:请求参数中是否必须提供此参数,默认值是true,必须提供
/**
* RequestParam
* */
@RequestMapping("/testRequestParam")
public String testRequestParam(@RequestParam(name="name") String username){
System.out.println("执行了"+username);
return "success";
}
<a href="anno/testRequestParam?name=ss">ResquestParam</a>
RequestBody注解
- 作用:用于获取请求体的内容(注意:get方法不可以)
- 属性
- required:是否必须有请求体,默认值是true
/**
* testRequestBody
* 获取到请求体的内容
* */
@RequestMapping(value = "/testRequestBody")
public String testRequestBody(@RequestBody String body){
System.out.println(body);
return "success";
}
<form action="anno/testRequestBody" method="post">
用户名:<input type="text" name="username"> <br>
用户密码:<input type="text" name="password"><br>
用户年龄:<input type="text" name="age"><br>
<input type="submit" value="提交"><br>
</form>
PathVariable注解
- 作用:
拥有绑定url中的占位符
。例如:url中有/delete/{id},{id}就是占位符 - 属性
- value:指定url中的占位符名称
- Restful风格的URL
- 请求路径一样,可以根据不同的请求方式去执行后台的不同方法
- restful风格的URL优点
- 结构清晰
- 符合标准
- 易于理解
- 扩展方便
/**
* PathVariable注解
*
* */
@RequestMapping(value = "/testPathVariable/{sid}",method = RequestMethod.GET)
public String testPathVariable(@PathVariable(name="sid") String id){
System.out.println(id);
return "success";
}
<a href="anno/testPathVariable/52151">PathVariable</a>
RequestHeader注解
- 作用:获取指定请求头的值
- 属性
- value:请求头的名称
@RequestMapping(value = "/testRequestHeader")
public String testRequestHeader(@RequestHeader(value = "Accept") String header){
System.out.println(header);
return "success";
}
<a href="anno/testRequestHeader">RequestHeader</a>
CookieValue注解
- 作用:用于获取指定cookie的名称的值
- 属性
- value:cookie的名称
/**
* 获得cookie的值
* */
@RequestMapping(value = "/testCookieValue")
public String testCookieValue(@CookieValue(value="JSESSIONID") String cookieValue){
System.out.println(cookieValue);
return "success";
}
<a href="anno/testCookieValue">CookieValue</a>
ModelAttribute注解
-
作用
- 出现在方法上:表示当前方法会在控制器方法执行前线执行。
- 出现在参数上:获取指定的数据给参数赋值。
-
应用场景
- 当提交表单数据不是完整的实体数据时,保证没有提交的字段使用数据库原来的数据。
-
修饰的方法有返回值
/**
* 作用在方法,先执行
*/
@ModelAttribute
public User showUser(String name) {
System.out.println("showUser执行了...");
// 模拟从数据库中查询对象
User user = new User();
user.setName("哈哈");
user.setPassword("123");
user.setMoney(100d);
return user;
}
/**
* 修改用户的方法
*/
@RequestMapping(path="/updateUser")
public String updateUser(User user) {
System.out.println(user);
return "success";
}
- 修饰的方法没有返回值
/**
* 作用在方法,先执行
*/
@ModelAttribute
public void showUser(String name,Map<String, User> map) {
System.out.println("showUser执行了...");
// 模拟从数据库中查询对象
User user = new User();
user.setName("哈哈");
user.setPassword("123");
user.setMoney(100d);
map.put("abc", user);
}
/**
* 修改用户的方法
*/
@RequestMapping(path="/updateUser")
public String updateUser(@ModelAttribute(value="abc") User user) {
System.out.println(user);
return "success";
}
SessionAttributes注解
- 作用:用于多次执行控制器方法间的参数共享
- 属性
- value:指定存入属性的名称
/**
* SessionAttributes
* */
@RequestMapping(value = "/testSessionAttributes")
public String testSessionAttributes(Model model){
System.out.println("testSessionAttributes");
//底层会存到request域中
model.addAttribute("ss","521");
return "success";
}
/**
* 获取值
* */
@RequestMapping(value = "/getSessionAttributes")
public String getSessionAttributes(ModelMap modelMap){
System.out.println("getSessionAttributes");
String msg = (String) modelMap.get("ss");
System.out.println(msg);
return "success";
}
/**
* 清除session
* */
@RequestMapping(value = "/deleteSessionAttributes")
public String deleteSessionAttributes(SessionStatus status){
System.out.println("delSessionAttributes");
status.setComplete();
return "success";
}
<a href="anno/testSessionAttributes">SessionAttributes</a>
<a href="anno/getSessionAttributes">get SessionAttributes value</a>
<a href="anno/deleteSessionAttributes">get SessionAttributes value</a>
<%--
Created by IntelliJ IDEA.
User: 10265
Date: 2020/2/9
Time: 14:08
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" isELIgnored="false" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<h3>入门成功了~</h3>
${ requestScope.ss }
<br>
${sessionScope}
</body>
</html>