SpringMVC实现数据绑定与传参
Posted 阿涛编程笔记
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SpringMVC实现数据绑定与传参相关的知识,希望对你有一定的参考价值。
1.1 URL绑定
@ReqeustMapping(value="/test/info", method=GET)
用于绑定Controller中的方法与对应的URL,默认可接受Get /Post请求,也可以用method进行限定。但是有更针对性的 @GetMapping
和 @PostMapping
,因此 @ReqeustMapping
主要用于在类层面添加注解,用于设置这个类下所有访问方法的URL前缀。
1.2 Controller接收请求参数
1.2.1原始的键值对直接传递,保证属性名相同即可
前端
<form action="/um/p" method="post">
<input name = "username"></br>
<input name = "password"></br>
<input type = "submit" value="提交"></br>
</form>
后端
@RequestMapping("/um")
public clss URLMappingController {
@PostMapping("/p")
@ResponseBody
public String postMapping(String username, Sring password){
}
}
SpringMVC
还可以进行自动类型转换,比如前端传的密码是数字,后端可以用Long接收,可以支持自动类型转换,但是如果前端密码是 "abcd",后端 Long password
就会报 400 错误,类型转换异常。因此出现400转换异常通常就是 前端表单验证不严导致的类型参数传递类型转换异常。
1.2.2 @RequestParam的使用
如果参数名无法保持一致,比如前端属性名是 user_name
,那么后端接收也要用同样的属性名,如此会违反驼峰命名变量名的规则,此时可以用 @RequestParam
使用别名来绑定。而且前端传来的复杂数据比如多选框的数据,后端如果用List和Map集合类型的属性,也必须用 @RequestParam
来修饰,这样SpringMVC才能正确识别并接收。此外@RquestParam
还可以设置默认值,即前端没有限制某个数据强制必填时或者表单匿名提交时,后端如何设置该参数的默认值(如下代码①位置所示)。
前端:复杂表单
<div class="container">
<h2>学员调查问卷</h2>
<form action="./apply" method="post">
<h3>您的姓名</h3>
<input name="name" class="text" style="width: 150px">
<h3>您正在学习的技术方向</h3>
<select name="course" style="width: 150px">
<option value="java">Java</option>
<option value="h5">html5</option>
<option value="python">Python</option>
<option value="php">PHP</option>
</select>
<div>
<h3>您的学习目的:</h3>
<input type="checkbox" name="purpose" value="1">就业找工作
<input type="checkbox" name="purpose" value="2">工作要求
<input type="checkbox" name="purpose" value="3">兴趣爱好
<input type="checkbox" name="purpose" value="4">其他
</div>
<div style="text-align: center;padding-top:10px" >
<input type="submit" value="提交" style="width:100px">
</div>
</form>
</div>
后端:
@Controller
public class FormController {
// ① @RequestParam可以设置当前端没有传参时的后端接收的默认值,如下 name会默认为 "ANON"
// @PostMapping("/apply")
@ResponseBody
public String apply(@RequestParam(value = "n",defaultValue = "ANON") String name, String course, Integer[] purpose){
System.out.println(name);
System.out.println(course);
for (Integer p : purpose) {
System.out.println(p);
}
return "SUCCESS";
}
// @RquestParam 修饰 List
// @PostMapping("/apply")
@ResponseBody
public String apply(String name, String course, @RequestParam List<Integer> purpose){
System.out.println(name);
System.out.println(course);
for (Integer p : purpose) {
System.out.println(p);
}
return "SUCCESS";
}
//用实体类来接收(只有在Post请求才会生效)
// ② @PostMapping("/apply")
@ResponseBody
public String apply(Form form){
return "SUCCESS";
}
// @RquestParam 修饰 Map
// @PostMapping("/apply")
@ResponseBody
public String apply(@RequestParam Map map){
System.out.println(map);
return "SUCCESS";
}
}
如果前端表单参数过多,比如有两个以上,可以用 Map来接收,但是会存在数据丢失的问题:在上面例子中,前端 name=purpose 多选框的数组数据 如果用Map接收只会保存选中的数组中的第一个数据,导致数据丢失。因此,这种结构化数据封装成实体类接收更为规范。但是用实体类接收,切记必须在Post请求下(如上代码②位置所示)。
1.2.3 @RequestBody
这里背景知识涉及到 Content-type
的类型,可以参考Conten-Type 和 MIME 以及 Content-Type几种主要类型
简而言之: Content-type
就是 请求和响应头中表明 信息主体以哪种格式编码的,主要的有:
- application/x-www-form-urlencoded:早些年原始Html表单提交 Post请求时默认使用的 Content-type,提交的数据按照 key1=val1&key2=val2 的方式进行编码,key和val都进行了URL转码;
- multipart/form-data:表单中存在上传的文件时 form 指定的 enctype;
- application/json:ajax以及后续的vue.js(axios) ,越来越多使用 application/json来编码消息;
- text/xml:一种使用 HTTP 作为传输协议,XML 作为编码方式的远程调用规范。
首先明确一点,一开始还是 Html简单页面的时候 表单发送Post请求,则请求的 content-type默认是application/www-urlencode。如果 SpringMVC后端使用某个类来接收,则后端传参时不需要添加 @RequestBody。但是如果 content-type=application/json 或者有文件上传的表单时,则必须使用 @RequestBody来修饰接收类。而现在的Vue.js前端框架搭配 axios(ajax变体) 实现表单传参都默认用 application/json的方式,所以Java后端实体类获取参数都必须前面加上 @RequestBody。 上述的演化历程可以参考 vue的axios使用时,Content-Type 引发的参数接收不到的问题回顾。
1.2.4 关联对象赋值
当前端表单如下:
<!--原始-->
<div>
<input name="username">
<input name="password">
<!---------------------->
<input name="name">
<input name="idno">
<input name="expire">
</div>
<!--与后端类匹配之后,进行针对性修改-->
<div>
<input name="username">
<input name="password">
<!---------------------->
<input name="idcard.name">
<input name="idcard.idno">
<input name="idcard.expire">
</div>
按照面向对象的涉及原则,在设计接收的实体类时,应该如下:
## User.java
public class User {
private String userName;
private String password;
private IDcard idcard = new IDcard();
}
## IDcard.java
public class IDcard {
private String name;
private String idno;
private Date expire;
}
由此可以将前端的表单的值准确的传递到User类的普通属性以及关联对象中。
1.2.5 @PathVariable注解
@PathVariable 用于获取 url中的路径变量
@GetMapping("/api/employees/{id}")
@ResponseBody
public String getEmployeesById(@PathVariable String id) {
return "ID: " + id;
}
## 直接指定,类似与 @RequestParam使用别名
@GetMapping("/api/employeeswithvariable/{id}")
@ResponseBody
public String getEmployeesByIdWithVariableName(@PathVariable("id") String employeeId) {
return "ID: " + employeeId;
}
## 多个变量
@GetMapping("/api/employees/{id}/{name}")
@ResponseBody
public String getEmployeesByIdAndName(@PathVariable String id, @PathVariable String name) {
return "ID: " + id + ", name: " + name;
}
1.2.6 时间类型参数的单个和全局转换
单个转换
@DateTimeFormat可以接收前端指定格式的表示时间的字符串格式的参数,并在后端解析成 Date类型或者LocalDate类型对应的属性。
## 解析前端传来的 "2021-10-01", 为Date类型
@PostMapping("/p1")
@ResponseBody
public String postMapping1(User user , String username ,@DateTimeFormat(pattern = "yyyy-MM-dd") Date createTime){
System.out.println(user.getUsername() + ":" + user.getPassword());
return "<h1>这是Post响应</h1>";
}
## 实体类接收,对应属性田间 @DateTimeFormat注解
public class User {
private String username;
private Long password;
@DateTimeFormat(pattern = "yyyy-MM-dd")
private Date createTime;
}
(BTW: 后端往前端转可以添加 @JsonFormat来实现自动转)
全局设置
如果要全局设置,需要自己写一个自定义转换器类:
public class MyDateConverter implements Converter<String, Date> {
public Date convert(String s) {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
try {
Date d = sdf.parse(s);
return d;
} catch (ParseException e) {
return null;
}
}
}
在applicationContext.html中添加以下代码添加到容器中
<mvc:annotation-driven conversion-service="conversionService">
</mvc:annotation-driven>
<bean id="conversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
<property name="converters">
<set>
<bean class="com.imooc.springmvc.converter.MyDateConverter"/>
</set>
</property>
</bean>
此时,后端获取到前端的表示时间的格式为 "yyyy-MM-dd" 的字符串就会自动转换为Date类型。单个与全局的设置,应该是互相搭配和补充。
以上是关于SpringMVC实现数据绑定与传参的主要内容,如果未能解决你的问题,请参考以下文章