文章目录
3. 请求参数绑定
SpringMVC通过进行参数解析器可以将请求的参数与方法中的参数进行绑定
3.1. 支持参数类型
- 基本类型
- String
- POJO类型
- 数组和集合类型
3.2. 使用要求
-
基本类型或String:请求参数名称和方法形参名称保持一致(区分大小写)
-
POJO类型:请求参数名称和 POJO类的属性名称保持一致,方法参数类型是POJO类型。
-
数组或集合类型
-
要求集合类型的请求参数必须在 POJO中。在表单中请求参数名称要和 POJO中集合属性名称相同。
给 List集合中的元素赋值,使用下标。
给 Map集合中的元素赋值,使用键值对。
-
接收的请求参数是 json格式数据。需要借助一个注解实现
-
3.3. 使用示例
3.3.1. 基本类型和 String 类型作为参数
- 请求路径
http://localhost:8080/user/select/id/username.do?id=1001&username=tomcat
- controller
@RequestMapping("/select/id/username")
public String testParam(Integer id,String username){
System.out.println("id="+id+" username="+username);
return "success";
}
3.3.2. POJO类型作为参数
- 添加POJO类
User.java
public class User {
private Integer id;
private String name;
private Float money;
private Address address;
//get set toString...
}
Address.java
public class Address {
private String provinceName;
private String cityName;
//get set toString...
}
-
添加表单页面
user.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<form action="/user/pojo.do" method="post">
用户名称:<input type="text" name="name" ><br/>
用户余额:<input type="text" name="money" ><br/>
用户地址-省:<input type="text" name="address.provinceName" ><br/>
用户地址-市:<input type="text" name="address.cityName" ><br/>
<input type="submit" value="保存">
</form>
</body>
</html>
- controller接收参数
@RequestMapping("/pojo")
public String saveAccount(User user){
System.out.println(user);
return "success";
}
3.3.3. 请求参数中文乱码处理
web.xml添加请求参数处理过滤器
<!-- 配置 springMVC编码过滤器 -->
<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>
<!-- 启动过滤器 -->
<init-param>
<param-name>forceEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<!-- 过滤所有请求 -->
<filter-mapping>
<filter-name>CharacterEncodingFilter</filter-name>
<url-pattern>*.do</url-pattern>
</filter-mapping>
3.3.4. POJO 类中包含集合类型参数
添加pojo类
public class Bank {
private String account;
private Double money;
//get set
}
修改User类
public class User {
private Integer id;
private String name;
private Float money;
private Address address;
//集合类型属性
private List<Integer> ids;
private List<Bank> bankList;
private Map<String,Integer> sizeMap;
private Map<String,Bank> bankMap;
//get set
}
collection.jsp
<form action="/user/collection.do" method="post">
用户名称:<input type="text" name="name" ><br/>
用户余额:<input type="text" name="money" ><br/>
用户地址-省:<input type="text" name="address.provinceName" ><br/>
用户地址-市:<input type="text" name="address.cityName" ><br/>
IdsItegerList:<input type="text" name="ids[0]" ><br/>
IdsItegerList:<input type="text" name="ids[1]" ><br/>
IdsItegerList:<input type="text" name="ids[2]" ><br/>
String[]:<input type="text" name="props" ><br/>
String[]:<input type="text" name="props" ><br/>
bankList[0].account:<input type="text" name="bankList[0].account" ><br/>
bankList[0].money:<input type="text" name="bankList[0].money" ><br/>
bankList[1].account:<input type="text" name="bankList[1].account" ><br/>
bankList[1].money:<input type="text" name="bankList[1].money" ><br/>
sizeMap-S:<input type="text" name="sizeMap['S']" ><br/>
sizeMap-M:<input type="text" name="sizeMap['M']"><br/>
sizeMap-L:<input type="text" name="sizeMap['L']"><br/>
bankMap-bank1-account: <input type="text" name="bankMap['bank1'].account"><br/>
bankMap-bank1-money: <input type="text" name="bankMap['bank1'].money"><br/>
bankMap-bank2-account: <input type="text" name="bankMap['bank2'].account"><br/>
bankMap-bank2-money: <input type="text" name="bankMap['bank2'].money"><br/>
<input type="submit" value="保存">
</form>
controller
@RequestMapping("/collection")
public String collection(User user,String[] props){
System.out.println(user);
return "success";
}
测试:
3.3. 日期类型参数
新建webapp/date.jsp
<!-- 特殊情况之:类型转换问题 -->
<a href="/user/select/date.do?date=2020/07/03">根据日期查询</a>
UserController添加方法
@RequestMapping("/select/date")
public String selectByDate(Date date){
System.out.println("date : "+date);
return "success";
}
当把参数2020/07/03 格式改为 2020-07-03时,抛出异常:String转换为Date类型出错
spingmvc默认是按照yyyy/mm/dd格式进行日期转换,不支持yyyy-mm-dd格式,需要自定义转换器
3.3.1. 自定义类型转换器
- 定义类实现Converter接口
- 配置自定义类型转换器
- 在
annotation-driven
标签中引用配置的类型转换服务
3.3.2. 定义类实现Converter接口
package com.czxy.mvc.converter;
import org.springframework.core.convert.converter.Converter;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
//public interface Converter<S, T> {//S:表示接受的类型,T:表示目标类型
public class StringToDateConverter implements Converter<String,Date> {
/**
* 实现类型转换的方法
* @param s
* @return
*/
@Override
public Date convert(String s) {
if(s != null && !s.trim().equals("")){
SimpleDateFormat format = new SimpleDateFormat("yyyy-mm-dd");
try {
Date date = format.parse(s);
return date;
} catch (ParseException e) {
System.out.println("日期格式错误!");
e.printStackTrace();
}
}
return null;
}
}
3.3.3. 配置自定义类型转换器
<!-- 配置类型转换器工厂 -->
<bean id="converterService" class="org.springframework.context.support.ConversionServiceFactoryBean">
<!-- 给工厂注入一个新的类型转换器 -->
<!-- 配置自定义类型转换器 -->
<property name="converters">
<array>
<bean class="com.czxy.mvc.converter.StringToDateConverter"></bean>
</array>
</property>
</bean>
3.3.4. 引用配置的类型转换服务
<!--第三步:在 annotation-driven标签中引用配置的类型转换服务-->
<!-- 引用自定义类型转换器 -->
<mvc:annotation-driven conversion-service="converterService"/>
3.3.5. 测试
http://localhost:8080/user/select/date.do?date=2020-07-03
控制台正常输出:Fri Jan 03 00:07:00 CST 2020
3.3.6. pojo中的日期类型
public class User {
//其他属性...
@DateTimeFormat(pattern = "yyyy-MM-dd")
private Date birthday;
// get set
}
只需要添加@DateTimeFormat指定日期格式即可
注意:需要在springmvc.xml中开启注解驱动:
<mvc:annotation-driven></mvc:annotation-driven>
- UserController
@RequestMapping("/select/date")
public String selectByDate(Date date,User user){
System.out.println("user.birthday : "+user.getBirthday());
System.out.println("date : "+date);
return "success";
}
- http://localhost:8080/user/select/date.do?birthday=2020-07-03
3.4. ServletAPI对象作为方法参数
SpringMVC还支持使用原始 ServletAPI对象作为控制器方法的参数。支持原始 ServletAPI对象有:
-
HttpServletRequest
(常用) -
HttpServletResponse
(常用) -
HttpSession
(常用) -
InputStream
-
OutputStream
-
Reader
-
Writer
-
java.security.Principal
-
Locale
我们可以把上述对象,直接写在控制的方法参数中使用。例如需要使用HttpSession获取session中登录的用户信息,可以将HttpSession对象作为方法参数
3.4.1. 使用示例
在controller方法上将Servlet API对象作为参数,Spring容器会注入这些对象,然后在方法中可以直接使用
@RequestMapping("/test/servletAPI")
public String testServetAPI(HttpServletRequest request,
HttpServletResponse response,
HttpSession session){
System.out.println(request);
System.out.println(response);
System.out.println(session);
return "success";
}
- 直接在浏览器地址栏访问该方法:
http://localhost:8080/user/test/servletAPI.do
- 控制台输出对象地址,说明获取到了这些对象:
org.apache.catalina.connector.RequestFacade@20b048eb
org.apache.catalina.connector.ResponseFacade@c5ebc7c
org.apache.catalina.session.StandardSessionFacade@4c9bebef
3.5. forward redirect
3.5.1. forward和redirect区别
- forward
- 转发都是一次请求: A -> B -> C 整个过程还是一次请求,也就是同个request,后面的方法可以获取前面请求中的域属性
- 转发地址栏显示地址不变
- redirect
- 重定向是2次请求:A -> B ,那么A和B 就是不同request,B无法获取到A 的request中的数据,但是只要没有关闭浏览器,A和B还在一次会话总,A和B可以使用session共享数据
- 重定向浏览器地址栏会显示新的请求地址
3.5.1. forward示例
使用Servlet API 可以获取内存(servlet域)中的参数,
@RequestMapping("/forward")
public String forward(HttpServletRequest request,
HttpSession session){
request.setAttribute("name","张三");
session.setAttribute("age",20);
System.out.println("参数设置完毕...转发...");
return "forward:/user/get/params.do";
}
@RequestMapping("/get/params")
public String getParams(HttpServletRequest request,
HttpSession session){
String name = (String) request.getAttribute("name");
Integer age = (Integer) session.getAttribute("age");
System.out.println("name : "+name+" age : "+age);
return "success";
}
浏览器地址:http://localhost:8080/user/forward.do
控制台输出:name : 张三 age : 20
3.5.2. redirect示例
@RequestMapping("/redirect")
public String redirect(HttpServletRequest request,
HttpSession session){
request.setAttribute("name","张三");
session.setAttribute("age",20);
System.out.println("参数设置完毕...转发...");
return "redirect:/user/get/params.do";
}
@RequestMapping("/get/params")
public String getParams(HttpServletRequest request,
HttpSession session){
String name = (String) request.getAttribute("name");
Integer age = (Integer) session.getAttribute("age");
System.out.println("name : "+name+" age : "+age);
return "success";
}
访问地址:http://localhost:8080/user/redirect.do
访问后地址:http://localhost:8080/user/get/params.do
控制台输出:name : null age : 20
3.6.3. 使用forward和request转发
- 使用forward转发
@RequestMapping("/forward")
public String forwar() {
//System.out.println("转发到...");
//转发能访问到webapp目录下所有资源
//return "forward:/a.html";
return "forward:/WEB-INF/b.html";
}
- 使用request转发
@RequestMapping("/req/forward")
public void forwar(HttpServletRequest request) throws Exception{
System.out.println("转发到...");
//转发能访问到webapp目录下所有资源
//return "forward:/a.html";
//return "forward:/WEB-INF/b.html";
request.getRequestDispatcher("/WEB-INF/b.html").forward(request,response);
}
3.6.4. 使用redirect和response重定向
- 使用redirect重定向
@RequestMapping("/redirect")
public String redirect(HttpServletResponse response) throws Exception{
System.out.println("重定向...");
//注意重定向是2次请求,不能访问到WEB-INF目录下的资源
//只能访问webapp目录下(不包含WEB-INF)的资源
//return "redirect:/user.jsp";
return "redirect:/a.html";
}
- 使用response重定向
@RequestMapping("/resp/redirect")
public void redirect(HttpServletResponse response) throws Exception {
System.out.println("重定向...");
//注意重定向是2次请求,不能访问到WEB-INF目录下的资源
//只能访问webapp目录下(不包含WEB-INF)的资源
//return "redirect:/user.jsp";
//return "redirect:/a.html";
response.sendRedirect("/user.jsp");
}