MyBatis-PlusにおけるMetaObjectHandlerを利用した自動フィールド設定

エンティティクラスへの自動フィールド設定アノテーションの追加

自動で値を設定したいフィールドには@TableFieldアノテーションを追加し、fill属性を指定します。

fill属性のオプション:

  • DEFAULT: デフォルト(処理なし)
  • INSERT: 挿入操作時にフィールドを自動設定
  • UPDATE: 更新操作時にフィールドを自動設定
  • INSERT_UPDATE: 挿入と更新操作の両方でフィールドを自動設定
@TableField(fill = FieldFill.INSERT)
private LocalDateTime registrationDate;

@TableField(fill = FieldFill.INSERT_UPDATE)
private LocalDateTime lastModifiedDate;   

@TableField(fill = FieldFill.INSERT)
private Long createdBy;

@TableField(fill = FieldFill.INSERT_UPDATE)
private Long modifiedBy;

MetaObjectHandlerインターフェースの実装

データの新規登録や更新操作時に、特定のフィールド(作成日時、更新日時、作成者、更新者など)を自動で設定するカスタムハンドラクラスを実装します。これらの値はシステムの現在時刻や、ThreadLocalを利用して取得した現在のユーザー情報などから設定されます。

@Component
public class CustomMetaObjectHandler implements MetaObjectHandler {
    /**
     * 挿入操作時の自動フィールド設定
     * @param metaObject メタオブジェクト
     */
    @Override
    public void insertFill(MetaObject metaObject) {
        logger.debug("Insert operation metaObject: {}", metaObject);
        
        // 現在日時の設定
        LocalDateTime now = LocalDateTime.now();
        this.strictInsertFill(metaObject, "registrationDate", LocalDateTime.class, now);
        this.strictInsertFill(metaObject, "lastModifiedDate", LocalDateTime.class, now);
        
        // 現在ユーザーの設定
        Long currentUserId = UserContext.getCurrentUserId();
        this.strictInsertFill(metaObject, "createdBy", Long.class, currentUserId);
        this.strictInsertFill(metaObject, "modifiedBy", Long.class, currentUserId);
    }
    
    /**
     * 更新操作時の自動フィールド設定
     * @param metaObject メタオブジェクト
     */
    @Override
    public void updateFill(MetaObject metaObject) {
        logger.debug("Update operation metaObject: {}", metaObject);
        
        // 現在日時の設定
        this.strictUpdateFill(metaObject, "lastModifiedDate", LocalDateTime.class, LocalDateTime.now());
        
        // 現在ユーザーの設定
        this.strictUpdateFill(metaObject, "modifiedBy", Long.class, UserContext.getCurrentUserId());
    }
}

ThreadLocalを利用したユーザー情報管理

ThreadLocalはスレッドごとに独立した変数を保持する機能です。各スレッドが自身の変数コピーにアクセスできるため、スレッドセーフな変数の共有と、スレッド単位でのデータ伝達が可能になります。

ThreadLocalの主な利点:

  1. スレッド安全性の確保
  2. スレッド単位での変数伝達

以下は、現在ログイン中のユーザーIDを管理するためのユーティリティクラスの実装例です。

/**
 * 現在のログインユーザーIDを管理するためのThreadLocalベースのユーティリティクラス
 */
public class UserContext {
    private static final ThreadLocal<Long> userContextHolder = new ThreadLocal<>();
    
    /**
     * 現在のユーザーIDを設定
     * @param userId ユーザーID
     */
    public static void setCurrentUserId(Long userId) {
        if (userId == null) {
            userContextHolder.remove();
        } else {
            userContextHolder.set(userId);
        }
    }
    
    /**
     * 現在のユーザーIDを取得
     * @return ユーザーID
     */
    public static Long getCurrentUserId() {
        return userContextHolder.get();
    }
    
    /**
     * 現在のスレッドからユーザー情報をクリア
     */
    public static void clear() {
        userContextHolder.remove();
    }
}

このクラスを利用することで、リクエスト処理のどの段階からでも現在のユーザー情報にアクセスでき、MetaObjectHandlerでの自動フィールド設定に活用できます。

タグ: MyBatis-Plus MetaObjectHandler ThreadLocal Java 自動フィールド設定

6月17日 19:03 投稿