概述
上篇文章我们讲了SpringMVC 概述和SpringMVC 入门,现在来讲SpringMVC中请求参数的绑定和常用的注解
文章目录
- 请求参数的绑定
- 绑定的机制
- 支持的数据类型:
- 基本类型和 String 类型作为参数
- POJO 类型作为参数
- 集合类型作为参数
- 请求参数乱码问题
- 自定义类型转换器
- 使用 Servlet 原生 API 作为参数
- 常用注解
- @RequestParam
- @RequestBody
- @PathVariable
- @RequestHeader
- @CookieValue
- @ModelAttribute
- @SessionAttributes
请求参数的绑定
绑定的机制
- 当我们从表单提交数据到后台的时候,请求参数都是基于
key=value
的形式,SpringMVC 绑定请求参数的过程是通过把表单提交请求参数
,作为控制器中方法参数进行绑定的。譬如:
<a href="user/findAccount?accountId=10">查询账户</a>
上面代码的请求参数是:
accountId=10
- 此时我们利用 SpingMVC 就可以这样接收:
/**
* 查询账户
* @return
*/
@RequestMapping("/user")
public String findAccount(Integer accountId) {
System.out.println("查询了账户。。。。"+accountId);
return "success";
}
支持的数据类型:
- 基本类型参数:
- 包括基本类型和
String
类型
- 包括基本类型和
- POJO 类型参数:
- 包括实体类,以及关联的实体类
- 数组和集合类型参数:
- 包括
List
结构和Map
结构的集合(包括数组)
- 包括
SpringMVC 绑定请求参数是自动实现的,但是要想使用,必须遵循使用要求。
基本类型和 String 类型作为参数
- 如果是基本类型或者 String 类型,要求我们的参数名称必须和控制器中方法的形参名称保持一致。(严格区分大小写),见以下示例:
- param.jsp代码:
<%-- 请求参数绑定--%>
<a href="param/testParam?username=zhang&password=123">请求参数绑定</a><hr/>
- ParamController控制器代码:
/**
* 请求参数绑定
*/
@Controller
@RequestMapping("/param")
public class ParamController {
/**
* 请求参数绑定入门
* @return
*/
@RequestMapping("/testParam")
public String testParam(String username,String password){
System.out.println("用户名:" +username);
System.out.println("密码:" +password);
System.out.println("执行了...");
return "success";
}
- 运行结果
POJO 类型作为参数
- 如果是 POJO 类型,或者它的关联对象, 要求表单中参数名称和 POJO 类的属性名称保持一致。并且控制器方法的参数类型是
POJO
类型。特别地,如果 POJO 类中含有其他 POJO 类的引用,那么请求参数名称应该为外部属性名.内部属性名
,见以下示例: - param.jsp代码:
<form action="param/saveAccount" method="post">
账号:<input type="text" name="username"><br/>
密码:<input type="text" name="password"><br/>
金额:<input type="text" name="money"><br/>
用户姓名:<input type="text" name="user.uname"><br/>
用户年龄:<input type="text" name="user.age"><br/>
<input type="submit" value="提交"><br/>
</form>
- ParamController控制器代码:
/**
* 请求参数绑定把数据封装到JavaBean的类中
* @return
*/
@RequestMapping("/saveAccount")
public String saveAccount(Account account){
System.out.println("执行了...");
System.out.println(account);
return "success";
}
- 实体类 Account 类、User 类代码:
public class Account implements Serializable {
private String username;
private String password;
private Double money;
private User user;
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 Double getMoney() {
return money;
}
public void setMoney(Double money) {
this.money = money;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
@Override
public String toString() {
return "Account{" +
"username='" + username + ''' +
", password='" + password + ''' +
", money=" + money +
", user=" + user +
'}';
}
}
public class User implements Serializable {
private String uname;
private Integer age;
public String getUname() {
return uname;
}
public void setUname(String uname) {
this.uname = uname;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
@Override
public String toString() {
return "User{" +
"uname='" + uname + ''' +
", age=" + age +
'}';
}
}
- 运行结果
集合类型作为参数
- 如果要绑定集合类型的参数,那么要求集合类型的请求参数必须在 POJO 类中,同时前端的请求参数名称和 POJO类的集合属性名称保持一致。当给
List
集合中的元素赋值时,使用下标;当给Map
集合中的元素赋值时,使用键值对。接收的请求参数是json
格式数据。需要借助一个注解实现。 - param.jsp代码:
<%--把数据封装Account类中,类中存在list和map的集合--%>
<form action="param/saveAccount" method="post">
账号:<input type="text" name="username"><br/>
密码:<input type="text" name="password"><br/>
金额:<input type="text" name="money"><br/>
<%-- 绑定到 List 集合 --%>
用户姓名:<input type="text" name="list[0].uname"><br/>
用户年龄:<input type="text" name="list[0].age"><br/>
<%-- 绑定到 map 集合 --%>
用户姓名:<input type="text" name="map['one'].uname"><br/>
用户年龄:<input type="text" name="map['one'].age"><br/>
<input type="submit" value="提交"><br/>
</form>
- Account 类代码::
public class Account implements Serializable {
private String username;
private String password;
private Double money;
private List<User> list;
private Map<String,User> map;
//private User user;
//getters and setters
//...
//toString()...
}
- 运行结果
请求参数乱码问题
-
对于
GET
方式提交的请求,如果参数中含有中文,那么是不会乱码的,因为 Tomcat 8 已经将乱码问题解决了。如果GET
方式请求乱码,那么可以在 Tomcat 安装目录下的confserver.xml
中进行添加,如图:
-
而对于
POST
方式提交的参数乱码问题,则应该在web.xml
中配置一个 SpringMVC 提供的过滤器CharacterEncodingFilter
,见代码
<!-- 配置编码过滤器 -->
<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>
<Filter>
位置最好出现在<servlet>
之前
自定义类型转换器
-
表单提交的任何数据类型全部都是字符串类型,但是后台定义Integer类型,数据也可以封装上,说明Spring框架内部会默认进行数据类型转换。
-
可是有的时候会出现这样的情况,前端提交了一个日期字符串,控制器方法使用
Date
类型的变量进行接收,由于日期字符串有很多种格式,所以 SpringMVC 的内置转换器不一定能帮我们转换成Date
类型。 -
param.jsp代码:
<%-- 自定义类型转换器--%>
<form action="param/saveUser" method="post">
用户姓名:<input type="text" name="uname" /><br/>
用户年龄:<input type="text" name="age" /><br/>
用户生日:<input type="text" name="date" /><br/>
<input type="submit" value="提交"><br/>
</form>
- ParamController控制器代码:
/**
* 自定义类型转换器
* @return
*/
@RequestMapping("/saveUser")
public String saveUser(User user){
System.out.println("自定义类型转换器...");
System.out.println(user);
return "success";
}
- 运行结果:
注意我写的日期格式
- 此时我们就可以根据自己的需求来定义自定义的类型转换器,要求实现
Converter<S,T>
接口,其中S
为待转换的类型,T
为目标类型。
/**
* 字符串转日期
*/
public class StringToDateConverter implements Converter<String, Date> {
/**
* String source 传入进来字符串
* @param source
* @return
*/
@Override
public Date convert(String source) {
//判断
if (source == null){
throw new RuntimeException("请传入数据");
}
DateFormat df = new SimpleDateFormat("yyyy-MM-dd");
try {
// 把字符串转换日期
return df.parse(source);
}catch (Exception e){
throw new RuntimeException("数据类型转换出现错误");
}
}
}
- 最后我们需要在 SpringMVC 的配置文件中配置该类型转换器
<!-- 配置自定义转换器 -->
<bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
<property name="converters">
<set>
<bean class="com.cz.utils.StringToDateConverter"></bean>
</set>
</property>
</bean>
<!-- 开启SpringMVC框架注解的支持 -->
<mvc:annotation-driven conversion-service="conversionService"/>
使用 Servlet 原生 API 作为参数
-
SpringMVC 支持使用原始
Servlet API
对象作为方法参数,也就是说,我们可以把这些参数直接写在控制器方法的参数列表上,支持原始ServletAPI
对象有: -
HttpServletRequest
HttpServletResponse
HttpSession
java.security.Principal
Locale
InputStream
OutputStream
Reader
Writer
我们可以把上述对象,直接写在控制的方法参数中使用。
- 示例代码:
/**
* Servlet原生的API
* @return
*/
@RequestMapping("/testServlet")
public String testServlet(HttpServletRequest request, HttpServletResponse response){
System.out.println("Servlet原生的API...");
System.out.println(request);
HttpSession session = request.getSession();
System.out.println(session);
System.out.println(response);
return "success";
}
常用注解
@RequestParam
-
作用:
- 把请求中指定名称的参数绑定到控制器方法的某个参数上
-
属性:
value / name
: 这两个属性互为别名,都是指定请求参数中的名称required
: 请求参数中是否必须提供此参数,默认值为true
,表示必须提供,否则报错
-
anno.jsp
代码:
<%--常用的注解--%>
<a href="anno/testRequestParam?name=哈哈">RequestParam</a>
- 控制器代码:
/**
* 常用注解
*/
@Controller
@RequestMapping("/anno")
public class AnnoController {
@RequestMapping("/testRequestParam")
public String testRequestParam(@RequestParam(name = "name") String username){
System.out.println("执行了");
System.out.println(username);
return "success";
}
}
此时使用
@RequestParam("name")
,那么如果请求参数中没有name
参数,程序就会报错。同时,由于已经使用@RequestParam
进行参数的绑定,所以控制器方法的参数名称username
已经无法绑定了,也就是说,即使请求参数中有参数username
,那么也不会绑定到控制器方法的username
参数上了。
@RequestBody
-
作用:
- 获取请求体内容,得到的内容为
key1=value1&key2=value2...
,只适用POST
方式提交的请求,因为GET
方式无请求体。
- 获取请求体内容,得到的内容为
-
属性:
required
: 是否必须有请求体,默认值为true
,表示必须有请求体,GET
方式请求会报错;当为false
时,GET
方式请求得到的为` null``
-
jsp代码:
<%--RequestBody注解--%>
<form action="anno/testRequestBody" method="post">
用户姓名:<input type="text" name="username" /><br/>
用户年龄:<input type="text" name="age" /><br/>
<input type="submit" value="提交" />
</form>
- 控制器代码
/**
* 获取到请求体的内容
* @return
*/
@RequestMapping("/testRequestBody")
public String testRequestBody(@RequestBody String body){
System.out.println("执行了...");
System.out.println(body);
return "success";
}
@PathVariable
-
作用:
- 将 URL 中的占位符绑定到控制器方法的参数上,例如
localhost:8080/springmvc/user/{id}
,这里的{id}
就是一个占位符。
- 将 URL 中的占位符绑定到控制器方法的参数上,例如
-
属性:
value
:指定 URL 中的占位符名称required
: 是否必须提供占位符
-
jsp代码:
<!-- PathVariable 注解 -->
<a href="anno/testPathVariable/10">testPathVariable</a>
- 控制器代码:
/**
* PathVariable注解
* @return
*/
@RequestMapping(value="/testPathVariable/{uid}")
public String testPathVariable(@PathVariable(name="uid") String id){
System.out.println("执行了...");
System.out.println(id);
return "success";
}
该注解可以用于绑定 REST 风格 URL 的占位符,restful 有以下特点:
资源(Resources)
:每一个 URI 对应着一个资源
- 它可以是一段文本、一张图片、一首歌曲、一种服务,总之就是一个具体的存在。可以用一个 URI(统一资源定位符)指向它,每种资源对应一个特定的 URI 。要获取这个资源,访问它的 URI 就可以,因此 URI
即为每一个资源的独一无二的识别符。表现层(Representation)
:把资源具体呈现出来的形式,叫做它的表现层 (Representation
)。
- 比如,文本可以用 txt 格式表现,也可以用 HTML 格式、XML 格式、JSON 格式表现,甚至可以采用二进制格式。
状态转化(State Transfer
):每发出一个请求,就代表了客户端和服务器的一次交互过程。
- HTTP协议,是一个无状态协议,即所有的状态都保存在服务器端。因此,如果客户端想要操作服务器,必须通过某种手段,让服务器端发生“状态转化”(
StateTransfer
)。而这种转化是建立在表现层之上的,所以就是
“表现层状态转化”。- 具体说,就是 HTTP 协议里面,四个表示操作方式的动词:
GET 、POST 、PUT、DELETE
。它们分别对应四种基本操作:GET用来获取资源,POST 用来新建资源,PUT 用来更新资源,DELETE
用来删除资源。restful 的示例
:
- /account/1 HTTP
GET
: 得到 id = 1 的 account- /account/1 HTTP
DELETE
: 删除 id = 1 的 account- /account/1 HTTP
PUT
: 更新 id = 1 的 account
@RequestHeader
-
作用:
- 用于获取请求消息头
-
属性:
value
: 要获取的消息头名称required
: 是否必须有此消息头
-
jsp代码:
<!-- RequestHeader注解 -->
<a href="anno/testRequestHeader">RequestHeader</a>
- 控制器代码:
/**
* 获取请求头的值
* @param header
* @return
*/
@RequestMapping(value="/testRequestHeader")
public String testRequestHeader(@RequestHeader(value="Accept") String header, HttpServletRequest request,HttpServletResponse response) throws IOException {
System.out.println("执行了...");
System.out.println(header);
// return "success";
// response.sendRedirect(request.getContextPath()+"/anno/testCookieValue");
return "redirect:/param.jsp";
}
@CookieValue
-
作用:
- 用于获取
Cookie
的值
- 用于获取
-
属性:
value
: 要获取的Cookie
名称required
: 是否必须有此Cookie
-
jsp代码:
<!-- CookieValue注解 -->
<a href="anno/testCookieValue">CookieValue</a>
- 控制器代码:
/**
* 获取Cookie的值
* @return
*/
@RequestMapping(value="/testCookieValue")
public String testCookieValue(@CookieValue(value="JSESSIONID") String cookieValue){
System.out.println("执行了...");
System.out.println(cookieValue);
return "success";
}
@ModelAttribute
-
作用:
- 用于修饰方法或者参数,如果修饰方法,那么该方法(有无返回值均可)会在控制器方法之前执行;如果修饰参数,可以获取指定的数据并赋值给参数。当表单提交的数据不是完整的实体类数据时,我们就可以借助该注解,对空属性进行预处理(譬如赋值为数据库记录中该对象原本的值)。
-
属性:
value
: 用于获取数据的key
,key
可以是POJO
类的属性名称,也可以是Map
集合的key
-
jsp代码:
<!-- ModelAttribute注解 -->
<form action="anno/testModelAttribute" method="post">
用户姓名:<input type="text" name="uname" /><br/>
用户年龄:<input type="text" name="age" /><br/>
<input type="submit" value="提交" />
</form>
- 控制器代码(
@ModelAttribute
修饰的方法带返回值)
/**
* ModelAttribute注解
* @return
*/
@RequestMapping(value="/testModelAttribute")
public String testModelAttribute(User user){
System.out.println("testModelAttribute执行了...");
System.out.println(user);
return "success";
}
//带返回值,对提交数据进行预处理
@ModelAttribute
public User showUser(String uname){
System.out.println("showUser执行了...");
// 通过用户查询数据库(模拟)
User user = new User();
user.setUname(uname);
user.setAge(20);
user.setDate(new Date());
return user;
}
- 控制器代码(
@ModelAttribute
修饰的方法不带返回值)
/**
* ModelAttribute注解
* @return
*/
@RequestMapping(value="/testModelAttribute")
public String testModelAttribute(@ModelAttribute("abc") User user){
System.out.println("testModelAttribute执行了...");
System.out.println(user);
return "success";
}
//不带返回值,将数据放入 Map 集合中
@ModelAttribute
public void showUser(String uname, Map<String,User> map){
System.out.println("showUser执行了...");
// 通过用户查询数据库(模拟)
User user = new User();
user.setUname(uname);
user.setAge(20);
user.setDate(new Date());
map.put("abc",user);
}
@SessionAttributes
-
作用:
- 可以将数据存入
Session
域,使得数据在多次执行控制器方法的时候共享,只能作用在类上。
- 可以将数据存入
-
属性:
value
: 用于指定存入的属性名称type
: 用于指定存入的数据类型
-
jsp代码:
<!-- SessionAttributes注解 -->
<a href="anno/testSessionAttributes">testSessionAttributes</a>
<a href="anno/getSessionAttributes">getSessionAttributes</a>
<a href="anno/delSessionAttributes">delSessionAttributes</a>
- 控制器代码
/**
* 常用的注解
*/
@Controller
@RequestMapping("/anno")
@SessionAttributes(value={"msg"}) // 把msg=美美存入到session域对中
public class AnnoController {
/**
* SessionAttributes的注解
* @param model
* @return
*/
@RequestMapping(value="/testSessionAttributes")
public String testSessionAttributes(Model model){
System.out.println("testSessionAttributes...");
// 底层会存储到request域对象中
model.addAttribute("msg","美美");
return "success";
}
/**
* 获取值
* @param modelMap
* @return
*/
@RequestMapping(value="/getSessionAttributes")
public String getSessionAttributes(ModelMap modelMap){
System.out.println("getSessionAttributes...");
String msg = (String) modelMap.get("msg");
System.out.println(msg);
return "success";
}
/**
* 清除
* @param status
* @return
*/
@RequestMapping(value="/delSessionAttributes")
public String delSessionAttributes(SessionStatus status){
System.out.println("getSessionAttributes...");
status.setComplete();
return "success";
}
}
最后
以上就是虚幻猎豹为你收集整理的SSM之SpringMVC系列(二)---- 请求参数的绑定和常用的注解请求参数的绑定常用注解的全部内容,希望文章能够帮你解决SSM之SpringMVC系列(二)---- 请求参数的绑定和常用的注解请求参数的绑定常用注解所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复