diff --git a/src/main/java/cokr/xit/foundation/boot/AbstractDatasource.java b/src/main/java/cokr/xit/foundation/boot/AbstractDatasource.java
new file mode 100644
index 0000000..a94638e
--- /dev/null
+++ b/src/main/java/cokr/xit/foundation/boot/AbstractDatasource.java
@@ -0,0 +1,124 @@
+package cokr.xit.foundation.boot;
+
+import java.util.List;
+import java.util.Properties;
+import java.util.stream.Stream;
+
+import javax.sql.DataSource;
+
+import org.apache.ibatis.mapping.VendorDatabaseIdProvider;
+import org.egovframe.rte.psl.dataaccess.mapper.MapperConfigurer;
+import org.mybatis.spring.SqlSessionFactoryBean;
+import org.springframework.boot.jdbc.DataSourceBuilder;
+import org.springframework.core.io.Resource;
+import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
+
+import cokr.xit.foundation.AbstractComponent;
+import cokr.xit.foundation.Assert;
+import cokr.xit.foundation.data.paging.MapperSupport;
+
+/**데이터베이스 접속 관련 설정
+ *
- {@link #dataSource() 데이터소스} 설정
+ * - {@link #sqlSession() MyBatis} 접속 설정
+ * - {@link #mapperConfigurer() 매퍼} 설정
+ *
+ * @author mjkhan
+ */
+public abstract class AbstractDatasource extends AbstractComponent {
+ private DataSource dataSource;
+
+ /**데이터소스 Bean을 반환한다. JDBC 접속은 application.yml 파일에 다음과 같이 설정한다.
+ * spring:
+ * datasource:
+ * hikari:
+ * driver-class-name: JDBC 드라이버 클래스 이름
+ * jdbc-url: 데이터베이스 접속 URL
+ * username: 데이터베이스 접속 아이디
+ * password: 데이터베이스 접속 비밀번호
+ * @return 데이터소스
+ */
+ protected DataSource dataSource() {
+ return dataSource != null ? dataSource : (dataSource = DataSourceBuilder.create().build());
+ }
+
+ /**SqlSessionFactoryBean을 반환한다.
+ * MyBatis의 설정 파일들은 다음 경로에 있어야 한다.
+ * - MyBatis 설정: classpath:sql/mybatis-config.xml
+ * - 매퍼 xml: classpath:sql/mapper/**/*.xml
+ *
+ * @return SqlSessionFactoryBean
+ */
+ protected SqlSessionFactoryBean sqlSession() {
+ try {
+ SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
+ bean.setDataSource(dataSource());
+
+ PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
+ bean.setConfigLocation(resolver.getResource("classpath:sql/mybatis-config.xml"));
+
+ Resource[] mapperLocations = getMapperLocations(resolver);
+ if (!isEmpty(mapperLocations))
+ bean.setMapperLocations(mapperLocations);
+ bean.setPlugins(new MapperSupport());
+ bean.setDatabaseIdProvider(databaseIdProvider());
+ return bean;
+ } catch (Exception e) {
+ throw Assert.runtimeException(e);
+ }
+ }
+
+ /**매퍼 위치목록을 반환한다.
+ * @param resolver PathMatchingResourcePatternResolver
+ * @return 매퍼 위치목록
+ * @throws Exception
+ */
+ private Resource[] getMapperLocations(PathMatchingResourcePatternResolver resolver) throws Exception {
+ List resources = Stream.of(mapperLocationPatterns())
+ .flatMap(location -> {
+ try {
+ return Stream.of(resolver.getResources(location));
+ } catch (Exception e) {
+ throw runtimeException(e);
+ }
+ })
+ .toList();
+ return resources.toArray(new Resource[resources.size()]);
+ }
+
+ /**매퍼 경로패턴을 반환한다.
+ * @return 매퍼 경로패턴 목록
+ */
+ protected String[] mapperLocationPatterns() {
+ return new String[] {"classpath:sql/mapper/**/*.xml"};
+ }
+
+ /**MapperConfigurer를 반환한다.
+ * base package는 cokr.xit로 설정한다.
+ * @return MapperConfigurer
+ */
+ protected MapperConfigurer mapperConfigurer() {
+ MapperConfigurer bean = new MapperConfigurer();
+ String basePackages = mapperBasePackages();
+ if (!isEmpty(basePackages))
+ bean.setBasePackage(basePackages);
+ bean.setSqlSessionFactoryBeanName(sqlSessionName());
+ return bean;
+ }
+
+ protected String mapperBasePackages() {
+ return "cokr.xit";
+ }
+
+ protected String sqlSessionName() {
+ return "sqlSession";
+ }
+
+ protected VendorDatabaseIdProvider databaseIdProvider() {
+ VendorDatabaseIdProvider databaseIdProvider = new VendorDatabaseIdProvider();
+ Properties properties = new Properties();
+ properties.put("MariaDB", "mariadb");
+ properties.put("Oracle", "oracle");
+ databaseIdProvider.setProperties(properties);
+ return databaseIdProvider;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/cokr/xit/foundation/boot/AbstractTransaction.java b/src/main/java/cokr/xit/foundation/boot/AbstractTransaction.java
new file mode 100644
index 0000000..912e670
--- /dev/null
+++ b/src/main/java/cokr/xit/foundation/boot/AbstractTransaction.java
@@ -0,0 +1,73 @@
+package cokr.xit.foundation.boot;
+
+import java.util.List;
+import java.util.Map;
+
+import javax.sql.DataSource;
+
+import org.springframework.aop.Advisor;
+import org.springframework.aop.aspectj.AspectJExpressionPointcut;
+import org.springframework.aop.support.DefaultPointcutAdvisor;
+import org.springframework.jdbc.datasource.DataSourceTransactionManager;
+import org.springframework.transaction.TransactionDefinition;
+import org.springframework.transaction.interceptor.NameMatchTransactionAttributeSource;
+import org.springframework.transaction.interceptor.RollbackRuleAttribute;
+import org.springframework.transaction.interceptor.RuleBasedTransactionAttribute;
+import org.springframework.transaction.interceptor.TransactionInterceptor;
+
+/**트랜잭션 설정 클래스.
+ * 트랜잭션의 적용 대상은 cokr.xit..service.bean..*ServiceBean 클래스의 메소드들이다.
+ * @author mjkhan
+ */
+public class AbstractTransaction {
+ private DataSource dataSource;
+
+ public DataSource getDataSource() {
+ return dataSource;
+ }
+
+ protected void setDataSource(DataSource dataSource) {
+ this.dataSource = dataSource;
+ }
+
+ protected DataSourceTransactionManager txManager() {
+ DataSourceTransactionManager bean = new DataSourceTransactionManager();
+ bean.setDataSource(getDataSource());
+ return bean;
+ }
+
+ protected TransactionInterceptor txAdvice() {
+ RuleBasedTransactionAttribute read = new RuleBasedTransactionAttribute(
+ TransactionDefinition.PROPAGATION_REQUIRED,
+ List.of(new RollbackRuleAttribute(Throwable.class))
+ );
+ read.setReadOnly(true);
+ RuleBasedTransactionAttribute write = new RuleBasedTransactionAttribute(
+ TransactionDefinition.PROPAGATION_REQUIRED,
+ List.of(new RollbackRuleAttribute(Throwable.class))
+ );
+
+ NameMatchTransactionAttributeSource txAttrSrc = new NameMatchTransactionAttributeSource();
+ txAttrSrc.setNameMap(Map.of(
+ "get*", read,
+ "*", write
+ ));
+
+ TransactionInterceptor bean = new TransactionInterceptor();
+ bean.setTransactionManager(txManager());
+ bean.setTransactionAttributeSource(txAttrSrc);
+ return bean;
+ }
+
+ protected Advisor txAdvisor() {
+ String expression = Foundation.transactionPointcut();
+ AspectJExpressionPointcut requiredTx = new AspectJExpressionPointcut();
+ requiredTx.setExpression(expression);
+
+ DefaultPointcutAdvisor bean = new DefaultPointcutAdvisor();
+ bean.setPointcut(requiredTx);
+ bean.setAdvice(txAdvice());
+
+ return bean;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/cokr/xit/foundation/boot/CommonConfig.java b/src/main/java/cokr/xit/foundation/boot/CommonConfig.java
index 7f0ff36..387fb4f 100644
--- a/src/main/java/cokr/xit/foundation/boot/CommonConfig.java
+++ b/src/main/java/cokr/xit/foundation/boot/CommonConfig.java
@@ -9,7 +9,6 @@ import java.util.stream.Collectors;
import org.egovframe.rte.fdl.cmmn.trace.LeaveaTrace;
import org.egovframe.rte.fdl.property.impl.EgovPropertyServiceImpl;
import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.support.ReloadableResourceBundleMessageSource;
import org.springframework.util.AntPathMatcher;
@@ -21,7 +20,6 @@ import com.fasterxml.jackson.databind.ObjectMapper;
* @author mjkhan
*/
@Configuration
-@ComponentScan(basePackages = "cokr.xit")
public class CommonConfig {
/**AntPathMatcher를 반환한다.
* @return AntPathMatcher
diff --git a/src/main/java/cokr/xit/foundation/boot/DatasourceConfig.java b/src/main/java/cokr/xit/foundation/boot/DatasourceConfig.java
index a0394b6..9768d57 100644
--- a/src/main/java/cokr/xit/foundation/boot/DatasourceConfig.java
+++ b/src/main/java/cokr/xit/foundation/boot/DatasourceConfig.java
@@ -1,20 +1,13 @@
package cokr.xit.foundation.boot;
-import java.util.Properties;
-
import javax.sql.DataSource;
import org.apache.ibatis.mapping.VendorDatabaseIdProvider;
import org.egovframe.rte.psl.dataaccess.mapper.MapperConfigurer;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.springframework.boot.context.properties.ConfigurationProperties;
-import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
-import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
-
-import cokr.xit.foundation.Assert;
-import cokr.xit.foundation.data.paging.MapperSupport;
/**데이터베이스 접속 관련 설정
*
- {@link #dataSource() 데이터소스} 설정
@@ -24,9 +17,7 @@ import cokr.xit.foundation.data.paging.MapperSupport;
* @author mjkhan
*/
@Configuration
-public class DatasourceConfig {
- private DataSource dataSource;
-
+public class DatasourceConfig extends AbstractDatasource {
/**데이터소스 Bean을 반환한다. JDBC 접속은 application.yml 파일에 다음과 같이 설정한다.
*
spring:
* datasource:
@@ -37,10 +28,11 @@ public class DatasourceConfig {
* password: 데이터베이스 접속 비밀번호
* @return 데이터소스
*/
+ @Override
@Bean("dataSource")
@ConfigurationProperties(prefix = "spring.datasource.hikari")
public DataSource dataSource() {
- return dataSource != null ? dataSource : (dataSource = DataSourceBuilder.create().build());
+ return super.dataSource();
}
/**SqlSessionFactoryBean을 반환한다.
@@ -50,42 +42,25 @@ public class DatasourceConfig {
*
* @return SqlSessionFactoryBean
*/
+ @Override
@Bean
public SqlSessionFactoryBean sqlSession() {
- try {
- SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
- bean.setDataSource(dataSource());
-
- PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
- bean.setConfigLocation(resolver.getResource("classpath:sql/mybatis-config.xml"));
- bean.setMapperLocations(resolver.getResources("classpath:sql/mapper/**/*.xml"));
- bean.setPlugins(new MapperSupport());
- bean.setDatabaseIdProvider(databaseIdProvider());
- return bean;
- } catch (Exception e) {
- throw Assert.runtimeException(e);
- }
+ return super.sqlSession();
}
/**MapperConfigurer를 반환한다.
* base package는 cokr.xit로 설정한다.
* @return MapperConfigurer
*/
+ @Override
@Bean
public MapperConfigurer mapperConfigurer() {
- MapperConfigurer bean = new MapperConfigurer();
- bean.setBasePackage("cokr.xit");
- bean.setSqlSessionFactoryBeanName("sqlSession");
- return bean;
+ return super.mapperConfigurer();
}
+ @Override
@Bean
- VendorDatabaseIdProvider databaseIdProvider() {
- VendorDatabaseIdProvider databaseIdProvider = new VendorDatabaseIdProvider();
- Properties properties = new Properties();
- properties.put("MariaDB", "mariadb");
- properties.put("Oracle", "oracle");
- databaseIdProvider.setProperties(properties);
- return databaseIdProvider;
+ public VendorDatabaseIdProvider databaseIdProvider() {
+ return super.databaseIdProvider();
}
}
\ No newline at end of file
diff --git a/src/main/java/cokr/xit/foundation/boot/FoundationApplication.java b/src/main/java/cokr/xit/foundation/boot/FoundationApplication.java
index 3045ba0..3fd6fd8 100644
--- a/src/main/java/cokr/xit/foundation/boot/FoundationApplication.java
+++ b/src/main/java/cokr/xit/foundation/boot/FoundationApplication.java
@@ -2,6 +2,7 @@ package cokr.xit.foundation.boot;
import org.springframework.boot.autoconfigure.ImportAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.context.annotation.ComponentScan;
import org.springframework.test.context.ContextConfiguration;
/**Spring Boot에서 xit-foundation.jar를 사용하는 웹 애플리케이션의 베이스 클래스
@@ -18,7 +19,8 @@ import org.springframework.test.context.ContextConfiguration;
ServletConfig.class,
MvcConfig.class,
DatasourceConfig.class,
- TransactionConfig.class,
+ TransactionConfig.class
})
+@ComponentScan(basePackages = "cokr.xit")
@ContextConfiguration("classpath:spring/context-*.xml")
public class FoundationApplication {}
diff --git a/src/main/java/cokr/xit/foundation/boot/StandAloneApplication.java b/src/main/java/cokr/xit/foundation/boot/StandAloneApplication.java
index 496a94d..9b3d57a 100644
--- a/src/main/java/cokr/xit/foundation/boot/StandAloneApplication.java
+++ b/src/main/java/cokr/xit/foundation/boot/StandAloneApplication.java
@@ -6,6 +6,7 @@ import org.springframework.boot.WebApplicationType;
import org.springframework.boot.autoconfigure.ImportAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration;
+import org.springframework.context.annotation.ComponentScan;
import org.springframework.test.context.ContextConfiguration;
/**Spring Boot에서 xit-foundation.jar를 사용하는 stand-alone 애플리케이션의 베이스 클래스
@@ -22,8 +23,9 @@ import org.springframework.test.context.ContextConfiguration;
@ImportAutoConfiguration({
CommonConfig.class,
DatasourceConfig.class,
- TransactionConfig.class,
+ TransactionConfig.class
})
+@ComponentScan(basePackages = "cokr.xit")
@ContextConfiguration("classpath:spring/context-*.xml")
public class StandAloneApplication implements CommandLineRunner {
@Override
diff --git a/src/main/java/cokr/xit/foundation/boot/TransactionConfig.java b/src/main/java/cokr/xit/foundation/boot/TransactionConfig.java
index 5eb67cc..11febac 100644
--- a/src/main/java/cokr/xit/foundation/boot/TransactionConfig.java
+++ b/src/main/java/cokr/xit/foundation/boot/TransactionConfig.java
@@ -1,24 +1,15 @@
package cokr.xit.foundation.boot;
-import java.util.List;
-import java.util.Map;
-
import javax.annotation.Resource;
import javax.sql.DataSource;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.aop.Advisor;
-import org.springframework.aop.aspectj.AspectJExpressionPointcut;
-import org.springframework.aop.support.DefaultPointcutAdvisor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
-import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.annotation.EnableTransactionManagement;
-import org.springframework.transaction.interceptor.NameMatchTransactionAttributeSource;
-import org.springframework.transaction.interceptor.RollbackRuleAttribute;
-import org.springframework.transaction.interceptor.RuleBasedTransactionAttribute;
import org.springframework.transaction.interceptor.TransactionInterceptor;
/**트랜잭션 설정 클래스.
@@ -29,51 +20,28 @@ import org.springframework.transaction.interceptor.TransactionInterceptor;
@Aspect
@EnableTransactionManagement
@EnableAspectJAutoProxy(proxyTargetClass = true)
-public class TransactionConfig {
+public class TransactionConfig extends AbstractTransaction {
+ @Override
@Resource(name = "dataSource")
- private DataSource dataSource;
+ public void setDataSource(DataSource dataSource) {
+ super.setDataSource(dataSource);
+ }
+ @Override
@Bean
public DataSourceTransactionManager txManager() {
- DataSourceTransactionManager bean = new DataSourceTransactionManager();
- bean.setDataSource(dataSource);
- return bean;
+ return super.txManager();
}
+ @Override
@Bean
public TransactionInterceptor txAdvice() {
- RuleBasedTransactionAttribute read = new RuleBasedTransactionAttribute(
- TransactionDefinition.PROPAGATION_REQUIRED,
- List.of(new RollbackRuleAttribute(Throwable.class))
- );
- read.setReadOnly(true);
- RuleBasedTransactionAttribute write = new RuleBasedTransactionAttribute(
- TransactionDefinition.PROPAGATION_REQUIRED,
- List.of(new RollbackRuleAttribute(Throwable.class))
- );
-
- NameMatchTransactionAttributeSource txAttrSrc = new NameMatchTransactionAttributeSource();
- txAttrSrc.setNameMap(Map.of(
- "get*", read,
- "*", write
- ));
-
- TransactionInterceptor bean = new TransactionInterceptor();
- bean.setTransactionManager(txManager());
- bean.setTransactionAttributeSource(txAttrSrc);
- return bean;
+ return super.txAdvice();
}
+ @Override
@Bean
public Advisor txAdvisor() {
- String expression = Foundation.transactionPointcut();
- AspectJExpressionPointcut requiredTx = new AspectJExpressionPointcut();
- requiredTx.setExpression(expression);
-
- DefaultPointcutAdvisor bean = new DefaultPointcutAdvisor();
- bean.setPointcut(requiredTx);
- bean.setAdvice(txAdvice());
-
- return bean;
+ return super.txAdvisor();
}
}
\ No newline at end of file