1 参数绑定概念

参数绑定指的是,将前端传到后端的数据绑定到方法的参数上。

Spring MVC 中有一些默认支持的请求类型,这些类型可以直接在 Controller 类的方法中定义,在参数绑定的过程中遇到该种类型就直接进行绑定。其默认支持的类型有以下几种:HttpServletRequest、HttpServletResponse、HttpSession 及 Model/ModelMap。

  1. HttpServletRequest 可以通过 request 对象获取请求信息。
  2. HttpServletResponse 可以通过 response 对象处理响应信息。
  3. HttpSession 可以通过 session 对象得到 session 中存放的对象。
  4. Model 是一个接口,ModelMap 是一个接口实现,它的作用就是将 Model 数据填充到 request 域,跟 ModelAndView 类似(ModelAndView 表示封装了 Model 和 View 的对象,推荐使用它)。

在参数绑定过程中,如果遇到上面类型就直接进行绑定。也就是说,我们可以在 Controller 的方法的形参中直接定义上面这些类型的参数,然后 SpringMVC 会自动绑定。

注意:从前端发送过来的请求参数都是 String 类型的,所以 SpringMVC 还提供了一些默认的格式转换器,这些格式转换器会自动根据数据类型进行类型转换。比如 age 会自动由字符串转换成了 int 类型。

2 Controller 类的方法参数

接收请求参数,使用的处理器方法的形参

  1. HttpServletRequest
  2. HttpServletResponse
  3. HttpSession
  4. 用户提交的数据

框架接收请求参数

  1. 使用 request 对象接收请求参数
    String strName = request. GetParameter (“name”);
    String strAge = request. GetParameter (“age”);
  2. Springmvc 框架通过 DispatcherServlet 调用 MyController 的 doSome () 方法
    调用方法时,按名称对应,把接收的参数赋值给形参 doSome(strName,Integer. ValueOf (strAge))
    框架会提供类型转换的功能,能把 String 转为 int ,long , float, double 等类型。

3 不同类型数据的参数绑定

3.1 简单类型参数绑定

对于简单类型的参数,这些类型是直接在 Controller 类的方法中定义。当用户发送请求后,Spring MVC 在处理 key/value 信息时,就会以 key 名寻找 Controller 类的方法中具有相同名称的形参并进行绑定。

注意:Controller 中的形参需要与前台提交的 name 属性一样才能完成绑定,如果请求中不包含其中的某个形参,此时是不会报错的,默认使用该参数时要进行空校验。

Controller 控制器类

@Controller
public class BookController {
    @RequestMapping(value = "book", method = RequestMethod.POST)
    public String getInfo(Integer id, String name, String publisher) {
        System.out.println("获取到的数据为:ID--" + id + ",名称--" + name + ",出版社--" + publisher);
        return "success"; //成功后跳转的页面
    }
}

前端页面

样例 1:

<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8" isELIgnored="false" %>
<!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>首页</title>
  </head>
  <body>
    <form action="${pageContext.request.contextPath}/book" method="post">
      <table>
        <tr>
          <td>图书ID:</td>
          <td><input type="text" name="id" /></td>
        </tr>
        <tr>
          <td>图书名称:</td>
          <td><input type="text" name="name" /></td>
        </tr>
        <tr>
          <td>出版社:</td>
          <td><input type="text" name="publisher" /></td>
        </tr>
        <tr>
          <td colspan="2"><input type="submit" value="提交" /></td>
        </tr>
      </table>
    </form>
  </body>
</html>

3.2 单一 POJO 类型绑定

POJO(Plain Ordinary Java Object)简单的 Java 对象,实际就是普通 JavaBeans,是为了避免和 EJB (Enterprise Java Beans,企业 Java Beans) 混淆所创造的简称。

前端需要的数据多而杂,通过传递简单数据开发效率较低,平时一般都会使用 POJO 类型来绑定数据。

Book 实体类:

public class Book {
    private Integer id;
    private String name;
    private String publisher;
    //getter,setter和toString省略
}

Controller 类:

@Controller
public class BookController {
    @RequestMapping(value = "book", method = RequestMethod.POST)
    public String getInfo(Book book) {
        System.out.println("获取到的数据为:ID--" + book.getId());
        return "success";
    }
}

前端页面:

<form action="${pageContext.request.contextPath}/book" method="post">
  <table>
    <tr>
      <td>图书ID:</td>
      <td><input type="text" name="id" /></td>
    </tr>
    <tr>
      <td>图书名称:</td>
      <td><input type="text" name="name" /></td>
    </tr>
    <tr>
      <td>出版社:</td>
      <td><input type="text" name="publisher" /></td>
    </tr>
    <tr>
      <td colspan="2"><input type="submit" value="提交" /></td>
    </tr>
  </table>
</form>

