请求参数里使用数组传递多个 id 值,然后在 java 程序中通过循环拼接分割符,最后传递 String 类型参数到 mybatis sql 查询中。调试发现,拼接后的 ids 只返回了一条数据。

StringBuilder idBuiler = new StringBuilder();
for (Integer suId : spApplyDto.getSuIds()) {
    idBuiler.append(suId).append(",");
}
// idBuiler.replace(idBuiler.length()-1, idBuiler.length(), "");
String ids = idBuiler.substring(0, idBuiler.length()-1); // ids:'4,2,3'

当然数组拼接字符串还可以这样(百度AI解答):

String ids = Arrays.toString(spApplyDto.getSuIds()).replaceAll("[\\[\\]]", "").trim();

通过数组的 toString 方法返回字符串([4,2,3]),再把数组转化的字符串前后中括号通过空字符替换掉,最后去除所有的空白、换行符之类的内容。

两种方法不影响输出的结果:4,2,3。查看调试面板下的 sql 输出:

==>  Preparing: select xx from sp_user as su left join sp_flow as sf on sf.id = su.flow_id where su.id in (?) and su.state = '1' order by sf.level asc 
==> Parameters: 4, 2, 3(String)
<==    Columns: id, flow_id, user_id, user_name, created_at, created_user, updated_at, updated_user, state, state_name, type, level, is_final
<==        Row: 4, 1, xx, xx, 2024-05-30 16:45:51, xx, null, null, 1, 正常, 0, 0, 0
<==      Total: 1

重点在于参数是 String 类型来着,所以真实的查询变成了 where su.id in ('4, 2, 3'),拿 sql 到数据库实测,确实只返回一条数据。

想起之前遇到过一次 Mybatis order by id #{order} 变量传入不进去,当时讨论过 #{} 用于预处理语句,${} 是原样输出。所以这里应该修改成后者,使用字符串原样输出,这样可以识别成多个 id。

    <select id="selectSpUserListByIds" parameterType="String" resultMap="SpUserResult">
        <include refid="selectSpUserVo"/>
        where su.id in (${ids}) and su.state = '1'
        order by sf.level asc
    </select>

再次调试,报错:nested exception is org.apache.ibatis.reflection.ReflectionException: There is no getter for property named 'ids' in 'class java.lang.String'

作为 String 参数,ids 在 #{} 中是可以正常识别的,但到了 ${} 突然提示找不到 getter,这让我很意外。有点不太清楚怎么回事,但之前 Mybatis 批量更新报错:Parameter 'orderList' not found. Available parameters are [collection, list] 遇到过,此时添加 @Param("ids") 标识参数名称即可

再次运行,成功!

当然还可以通过 mybatis 自带的 foreach 循环来实现:直接传入 String[] ids 参数(因为请求传入参数为拼接后的字符串,通过 str.split(",") 转换就得到了 String[] 类型):

    <delete id="deleteSpUserByIds" parameterType="String">
        update sp_user set state = '0' where id in
        <foreach item="id" collection="array" open="(" separator="," close=")">
            #{id}
        </foreach>
    </delete>

参数都是通过占位符传入数组中的元素,相比前面原样输出传入安全性更高。