주요글: 도커 시작하기
반응형

현재 참여하고 있는 프로젝트는 레거시 시스템과 관련이 있다. CHAR 타입 칼럼의 기본값으로 공백문자(' ')를 지정한 테이블이 많아서 기존 코드를 보면 TRIM 처리를 하는 쿼리가 많이 있다. 현재 프로젝트는 JPA를 사용하고 있는데, 조회 결과에서 불필요한 공백을 제거할 필요가 생겼다. 이를 위해 EntityListener와 커스텀 애노테이션을 사용했다.


@Trim 커스텀 애노테이션


DB에서 읽어온 값을 trim해야 하는 대상을 설정하기 위해 @Trim 애노테이션을 추가했다.


@Target({ ElementType.FIELD })

@Retention(RUNTIME)

public @interface Trim {

}


JPA 엔티티 리스너(entity listener) 메서드 구현


엔티티 단위로 @Trim 애노테이션이 붙은 필드에 대해 trim 처리를 수행하기 위해 JPA 엔티티 리스너 메서드를 구현했다. 엔티티 리스너 메서드는 크게 별도 클래스로 구현하거나 엔티티 메서드로 구현하는 두 가지 방법이 존재하는데 범용적으로 적용하기 위해 별도 클래스로 구현했다. 구현 클래스는 아래와 같다.


import javax.persistence.PostLoad;


public class TrimEntityListener {


    @PostLoad

    public void postLoad(Object entity) {

        Field[] fields = entity.getClass().getDeclaredFields();

        for (Field field : fields) {

            if (field.isAnnotationPresent(Trim.class)) {

                field.setAccessible(true);

                try {

                    Object value = field.get(entity);

                    if (value != null && value instanceof String) {

                        String s = (String) value;

                        field.set(entity, s.trim());

                    }

                } catch (Exception ex) {

                }

            }

        }

    }

}


@PostLoad 애노테이션은 엔티티를 로딩한 후에 호출할 메서드를 설정한다. @PostLoad 외에도 엔티티 라이프사이클에 맞춘 @PrePersist, @PostPersist, @PreUpdate, @PostUpdate 등의 애노테이션이 존재한다.


postLoad() 메서드의 entity 파라미터를 로딩한 엔티티 객체이다. postLoad() 메서드는 엔티티 객체의 필드 중에서 @Trim 애노테이션이 존재하는 필드를 찾아서 값에 대해 trim 처리를 한다.


엔티티 리스너 클래스 적용


이제 엔티티 리스너 클래스를 사용하도록 설정만 하면 된다. 전체 엔티티를 대상으로 엔티티 리스너 클래스를 적용하고 싶다면 JPA 설정 파일(스프링 부트를 사용한다면 META-INF/orm.xml 파일)의 <entity-listener> 태그에 엔티티 리스너 클래스를 설정하면 된다.


<?xml version="1.0" encoding="UTF-8"?>


<entity-mappings xmlns="http://xmlns.jcp.org/xml/ns/persistence/orm"

  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

  xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence/orm

                    http://xmlns.jcp.org/xml/ns/persistence/orm_2_1.xsd"

  version="2.1">


  <persistence-unit-metadata>

    <persistence-unit-defaults>

      <entity-listeners>

        <entity-listener class="jpa.TrimEntityListener" />

      </entity-listeners>

    </persistence-unit-defaults>

  </persistence-unit-metadata>

  

</entity-mappings>


엔티티별로 엔티티 리스너 클래스를 적용할 수도 있다. @EntityListener 애노테이션을 사용해서 각 엔티티 클래스에 사용할 엔티티 리스너를 지정하면 된다.


import javax.persistence.EntityListeners;


@Entity

@EntityListeners({TrimEntityListener.class})

public class Division {


    @Trim

    private String location;

    ...

}


TrimEntityListener는 @PostLoad 메서드를 정의하고 있으므로, 엔티티를 로딩할 때마다 @PostLoad 메서드를 사용해서 @Trim이 붙은 필드 값을 trim 처리할 수 있다.

+ Recent posts