注:前端提交的 name 属性必须与 POJO 里面的属性一致,这样 SpringMVC 才会自动帮我们绑定数据,否则会绑定失败!!!

3.3 嵌套 POJO 类型绑定

嵌套 POJO 类型就是在一个 Java 实体类中包含了其它的实体类,此时 Spring MVC 依然可以解析并成功绑定该类型的包装类。

前端发送数据时,嵌套对象的属性 key 应该为 嵌套对象.属性 的形式。

用于嵌套的 Author 类

public class Author {
    private String name;
    private String age;
    //getter,setter和toString省略
}

Book 类

public class Book {
    private Integer id;
    private String name;
    private String publisher;
    private Author author;
    //getter,setter和toString省略
}

Controller 类
当前端页面发出请求后,处理器适配器会解析这种格式的 name,将该参数当做 POJO 类的成员参数绑定起来,作为 Controller 方法的形参。这样在 Controller 方法中就可以通过 POJO 类获取其 POJO 类的其他类的对象。

@Controller
public class BookController {
    @RequestMapping(value = "book", method = RequestMethod.POST)
    public String getInfo(Book book) {
        System.out.println("获取到的数据为:ID--" + book.getId()+ ",作者信息--" + book.getAuthor());
        return "success";
    }
}

提交图书信息的页面

<form action="${pageContext.request.contextPath}/book" method="post">
    <table>
        <tr><td>图书ID:</td><td><input type="text" name="id"></td></tr>
        <tr><td>作者名称:</td><td><input type="text" name="author.name"></td></tr>
        <tr><td>作者年龄:</td>td><input type="text" name="author.age"></td></tr>
        <tr><td colspan="2"><input type="submit" value="提交"></td></tr>
    </table>
</form>

3.4 List 集合绑定

Book 类包含集合数据:

public class Book {
    private List<Author> author;
    //getter,setter和toString省略
}

前端页面中每一组数据的 input 控件的 name 属性的格式为:集合名[下标].属性,当请求传递到后端时,处理器适配器会根据 name 的格式将请求参数解析为相应的 List 集合。

<form action="${pageContext.request.contextPath}/book" method="post">
  List类型-作者1名称:<input type="text" name="author[0].name" /><br />
  List类型-作者1年龄:<input type="text" name="author[0].age" /><br />
  List类型-作者2名称:<input type="text" name="author[1].name" /><br />
  List类型-作者2年龄:<input type="text" name="author[1].age" /><br />
  <input type="submit" value="提交" />
</form>

3.5 Array 数组绑定

Book 类包含数组数据:

public class Book {
    private String[] bookType;
    //getter,setter和toString省略
}

如果前台传输了多个相同 name 的数据,比如多选框,SpringMVC 可以在处理器方法中使用数组参数接收这些数据。

<form action="${pageContext.request.contextPath}/book" method="post">
  图书类型 :
  <input type="checkbox" name="bookType" value="Java" />Java
  <input type="checkbox" name="bookType" value="C++" />C++
  <input type="checkbox" name="bookType" value="PHP" />PHP
  <input type="checkbox" name="bookType" value="Python" />Python <br />
  <input type="submit" value="提交" />
</form>

例如: localhost:8080/springmvc/test?bookType=Java&bookType=PHP&bookType=Python

如果不使用数组来接受数据,只是使用 String 类型来接受,那么 SpringMVC 会自动将这几个数据通过逗号拼接起来。

public String getInfo(String bookType) {
	// 此时 bookType 为 "Java,PHP,Python"
}

3.6 Map 集合绑定

Map 的绑定其实和 List 的绑定是差不多的。虽然 Map 的使用比较灵活,但是对于这里绑定数据而言就显得乏力了,可维护性比较差,所以因此一般不推荐使用。

Book 类包含集合数据:

public class Book {
	private Map<String, Author> authorMap;
    //getter,setter和toString省略
}

在前端 index. Jsp 页面额外添加如下 JSP 代码。当想把页面上的批量数据通过 Spring MVC 转换为 Web 端的 Map 类型的对象时,每一组数据的 input 控件的 name 属性使用 Map名['key值'] 的形式。当请求传递到 Web 端时,处理器适配器会根据 name 的格式将请求参数解析为相应的 Map 集合。

<form action="${pageContext.request.contextPath}/book" method="post">
  Map类型-作者1名称:<input type="text" name="authorMap['a1'].name" /><br />
  Map类型-作者1年龄:<input type="text" name="authorMap['a1'].age" /><br />
  Map类型-作者2名称:<input type="text" name="authorMap['a2'].name" /><br />
  Map类型-作者2年龄:<input type="text" name="authorMap['a2'].age" /><br />
  <input type="submit" value="提交" />
</form>

3.7 JSON Array

@PostMapping("/param/jsonarray")
public String getJsonDataArray(@RequestBody List<User> users){
  System.out.println("接收的json array:"+users.toString());
  return "json转为List<User>对象"+users.toString();
}
 
