文章目录
说明
请求参数的绑定说明
SpringMVC的参数绑定过程是把表单提交的请求参数,作为控制器中方法的参数进行绑定。一般来说要求请求参数名和方法参数名相同,但是也可以通过@RequestParam
注解指定请求参数的名称,然后绑定到其他名称的方法参数上
支持的数据类型
- 基本数据类型和字符串类型
- 实体类型(JavaBean)
- 集合数据类型(List,map集合等)
@RequestMapping
@RequestMapping
注解不仅可以指定映射的URL、请求方法等,它的params
属性还可以用来指定请求参数等
@Controller
@RequestMapping(path="/user")
public class HelloController {
@RequestMapping(path="/hello")
public String sayHello(){
System.out.println("Hello StringMVC");
return "success";
}
// 对于params要求的参数,可以是URL携带的,也可以是POST请求中放到请求体中的参数
// params属性表明请求必须携带username参数
// @RequestMapping(value="/testRequestMapping",params = {"username"},method = RequestMethod.POST)
// 请求必须携带username参数,并且值必须是hh
@RequestMapping(value="/test1",params = {"username=hh"},method = RequestMethod.POST)
public String test1(){
System.out.println("测试RequestMapping注解...post");
return "success";
}
// 可以存在相同的URI,只要请求方式不同就行
// headers参数表示必须携带的请求头
@RequestMapping(value="/test1",params = {"username=hh"},headers = {"Accept"})
public String test2(){
System.out.println("测试RequestMapping注解...");
return "success";
}
// 请求必须携带username参数,并且值不能是hh
@RequestMapping(value="/test3",params = {"username!hh"},method = RequestMethod.POST)
public String test3(){
System.out.println("测试RequestMapping注解...post");
return "success";
}
}
基本数据类型和字符串类型
直接将方法参数名和请求参数名一 一对应,参数放在URL或者请求体中都可以
对于get请求,需要把参数放到url上注解才生效,否则得到的参数值是null
对于post请求,如果把参数放到了请求体上(当然,你也可以把参数放到url上,只是这样做不符合规范),请求参数格式需要设置成contentType:"application/x-www-form-urlencoded"
,如果是contentType: "application/json;charset-UTF-8"
等其他类型,得到的参数值是null
通过反射的方式,当testParam方法中有名为username和password的参数时,会将请求参数username和password分别赋值给testParam方法中的参数。
ParamController.java
@Controller
@RequestMapping("/param")
public class ParamController {
@RequestMapping("/testParam")
public String testParam(String username,String password){
System.out.println("执行了...");
System.out.println("用户名:"+username);
System.out.println("密码:"+password);
return "success";
}
}
index.jsp
<a href="param/testParam?username=www&password=123">绑定一般类型</a>
把请求参数封装到JavaBean中
直接用一个JavaBean作为方法参数接收就行
对于get请求,需要把参数放到url上注解才生效,,否则得到的JavaBean属性都是null
对于post请求,如果把参数放到了请求体上(当然,你也可以把参数放到url上,只是这样做不符合规范),请求参数格式需要设置成contentType:"application/x-www-form-urlencoded"
,如果是contentType: "application/json;charset-UTF-8"
等其他类型,否则得到的JavaBean属性都是null
基本原理是调用setUsername()、setPassword()、setMoney()方法将请求参数username、password、money赋值给Account 对象的三个属性,再调用user.setUname()、user.setAge()将请求参数user.uname和user.age赋值给user对象的属性。请求参数名和对象中的属性名要相同才能找到set方法。
Account.java
public class Account implements Serializable{
private String username;
private String password;
private Double money;
// 这里还有个引用类型
private User user;
//生成getter和setter方法
//生成toString方法
}
User.java
public class User implements Serializable{
private String uname;
private Integer age;
//生成getter和setter方法
//生成toString方法
}
index.jsp
<%--html标签的name属性要和后端JavaBean的属性名相同--%>
<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="提交" />
</form>
ParamController.java
@Controller
@RequestMapping("/param")
public class ParamController {
@RequestMapping("/saveAccount")
public String saveAccount(Account account){
System.out.println("执行了...");
System.out.println(account);
return "success";
}
}
把请求参数封装到JavaBean中-包含集合类型的属性
直接用一个JavaBean作为方法参数接收就行
Account.java
public class Account implements Serializable{
private String username;
private String password;
private Double money;
//包含集合类型的属性
private List<User> list;
private Map<String,User> map;
//生成getter和setter方法
//生成toString方法
}
User.java
public class User implements Serializable{
private String uname;
private Integer age;
//生成getter和setter方法
//生成toString方法
}
index.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/>
<%--list[0].uname和list[0].age表示把uname和age的值赋值给user对象的属性,然后把user对象存到集合的0号位置--%>
用户姓名:<input type="text" name="list[0].uname" /><br/>
用户年龄:<input type="text" name="list[0].age" /><br/>
<%--map['one'].uname和map['one'].age表示把uname和age的值赋值给user对象的属性,然后把键为'one',值为user对象的键值对存到map集合中--%>
用户姓名:<input type="text" name="map['one'].uname" /><br/>
用户年龄:<input type="text" name="map['one'].age" /><br/>
<input type="submit" value="提交" />
</form>
@RequestParam
用于规定请求参数的名称、是否必须存在。一个方法中可以有多个@RequestParam注解。get和post方式都可用
对于get请求,需要把参数放到url上注解才生效,否则会报错400
对于post请求,如果把参数放到了请求体上(当然,你也可以把参数放到url上,只是这样做不符合规范),请求参数格式需要设置成contentType:"application/x-www-form-urlencoded"
,如果是contentType: "application/json;charset-UTF-8"
等其他类型,会报错400
属性:
- value/name:请求参数中的参数名
- required:请求参数中是否必须提供此参数
// name属性也可以替换成value属性,表示请求参数必须有uname,并把参数值赋值给username参数
// required默认是true,表示请求必须待这个参数,取值false表示可以没有该参数,然后把参数值设置为null
@RequestMapping("/test")
public String test(@RequestParam(name="uname", required = false) String username){
System.out.println("执行了...");
System.out.println(username);
return "success";
}
@RequestBody
用于获取请求体内容。一个方法中只能有一个@RequestBody注解。
属性:
required:默认是true,表示必须有请求体,所以get请求会报错;取值false,get请求得到的是null
对于post请求,请求参数格式需要设置成
application/json;charset-UTF-8"
,否则会报错“415 – 不支持的媒体类型”
(1)
<a href="anno/testRequestBody?uname=哈哈&age=12">RequestParam</a>
@RequestMapping("/testRequestBody")
public String testRequestBody(@RequestBody(required = false) String user){
System.out.println(user); //get请求,得到的值是null,如果不加required=false,则会报错
return "success";
}
(2)
<form action="anno/testRequestBody" method="post">
用户姓名:<input type="text" name="uname" /><br/>
用户年龄:<input type="text" name="age" /><br/>
<input type="submit" value="提交" />
</form>
@RequestMapping("/testRequestBody")
public String testRequestBody(@RequestBody String user){
System.out.println(user); //以字符串形式接受数据uname=1&age=1
return "success";
}
(3)将请求的json字符串映射成JavaBean参数
需要引入jar包:
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.0</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.9.0</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.9.0</version>
</dependency>
<script>
// 页面加载,绑定单击事件
$(function(){
$("#btn").click(function(){
$.ajax({
url:"testAjax",
contentType:"application/json;charset=UTF-8",
//data:'{"username":"张三","password":"123","age":30}',
data:JSON.stringify({"username":"张三","password":"123","age":30}),
dataType:"json",
type:"post",
success:function(data){
// data服务器端响应的json的数据,进行解析
alert(data);
alert(data.username);
alert(data.password);
}
});
});
});
</script>
@RequestMapping("/testAjax")
public @ResponseBody User testAjax(@RequestBody User user){
// 客户端发送ajax的请求,传的是json字符串,后端把json字符串封装到user对象中
user.setUsername("李四");
user.setAge(40);
// 返回user对象,因为有@ResponseBody注解,框架会自动将该对象的属性转成json字符串
return user;
}
@PathVariable
用于支持Restful风格的URL,绑定url中的占位符,例如请求url中/delete/{id}
,这个{id}就是url占位符
属性:
- value:指定url中的占位符
- required:是否必须提供占位符
原来的方式:
restful风格的方式(即使path相同,请求方式不同,会根据请求方式映射到不同的方法中):
根据id查询,传统方式写法是“user?id=10”:
例:
<a href="anno/testPathVariable/10">testPathVariable</a>
//name属性用于指定把url中的占位符sid的值取出来赋值给id参数
@RequestMapping(value="/testPathVariable/{sid}")
public String testPathVariable(@PathVariable(name="sid") String id){
System.out.println(id);
return "success";
}
@RequestHeader
用于获取请求消息头信息
//获取Accept请求头的值
@RequestMapping(value="/testRequestHeader")
public String testRequestHeader(@RequestHeader(value="Accept") String header, HttpServletRequest request,HttpServletResponse response) throws IOException {
System.out.println(header);
return "success";
}
@ModelAttribute
- 用在方法上,表示该方法会在控制器的方法执行之前先执行
- 用在参数上,获取指定的数据给参数赋值
@RequestMapping(value="/testModelAttribute")
public String testModelAttribute(@ModelAttribute("abc") User user){
System.out.println("testModelAttribute执行了...");
System.out.println(user);
return "success";
}
// 在执行testModelAttribute()方法之前,这个方法会先执行
// 应用场景就是,如果我们在编辑一个用户信息时,我们只传递了用户名和年龄到后台,没有日期,那这个日期字段对
// 应的属性就是null,而我们期望的是修改的时候,这个字段用原本数据库中的字段,那这个注解就能解决这个问题
// 假如请求参数是uname=‘hh’,age=10;而数据库中这条记录对应的是uname=‘sl’,age=20,data=‘3030-05-02’,那么在testModelAttribute()方法中,user参数对应的值就是uname=‘hh’,age=10,data=‘3030-05-02’
@ModelAttribute
public void showUser(String uname, Map<String,User> map){
System.out.println("showUser执行了...");
// 模拟从数据库中查到这个用户
User user = new User();
user.setUname(‘hh’);
user.setAge(20);
user.setDate(new Date());
map.put("abc",user);
}
// 也可以是这种写法
@ModelAttribute
public User showUser(String uname){
System.out.println("showUser执行了...");
// 模拟从数据库中查到这个用户
User user = new User();
user.setUname(‘hh’);
user.setAge(20);
user.setDate(new Date());
return user;
}
解决post请求中文乱码
SpringMVC框架提供的请求参数过滤器,在web.xml中添加过滤器:
<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>
自定义类型转换器
一般类型,如Account中有一个为Integer类型的属性,请求参数是字符串类型,则框架会自动将字符串类型转为整型。但是也有转换异常的情况,如Account有一个为Data类型的属性,只有请求参数字符串是’xxxx/xx/xx’格式的时候才会正常转换成Data类型,'xxxx-xx-xx’格式则不会转换成功,因此这时候就需要我们自定义类型转换器。
SpringMVC框架是一个基于组件的框架,我们可以编写一个类型转换器,然后在resources/springmvc.xml文件中配置这个类型转换器类,当需要类型转换的时候,前端控制器会找到类型转换器帮助我们完成类型转换。
Converter是类型转换的总接口,所有自定义的类型转换器类都必须实现这个接口。
StringToDateConverter.java
/**
* 把字符串转换日期
*/
public class StringToDateConverter implements Converter<String,Date>{
/**
* String source 传入进来字符串
* @param source
* @return
*/
public Date convert(String source) {
System.out.println("lxzh");
// 判断
if(source == null){
throw new RuntimeException("参数不能为空");
}
DateFormat df = new SimpleDateFormat("yyyy-MM-dd");
try {
// 把字符串转换日期
return df.parse(source);
} catch (Exception e) {
throw new RuntimeException("数据类型转换出现错误");
}
}
}
resources/springmvc.xml
<!--其它配置...-->
<!--配置自定义类型转换器-->
<bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
<property name="converters">
<set>
<bean class="cn.ith.utils.StringToDateConverter"/>
</set>
</property>
</bean>
<!--开启springmvc框架注解的支持,并开启类型转换器-->
<mvc:annotation-driven conversion-service="conversionService"/>
<!--其它配置...-->
这样,当Account中有一个为Data的属性,为这个属性赋值的时候,就会调用类型转换器类将"xxxx-xx-xx"转换成正确的日期类型。应该注意的是,框架默认的将"xxxx/xx/xx"格式字符串转成日期类型将不再起作用。