(一)绑定说明
1、绑定的机制
我们都知道,表单中请求参数都是基于 key=value 的。SpringMVC绑定请求参数的过程是通过把表单提交请求参数,作为控制器中方法参数进行绑定的。
2、支持的数据类型
基本类型参数:包括基本类型和 String 类型
POJO 类型参数:包括实体类,以及关联的实体类
数组和集合类型参数:包括 List 结构和 Map 结构的集合(包括数组)
3、使用要求:
如果是基本类型或者 String 类型:要求我们的参数名称必须和控制器中方法的形参名称保持一致。(严格区分大小写)
如果是 POJO 类型,或者它的关联对象:要求表单中参数名称和 POJO 类的属性名称保持一致。并且控制器方法的参数类型是 POJO 类型。
如果是集合类型,有两种方式:
(1)第一种:要求集合类型的请求参数必须在 POJO 中。在表单中请求参数名称要和 POJO 中集合属性名称相同。给 List 集合中的元素赋值,使用下标。给 Map 集合中的元素赋值,使用键值对。
(2)第二种:接收的请求参数是 json 格式数据。需要借助一个注解实现。
(二)参数绑定示例
1、基本类型和 String 类型作为参数
(1)页面定义请求:
<form action="stringTest" method="post">
name :<input type="text" name="name"><br>
age :<input type="text" name="age"><br>
<input type="submit" value="提交">
</form>
(2)执行器方法绑定参数:
//测试String类型作为参数
@RequestMapping("stringTest")
public String testString(String name,int age){
System.out.println("name:" + name);
System.out.println("age:" + age);
return "RequestSuccessful";
}
2、POJO 类型作为参数
(1)实体类创建:
Car:
package com.jn.pojo;
public class Car {
private String name;
private int price;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getPrice() {
return price;
}
public void setPrice(int price) {
this.price = price;
}
@Override
public String toString() {
return "Car{" +
"name='" + name + '\'' +
", price=" + price +
'}';
}
}
User:
package com.jn.pojo;
public class User {
private String name;
private int age;
private Car car;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Car getCar() {
return car;
}
public void setCar(Car car) {
this.car = car;
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", age=" + age +
", car=" + car +
'}';
}
}
(2)页面定义请求:
<div>
<form action="pojoTest">
name :<input type="text" name="name"><br>
age :<input type="text" name="age"><br>
carName :<input type="text" name="car.name"><br>
carPrice :<input type="text" name="car.price"><br>
<input type="submit" value="提交">
</form>
</div>
(3)执行器方法绑定参数:
//测试Pojo类型作为参数
@RequestMapping("pojoTest")
public String testPojo(User user){
System.out.println(user);
return "RequestSuccessful";
}
3、POJO 类中包含集合类型参数
(1)User类修改
package com.jn.pojo;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
public class User {
private String name;
private int age;
private Car car;
private List<Car> carList;
private Set<Car> carSet;
private HashMap<String,Car> carMap;
User(){
//初始化set集合
carSet=new HashSet<>();
Car car = new Car();
Car car1=new Car();
carSet.add(car);
carSet.add(car1);
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Car getCar() {
return car;
}
public void setCar(Car car) {
this.car = car;
}
public List<Car> getCarList() {
return carList;
}
public void setCarList(List<Car> carList) {
this.carList = carList;
}
public Set<Car> getCarSet() {
return carSet;
}
public void setCarSet(Set<Car> carSet) {
this.carSet = carSet;
}
public HashMap<String, Car> getCarMap() {
return carMap;
}
public void setCarMap(HashMap<String, Car> carMap) {
this.carMap = carMap;
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", age=" + age +
", car=" + car +
", carList=" + carList +
", carSet=" + carSet +
", carMap=" + carMap +
'}';
}
}
(2)页面定义请求:
<div>
<form action="listTest">
name :<input type="text" name="name"><br>
age :<input type="text" name="age"><br>
carName :<input type="text" name="car.name"><br>
carPrice :<input type="text" name="car.price"><br>
listCarName :<input type="text" name="carList[0].name"><br>
listCarPrice :<input type="text" name="carList[0].price"><br>
listCarName1 :<input type="text" name="carList[1].name"><br>
listCarPrice1 :<input type="text" name="carList[1].price"><br>
setCarName :<input type="text" name="carSet[0].name"><br>
setCarPrice :<input type="text" name="carSet[0].price"><br>
setCarName1 :<input type="text" name="carSet[1].name"><br>
setCarPrice1 :<input type="text" name="carSet[1].price"><br>
mapCarName :<input type="text" name="carMap['x'].name"><br>
mapCarPrice :<input type="text" name="carMap['x'].price"><br>
mapCarName1 :<input type="text" name="carMap['y'].name"><br>
mapCarPrice1 :<input type="text" name="carMap['y'].price"><br>
<input type="submit" value="提交">
</form>
</div>
(3)执行器方法绑定参数:
//测试List类型作为参数
@RequestMapping("listTest")
public String testList(User user){
System.out.println(user);
return "RequestSuccessful";
}
4、数组类型参数
(1)页面定义请求:
<div>
<form action="arrTest">
hobby1 :<input type="text" name="hobbies" ><br>
hobby2 :<input type="text" name="hobbies" ><br>
hobby3 :<input type="text" name="hobbies" ><br>
hobby4 :<input type="text" name="hobbies" ><br>
<input type="submit" value="提交">
</form>
</div>
(2)执行器方法绑定参数:
//测试数组类型作为参数
@RequestMapping("arrTest")
public String testArray(String[] hobbies){
for (String hobby : hobbies) {
System.out.println(hobby);
}
return "RequestSuccessful";
}
5、使用 ServletAPI 对象作为方法参数
(1)引入servletAPI的依赖jar包
(注意jar包作用范围provided:不参与项目部署)
<!--servlet-api依赖-->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
</dependency>
(2)执行器方法绑定参数
浏览器启动时直接访问servletTest然后就能进行跳转到hello
//servlet API对象作为返回参数
@RequestMapping("servletTest")
public void testServlet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//转发到/test1
System.out.println("正在请求转发");
request.getRequestDispatcher("/hello").forward(request,response);
}
6、请求参数乱码问题
tomacat 对 GET 和 POST 请求处理方式是不同的:
(1)GET 请求的编码问题,要改 tomcat 的 server.xml配置文件:
进行修改:
<Connector port="8080" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443" URIEncoding="UTF-8"/>
(2)POST 请求的编码问题,要在web.xml文件中配置编码过滤器:
在进行过滤器添加的时候报错The content of element type "web-app" must match "(icon?,display-name?,description?,distributable?,context-param*,filter*,filter-mapping*,listener*,servlet*,servlet-mapping*,session-config?,mime-mapping*,welcome-file-list?,error-page*,taglib*,resourc。最后发现是DOM树里面的元素<head> 版本不匹配,我们改为以下配置就行:
<?xml version="1.0" encoding="UTF-8"?>
<web-app id="WebApp_9" version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
</web-app>
然后加入过滤器:
<!--配置post请求时的编码过滤器-->
<filter>
<filter-name>encodingFilter</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>encodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
7、静态资源访问:
静态资源的配置有两种方式,下面的两种配置方式任选一种配置就行
(1)将静态资源交给默认的DefaultServlet处理
在springMVC.xml配置文件中加如下配置:
<!--开启静态资源配置-->
<mvc:default-servlet-handler></mvc:default-servlet-handler>
(2)指定静态资源的访问路径:
在springMVC.xml配置文件中加如下配置:
<!--开启静态资源配置 第二种方式-->
<mvc:resources mapping="/images/**" location="/images/"/>
(3)web-app目录下新建images存入图片
(4)index.jsp配置显示静态路径图片
<div>
<img src="./images/girls.jpg">
</div>
(5)测试
图片正常显示
(三)自定义参数处理
1、使用场景:
SpringMVC不能自动识别参数转换为我们需要的数据类型,浏览器报400错误,类型转换异常;
2、使用步骤:
(1)定义类型转换器
package com.jn.utils;
import org.springframework.core.SimpleAliasRegistry;
import org.springframework.core.convert.converter.Converter;
import java.text.SimpleDateFormat;
import java.util.Date;
/*
定义类型转化器
定义了一个名为 MyDateConverter 的类,该类实现了 Converter<String, Date> 接口。
主要功能是将字符串格式的日期转换为 Date 对象。
*/
public class MyDateConverter implements Converter<String, Date> {
@Override
public Date convert(String s) {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
Date date = null;
try {
date = sdf.parse(s);
} catch (Exception e) {
e.printStackTrace();
}
return date;
}
}
(2)配置类型转换器
<!--配置类型转换器
将自定义的 MyDateConverter 注册到 Spring 的类型转换服务中,使得在应用中可以使用 MyDateConverter 来进行字符串到日期的转换。-->
<bean id="formattingConversionServiceFactoryBean" class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
<property name="converters">
<bean class="com.jn.utils.MyDateConverter"></bean>
</property>
</bean>
(3)引用类型转换器
1.页面定义请求
//测试自定义类型转换器
@RequestMapping("typeChange")
public String testDate(Date birthday){
System.out.println(birthday);
return "RequestSuccessful";
}
2. 执行器方法绑定参数:
//测试自定义类型转换器
@RequestMapping("typeChange")
public String testDate(Date date){
System.out.println(date);
return "RequestSuccessful";
}
3.发现错误
Failed to convert value of type 'java.lang.String' to required type 'java.util.Date'; nested exception is java.lang.IllegalStateException: Cannot convert value of type 'java.lang.String' to required type 'java.util.Date': no matching editors or conversion strategy found
然后死活不知道怎么修改这个错误,最后折腾了半个小时发现只要早controller里面加入配置函数运行就好了。
@InitBinder
protected void initBinder(WebDataBinder binder) {
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
binder.registerCustomEditor(Date.class, new CustomDateEditor(dateFormat, true));
}