在Mybatis中通过foreach遍历集合(List, Array, Map)

Mybatis框架的动态SQL可以方便的拼接SQL语句,而其foreach标签可用于处理集合类型数据。本文介绍如何使用foreach标签遍历传入的集合(List, Array, Map)

abstract

概述

foreach标签,可以实现遍历集合类型(List, Array, Map)数据。该标签包含如下属性:

  • collection: [必选参数] 需要进行遍历对象对应的键:List对象默认使用list作为键,Array对象默认使用array作为键,Map对象没有默认的键(需要使用@Param注解完成Map对象的绑定,下文将详述),当集合(List, Array, Map)对象为所传实参POJO的一个属性时,集合对象使用属性名作为键
  • item: [必选参数] 用于表示每次遍历时的集合中的元素名称,可以通过点操作符访问元素属性。在Map中,表示value
  • index: [可选参数] List、Array集合中表示元素序号。Map集合中表示key
  • separator: [可选参数] 两次遍历结果之间所添加的分隔符
  • open: [可选参数] 添加在最终遍历结果之前的符号
  • close: [可选参数] 添加在最终遍历结果之后的符号

先给出本文代码可能用到的相关POJO类(属性名和数据表的字段均对应)

1
2
3
4
5
6
public class Student {       
private int id;
private String username;
private String sex;
private String address;
}
1
2
3
4
5
6
public class UserVo {
private String sex;
private Student[] stuArray;
private List<Student> stuList;
private Map<String, String> stuMap;
}

参数为集合

传入的参数为集合类型时,collection按上文所述配置相应的键即可

List

构造一个Student的List集合对象后传入service

1
2
3
4
List<Student> list = new LinkedList<>();
list.add( new Student("Aaron", "3") );
list.add( new Student("Zeal", "1") );
studentService.findAddByName3(list);

Mapper接口如下,service将调用该接口方法

1
2
3
4
@Mapper
public interface StudentMapper {
public List<Student> findAddByName3(List<Student> stuList);
}

传入参数为集合时,映射文件的sql标签parameterType属性可省略。这里由于是List集合,故collection使用默认键list,而item属性可以任意指定,用来标识每次遍历的元素对象名称,这里记为node,则表示每次遍历的元素的属性时,可以使用点操作符,如node.address,node.sex所示

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<select id="findAddByName3" resultMap="studentResultMap">
SELECT * FROM user
<where>
<foreach collection="list" item="node">
<if test="node.address != null">
OR address = #{node.address}
</if>
<if test="node.username != null">
OR username = #{node.username}
</if>
<if test="node.sex != null">
OR sex = #{node.sex}
</if>
</foreach>
</where>
</select>

下图即为上述代码执行后的结果,可以看出正确遍历拼接出List中元素的属性数据

report 1.jpg

Array

构造一个Student的Array集合对象后传入service

1
2
3
4
Student[] array = new Student[21];
array[0] = new Student("Aaron", "3");
array[1] = new Student("Tom", "1");
studentService.findAddByName4(array);

Mapper接口如下,service将调用该接口方法

1
2
3
4
@Mapper
public interface StudentMapper {
public List<Student> findAddByName4(Student[] stuArray);
}

传入参数为集合时,映射文件的sql标签parameterType属性可省略。这里由于是Array,故collection使用默认键array,而item属性可以任意指定,用来标识每次遍历的元素对象名称,这里记为node,则表示每次遍历的元素的属性时,可以使用点操作符,如node.address,node.sex所示。需要注意的是,foreach将遍历数组的所有元素,所以每次取该元素的属性前,需要先对该元素对象进行判空(如下所示)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<select id="findAddByName4" resultMap="studentResultMap">
SELECT * FROM user
<where>
<foreach collection="array" item="node">
<if test="node != null">
<if test="node.username != null">
OR username = #{node.username}
</if>
<if test="node.address != null">
OR address = #{node.address}
</if>
<if test="node.sex != null">
OR sex = #{node.sex}
</if>
</if>
</foreach>
</where>
</select>

下图即为上述代码执行后的结果,可以看出正确遍历拼接出数组中元素的属性数据

report 2.jpg

Map

构造一个Student的Map集合对象后传入service

1
2
3
4
Map<String,String> map = new HashMap<>();
map.put("username", "Aaron");
map.put("address", "NanJing");
studentService.findAddByName2(map);

Mapper接口如下,service将调用该接口方法,需要注意的是,Map集合在foreach由于没有默认键可用,故需要使用 @Param 注解手动指定一个标识,后面将在foreach中将其作为键使用。该标识任意指定即可,这里使用”stuMap”

1
2
3
@Mapperpublic interface StudentMapper {
public List<Student> findAddByName2(@Param("stuMap") Map<String, String> stuMap);
}

传入参数为集合时,映射文件的sql标签parameterType属性可省略。由于是Map集合,collection无默认键,故配置其为对应的接口方法中的形参前的@Param注解中的标识(此处即为”stuMap”)。由于是Map集合,index、item属性分别表示为该Map集合中的key、value,故可以分别用${k},#{v}来获取该Map集合中的key、value

