본문 바로가기

프로그래밍/MyBatis

[MyBatis] Interceptor로 생성일(CreatedDate) 자동 입력하기, Auditing

JPA는 데이터의 생성일, 수정일 등 을 자동으로 넣어주는 Audit라는 기능을 제공합니다.

 

Auditing을 이용하여 엔티티를 언제 생성/수정 했는지 기록하게 할 수 있습니다.

Mybatis Interceptor를 이용하여 Message객체를 DB에 저장할 때 생성일을 (CreatedDate) 자동으로 추가 시켜보겠습니다.

 

 

application.properties

mybatis.config-location=classpath:mybatis-config.xml
  • mybatis-config의 위치를 설정해줍니다.

 

mybatis-config.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <plugins>
        <plugin interceptor="본인프로젝트.AuditingInterceptor"/>
    </plugins>
</configuration>
  • AuditingInterceptor라는 Interceptor를 만들어서 플러그인 등록 해줍니다.

 

Message

public class Message {
    private Long id;
    private String content;
    private LocalDateTime createdDate;
}
  • 쉬운 예제를 위해 다른 필드들은 생략하고 createdDate를 Interceptor로 자동으로 넣어보겠습니다.

 

 

AuditingInterceptor

@Intercepts({@Signature(type = Executor.class, method = "update", args = {MappedStatement.class, Object.class})})
public class AuditingInterceptor implements Interceptor {

    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        MappedStatement mappedStatement = (MappedStatement) invocation.getArgs()[0];

        if (mappedStatement.getSqlCommandType() == SqlCommandType.INSERT) {
            Object parameter = invocation.getArgs()[1];
            // Message 객체인지 확인하고 CreatedDate 필드 설정
            if (parameter instanceof Message) {
                Message message = (Message) parameter;
                message.setCreatedDate(LocalDateTime.now());
            }
        }

        return invocation.proceed();
    }
}
  • Message 객체를 저장 할 때만 createdDate를 세팅 해주기 위해, Message 객체인지 판단하는 로직을 넣고 setCreatedDate를 해줍니다.
  • Signature 어노테이션 : 인터셉터가 적용되는 메서드의 정보를 지정하는 어노테이션입니다.
  • type : 인터셉터가 적용되는 인터페이스 또는 클래스를 지정합니다
    • Executor 인터페이스는 MyBatis에서 SQL 쿼리를 실행하는 데 사용되는 인터페이스입니다. 따라서, Signature 어노테이션은 Executor 인터페이스의 모든 메서드에 인터셉터가 적용됨을 의미합니다.
  • method : 인터셉터가 적용되는 메서드의 이름을 지정합니다.
    • update 메서드는 insert, update, delete 쿼리를 실행하는 메서드입니다. 따라서, Signature 어노테이션은 update, insert, delete 쿼리를 실행할 때 인터셉터가 적용됨을 의미합니다.
  • args : 인터셉터가 적용되는 메서드의 인자 타입을 지정합니다.
    • MappedStatement는 SQL 쿼리와 그 쿼리를 실행하는 방법에 대한 정보를 포함하는 객체입니다. 따라서, Signature 어노테이션은 인터셉터가 적용되는 메서드의 인자로 MappedStatement 객체와 Object 객체가 전달됨을 의미합니다.

 

MessageRepository

public class MessageRepository {
    private final MessageMapper messageMapper;

    public Long save(Message message) {
        messageMapper.save(message);
        return message.getId();
    }
  • MessageRepository의 save 함수는 MessageMapper의 save를 호출합니다.

 

MessageMapper

@Mapper
public interface MessageMapper {
    public void save(Message message);
}
  • MessageMapper의 save함수는 MessageMapper.xml 에 정의 된 SQL을 호출합니다.

 

MessageMapper.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="프로젝트경로.mapper.MessageMapper">
    <insert id="save" useGeneratedKeys="true" keyProperty="id" parameterType="com.seojs.ptmanager.domain.message.Message">
        insert into message (content, created_date)
        values (#{content}, #{createdDate})
    </insert>
</mapper>
  • save SQL이 정의 된 MessageMapper.xml 입니다.

 

 

메세지를 저장 할 클래스 및 함수들은 다 정의 되었고

 

테스트 에서 MessageRepository의 save를 호출 할 때

 

createdDate를 넣지 않고 content만 넣어서 SQL을 호출 하면 어떻게 될까요?

messageRepository.save(new Message("message");

 

Interceptor에서 Message 객체에 setCreatedDate를 해주었기 때문에

 

insert SQL values에 createdDate가 들어가서 호출 됩니다.

 

출력 로그

==> Parameters: message(String), false(Boolean), 1(Long) , 2024-02-01T00:28:46.500004(LocalDateTime)