저작권 안내: 저작권자표시 Yes 상업적이용 No 컨텐츠변경 No

스프링4 입문

스프링 4

DDD Start

객체 지향과
디자인 패턴

JSP 2.3

JPA 입문

현재 참여하고 있는 프로젝트는 레거시 시스템과 관련이 있다. 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 처리할 수 있다.

저작자 표시 비영리 변경 금지
신고
Posted by 최범균 madvirus

댓글을 달아 주세요

페이스북 친구들과 댓글을 공유하고 싶다면 아래를 이용해주세요.

스프링부터 다중 데이터소스 설정 방법은 간단하다. 먼저 application.properties 파일에 "구분.datasource"로 시작하는 데이터소스 설정을 추가한다. 다음은 예이다.



# datasource 1

spring.datasource.driver-class-name=oracle.jdbc.OracleDriver

spring.datasource.url=jdbc:oracle:thin:@10.xx.xx.xx:SID

spring.datasource.username=dbuser

spring.datasource.password=dbpw


spring.datasource.tomcat.initialSize=5

spring.datasource.tomcat.maxActive=40

spring.datasource.tomcat.maxIdle=40

spring.datasource.tomcat.minIdle=5

spring.datasource.tomcat.maxWait=5

spring.datasource.tomcat.validationQuery=select 1+1 from dual

spring.datasource.tomcat.testWhileIdle=true

spring.datasource.tomcat.timeBetweenEvictionRunsMillis=60000


# datasource 2

sms.datasource.driver-class-name=com.microsoft.sqlserver.jdbc.SQLServerDriver

sms.datasource.url=jdbc:sqlserver://10.xx.xx.xx:1433;databaseName=SMS

sms.datasource.username=dbuser1

sms.datasource.password=dbpw1


sms.datasource.tomcat.initialSize=1

sms.datasource.tomcat.maxActive=20

sms.datasource.tomcat.maxIdle=20

sms.datasource.tomcat.minIdle=1

sms.datasource.tomcat.maxWait=1

sms.datasource.tomcat.validationQuery=select 1

sms.datasource.tomcat.testWhileIdle=true

sms.datasource.tomcat.timeBetweenEvictionRunsMillis=60000


이 코드는 spring.datasource로 시작하는 데이터소스와 sms.datasource로 시작하는 데이터소스를 설정했다. "구분.datasource.tomcat"으로 시작하는 설정은 톰캣 DBCP 설정이다.


스프링부트는 별도 설정을 하지 않으면 spring.datasource로 시작하는 설정만 데이터소스로 사용하므로, 다중 데이터소스를 사용하려면 별도 설정을 추가해야 한다. 다음은 다중 데이터소스를 위한 자바 설정 예이다.


@Configuration

public class DataSourceConfiguration {


    @Bean

    @ConfigurationProperties(prefix = "spring.datasource")

    public DataSourceProperties dataSourceProp() {

        return new DataSourceProperties();

    }


    @Primary

    @Bean(name = "dataSource")

    @ConfigurationProperties(prefix = "spring.datasource.tomcat")

    @Qualifier("primary")

    public DataSource dataSource() {

        return dataSourceProp().initializeDataSourceBuilder().build();

    }


    @Primary

    @Bean(name = "transactionManager")

    @Qualifier("primary")

    public PlatformTransactionManager transactionManager() {

        return new DataSourceTransactionManager(dataSource());

    }


    @Bean

    @ConfigurationProperties(prefix = "sms.datasource")

    public DataSourceProperties smsDataSourceProp() {

        return new DataSourceProperties();

    }


    @Bean(name = "smsDataSource")

    @ConfigurationProperties(prefix = "sms.datasource.tomcat")

    @Qualifier("sms")

    public DataSource smsDataSource() {

        return smsDataSourceProp().initializeDataSourceBuilder().build();

    }


    @Bean(name = "smsTransactionManager")

    @Qualifier("sms")

    public PlatformTransactionManager smsTransactionManager() {

        return new DataSourceTransactionManager(smsDataSource());

    }



각 데이터소스 설정별로 세 개의 빈을 설정했다.

  • 설정 프로퍼티를 담은 DataSourceProperties 빈
    • @ConfigurationProperties를 사용해서 접두어를 지정(예, smsDataSourceProp() 빈 설정은 @ConfigurationProperties의 prefix 값으로 sms.datasource 사용)
  • DataSourceProperties 빈을 이용해서 DataSource 빈 생성
    • DataSourceProperties의 initializeDataSourceBuilder() 메서드를 이용해서 생성해야 tomcat 설정이 적용
  • 각 DataSource 마다 트랜잭션관리자 생성
    • 글로벌 트랜잭션을 사용해야 하면 JTA 트랜잭션 설정


저작자 표시 비영리 변경 금지
신고
Posted by 최범균 madvirus

댓글을 달아 주세요

페이스북 친구들과 댓글을 공유하고 싶다면 아래를 이용해주세요.