1
2
3
4
5
6
7
8
<select id="findAddByName2" resultMap="studentResultMap">
SELECT * FROM user
<where>
<foreach collection="stuMap" index="k" item="v">
AND ${k} = #{v}
</foreach>
</where>
</select>

下图即为上述代码执行后的结果,可以看出正确遍历拼接出Map集合中key-value数据

report 3.jpg

参数为包含集合属性的POJO

传入的参数为一个POJO,其属性中有集合类型时,collection直接配置为相应集合中的属性名即可

POJO 属性为 List

构造下列一个UserVo对象同时设置一个List集合属性,传入service

1
2
3
4
5
6
7
UserVo userVo = new UserVo();
userVo.setSex("123");
List<Student> list = new LinkedList<>();
list.add( new Student("Aaron", "3", "NanJing") );
list.add( new Student("tony", "0", "Beijing") );
userVo.setStuList(list);
studentService.findAddByName6(userVo);

Mapper接口如下,service将调用该接口方法

1
2
3
public interface StudentMapper {
public List<Student> findAddByName6(UserVo userVo);
}

传入参数为UserVo类型,故映射文件的sql标签parameterType属性配置为UserVo。该POJO的stuList属性为List集合类型,在遍历该属性的List集合时,collection配置为该属性名stuList即可。而item属性可以任意指定,用来标识每次遍历的元素对象名称,这里记为node,则表示每次遍历的元素的属性时,可以使用点操作符,如node.address,node.sex所示

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<select id="findAddByName6" parameterType="com.aaron.springbootdemo.pojo.UserVo" resultMap="studentResultMap">
SELECT * FROM user
<where>
<if test="sex != null">
OR sex = #{sex}
</if>
<foreach collection="stuList" item="node">
<if test="node.username != null">
OR username = #{node.username}
</if>
<if test="node.sex != null">
OR sex = #{node.sex}
</if>
<if test="node.address != null">
OR address = #{node.address}
</if>
</foreach>
</where>
</select>

下图即为上述代码执行后的结果,可以看出正确遍历拼接出List中元素的属性数据

report 4.jpg

POJO 属性为 Array

构造下列一个UserVo对象同时设置一个Array属性,传入service

1
2
3
4
5
6
7
UserVo userVo = new UserVo();
userVo.setSex("456");
Student[] stuArray = new Student[4];
stuArray[0] = new Student("Aaron", "3");
stuArray[1] = new Student("Tom", "1");
userVo.setStuArray(stuArray);
studentService.findAddByName5(userVo);

Mapper接口如下,service将调用该接口方法

1
2
3
public interface StudentMapper {
public List<Student> findAddByName5(UserVo userVo);
}

传入参数为UserVo类型,故映射文件的sql标签parameterType属性配置为UserVo。该POJO的stuArray属性为Array类型,在遍历该属性的Array时,collection配置为该属性名stuArray即可。而item属性可以任意指定,用来标识每次遍历的元素对象名称,这里记为node,则表示每次遍历的元素的属性时,可以使用点操作符,如node.address,node.sex所示。需要注意的是,foreach将遍历数组的所有元素,所以每次取该元素的属性前,需要先对该元素对象进行判空(如下所示)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<select id="findAddByName5" parameterType="com.aaron.springbootdemo.pojo.UserVo" resultMap="studentResultMap">
SELECT * FROM user
<where>
<if test="sex != null ">
OR sex = #{sex}
</if>
<foreach collection="stuArray" item="node">
<if test="node != null">
<if test="node.address != null">
OR address = #{node.address}
</if>
<if test="node.username != null">
OR username = #{node.username}
</if>
<if test="node.sex != null">
OR sex = #{node.sex}
</if>
</if>
</foreach>
</where>
</select>

下图即为上述代码执行后的结果,可以看出正确遍历拼接出数组中元素的属性数据

report 5.jpg

POJO 属性为 Map

构造下列一个UserVo对象同时设置一个Map属性,传入service

1
2
3
4
5
6
7
8
UserVo userVo = new UserVo();
userVo.setSex("987");
Map<String, String> map = new HashMap<>();
map.put("address", "Shanghai");
map.put("id", "2");
map.put("username", "Bob");
userVo.setStuMap(map);
studentService.findAddByName7(userVo);

Mapper接口如下,service将调用该接口方法

1
2
3
public interface StudentMapper {
public List<Student> findAddByName7(UserVo userVo);
}

传入参数为UserVo类型,故映射文件的sql标签parameterType属性配置为UserVo。该POJO的stuMap属性为Map类型,在遍历该属性的Map时,collection配置为该属性名stuMap即可。由于是Map集合,index、item属性分别表示为该Map集合中的key、value,故可以分别用${k},#{v}来获取该Map集合中的key、value

1
2
3
4
5
6
7
8
9
10
11
<select id="findAddByName7" parameterType="com.aaron.springbootdemo.pojo.UserVo" resultMap="studentResultMap">
SELECT * FROM user
<where>
<if test="#{sex} != null">
OR sex = #{sex}
</if>
<foreach collection="stuMap" index="k" item="v">
OR ${key} = #{value}
</foreach>
</where>
</select>

下图即为上述代码执行后的结果,可以看出正确遍历拼接出Map集合中key-value数据

report 6.jpg

0%