結論
ORDER BY
句に変数を渡す際に、#{}(プレースホルダー形式)
ではなく、${}(文字列展開形式)
を使用する必要があります。
理由
-
#{}(プレースホルダー形式)
- SQL文に値をバインドする際に使用される
-
${}(文字列展開形式)
- 値をそのままSQL文の一部として挿入する
-
SQL構文の一部(カラム名、テーブル名、
ORDER BY
句など)を動的に構築する場合に使用される。
正しい使い方
xml name=UserMapper.xml
<mapper namespace="com.example.UserMapper">
<select id="findUsers" resultType="com.example.User">
SELECT id, user_name, email
FROM users
ORDER BY ${orderBy} <!-- 動的なカラム名 -->
</select>
</mapper>
注意点
${}
を使用する際には、SQLインジェクションを防ぐために、入力された値を以下のように検証することが推奨される
許可リストを使用:
動的に渡される値が想定されたカラム名やソート順であることを確認します。
private final String CREATED_AT = "created_at";
public UserDto list(Pageable pageable, String sortColumn, Integer sortOrder) {
// 指定可能なソート列名が複数ある場合も考慮
String[] allows = {CREATED_AT};
// 引数.ソート列名とソート順の相関チェック
this.mismatchSortOrder(allows, sortColumn, sortOrder);
// 以降処理省略
}
public void mismatchSortOrder(String[] allows, String sortColumn, Integer sortOrder) {
if (!StringUtils.isEmpty(sortColumn) && !Arrays.asList(allows).contains(sortColumn)) {
// 不正な物理名が指定された場合
throw new BusinessException(HttpStatus.BAD_REQUEST, MessageKey.VALIDATION_ERROR.getValue(),
"invalidSortColumnName:" + sortColumn);
}
if ((!StringUtils.isEmpty(sortColumn) && Objects.isNull(sortOrder))
|| StringUtils.isEmpty(sortColumn) && Objects.nonNull(sortOrder)) {
// どちらか片方のみに値が設定されている場合
throw new BusinessException(HttpStatus.BAD_REQUEST, MessageKey.VALIDATION_ERROR.getValue(),
"One of the two parameters is null sortColumn:" + sortColumn + " sortOrder:" + sortOrder);
}
}