一、Spring MVC概述
1.1 Spring MVC简介
- Spring为展现层提供的基于MVC设计理念的优秀的Web框架,是目前最主流的MVC框架之一
- Spring MVC通过一套MVC注解,让POJO成为处理请求的控制器,而无须实现任何接口
- 一种轻量级的、基于MVC的Web层应用框架,偏前端而不是基于业务逻辑层,Spring框架的一个后续产品
1.2 Spring MVC的第一个程序
1.2.1 创建项目,导入jar包
spring-aop-4.3.6.RELEASE.jar
spring-beans-4.3.6.RELEASE.jar
spring-context-4.3.6.RELEASE.jar
spring-core-4.3.6.RELEASE.jar
spring-expression-4.3.6.RELEASE.jar
spring-web-4.3.6.RELEASE.jar
spring-webmvc-4.3.6.RELEASE.jar
commons-logging-1.2.jar
1.2.2 在web.xml中配置Spring MVC的核心(前端)控制器DispatcherServlet
- 作用: 加载Spring MVC的配置文件。在下方的配置方式下,DispatcherServlet自动加载配置文件,此时的配置文件有默认的位置和名称
- 默认位置: WEB-INF下
- 默认名称:
<servlet-name>-servlet.xml
,例如下面配置方式的文件名是springMVC-servlet.xml - 当加载了配置文件,Spring MVC就会根据扫描组件找到控制层
<servlet>
<servlet-class>springMVC</servlet-class>
<servlet-name>org.springframework.web.servlet.DispatcherServlet</servlet-name>
</servlet>
<servlet-mapping>
<servlet-name>springMVC</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
1.2.3 创建一个POJO类充当控制层
- 在此类上加上
@Controller
注解,Spring MVC就会将此类作为控制层加载,让其处理请求响应 - 在控制层中,需要在方法上设置
@RequestMapping(value="xxx")
,SpringMVC就是通过此注解将请求路径与控制层中的方法相匹配,此时请求路径为localhost:8080/projectName/xxx
- 处理请求的方法会返回一个字符串String,即视图名称,这里的例子就是返回的success
- 最终会通过1.2.4的配置文件中的视图解析器实现页面跳转
package com.hkd.test;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class TestController {
// 下面例子的请求路径是`localhost:8080/SpringMVC/hello
@RequestMapping(value = "hello")
public String hello() {
System.out.println("SUCCESS");
return "success"; //视图名称
}
}
1.2.4 在WEB-INF下创建创建springMVC-servlet.xml文件
- 文件名:这里的文件名,在1.2.2中已经提到,需要使用
<servlet-name>-servlet.xml
- 扫描组件:将加上@controller注解的类作为SpringMVC的控制层
- 视图解析器的作用:设置最终跳转的页面路径为
prefix + 视图名称 + suffix
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd">
<!-- 扫描组件,将加上@controller注解的类作为SpringMVC的控制层 -->
<context:component-scan base-package="com.hkd.test"></context:component-scan>
<!-- 视图解析器:
作用:将prefix + 视图名称 + suffix 为最终要跳转的页面
-->
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/"/>
<property name="suffix" value=".jsp"/>
</bean>
</beans>
1.3 Spring MVC指定配置文件的位置和名称
- 如果不想让Spring MVC的配置文件名字叫“<servlet-name>-servlet”,那么就可以在web.xml文件里设置指定位置的配置文件
- 在<servlet>标签里加入<init-param>标签,指定初始化参数
- 注意,这里的<param-name>一定得是
ContextConfigLocation
,<param-value>就是自己定义的Spring MVC配置文件的名称
<servlet>
<servlet-name>spring</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>
<servlet-mapping>
<servlet-name>spring</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
1.4 控制servlet的加载时间
- servlet默认在第一次访问时加载
- 若设置
<load-on-startup>
标签,会将servlet的加载时间提前到项目启动时 - 此标签中可以写整数,但是写负整数和0的话,就和没设置一个效果,只有正整数才有用
- 此标签里的值越小,优先级越高
<servlet>
<servlet-name>spring</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!-- 设置springmvc配置文件的位置以及名称 -->
<init-param>c
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springMVC.xml</param-value>
</init-param>
<!-- 设置servlet的加载时间,默认在第一次访问时加载 -->
<load-on-startup>1</load-on-startup>
</servlet>
1.5 配置编码过滤器
- 为了防止前后台响应时候,出现乱码问题,一般要在web.xml文件中设置编码过滤器
- 编码过滤器要放在第一个位置
<filter>
<filter-name>CharacterEncodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>CharacterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
1.6 Spring MVC原理解析
- 前端发请求到前端控制器
DispatcherServlet
; DispatcherServlet
收到请求后调用HandlerMapping
处理器映射器;- 处理器映射器根据xml或者注解,找到最终执行的Handler,生成处理器对象及处理器拦截器,并一并返回给
DispatcherServlet
; DispatcherServlet
调用HandlerAdapter
处理器适配器;HandlerAdapter
根据handler规则执行不同类型的Handler,也叫后端处理器;- Handler执行完毕返回
ModelAndView
给DispatcherServlet
; DispatcherServlet
将ModelAndView交给ViewReslover视图解析器;- 视图解析器解析后返回具体view;
DispatcherServlet
根据view进行渲染视图,再响应给用户。
二、@RequestMapping映射请求注解
2.1 @RequestMapping的概念和作用
- Spring MVC使用
@RequestMapping
注解为控制器指定可以处理哪些url请求 - DispatcherServlet截获请求后,就通过控制器上
@RequestMapping
提供的映射信息确定请求所对应的处理方法 - 设置请求映射,把请求和控制层中的方法二者设置映射关系
2.2 @RequestMapping的位置
- 在控制器的类和方法上都可使用
@RequestMapping
① 标记在类上:提供初步的请求映射信息,相对于web应用的根目录
② 标记在方法上:提供进一步的细分映射信息,相对于标记在类上的url - 若类上未标注
@RequestMapping
,则方法处标记的url相对于web应用的根目录 - 若类和方法都加的有,应该一层一层的访问,先访问类再访问方法
2.3 @RequestMapping的注解参数
2.3.1 value参数
当请求路径和@RequestMapping
的value属性值一致时,则该注解所标注的方法即为处理方法
2.3.2 method参数
- method:用来设置请求方式,只有客户端发送请求的方式和method的值一致,才能处理请求
- 使用方法:
RequestMethod.请求方式
- 请求方式:GET查询、POST添加、PUT修改、DELETE删除
// 请求路径为hello,并且请求方式为GET方式,才能走这个函数
@RequestMapping(value = "/hello", method = RequestMethod.GET)
public String hello() {
System.out.println("SUCCESS");
return "success"; //视图名称
}
2.3.3 params参数
- params:用来设置客户端传到服务器的数据,支持表达式
- 在访问地址上如果有参数,这个属性可以进行对参数的处理
- 注意:传递的是一个数组,使用大括号
// 请求路径为hello,并且必须传递参数username,但不能带有age参数
@RequestMapping(value = "/hello", params = {"username","!age"})
public String hello() {
System.out.println("SUCCESS");
return "success"; //视图名称
}
2.3.4 headers参数
- headers:设置请求头信息,所发送的请求的请求头一定要和headers属性中所设置的一致
- 注意:传递的是一个数组,使用大括号
2.4 @RequestMapping支持Ant路径风格
- Ant 风格资源地址支持 3 种匹配符
? 匹配文件名中任意一个字符
* 匹配文件名中的任意字符
** 匹配多层路径
@RequestMapping(value = "/*/testAnt")
表示路径要写成类似/abcd…/testAnt@RequestMapping(value = "/*/ant??/testAnt")
表示路径要写成类似/abcd…/antab/testAnt@RequestMapping(value = "/*/ant??/**/testAnt")
表示路径要写成类似/abc/antab/a/b/testAnt
2.5 @PathVariable请求占位符
- 带占位符的url是Spring3.0新增的功能,该功能在Spring MVC向REST目标挺进发展过程中具有里程碑的意义
- 通过@PathVariable可以将url中占位符参数绑定到控制器处理方法的入参中
- url中的{xxx}占位符可以通过@PathVariable(“xxx”)绑定到操作方法的参数中
- 相当于在
@PathVariable("id")
获得id的值,赋值给形参Integer id,然后匹配到对应的占位符中{id},这时,以下例子就可以使用:localhost:8080/SpringMVC01/testREST/1001/admin进入
@RequestMapping(value = "/testREST/{id}/{username}")
public String testREST(@PathVariable("id")Integer id, @PathVariable("username")String username) {
System.out.println("id="+id+",username="+username);
return "success";
}
三、RESTful架构和JSON数据交互
3.1 什么是RESTful
- RESTful,即Representational State Transfer(资源)表现层状态转化。
- 目前最流行的一种互联网软件架构。它结构清晰、符合标准、易于理解、扩展方便,所以正得到越来越多网站的采用
3.2 HiddenHttpMethodFilter过滤器
3.2.1 为什么要使用HiddenHttpMethodFilter过滤器
- 我们已经知道,在@RequestMapping的method方法中,存在PUT增加、DELETE删除的请求方式
- 但在form表单里,只存在GET、POST请求方式,这时候就可以用HiddenHttpMethodFilter过滤器,来间接把PUT和DELETE传递到后台
- HiddenHttpMethodFilter过滤器会根据以下条件对POST请求做出转换:a. 必须是post请求;b. 请求必须传_method参数
- 若不符合条件,即没有传递_method参数,那么就是单纯的post请求
- 若符合条件,经过转换后真正的请求方式,其实就是_method的值
3.2.2 RESTful风格演示过滤器
1. 在web.xml文件中,添加过滤器filter相关标签并配置
<filter>
<filter-name>HiddenHttpMethodFilter</filter-name>
<filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>HiddenHttpMethodFilter</filter-name>
<!-- 拦截所有请求 -->
<url-pattern>/*</url-pattern>
</filter-mapping>
2. 创建一个rest.jsp文件,发送POST请求时通过隐藏域传递_method参数
前端页面,发送请求
<%@ page language="java" contentType="text/html; charset=utf-8"
pageEncoding="utf-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Insert title here</title>
</head>
<body>
<!-- 增加 -->
<form action="testREST" method="POST">
<!-- 使用隐藏域进行传递参数 -->
<input type="hidden" name="_method" value="PUT">
<input type="submit" value="测试PUT">
</form>
<!-- 删除 -->
<form action="testREST/1001" method="POST">
<input type="hidden" name="_method" value="DELETE">
<input type="submit" value="测试DELETE">
</form>
</body>
</html>
3. 创建RESTcontroller.java控制器
package com.hkd.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
@Controller
public class RESTcontroller {
// 注意这里RequestMethod.PUT是怎样接收到的
@RequestMapping(value = "/testREST", method = RequestMethod.PUT)
public String updateUser() {
System.out.println("PUT");
return "success";
}
@RequestMapping(value = "/testREST/{id}", method = RequestMethod.DELETE)
public String deleteUser(@PathVariable("id") Integer id) {
System.out.println("DELETE,id="+id);
return "success";
}
}
4. 创建success.jsp页面
在tomcat8中,如果直接写PUT,DELETE是认不出来的,需要在响应页面头部添加isErrorPage="true"
<%@ page language="java" contentType="text/html; charset=utf-8"
pageEncoding="utf-8" isErrorPage="true"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Insert title here</title>
</head>
<body>
<h1>成功</h1>
</body>
</html>
3.3 静态资源的访问
- 可以使用
<mvc:default-servlet-handler/>
标签访问静态资源 <mvc:default-servlet-handler/>
标签:配置Tomcat中默认的servlet,叫DefaultServlet- 作用:当客户端发送请求,由于DefaultServlet所设置的<url-pattern>的值和开发人员配置的DispatchServlet的<url-pattern>相同,因此先通过DispatchServlet处理请求,找该请求是否有相对应的处理器,有则处理,无则交给DefaultServlet处理
- 注意:当DefaultServlet所设置的<url-pattern>的值和开发人员所配置的servlet的<url-pattern>相同,则优先处理开发人员配置的
- 要配合
<mvc:annotation-driven />
标签使用
<mvc:default-servlet-handler />
<mvc:annotation-driven />
3.4 JSON概述
- JSON有两种格式:
- JSON对象:{key:value, key:value}
- JSON数组:[value1, value2, …]
- JSON解析方式:
- JSON对象解析方式:对象.key
- JSON数组解析方式:for循环遍历
- Java对象转换JSON:
- Bean和Map ----> JSON对象
- List ----> JSON数组
3.5 JSON里的注解
- 在处理请求的方法里,加上
@ResponseBody
注解,就会把最后return的数据作为结果响应到客户端,而不再是页面跳转了 - 要将请求体中的数据绑定到请求方法的形参中,就要使用
@RequestBody
注解,该注解用于方法的形参上 - 记得在配置文件中,添加开启注解的标签
<mvc:annotation-driven />
package com.hkd.controller;
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.ResponseBody;
import com.hkd.bean.User;
@Controller
public class UserController {
@RequestMapping("/testJson")
@ResponseBody
public User testJson(@RequestBody User user) {
// 打印接收的JSON数据
System.out.println(user);
// 返回JSON格式的响应
return user;
}
}
3.6 Spring MVC处理JSON的步骤
3.6.1 导入jackson相关jar包
jackson-annotations-2.8.8.jar
jackson-core-2.8.8.jar
jackson-databind-2.8.8.jar
3.6.2 开启mvc驱动
- 在springMVC.xml文件中,开启mvc的注解驱动
<mvc:annotation-driven />
- 命名空间需要加上mvc的命名空间
- xmlns:mvc=“http://www.springframework.org/schema/mvc”
- xsi:schemaLocation=" http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.3.xsd"
3.6.3 在处理Ajax的请求方法上加上注解
在请求的方法上加入@ResponsBody
注解,详见3.5节
3.6.4 将要转换为JSON且响应到客户端的数据,直接作为该方法的返回值返回
3.7 JSON的完整案例
1. 创建新项目,配置web.xml文件,并导入jar包
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" version="3.1">
<display-name>SpringMVC04</display-name>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
<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>
<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>
</web-app>
2. 配置文件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:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.3.xsd">
<context:component-scan base-package="com.hkd"/>
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/view"/>
<property name="suffix" value=".jsp"/>
</bean>
<!-- 默认的servlet处理静态资源 -->
<mvc:default-servlet-handler />
<!-- 开启mvc注解驱动 -->
<mvc:annotation-driven />
</beans>
3. 实体类User.java
package com.hkd.bean;
public class User {
private String username;
private String 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 + "]";
}
}
4. 请求方法UserController.java
package com.hkd.controller;
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.ResponseBody;
import com.hkd.bean.User;
@Controller
public class UserController {
@RequestMapping("/testJson")
@ResponseBody
public User testJson(@RequestBody User user) {
// 打印接收的JSON数据
System.out.println(user);
// 返回JSON格式的响应
return user;
}
}
5. 前端页面Ajax跳转
<%@ page language="java" contentType="text/html; charset=utf-8"
pageEncoding="utf-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>测试json交互</title>
</head>
<script type="text/javascript" src="${pageContext.request.contextPath}/js/jquery-1.12.4.js"></script>
<script type="text/javascript">
$(function(){
$("#btn").click(function(){
$.ajax({
url: "testJson",
type:"POST",
// data表示发送的数据
data:JSON.stringify({username:username,password:password}),
// 定义发送请求的数据格式为json字符串
contextType:"application/json;charset=UTF-8",
dataType:"json",
success:function(msg){
if(msg != null){
alert("你输入的用户名是:"+msg.username+",密码是:"+msg.password);
}
}
});
});
});
</script>
<body>
<form>
用户名:<input type="text" name="username" id="username"><br>
密码:<input type="password" name="password" id="password"><br>
<input type="button" value="测试json" onclick="testJson()" id="btn">
</form>
</body>
</html>
四、Spring MVC中的数据绑定
4.1 绑定简单数据类型
4.1.1 处理方法及应用实例
- 简单数据类型,指的是int, String, Double等Java中的基本数据类型
- 绑定简单数据类型只需要在处理请求的方法中,加入相对应的形参,保证形参参数名和传递的数据的参数名一致,就可以自动赋值
1. 要得到form表单中传递的各个值的例子如下,创建form表单
<%@ page language="java" contentType="text/html; charset=utf-8"
pageEncoding="utf-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Insert title here</title>
</head>
<body>
<form action="param" method="post">
username:<input type="text" name="username"/><br>
password:<input type="text" name="password"/><br>
age:<input type="text" name="age"/><br>
province:<input type="text" name="province"/><br>
city:<input type="text" name="city"/><br>
country:<input type="text" name="country"/><br>
<input type="submit" />
</form>
</body>
</html>
2. 在控制器中的方法上加入形参
package com.hkd.controller;
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;
@Controller
public class ParamController {
@RequestMapping(value = "/param", method = RequestMethod.POST)
// 方法的参数中加上形参,必要时加上@RequestParam注解
public String param(String username, String password, String age) {
System.out.println("username="+username+",password="+password+",age="+age);
return "success";
}
}
4.1.2 @RequestParam注解
- 在处理方法入参处使用
@RequestParam
可以把请求参数传递给请求方法 - value:请求参数的名字与形参不一致时,使用此属性指定映射关系
- required:设置形参是否被赋值。默认为 true, 表示请求参数中必须包含对应的参数,若不存在会抛出异常
- defaultValue:默认值,如果请求中没有同名参数时的默认值。用于分页和模糊查询中
@RequestMapping(value = "/param", method = RequestMethod.POST)
// 表示请求中传递过来的参数名叫name的参数值,赋值给username形参
// 如果请求中无name参数,则非必要也可以,不会报错,并且会给username值赋值成默认的admin
public String param(@RequestParam(value = "name", required = false, defaultValue = "admin")String username, String password, String age) {
System.out.println("username="+username+",password="+password+",age="+age);
return "success";
}
4.2 绑定POJO类型
- 可以使用POJO类获取客户端数据
- 要求实体类对象中的属性一定要和页面中元素的name属性值一致,且支持级联关系
1. 要得到form表单中传递的各个值的例子如下,创建form表单
<%@ page language="java" contentType="text/html; charset=utf-8"
pageEncoding="utf-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Insert title here</title>
</head>
<body>
<form action="param" method="post">
username:<input type="text" name="name"/><br>
password:<input type="text" name="password"/><br>
age:<input type="text" name="age"/><br>
<!-- 注意:下面属性name值的级联属性写法 -->
province:<input type="text" name="address.province"/><br>
city:<input type="text" name="address.city"/><br>
country:<input type="text" name="address.country"/><br>
<input type="submit" />
</form>
</body>
</html>
2. 创建User实体类和Address实体类
package com.hkd.bean;
public class User {
private Integer id;
private String username;
private String password;
private String age;
private Address address;
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 getAge() {
return age;
}
public void setAge(String age) {
this.age = age;
}
public Address getAddress() {
return address;
}
public void setAddress(Address address) {
this.address = address;
}
@Override
public String toString() {
return "User [id=" + id + ", username=" + username + ", password=" + password + ", age=" + age + ", address="
+ address + "]";
}
}
package com.hkd.bean;
public class Address {
private String province;
private String city;
private String country;
public String getProvince() {
return province;
}
public void setProvince(String province) {
this.province = province;
}
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
public String getCountry() {
return country;
}
public void setCountry(String country) {
this.country = country;
}
@Override
public String toString() {
return "Address [province=" + province + ", city=" + city + ", country=" + country + "]";
}
}
3. 创建控制器,在方法上传递User类型的形参
@RequestMapping(value = "/param", method = RequestMethod.POST)
public String param(User user) {
System.out.println(user);
return "success";
}
4.3 使用Servlet原生API
- HttpServletRequest
- HttpServletResponse
- HttpSession
- java.security.Principal
- Locale
- InputStream
- OutputStream
- Reader
- Writer
@RequestMapping(value = "/param", method = RequestMethod.POST)
public String param(HttpServletRequest request, HttpServletResponse response) {
String username = request.getParameter("username");
System.out.println(username);
return "success";
}
4.4 绑定请求头@RequestHeader
- 使用
@RequestHeader
绑定请求报头的属性值 - 请求头包含了若干个属性,服务器可据此获知客户端的信息,通过
@RequestHeader
即可将请求头中的属性值绑定到处理方法的入参中 - 用法和属性跟@RequestParam一致
@RequestMapping(value = "/header", method = RequestMethod.GET)
public String header(@RequestHeader(value = "Accept-Language")String AcceptLanguage) {
System.out.println("Accept-Language:"+AcceptLanguage);
return "success";
}
结果:
4.5 绑定Cookie值@CookieValue
- 使用
@CookieValue
绑定请求中的Cookie值 @CookieValue
可让处理方法入参绑定某个Cookie值- 用法和属性跟@RequestParam一致
@RequestMapping(value = "/cookie", method = RequestMethod.GET)
public String cookie(@CookieValue(value = "JSESSIONID")String JSESSIONID) {
System.out.println("JSESSIONID:"+JSESSIONID);
return "success";
}
结果:
4.6 ModelAndView向作用域中放值的三种方式
根据ModelAndView源码调试,不管使用以下哪种方式,最终都会把model数据和view数据封装到一个ModelAndView中
4.6.1 第一种方式
- 控制器处理方法的返回值如果为ModelAndView, 则其既包含视图信息,也包含模型数据信息
- ModelAndView对象的
addObject
方法,是向request作用域中放一个值 - ModelAndView对象的
setViewName
方法,设置视图名称,实现页面跳转
@RequestMapping(value = "/modelandview")
public ModelAndView modelandview(User user) {
ModelAndView mav = new ModelAndView();
mav.addObject("username", "root"); //往request作用域中放值
mav.setViewName("success"); //设置视图名称,实现页面跳转
return mav;
}
4.6.2 第二种方式
@RequestMapping(value = "/modelandview")
public String modelandview(Map<String, Object> map) {
map.put("username","admin"); //向作用域中放值
return "success"; //返回视图名称
}
4.6.3 第三种方式
@RequestMapping(value = "/modelandview")
public String modelandview(Model model) {
model.addAttribute("username", "张三");
return "success"; //返回视图名称
}
五、View视图
5.1 什么是视图
- 视图的作用是渲染模型数据,将模型里的数据以某种形式呈现给客户
- 视图对象由视图解析器负责实例化。由于视图是无状态的,所以他们不会有线程安全的问题
- View的作用:一是处理模型数据;二是实现页面跳转(请求转发,重定向)
5.2 视图的类型
- InternalResourceView:请求转发视图
- JstlView:请求转发视图
- RedirectView:重定向视图
5.3 请求转发和重定向
1. forward请求转发
forward:success.jsp
:会完成一个到 success.jsp 的转发操作
@RequestMapping(value = "/param", method = RequestMethod.POST)
public String param(HttpServletRequest request, HttpServletResponse response) {
...
return "forward: success";
}
2. redirect重定向
redirect:success.jsp
:会完成一个到 success.jsp 的重定向的操作
@RequestMapping(value = "/param", method = RequestMethod.POST)
public String param(User user, HttpServletRequest request, HttpServletResponse response) {
...
return "redirect: success";
}
六、文件上传
6.1 文件上传原理
- Spring MVC为文件上传提供了直接的支持,这种支持是通过即插即用的 MultipartResolver 实现的
- Spring用Jakarta Commons FileUpload技术实现了一个MultipartResolver实现类:CommonsMultipartResolver
- Spring MVC上下文中默认没有装配MultipartResovler,因此默认情况下不能处理文件的上传工作,如果想使用 Spring 的文件上传功能,需现在上下文中配置 MultipartResolver
6.2 文件上传演示
1. 导入jar包
commons-fileupload-1.4.jar
commons-io-2.6.jar
2. 配置文件上传解析器
处理文件,将客户端上传的File文件处理为MultipartResolver,这里bean的id必须设置为multipartResolver
<!-- 这里的id必须设置为multipartResolver -->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<!-- 设置文件解析的编码,一定要和页面的pageEncoding一致-->
<property name="defaultEncoding" value="UTF-8"></property>
<!-- 设置最大上传文件的大小-->
<property name="maxUploadSize" value="1024000"></property>
</bean>
3. 上传页面
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<!-- method方法是post enctype属性要为multipart/from-data -->
<form action="up" method="post" enctype="multipart/form-data">
<!-- 文件类型为file -->
文件: <input type="file" name="file"/><br><br>
描述: <input type="text" name="desc"/><br><br>
<input type="submit" value="提交"/>
</form>
</body>
</html>
4. 控制层编写
@Controller
public class UploadHandler {
@RequestMapping(value="/up",method=RequestMethod.POST)
public String up(String desc, MultipartFile uploadFile, HttpSession session) throws IOException{
// 获取上传文件的名称
String fileName = uploadFile.getOriginalFilename();
// 截取后缀名
String finalFileName = UUID.randomUUID() + fileName.substring(fileName.lastIndexOf("."));
String path = session.getServletContext().getRealPath("photo") + File.separator + fileName;
File file = new File(path);
uploadFile.transferTo(file);
return "success";
}
}
七、拦截器
7.1 什么是拦截器
Spring MVC也可以使用拦截器对请求进行拦截处理,用户可以自定义拦截器来实现特定的功能,自定义的拦截器可以实现HandlerInterceptor接口,也可以继承HandlerInterceptorAdapter适配器类
7.2 拦截器中的方法
1. preHandle()
A. 此方法在业务处理器处理请求之前被调用,在该方法中对用户请求request进行处理
B. 如果程序员决定该拦截器对请求进行拦截处理后还要调用其他的拦截器,或者是业务处理器去进行处理,则返回true
C. 如果程序员决定不需要再调用其他的组件去处理请求,则返回false
2. postHandle()
这个方法在业务处理器处理完请求后,但是DispatcherServlet向客户端返回响应前被调用,在该方法中对用户请求request进行处理
3. afterCompletion()
这个方法在DispatcherServlet完全处理完请求后被调用,可以在该方法中进行一些资源清理的操作
7.3 拦截器的演示
1. 前台简单页面
<%@ page language="java" contentType="text/html; charset=utf-8"
pageEncoding="utf-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>测试拦截器</title>
</head>
<a href="/testInterceptor">测试拦截器</a>
</body>
</html>
2. 拦截器类
package com.hkd.inerceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
@Component
public class FirstInterceptor implements HandlerInterceptor{
@Override
public void afterCompletion(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, Exception arg3)
throws Exception {
System.out.println("First:afterCompletion");
}
@Override
public void postHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, ModelAndView arg3)
throws Exception {
System.out.println("First:postHandle");
}
@Override
public boolean preHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2) throws Exception {
System.out.println("First:preHandle");
return false;
}
}
3. 拦截器的控制层
package com.hkd.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class TestInterceptorController {
@RequestMapping("/testInterceptor")
public String testInterceptor() {
return "success";
}
}
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:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.3.xsd">
<context:component-scan base-package="com.hkd"/>
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/view"/>
<property name="suffix" value=".jsp"/>
</bean>
<!-- 默认的servlet处理静态资源 -->
<mvc:default-servlet-handler />
<!-- 开启mvc注解驱动 -->
<mvc:annotation-driven />
<!-- 配置拦截器 -->
<mvc:interceptors>
<!-- 1. 默认拦截所有请求,两种方法 -->
<!-- 第一种:直接配置bean -->
<bean class="com.hkd.inerceptor.FirstInterceptor"></bean>
<!-- 第二种:要在拦截器上加上注解@Component -->
<!-- <ref bean="firstInterceptor"/> -->
<!-- 2. 设置自定义拦截方式 -->
<!-- <mvc:interceptor>
<bean></bean>
<mvc:mapping path=""/>
<mvc:exclude-mapping path=""/>
</mvc:interceptor> -->
</mvc:interceptors>
</beans>