您现在的位置是:首页 >技术杂谈 >Spring【Again】——复杂POJO的绑定网站首页技术杂谈
Spring【Again】——复杂POJO的绑定
简单介绍:
Again系列是将之前的内容我认为做的不好的地方或者是理解不到位的地方再来一次,加深记忆或者改错。我们就在来复习一下之前我们说过的复杂类型的数据绑定。
先来复习一下简单数据绑定:
简单数据绑定就是我们在传递参数的时候,传递的参数数量很少,数据类型单一,基本就是一两个的基本数据类型的时候才会用到,我们举个例子:
做一个简单的案例,首先我们创建一个空的项目,然后通过发送一个带有参数的请求,然后在Controller中接受这个参数的案例来介绍简单的数据绑定需要做什么:
创建一个Controller:
package com.Spring.controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/users")
public class UserController {
@GetMapping
public String select(String username){
System.out.println(username);
return username;
}
}
这是一个接受请求参数的Controller,参数名叫做username,类型是String。当请求成功之后会将请求中的参数返回到请求端,并且在控制台上打印。
然后我们发送一个请求:
我们的请求参数是张三,那么我们看到返回的值肯定也是张三,并且在控制台打印的就是张三,简单的数据绑定的格式和方式都很简单。
这种简单的方式适用于参数很少,一般也就一两个,并且类型简单的数据。如果是多个数据,我们一般会将它绑定到Java类上,这种方式叫做POJO绑定:
POJO绑定:
我们先创建一个封装数据的POJO类:
package com.Spring.pojo;
import lombok.Data;
@Data
public class user {
private String name;
private String password;
}
然后是发送请求的Controller
// POJO绑定
@GetMapping("/ByUser")
public String selectUser(user user){
System.out.println(user.toString());
return user.toString();
}
我接下来写的所有的controller都会只写方法体,如果想要自己验证,可以随便粘贴放在类中,然后通过映射路径访问即可。
然后我们请求一下POJO绑定的路径:
这里还是注意一下我们请求的时候的参数,参数名要和类中的属性名一样才能被接受,如果参数名和属性名不一样,需要通过属性进行指定,否则无法自动接收。
核心思想:
其实在一开始的时候,我们就要对这个参数有一个明确的认知,这个参数是什么,多个参数之间的关系是什么。对于前端浏览器来说,多个参数时间是松散的,可以是没有关系的,可以是单一的,对于前端来说,这个参数的格式对他们来说并不重要,只需要输入参数,然后发送到后端的controller就可以了,那么后端如何处理这个参数是我们要关心的事情,比如这个参数是什么类型,参数名是什么,参数要如何封装。
在现阶段,我们用来接收参数的对象,也就是这个东西:
这个方法中的参数user,我们就可以暂时先不把他理解成一个对象,理解成一个盒子,一个用来存放多个属性值的盒子,这个属性名和前端保持一致就可以了,这就是一个盒子,放了很多的数据,或者说多个数据存放到了一个盒子里面,为什么这个盒子是Java类,因为我们用的是Java做后端语言,操作Java类肯定是更方便一些。如果用别的语言肯定就是其他格式的盒子。
带着这种想法,我们剩下的就是怎么往盒子里面放数据了,其实格式非常的简单,因为我们现在学的前端的那些表单控件无法做到一次传递多个数据,也就是一个input标签只能传递一个数据,那么我们在传递的时候就可以通过精确定位某一个数据的形式,可丁可卯的把数据放到盒子里。
复杂数据类型绑定——数组:
数组类型的绑定适用于多个属性名相同,但是属性值不相同的,比如我们在使用多选功能的时候,我们一次性选择了多个,我们又想把多个数据存储在一起,那么就需要后台绑定的时候,将前端传递进来的数据绑定成数组,基本步骤如下:
1、定义一个前端表单,向后端传递多个参数名一样但是参数值不一样的数据。使用我们的多选框是最适合不过的了:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>首页</title>
</head>
<body>
<form action="http://localhost:8080/users/ByList" method="post">
<table>
<tr>
<th>选择</th> <th>学科</th>
</tr>
<tr>
<th><input type="checkbox" name="args" value="1"></th> <th>数学</th>
</tr>
<tr>
<th><input type="checkbox" name="args" value="2"></th> <th>语文</th>
</tr>
<tr>
<th><input type="checkbox" name="args" value="3"></th> <th>英语</th>
</tr>
<tr>
<td><input type="submit" value="提交"></td>
</tr>
</table>
</form>
</body>
</html>
然后就是一个简单的只有一个复选框的表单,我们需要注意三个地方,第一个就是表单的提交路径,这个路径对应我们controller的映射地址,这个地址写错了你后面的controller铁定是接收不到数据。第二个就是表单的name,这个值对应我们controller中的方法的形参的变量名。最后就是value,这个值就是我们选中后将要填充进数组中的值,最后我们选中了几,就会看到他输出的是几,然后我们就来看后台的controller是如何写的:
// List数组绑定
@PostMapping("/ByList")
public Integer[] selectList(Integer [] args){
System.out.println(Arrays.toString(args));
return args;
}
其实跟之前一样的,只不过注意这个地方方法的形参的参数要和前端的表单中的input标签中的name的属性值保持一致,然后因为我们的表单提交是使用post方式,所以方法使用@PostMapping注解标注。
然后我们先启动程序,然后提交标签:
我们先全选,然后提交:
最后一行已经显示了我们选择的value值,然后我们少选一个:
按照我们的猜想,这次输出的数组中不会存在2:
合理,跟我们的猜想是一样,说明我们之前做的对的。
图示看起来非常的简单,在实际操作的时候也确实是很简单,毕竟数组就是一个可变的盒子,多一个少一个都无所谓,甚至没有都可以。
泛型为基本数据类型的绑定和之前的数组的绑定的格式是基本差不多的,唯一的区别就是在controller上作为参数接收的时候,需要加上一个@RequestParam,否则会导致一个报错,待会我们会演示这个报错并说明一下这个报错是如何形成的。
先给看一下后台的controller是如何写的,前端的页面是没有发生改变的,然后我们启动程序,向这个controller中发送一些参数:
我们选择跟之前一样的表单数据,然后观察他的返回值:
跟之前是一样的,也就是说格式不变,只不过参数的类型改变,以及添加了一个注释,那么这个注释如果不加会怎么样的?
现在我们删除这个注释,然后重启服务器,再次发送请求:
在控制台爆出了这么一个错误,这个错误的意思是找不到接口java.util.List的主构造函数或单个唯一构造函数,找不到构造函数,那么他是想干什么才会用到这个构造函数呢?他想创建一个List对象,但是接口不能直接创建对象,所以我们要用这个注解表示我们创建的其实不是List的集合,而是将我们接受到的参数作为一组数据存储到集合中,这个注解的作用就是指明我们传递进来的数据是要以何种类型存储。
复杂POJO绑定:
还记得之前我们说过的,对于数据绑定来说,我们的对象就是一个盒子,那么既然他是一个盒子,那么盒子就可以套盒子,那么有趣的地方就来了。所谓的复杂POJO是和简单POJO对比来的,简单POJO的属性都是简单数据类型,String虽然是对象,但是此处也暂时当简单数据类型。那么复杂POJO的属性可以是对象,可以是数组,可以是集合,可以是Map,可以是集合里面套数组,可以是集合里面套对象,可以是集合里面套对象套数组,可以是……
简单来说,复杂POJO的复杂就体现在我们现在的盒子不是打开就能看见数据了,是打开之后是盒子,盒子再打开才是数据,甚至盒子打开之后还是盒子,盒子打开之后开始盒子,然后才是数据,那就自己玩去吧。
我们就说集中常见的:
POJO属性是对象的情况:
我们先学思想,然后看图,最后看代码实现,如果能不看到代码就做出来,那就是学会了:
现在有一个类叫做A,然后A里面包含一个属性,这个属性是一个对象,叫做B,就像这样:
这是可以的吧,我的属性是一个对象,然后这个对象有自己的属性,那么我们怎么访问这个属性呢?
调用呗~回归到最基础的Java语法了,怎么调用啊?
A.B.name呗,是不是?如果忘记了我们就用代码写一写:
这是B他的属性都用基本数据类型,然后我们创建A:
为了做对比,我们在A里面除了B属性之外,再添加一个简单数据类型的属性,然后我怎么通过A获取B里面的数据啊?直接调用方法就行了:
我可以这么写吧,如果这里不理解,建议回去复习一下Java的语法,为什么要说到这个呢,因为前段传入数据的方式也是这么来的,只不过我们这里是调用方法,getB啊,getName啊,前端更方便,直接调用属性就行了:
注意看input标签的name属性,就直接用你要绑定的类的属性去调用就可以了,比如我的b属性是一个对象,b对象中包含name属性和age属性,那么就直接写“b.name”就可以将数据绑定到B属性的name属性上,然后我们看返回值:
是不是跟我们写的一样,id是普通数据类型, b是复杂数据类型,也就是对象,然后输出的格式就像上面是一样的。然后来看我们controller是怎么写的。
还有一个重要的地方就是,我们所有的数据绑定的这些写法,都是写在前端的,对我们的后端来说,Java类就是Java类,我们直接拿来用就可以了,这就是为什么我要用数据绑定的方式将数据放在盒子里,因为我们的Java操作盒子非常的简单。
其他方式:
其实道理都是一样的,其他的无非就是属性是LIst还是属性是Map,我把这两个的图画出来,然后简单的说一下,但是代码就不写了,如果看完之后还是不会写的,评论或者私信我,我单独发给你。
属性为List的,List的泛型是对象类型的:
通过数组的下标定位到集合中的元素,然后通过集合的元素调用对象的属性
属性为Map类型,Map值的泛型是B类型:
Map类型通过键查找对应的值,所以在插入的时候通知键查找到最对应的值,然后值包含多个属性,通过值找到对应的属性,完成赋值