SpringMVC学习笔记(一)-三、SpringMVC中的请求参数绑定

(一)绑定说明

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));
    }

上一篇:Vue全栈开发旅游网项目(10)-设计用户模型


下一篇:【Linux网络编程】Socket编程--TCP:echo server | 多线程远程命令执行