李林超博客
首页
归档
留言
友链
动态
关于
归档
留言
友链
动态
关于
首页
Java
正文
05.MyBatis自定义映射resultMap
Leefs
2022-12-08 AM
1241℃
0条
[TOC] ### 前言 如果从数据库查询出来的数据无法直接映射到实体类对象,那么就可以通过自定义映射来解决这个问题。 ### 一、准备工作 #### 1.1 创建表 创建两个员工表格`t_emp`和`t_dept` + **职员表(t_emp)** ```sql CREATE TABLE `t_emp` ( `eid` int(11) NOT NULL AUTO_INCREMENT, `emp_name` varchar(255) DEFAULT NULL, `age` int(11) DEFAULT NULL, `sex` varchar(255) DEFAULT NULL, `email` varchar(255) DEFAULT NULL, `did` int(11) DEFAULT NULL, PRIMARY KEY (`eid`) ) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8; INSERT INTO `t_emp` VALUES (1, '张三', 23, '男', '123@qq.com', 1); INSERT INTO `t_emp` VALUES (2, '李四', 22, '男', '12@qq.com', 2); INSERT INTO `t_emp` VALUES (3, '王五', 33, '女', '23@qq.com', 3); INSERT INTO `t_emp` VALUES (4, '赵六', 25, '女', '32@qq.com', 1); INSERT INTO `t_emp` VALUES (5, '田七', 31, '男', '34@qq.com', 2); ``` + **部门表(t_dept)** ```sql CREATE TABLE `t_dept` ( `did` int(11) NOT NULL AUTO_INCREMENT, `dept_name` varchar(255) DEFAULT NULL, PRIMARY KEY (`did`) ) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8; INSERT INTO `t_dept` VALUES (1, 'A'); INSERT INTO `t_dept` VALUES (2, 'B'); INSERT INTO `t_dept` VALUES (3, 'C'); ``` 职员表(t_emp)和部门表(t_dept)之间为多对一关系,多个职员可以同属于一个部门,即一个部门可以包含多个职员。 #### 1.2 创建实体类 + **Emp** ```java public class Emp { private Integer eid; private String empName; private Integer age; private String sex; private String email; private Dept dept; ...... } ``` + **Dept** ```java public class Dept { private Integer did; private String deptName; private List
emps; ...... } ``` GET、SET方法和toString方法将省略 ### 二、resultMap处理字段和属性的映射关系 > 若字段名和属性名不一致,则查询的结果中,属性名和字段名不一致的属性值为null 若字段名和实体类中的属性名不一致,但是字段名符合数据库的规则(使用`_`),实体类中的属性名符合Java的规则(使用驼峰)如字段名`user_name`,属性名`userName`。 #### 2.1 解决办法一:在 SQL 语句中起别名 + **在 `EmpMapper` 添加方法** ```java /** * 查询所有的员工信息 */ List
getAllEmp(); ``` + **在 `EmpMapper.xml` 添加 SQL 语句** ```xml
select eid, emp_name empName, age, sex, email from t_emp
``` + **测试方法** ```java @Test public void testGetAllEmp(){ SqlSession sqlSession = SqlSessionUtils.getSqlSession(); EmpMapper mapper = sqlSession.getMapper(EmpMapper.class); List
list = mapper.getAllEmp(); list.forEach(emp -> System.out.println(emp)); } ``` **运行结果** ``` Emp{eid=1, empName='张三', age=23, sex='男', email='123@qq.com', dept=null} Emp{eid=2, empName='李四', age=22, sex='男', email='12@qq.com', dept=null} Emp{eid=3, empName='王五', age=33, sex='女', email='23@qq.com', dept=null} Emp{eid=4, empName='赵六', age=25, sex='女', email='32@qq.com', dept=null} Emp{eid=5, empName='田七', age=31, sex='男', email='34@qq.com', dept=null} ``` #### 2.2 解决办法二:在核心配置文件的 settings 标签设置全局配置 + **在核心配置文件 `mybatis-config.xml` 中的 settings 标签进行设置** ```xml
``` *注意:settings 标签要在 properties 标签之后* + **SQL 语句取消设置别名** ```xml
select * from t_emp
``` + **测试输出结果** ``` Emp{eid=1, empName='张三', age=23, sex='男', email='123@qq.com', dept=null} Emp{eid=2, empName='李四', age=22, sex='男', email='12@qq.com', dept=null} Emp{eid=3, empName='王五', age=33, sex='女', email='23@qq.com', dept=null} Emp{eid=4, empName='赵六', age=25, sex='女', email='32@qq.com', dept=null} Emp{eid=5, empName='田七', age=31, sex='男', email='34@qq.com', dept=null} ``` 测试代码和解决办法一相同。 #### 2.3 解决办法三:使用 resultMap + **在 `EmpMapper.xml` 设置 resultMap 并更改 SQL 语句** ```xml
select * from t_emp
``` **属性说明** **父级标签** 1. `resultMap`:设置自定义映射关系 2. `id`:唯一标识,不能重复 3. `type`:设置映射关系中的实体类类型【就是查询结果给那个`JavaBean`赋值】 **子标签** 1. `id`:设置主键的映射关系 2. `result`:设置普通字段映射关系 属性: + `property`:设置映射关系中的属性名,必须是`type`属性所设置的实体类类型中的属性名【就是`type`设置`JavaBean`类中的属性】 + `column`:设置映射关系中字段名,必须是`sql`语句查询出字段名【就是查询语句中的字段】 注意:将 `mybatis-config.xml` 的 settings 标签注释掉,方便进行测试 + **测试输出结果** ``` Emp{eid=1, empName='张三', age=23, sex='男', email='123@qq.com', dept=null} Emp{eid=2, empName='李四', age=22, sex='男', email='12@qq.com', dept=null} Emp{eid=3, empName='王五', age=33, sex='女', email='23@qq.com', dept=null} Emp{eid=4, empName='赵六', age=25, sex='女', email='32@qq.com', dept=null} Emp{eid=5, empName='田七', age=31, sex='男', email='34@qq.com', dept=null} ``` ### 三、多对一映射处理 > 多对一关系:就是表A中多条数据对应表B中的一条数据,例如,员工和部门之间的关系,多名员工可以属于同一部门 #### 3.1 方法一:使用 resultMap 级联属性赋值 + **在 EmpMapper 接口添加方法** ```java /** * 查询员工以及员工所对应的部门信息 */ Emp getEmpAndDept(@Param("eid") Integer eid); ``` + **在 `EmpMapper.xml` 添加 SQL 语句** ```xml
select * from t_emp left join t_dept on t_emp.did = t_dept.did where t_emp.eid = #{eid}
``` 两表联查之后直接将did,`deptName`部门属性赋值给员工对象中的成员变量dept,通过`dept.did`,`dept.deptName`这种方式就可以指定要为成员变量的哪一个属性来进行赋值 + **测试代码** ```java @Test public void testGetEmpAndDept(){ SqlSession sqlSession = SqlSessionUtils.getSqlSession(); EmpMapper mapper = sqlSession.getMapper(EmpMapper.class); Emp emp = mapper.getEmpAndDept(1); System.out.println(emp); } ``` **运行结果** ``` Emp{eid=1, empName='张三', age=23, sex='男', email='123@qq.com', dept=Dept{did=1, deptName='A', emps=null}} ``` #### 3.2 方式二:使用 association + **`EmpMapper.xml` 的 SQL 语句** ```xml
select * from t_emp left join t_dept on t_emp.did = t_dept.did where t_emp.eid = #{eid}
``` 先设置`javaTyp`属性是将查询到的字段值为`javaType`的`javabean`对象赋值,赋值完成后再将`javaType`赋值的对象给`propery`的属性赋值。 **属性说明** - **association**:处理多对一的映射关系 - **property**:需要处理多对一的映射关系的属性名(dept) - **javaType**:该属性的类型(Dept) - **子标签** + **id**:表示为`javaType`属性中的`Dept`的属性`id`值赋值 + **property**:表示为`javaType`属性中的`Dept`的属性赋值 + **测试运行结果** ``` Emp{eid=1, empName='张三', age=23, sex='男', email='123@qq.com', dept=Dept{did=1, deptName='A', emps=null}} ``` #### 3.3 方式三:分布查询与 association + **在 `EmpMapper` 接口添加分步查询的第一步** ```java /** * 通过分步查询查询员工以及员工所对应的部门信息 * 分步查询第一步:查询员工信息 */ Emp getEmpAndDeptByStepOne(@Param("eid") Integer eid); ``` + **在 `EmpMapper.xml` 添加 SQL 语句及 resultMap** ```xml
select * from t_emp where eid = #{eid}
``` + **在 DeptMapper 接口添加分步查询的第二步** ```java /** * 通过分布查询查询员工及其对应的部门信息 * 分布查询第二步:通过did查询员工所对应的部门信息 */ Dept getEmpAndDeptByStepTwo(@Param("did") Integer did); ``` + **在 `DeptMapper.xml` 添加 SQL 语句** ```xml
select * from t_dept where did = #{did}
``` + **测试方法** ```java @Test public void testGetEmpAndDeptByStep(){ SqlSession sqlSession = SqlSessionUtils.getSqlSession(); EmpMapper mapper = sqlSession.getMapper(EmpMapper.class); Emp empAndDeptByStepOne = mapper.getEmpAndDeptByStepOne(3); System.out.println(empAndDeptByStepOne); } ``` **运行结果** ``` [23:02:50.386] [DEBUG] [main] [com.atguigu.mybatis.mapper.EmpMapper.getEmpAndDeptByStepOne] [==> Preparing: select * from t_emp where eid = ?] [23:02:50.397] [DEBUG] [main] [com.atguigu.mybatis.mapper.EmpMapper.getEmpAndDeptByStepOne] [==> Parameters: 3(Integer)] [23:02:50.409] [DEBUG] [main] [com.atguigu.mybatis.mapper.DeptMapper.getEmpAndDeptByStepTwo] [====> Preparing: select * from t_dept where did = ?] [23:02:50.409] [DEBUG] [main] [com.atguigu.mybatis.mapper.DeptMapper.getEmpAndDeptByStepTwo] [====> Parameters: 3(Integer)] [23:02:50.416] [DEBUG] [main] [com.atguigu.mybatis.mapper.DeptMapper.getEmpAndDeptByStepTwo] [<==== Total: 1] [23:02:50.416] [DEBUG] [main] [com.atguigu.mybatis.mapper.EmpMapper.getEmpAndDeptByStepOne] [<== Total: 1] Emp{eid=3, empName='王五', age=33, sex='女', email='23@qq.com', dept=Dept{did=3, deptName='C', emps=null}} ``` **运行过程分析** 1. 先是第一步查询到的`did`【部门`id`】给第二步查询的条件赋值,使用的属性是`column` 2. 第二步查询到的结果给`Dept`对象赋值 3. 第三步是将第二的查询到的`Dept`对象值赋值给指定的属性 ### 四、一对多映射处理 > 一对多关系:就是表A中一条数据对应表B中的多条数据,例如,员工和部门之间的关系,一个部门可以有多个员工信息。 #### 4.1 方法一:使用 collection + **在 DeptMapper 接口添加方法** ```java /** * 获取部门及部门中所有的员工信息 */ Dept getDeptAndEmp(@Param("did") Integer did); ``` + **在 `DeptMapper.xml` 添加 SQL 语句和 resultMap** ```xml
select * from t_dept left join t_emp on t_dept.did = t_emp.did where t_dept.did = #{did}
``` 部门表左外连接员工表之后通过collection集合可以将查询出来的数据中关于员工信息的数据不断地循环赋值到emps员工集合之中。 + **测试方法** ```java @Test public void testGetDeptAndEmp(){ SqlSession sqlSession = SqlSessionUtils.getSqlSession(); DeptMapper mapper = sqlSession.getMapper(DeptMapper.class); Dept dept = mapper.getDeptAndEmp(1); System.out.println(dept); } ``` **运行结果** ``` [23:22:10.609] [DEBUG] [main] [com.atguigu.mybatis.mapper.DeptMapper.getDeptAndEmp] [==> Preparing: select * from t_dept left join t_emp on t_dept.did = t_emp.did where t_dept.did = ?] [23:22:10.624] [DEBUG] [main] [com.atguigu.mybatis.mapper.DeptMapper.getDeptAndEmp] [==> Parameters: 1(Integer)] [23:22:10.638] [DEBUG] [main] [com.atguigu.mybatis.mapper.DeptMapper.getDeptAndEmp] [<== Total: 2] Dept{did=1, deptName='A', emps=[Emp{eid=1, empName='张三', age=23, sex='男', email='123@qq.com', dept=null}, Emp{eid=4, empName='赵六', age=25, sex='女', email='32@qq.com', dept=null}]} ``` #### 4.2 方法二:分步查询 > 分步查询就是将一条`sql`语句,分成多步查询获取最终结果 **案例:查询指定部门信息及该部门的所有员工** + **在 DeptMapper 添加分步查询的第一步** ```java /** * 通过分步查询查询部门及部门中所有员工的信息 * 分步查询第一步:查询部门信息 */ Dept getDeptAndEmpByStepOne(@Param("did") Integer did); ``` + **在 `DeptMapper.xml` 添加SQL语句及 resultMap** ```xml
select * from t_dept where did = #{did}
``` **说明** + **collection**:标签用来指定需要映射回去的数据的类型并循环赋值 + **select**:标签用来指定第二步查询的方法位置 + **column**:指定查询的条件 先通过部门ID获取部门信息,然后通过第二步查询获取员工信息赋值给部门对象中的emps集合属性 + **在 EmpMapper 添加分步查询的第二步** ```java /** * 通过分步查询查询部门及部门中所有员工的信息 * 分步查询第二步:根据did查询员工信息 */ List
getDeptAndEmpByStepTwo(@Param("did") Integer did); ``` + **在 `EmpMapper.xml` 添加SQL语句** ```xml
select * from t_emp where did = #{did}
``` 通过部门ID查询员工信息并将返回的数据赋值给部门的emps员工集合属性 + **测试方法** ```java @Test public void testGetDeptAndEmpByStep(){ SqlSession sqlSession = SqlSessionUtils.getSqlSession(); DeptMapper mapper = sqlSession.getMapper(DeptMapper.class); Dept dept = mapper.getDeptAndEmpByStepOne(1); System.out.println(dept.getDeptName()); System.out.println("++++++++++++++++++++++++++++++++++++++++++++++++++++"); System.out.println(dept); } ``` **运行结果** ``` [23:38:52.410] [DEBUG] [main] [com.atguigu.mybatis.mapper.DeptMapper.getDeptAndEmpByStepOne] [==> Preparing: select * from t_dept where did = ?] [23:38:52.422] [DEBUG] [main] [com.atguigu.mybatis.mapper.DeptMapper.getDeptAndEmpByStepOne] [==> Parameters: 1(Integer)] [23:38:52.439] [DEBUG] [main] [com.atguigu.mybatis.mapper.EmpMapper.getDeptAndEmpByStepTwo] [====> Preparing: select * from t_emp where did = ?] [23:38:52.439] [DEBUG] [main] [com.atguigu.mybatis.mapper.EmpMapper.getDeptAndEmpByStepTwo] [====> Parameters: 1(Integer)] [23:38:52.457] [DEBUG] [main] [com.atguigu.mybatis.mapper.EmpMapper.getDeptAndEmpByStepTwo] [<==== Total: 2] [23:38:52.458] [DEBUG] [main] [com.atguigu.mybatis.mapper.DeptMapper.getDeptAndEmpByStepOne] [<== Total: 1] A ++++++++++++++++++++++++++++++++++++++++++++++++++++ Dept{did=1, deptName='A', emps=[Emp{eid=1, empName='张三', age=23, sex='男', email='123@qq.com', dept=null}, Emp{eid=4, empName='赵六', age=25, sex='女', email='32@qq.com', dept=null}]} ``` **运行过程分析** 1. 先是第一步查询到的`did`【部门id】给第二步查询的条件赋值,使用的属性是`column` 2. 第二步查询到的结果给`Emp`对象赋值 3. 第三步是将第二的查询到的`Dept`对象值赋值给指定的属性 ### 五、延迟加载 **分步查询的优点**:可以实现延迟加载,但是必须在核心配置文件中设置全局配置信息(在 settings 标签中进行设置) + **lazyLoadingEnabled**:延迟加载的全局开关。当开启时,所有关联对象都会延迟加载。这里需要设置为 true + **aggressiveLazyLoading**:当开启时,任何方法的调用都会加载该对象的所有属性。 否则,每个属性会按需加载。这里需要设置为 false(mybatis 版本小于等于3.4.1时,默认为 true,其他版本默认为 false,所以高版本可以不用设置) 此时就可以实现按需加载,获取的数据是什么,就只会执行相应的sql。此时可通过association和collection中的fetchType属性设置当前的分步查询是否使用延迟加载 ``` fetchType="lazy(延迟加载)|eager(立即加载)" ``` #### 5.1 区别一:按需加载 + **在没有开启延迟加载时,运行以下方法** ```java @Test public void testGetEmpAndDeptByStep(){ SqlSession sqlSession = SqlSessionUtils.getSqlSession(); EmpMapper mapper = sqlSession.getMapper(EmpMapper.class); Emp emp = mapper.getEmpAndDeptByStepOne(3); System.out.println(emp.getEmpName()); } ``` **运行结果** ``` [00:27:35.418] [DEBUG] [main] [com.atguigu.mybatis.mapper.EmpMapper.getEmpAndDeptByStepOne] [==> Preparing: select * from t_emp where eid = ?] [00:27:35.432] [DEBUG] [main] [com.atguigu.mybatis.mapper.EmpMapper.getEmpAndDeptByStepOne] [==> Parameters: 3(Integer)] [00:27:35.448] [DEBUG] [main] [com.atguigu.mybatis.mapper.DeptMapper.getEmpAndDeptByStepTwo] [====> Preparing: select * from t_dept where did = ?] [00:27:35.448] [DEBUG] [main] [com.atguigu.mybatis.mapper.DeptMapper.getEmpAndDeptByStepTwo] [====> Parameters: 3(Integer)] [00:27:35.454] [DEBUG] [main] [com.atguigu.mybatis.mapper.DeptMapper.getEmpAndDeptByStepTwo] [<==== Total: 1] [00:27:35.455] [DEBUG] [main] [com.atguigu.mybatis.mapper.EmpMapper.getEmpAndDeptByStepOne] [<== Total: 1] 王五 ``` 可以看到执行了两个 SQL 语句 + **在 `mybatis-config.xml` 开启延迟加载** ```xml
``` 然后再次运行上面的方法,输出结果如下 ``` [00:30:09.646] [DEBUG] [main] [com.atguigu.mybatis.mapper.EmpMapper.getEmpAndDeptByStepOne] [==> Preparing: select * from t_emp where eid = ?] [00:30:09.662] [DEBUG] [main] [com.atguigu.mybatis.mapper.EmpMapper.getEmpAndDeptByStepOne] [==> Parameters: 3(Integer)] [00:30:09.701] [DEBUG] [main] [com.atguigu.mybatis.mapper.EmpMapper.getEmpAndDeptByStepOne] [<== Total: 1] 王五 ``` 可以看到只执行了一个 SQL 语句。 #### 5.2 区别二:若需要执行第二个SQL语句,执行顺序不一样 若没有开启延迟加载,所有SQL语句是一起执行的 若开启了延迟加载,SQL 语句不是一起执行 + **若没有开启延迟加载,执行以下方法** ```java @Test public void testGetEmpAndDeptByStep(){ SqlSession sqlSession = SqlSessionUtils.getSqlSession(); EmpMapper mapper = sqlSession.getMapper(EmpMapper.class); Emp emp = mapper.getEmpAndDeptByStepOne(3); System.out.println(emp.getEmpName()); System.out.println("+++++++++++++++++++++++++++++++++++++"); System.out.println(emp.getDept()); } ``` **运行结果** ``` [00:36:25.023] [DEBUG] [main] [com.atguigu.mybatis.mapper.EmpMapper.getEmpAndDeptByStepOne] [==> Preparing: select * from t_emp where eid = ?] [00:36:25.038] [DEBUG] [main] [com.atguigu.mybatis.mapper.EmpMapper.getEmpAndDeptByStepOne] [==> Parameters: 3(Integer)] [00:36:25.052] [DEBUG] [main] [com.atguigu.mybatis.mapper.DeptMapper.getEmpAndDeptByStepTwo] [====> Preparing: select * from t_dept where did = ?] [00:36:25.052] [DEBUG] [main] [com.atguigu.mybatis.mapper.DeptMapper.getEmpAndDeptByStepTwo] [====> Parameters: 3(Integer)] [00:36:25.059] [DEBUG] [main] [com.atguigu.mybatis.mapper.DeptMapper.getEmpAndDeptByStepTwo] [<==== Total: 1] [00:36:25.059] [DEBUG] [main] [com.atguigu.mybatis.mapper.EmpMapper.getEmpAndDeptByStepOne] [<== Total: 1] 王五 +++++++++++++++++++++++++++++++++++++ Dept{did=3, deptName='C', emps=null} ``` 可以看到两条SQL语句是一起执行的 + **开启延迟加载,再次执行上面的方法** 输出结果如下: ``` [00:37:37.937] [DEBUG] [main] [com.atguigu.mybatis.mapper.EmpMapper.getEmpAndDeptByStepOne] [==> Preparing: select * from t_emp where eid = ?] [00:37:37.949] [DEBUG] [main] [com.atguigu.mybatis.mapper.EmpMapper.getEmpAndDeptByStepOne] [==> Parameters: 3(Integer)] [00:37:37.986] [DEBUG] [main] [com.atguigu.mybatis.mapper.EmpMapper.getEmpAndDeptByStepOne] [<== Total: 1] 王五 +++++++++++++++++++++++++++++++++++++ [00:37:37.987] [DEBUG] [main] [com.atguigu.mybatis.mapper.DeptMapper.getEmpAndDeptByStepTwo] [==> Preparing: select * from t_dept where did = ?] [00:37:37.987] [DEBUG] [main] [com.atguigu.mybatis.mapper.DeptMapper.getEmpAndDeptByStepTwo] [==> Parameters: 3(Integer)] [00:37:37.990] [DEBUG] [main] [com.atguigu.mybatis.mapper.DeptMapper.getEmpAndDeptByStepTwo] [<== Total: 1] Dept{did=3, deptName='C', emps=null} ``` 可以看到两条SQL语句不是同时执行 #### 5.3 开启全局的延迟加载后设置立即加载效果 + **在分步查询的 association 标签设置 fetchType** ```xml
select * from t_emp where eid = #{eid}
``` + **在开启了全局的延迟加载后,执行以下方法** ```java @Test public void testGetEmpAndDeptByStep(){ SqlSession sqlSession = SqlSessionUtils.getSqlSession(); EmpMapper mapper = sqlSession.getMapper(EmpMapper.class); Emp emp = mapper.getEmpAndDeptByStepOne(3); System.out.println(emp.getEmpName()); System.out.println("+++++++++++++++++++++++++++++++++++++"); System.out.println(emp.getDept()); } ``` **运行结果** ``` [00:41:10.954] [DEBUG] [main] [com.atguigu.mybatis.mapper.EmpMapper.getEmpAndDeptByStepOne] [==> Preparing: select * from t_emp where eid = ?] [00:41:10.966] [DEBUG] [main] [com.atguigu.mybatis.mapper.EmpMapper.getEmpAndDeptByStepOne] [==> Parameters: 3(Integer)] [00:41:10.979] [DEBUG] [main] [com.atguigu.mybatis.mapper.DeptMapper.getEmpAndDeptByStepTwo] [====> Preparing: select * from t_dept where did = ?] [00:41:10.979] [DEBUG] [main] [com.atguigu.mybatis.mapper.DeptMapper.getEmpAndDeptByStepTwo] [====> Parameters: 3(Integer)] [00:41:10.987] [DEBUG] [main] [com.atguigu.mybatis.mapper.DeptMapper.getEmpAndDeptByStepTwo] [<==== Total: 1] [00:41:10.988] [DEBUG] [main] [com.atguigu.mybatis.mapper.EmpMapper.getEmpAndDeptByStepOne] [<== Total: 1] 王五 +++++++++++++++++++++++++++++++++++++ Dept{did=3, deptName='C', emps=null} ``` 可以看到SQL语句一起执行了
标签:
MyBatis
非特殊说明,本博所有文章均为博主原创。
如若转载,请注明出处:
https://lilinchao.com/archives/2669.html
上一篇
04.MyBatis特殊SQL执行
下一篇
06.MyBatis动态SQL介绍
评论已关闭
栏目分类
随笔
2
Java
326
大数据
229
工具
31
其它
25
GO
47
NLP
4
标签云
Ubuntu
数学
国产数据库改造
JavaWEB项目搭建
Shiro
随笔
NIO
BurpSuite
SpringCloudAlibaba
VUE
Scala
Beego
Filter
Thymeleaf
Spark SQL
Azkaban
GET和POST
JavaScript
nginx
Docker
算法
MySQL
Yarn
Eclipse
JavaWeb
MyBatisX
Jenkins
链表
RSA加解密
锁
友情链接
申请
范明明
庄严博客
Mx
陶小桃Blog
虫洞
评论已关闭