测试:
POST http://localhost:8080/param/jsonarray
Content-Type: application/json
 
[
 {"name":"lisi","age":22},
 {"name":"zhangesan","age":26},
 {"name":"zhouli","age":30}
]

3.8 Reader-InputStream

Reader 或 InputStream 读取请求体的数据,适合 post 请求体的各种数据。具有广泛性。

step1:创建新的控制器方法

@PostMapping("/param/json2")
public String getJsonData2(Reader in)  {
  StringBuffer content = new StringBuffer("");
  try(BufferedReader bin = new BufferedReader(in)){
      String line = null;
      while( (line=bin.readLine()) != null){
        content.append(line);
      }
  } catch (IOException e) {
     throw new RuntimeException(e);
  }
  return "读取请求体数据"+ content.toString();
}
 
POST http://localhost:8080/param/json2
Content-Type: application/json 可无
 
{"name":"lisi","age":26}
 

3.9 默认支持的类型

Spring MVC 中有一些默认支持的请求类型,这些类型可以直接在 Controller 类的方法中定义,在参数绑定的过程中遇到该种类型就直接进行绑定。其默认支持的类型有以下几种:HttpServletRequest、HttpServletResponse、HttpSession 及 Model/ModelMap。

  1. HttpServletRequest 可以通过 request 对象获取请求信息。
  2. HttpServletResponse 可以通过 response 对象处理响应信息。
  3. HttpSession 可以通过 session 对象得到 session 中存放的对象。
  4. Model 是一个接口,ModelMap 是一个接口实现,它的作用就是将 Model 数据填充到 request 域,跟 ModelAndView 类似(ModelAndView 表示封装了 Model 和 View 的对象,推荐使用它)。
//不指定请求方式,没有限制
@RequestMapping(value = "/first.do")
public ModelAndView doFirst(HttpServletRequest request, HttpServletResponse response, HttpSession session){
    ModelAndView mv  = new ModelAndView();
	mv.addObject("msg","====欢迎使用springmvc做web开发====" + request.getParameter("name"));
	mv.addObject("fun","执行的是doFirst方法");
	mv.setViewName("other");
	return mv;
}

request.getParameterValues() 可以获取一个属性的多个值,针对 checkbox 情况。例如网页请求为:localhost:8080/springmvc/test?hobby=a&hobby=b&hobby=c

4 @RequestParam - 请求参数与方法参数绑定

@RequestParam 用于将请求参数区域的数据映射到 Handler 方法的参数上。有一些特殊情况,前端的 name 属性值与后端 Handler 方法中的形参不一致,这个时候就可以通过 @RequestParam 注解来解决。

语法:@RequestParam (value=”参数名”, required=”true|false”, defaultValue=””)

  • value :请求中传入参数的名称。
  • required :该参数是否为必传项,默认为 true,表示该请求路径中必须包含该参数,如果不包含就报错。
  • defaultValue :默认参数值,如果设置了该值,required=true 将失效,自动为 false,如果没有传该参数,就使用默认值。

@RequestParam 注解的简单举例:

<!-- 表单数据,这里的name属性值为name。 -->
<input type="text" name="name" />
@Controller
@RequestMapping("hello")
public class HelloController {
    //表示将请求路径中参数名称为name映射为userName,相当于重命名一样
    @RequestMapping("one")
    public String show1(@RequestParam("name") String userName) {
        System.out.println(userName);
        return "success";
    }
    //表示请求路径中不一定要包含名称为name的参数
    @RequestMapping("two")
    public String show2(@RequestParam(value = "name", required = false) String userName) {
        System.out.println(userName);
        return "success";
    }
    //表示请求路径中必须包含名称为name的参数,如果name参数的值为空,则使用默认的值"hello"
    @RequestMapping("three")
    public String show3(@RequestParam(value = "name" ,required=true, defaultValue = "hello") String userName) {
        System.out.println(userName);
        return "success";
    }
}

5 @RequestHeader - 请求头与方法参数绑定

@RequestHeader 是将请求头信息和控制器方法的形参创建映射关系

@RequestHeader 注解一共有三个属性:value、required、defaultValue,用法同 @RequestParam

@CookieValue 是将 cookie 数据和控制器方法的形参创建映射关系

@CookieValue 注解一共有三个属性:value、required、defaultValue,用法同@RequestParam

7 解决获取请求参数的乱码问题

解决获取请求参数的乱码问题,可以使用 SpringMVC 提供的编码过滤器 CharacterEncodingFilter,但是必须在 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>forceResponseEncoding</param-name>
        <param-value>true</param-value>
    </init-param>
</filter>
<filter-mapping>
    <filter-name>CharacterEncodingFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

注:

SpringMVC 中处理编码的过滤器一定要配置到其他过滤器之前,否则无效。