前言
我们经常有需要动态使用 order by 的需求,最简单的方法是使用字符串拼接的方式,然而这样并不安全,容易被注入攻击。其实只要简单的使用 MyBatis 的 <trim> 标签即可实现安全的动态的 order by 功能。
实现
在 XxQuery 类里添加 orderByXxx 参数
这里的布尔值表达是否需要该字段的 order by 的含义,若以 Desc 为后缀表示降序。因此有两种格式 orderByXxxx 和 orderByXxxxDesc。
public class OrganizationLabelQuery implements Serializable {
private Long pageNum;
private Long pageSize;
private Long id;
private List<Long> ids;
private String labelName;
private Boolean available;
private Boolean orderByAvailable;
private Boolean orderByAvailableDesc;
private Boolean orderByReferenceNumber;
private Boolean orderByReferenceNumberDesc;
private Boolean orderByLabelName;
private Boolean orderByLabelNameDesc;
private Boolean orderByCreateTime;
private Boolean orderByCreateTimeDesc;
private Boolean orderByUpdateTime;
private Boolean orderByUpdateTimeDesc;
// getters and getters
}
在 XxxxMapper.xml 里使用 <trim> 标签动态添加 order by 参数
这里的重点是 <where> 标签后的代码。先使用一个 <if> 判断是否需要 order by 语句,若需要,添加 order by。然后判断哪个参数需要 order by,并使用 <trim> 去除多余 ,。
<select id="listOrganizationLabels" resultMap="organizationLabel">
select <include refid="organizationLabel"/>
from organization_label
<where>
<if test="id != null">
and id = #{id}
</if>
<if test="ids != null">
and id in (
<foreach collection="ids" item="item" index="index" separator=",">
#{item}
</foreach>
)
</if>
<if test="labelName != null">
and label_name like "%"#{labelName}"%"
</if>
<if test="available != null">
and is_available = #{available}
</if>
</where>
<if test="orderByAvailable || orderByAvailableDesc || orderByReferenceNumber || orderByReferenceNumberDesc
|| orderByLabelName || orderByLabelNameDesc || orderByCreateTime || orderByCreateTimeDesc
|| orderByUpdateTime || orderByUpdateTimeDesc">
order by
<trim suffixOverrides=",">
<if test="orderByAvailable">
is_available,
</if>
<if test="orderByAvailableDesc">
is_available desc,
</if>
<if test="orderByReferenceNumber">
reference_number,
</if>
<if test="orderByReferenceNumberDesc">
reference_number desc,
</if>
<if test="orderByLabelName">
label_name,
</if>
<if test="orderByLabelNameDesc">
label_name desc,
</if>
<if test="orderByCreateTime">
create_time,
</if>
<if test="orderByCreateTimeDesc">
create_time desc,
</if>
<if test="orderByUpdateTime">
update_time,
</if>
<if test="orderByUpdateTimeDesc">
update_time desc,
</if>
</trim>
</if>
</select>
使用
使用就非常简单了,只需要设置需要 order by 的字段即可。
Result<PageInfo<OrganizationLabelDTO>> listOrganizationLabelsResult =
organizationLabelService.listOrganizationLabels(
new OrganizationLabelQuery
.Builder()
.pageNum(1L)
.pageSize(50L)
.orderByReferenceNumberDesc(true)
.orderByUpdateTime(true)
.build());