From af4ed79add0244f2543b985c4013a5a6d6707a00 Mon Sep 17 00:00:00 2001 From: mjkhan21 Date: Sun, 11 Jun 2023 16:59:31 +0900 Subject: [PATCH] =?UTF-8?q?=EC=B5=9C=EC=B4=88=20=EC=BB=A4=EB=B0=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 142 ++++++++++++++++++ .../xit/foundation/boot/CommonConfig.java | 133 ++++++++++++++++ .../xit/foundation/boot/DatasourceConfig.java | 108 +++++++++++++ .../boot/FoundationApplication.java | 24 +++ .../xit/foundation/boot/FoundationTest.java | 56 +++++++ .../cokr/xit/foundation/boot/MvcConfig.java | 102 +++++++++++++ .../xit/foundation/boot/ServletConfig.java | 60 ++++++++ .../foundation/boot/TransactionConfig.java | 70 +++++++++ .../java/cokr/xit/foundation/boot/Yml.java | 130 ++++++++++++++++ .../xit/foundation/boot/package-info.java | 6 + 10 files changed, 831 insertions(+) create mode 100644 pom.xml create mode 100644 src/main/java/cokr/xit/foundation/boot/CommonConfig.java create mode 100644 src/main/java/cokr/xit/foundation/boot/DatasourceConfig.java create mode 100644 src/main/java/cokr/xit/foundation/boot/FoundationApplication.java create mode 100644 src/main/java/cokr/xit/foundation/boot/FoundationTest.java create mode 100644 src/main/java/cokr/xit/foundation/boot/MvcConfig.java create mode 100644 src/main/java/cokr/xit/foundation/boot/ServletConfig.java create mode 100644 src/main/java/cokr/xit/foundation/boot/TransactionConfig.java create mode 100644 src/main/java/cokr/xit/foundation/boot/Yml.java create mode 100644 src/main/java/cokr/xit/foundation/boot/package-info.java diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..b248eb1 --- /dev/null +++ b/pom.xml @@ -0,0 +1,142 @@ + + + 4.0.0 + + + org.springframework.boot + spring-boot-starter-parent + 2.7.12 + + + + cokr.xit.boot + xit-foundation-starter + 23.04.01-SNAPSHOT + jar + xit-foundation-starter + xit-foundation for Spring Boot + + + 17 + ${java.version} + ${java.version} + + + + + mvn2 + http://repo1.maven.org/maven2/ + + true + + + true + + + + egovframe + http://www.egovframe.go.kr/maven/ + + true + + + false + + + + egovframe2 + http://maven.egovframe.kr:8080/maven/ + + true + + + false + + + + maven-public + http://xit.xit-nexus.com:8081/repository/maven-public/ + + + + + + + + org.springframework.boot + spring-boot-starter-web + + + org.mybatis.spring.boot + mybatis-spring-boot-starter + 2.3.1 + + + org.springframework.boot + spring-boot-configuration-processor + + + org.apache.tomcat.embed + tomcat-embed-jasper + + + org.springframework.boot + spring-boot-devtools + + + + cokr.xit.base + xit-foundation + 23.04.01-SNAPSHOT + + + + org.projectlombok + lombok + + + + org.springframework.boot + spring-boot-starter-test + + + + + + + org.apache.maven.plugins + maven-jar-plugin + + + **/*.class + + + + + + + + + maven-snapshot + http://xit.xit-nexus.com:8081/repository/maven-snapshots/ + + + + maven-release + http://xit.xit-nexus.com:8081/repository/maven-releases/ + + + + \ 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 new file mode 100644 index 0000000..a74587a --- /dev/null +++ b/src/main/java/cokr/xit/foundation/boot/CommonConfig.java @@ -0,0 +1,133 @@ +package cokr.xit.foundation.boot; + +import java.text.SimpleDateFormat; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Set; +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; +import org.springframework.web.servlet.i18n.SessionLocaleResolver; +import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping; + +import com.fasterxml.jackson.core.JsonParser.Feature; +import com.fasterxml.jackson.databind.ObjectMapper; + +import cokr.xit.foundation.ApplicationContainer; + +/**전자정부 프레임웤과 xit foundation을 사용하는 애플리케이션의 공통 Bean들을 설정한다. + * @author mjkhan + */ +@Configuration +@ComponentScan(basePackages = "cokr.xit") +public class CommonConfig { + /**ApplicationContainer를 반환한다. + * @return ApplicationContainer + */ + @Bean + public ApplicationContainer applicationContainer() { + return new ApplicationContainer(); + } + + /**AntPathMatcher를 반환한다. + * @return AntPathMatcher + */ + @Bean + public AntPathMatcher antPathMatcher() { + return new AntPathMatcher(); + } + + /**ObjectMapper를 반환한다. + * @return ObjectMapper + */ + @Bean + public ObjectMapper objectMapper() { + ObjectMapper bean = new ObjectMapper(); + bean.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss")); + bean.configure(Feature.ALLOW_COMMENTS, true); + return bean; + } + + /**SessionLocaleResolver를 반환한다. + * @return SessionLocaleResolver + */ + @Bean + public SessionLocaleResolver localeResolver() { + SessionLocaleResolver bean = new SessionLocaleResolver(); + bean.setDefaultLocale(Locale.getDefault()); + return bean; + } + + /**LeaveaTrace를 반환한다. + * @return LeaveaTrace + */ + @Bean + public LeaveaTrace leaveaTrace() { + return new LeaveaTrace(); + } + + /**RequestMappingHandlerMapping을 반환한다. + * @return RequestMappingHandlerMapping + */ + @Bean + public RequestMappingHandlerMapping requestHandlers() { + return new RequestMappingHandlerMapping(); + } + + private Yml yml = new Yml("application.yml", "application.yml"); + + /**application.yml의 설정 내용을 읽어 MessageSource Bean을 설정하여 반환한다. + *
 messageSource:
+  	 *   basenames:
+     *     - classpath:message/message-common
+     *     - classpath:message/authentication-message
+     *     - classpath:org/egovframe/rte/fdl/property/messages/properties
+ * @return ReloadableResourceBundleMessageSource + */ + @Bean + public ReloadableResourceBundleMessageSource messageSource() { + ReloadableResourceBundleMessageSource bean = new ReloadableResourceBundleMessageSource(); + bean.setDefaultEncoding("UTF-8"); + bean.setCacheSeconds(60); + + List basenames = yml.getValues("messageSource.basenames"); + if (!basenames.isEmpty()) + bean.setBasenames(basenames.toArray(new String[basenames.size()])); + + return bean; + } + + /**application.yml의 설정 내용을 읽어 EgovPropertyServiceImpl Bean을 설정하여 반환한다. + *
 propertyService:
+  	 *   properties: # 인라인 프로퍼티가 있을 경우
+     *     - property0: value0
+     *     - property1: value1
+     *   extFileName: #외부 프로퍼티 파일이 있을 경우
+     *     - encoding: UTF-8
+     *       filename: classpath*:properties/your-file-01.properties
+     *     - encoding: UTF-8
+     *       filename: classpath*:properties/your-file-02.properties
+ * @return EgovPropertyServiceImpl + */ + @Bean + public EgovPropertyServiceImpl propertyService() { + EgovPropertyServiceImpl bean = new EgovPropertyServiceImpl(); + + Map properties = yml.getMap("propertyService.properties"); + if (!properties.isEmpty()) + bean.setProperties(properties); + + Set filenames = yml.getMaps("propertyService.extFileName").stream().collect(Collectors.toSet()); + if (!filenames.isEmpty()) + bean.setExtFileName(filenames); + + return bean; + } +} \ No newline at end of file diff --git a/src/main/java/cokr/xit/foundation/boot/DatasourceConfig.java b/src/main/java/cokr/xit/foundation/boot/DatasourceConfig.java new file mode 100644 index 0000000..eacb2c7 --- /dev/null +++ b/src/main/java/cokr/xit/foundation/boot/DatasourceConfig.java @@ -0,0 +1,108 @@ +package cokr.xit.foundation.boot; + +import javax.sql.DataSource; + +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 lombok.Setter; + +/**데이터베이스 접속 관련 설정 + *
  • {@link #dataSource() 데이터소스} 설정
  • + *
  • {@link #sqlSession() MyBatis} 접속 설정
  • + *
  • {@link #mapperConfigurer() 매퍼} 설정
  • + *
+ * @author mjkhan + */ +@Configuration +@ConfigurationProperties(prefix = "spring.datasource") +@Setter +public class DatasourceConfig { + private String driverClassName; + private String url; + private String username; + private String password; +/* + @Value("${spring.datasource.driver-class-name}") + private String driverClassName; + @Value("${spring.datasource.url}") + private String url; + @Value("${spring.datasource.username}") + private String username; + @Value("${spring.datasource.password}") + private String password; +*/ + /**데이터소스 Bean을 반환한다. JDBC 접속은 application.yml 파일에 다음과 같이 설정한다. + *
 spring:
+	 *   datasource:
+	 *     driver-class-name: JDBC 드라이버 클래스 이름
+	 *     url: 데이터베이스 접속 URL
+	 *     username: 데이터베이스 접속 아이디
+	 *     password: 데이터베이스 접속 비밀번호
+ * @return 데이터소스 + */ + @Bean + public DataSource dataSource() { + setConfig(); + return DataSourceBuilder.create() + .driverClassName(driverClassName) + .url(url) + .username(username) + .password(password) + .build(); + } + + private void setConfig() { + if (driverClassName != null) return; + + try { + Yml yml = new Yml("application.yml", "application.yml"); + driverClassName = yml.getValue("spring.datasource.driver-class-name"); + url = yml.getValue("spring.datasource.url"); + username = yml.getValue("spring.datasource.username"); + password = yml.getValue("spring.datasource.password"); + } catch (Exception e) { + throw Assert.runtimeException(e); + } + } + + /**SqlSessionFactoryBean을 반환한다.
+ * MyBatis의 설정 파일들은 다음 경로에 있어야 한다. + *
  • MyBatis 설정: classpath:sql/mybatis-config.xml
  • + *
  • 매퍼 xml: classpath:sql/mapper/**/*.xml
  • + *
+ * @return SqlSessionFactoryBean + */ + @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")); + return bean; + } catch (Exception e) { + throw Assert.runtimeException(e); + } + } + + /**MapperConfigurer를 반환한다.
+ * base package는 cokr.xit로 설정한다. + * @return MapperConfigurer + */ + @Bean + public MapperConfigurer mapperConfigurer() { + MapperConfigurer bean = new MapperConfigurer(); + bean.setBasePackage("cokr.xit"); + bean.setSqlSessionFactoryBeanName("sqlSession"); + return bean; + } +} \ 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 new file mode 100644 index 0000000..ac8217a --- /dev/null +++ b/src/main/java/cokr/xit/foundation/boot/FoundationApplication.java @@ -0,0 +1,24 @@ +package cokr.xit.foundation.boot; + +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.annotation.Import; +import org.springframework.test.context.ContextConfiguration; + +/**xit-foundation.jar에 의존하는 spring boot 애플리케이션의 베이스 클래스 + *

설정 파일을 추가하여 사용하는 경우 설정 파일은 + *

  • 클래스패스의 spring 폴더 아래에 있어야 하고
  • + *
  • 이름은 'context-'로 시작하는 xml이어야 한다
  • + *
  • 즉 classpath*:spring/context-*.xml 경로에 해당해야 한다.
  • + *
+ * @author mjkhan + */ +@SpringBootApplication +@ContextConfiguration("classpath*:spring/context-*.xml") +@Import({ + CommonConfig.class, + ServletConfig.class, + MvcConfig.class, + DatasourceConfig.class, + TransactionConfig.class, +}) +public class FoundationApplication {} diff --git a/src/main/java/cokr/xit/foundation/boot/FoundationTest.java b/src/main/java/cokr/xit/foundation/boot/FoundationTest.java new file mode 100644 index 0000000..74fff86 --- /dev/null +++ b/src/main/java/cokr/xit/foundation/boot/FoundationTest.java @@ -0,0 +1,56 @@ +package cokr.xit.foundation.boot; + +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import javax.annotation.Resource; + +import org.junit.jupiter.api.extension.ExtendWith; +import org.springframework.boot.test.context.SpringBootTestContextBootstrapper; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.context.BootstrapWith; +import org.springframework.test.context.junit.jupiter.SpringExtension; + +import cokr.xit.foundation.AbstractComponent; +import cokr.xit.foundation.UserInfo; +import cokr.xit.foundation.data.DataObject; +import cokr.xit.foundation.test.TestMapper; + +/**Spring Boot에서 xit-foundation을 사용하는 클래스의 단위 테스트 작성을 위한 베이스 클래스. + *

FoundationTest는 + *

  • JUnit5를 사용하며
  • + *
  • "test" 프로필을 설정한다.
  • + *
  • AbstractComponent의 기능을 사용할 수 있다.
  • + *
+ * @author mjkhan + */ +@ExtendWith(SpringExtension.class) +@BootstrapWith(SpringBootTestContextBootstrapper.class) +@ActiveProfiles("test") +public class FoundationTest extends AbstractComponent { + @Resource(name="testMapper") + protected TestMapper testMapper; + + /**DataObject를 반환한다. + * @return DataObject + */ + protected DataObject dataObject() { + return new DataObject(); + } + + /**user를 현재 사용자로 설정한다. + * @param user 사용자 객체 + */ + protected void currentUser(UserInfo user) { + UserInfo.Provider.get().setUserInfo(user); + } + + /**주어진 인자들을 각각 SQL 문자 리터럴로 변환하고, 컴마(,)로 연결하여 반환한다.
+ * SQL의 IN (...) 문장에 조건을 명시하는 것을 돕기 위한 것이다. + * @param params 인자 + * @return 컴마(,)로 연결된 SQL 문자 리터럴 + */ + protected String join(Object... params) { + return Stream.of(params).map(obj -> "'" + obj + "'").collect(Collectors.joining(",")); + } +} \ No newline at end of file diff --git a/src/main/java/cokr/xit/foundation/boot/MvcConfig.java b/src/main/java/cokr/xit/foundation/boot/MvcConfig.java new file mode 100644 index 0000000..b502785 --- /dev/null +++ b/src/main/java/cokr/xit/foundation/boot/MvcConfig.java @@ -0,0 +1,102 @@ +package cokr.xit.foundation.boot; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.multipart.commons.CommonsMultipartResolver; +import org.springframework.web.servlet.config.annotation.InterceptorRegistry; +import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; +import org.springframework.web.servlet.view.BeanNameViewResolver; +import org.springframework.web.servlet.view.JstlView; +import org.springframework.web.servlet.view.UrlBasedViewResolver; +import org.springframework.web.servlet.view.json.MappingJackson2JsonView; + +import com.fasterxml.jackson.databind.ObjectMapper; + +import cokr.xit.foundation.web.AccessInitializer; + +/**web mvc 설정(기존 dispatcher servlet) 클래스 + * @author mjkhan + */ +@Configuration +public class MvcConfig implements WebMvcConfigurer { + protected static String[] URL_PATTERNS = {"/", "/**/*.do"}; + + /**AccessInitializer를 반환한다. + * @return AccessInitializer + */ + @Bean + public AccessInitializer accessInitializer() { + return new AccessInitializer(); + } + + /**정적 파일 자원 접근에 대한 설정을 추가한다. + *
  • url: /resources/**
  • + *
  • 위치: /resources/
  • + *
+ */ + @Override + public void addResourceHandlers(ResourceHandlerRegistry registry) { + registry + .addResourceHandler("/resources/**") + .addResourceLocations("/resources/"); + } + + /**AccessInitializer를 interceptor로 추가한다. + */ + @Override + public void addInterceptors(InterceptorRegistry registry) { + registry.addInterceptor(accessInitializer()).addPathPatterns(URL_PATTERNS); + } + + /**BeanNameViewResolver를 반환한다. + * @return BeanNameViewResolver + */ + @Bean + public BeanNameViewResolver beanNameViewResolver() { + BeanNameViewResolver bean = new BeanNameViewResolver(); + bean.setOrder(0); + return bean; + } + + /**UrlBasedViewResolver를 반환한다. + * @return UrlBasedViewResolver + */ + @Bean + public UrlBasedViewResolver urlBasedViewResolver() { + UrlBasedViewResolver bean = new UrlBasedViewResolver(); + bean.setViewClass(JstlView.class); + bean.setPrefix("/WEB-INF/jsp/"); + bean.setSuffix(".jsp"); + bean.setExposeContextBeansAsAttributes(true); + bean.setOrder(1); + return bean; + } + + @Autowired + private ObjectMapper objectMapper; + + /**MappingJackson2JsonView를 반환한다. + * @return MappingJackson2JsonView + */ + @Bean + public MappingJackson2JsonView jsonView() { + MappingJackson2JsonView bean = new MappingJackson2JsonView(); + bean.setContentType("application/json;charset=UTF-8"); + bean.setObjectMapper(objectMapper); + return bean; + } + + /**CommonsMultipartResolver를 반환한다. + * @return CommonsMultipartResolver + */ + @Bean + public CommonsMultipartResolver multipartResolver() { + CommonsMultipartResolver bean = new CommonsMultipartResolver(); + int oneGB = 1_073_741_824; // 1GB=1,073,741,824 byte + bean.setMaxUploadSize(oneGB); + bean.setMaxInMemorySize(oneGB); + return bean; + } +} \ No newline at end of file diff --git a/src/main/java/cokr/xit/foundation/boot/ServletConfig.java b/src/main/java/cokr/xit/foundation/boot/ServletConfig.java new file mode 100644 index 0000000..8d87667 --- /dev/null +++ b/src/main/java/cokr/xit/foundation/boot/ServletConfig.java @@ -0,0 +1,60 @@ +package cokr.xit.foundation.boot; + +import java.util.HashMap; + +import org.apache.catalina.servlets.DefaultServlet; +import org.springframework.boot.web.servlet.FilterRegistrationBean; +import org.springframework.boot.web.servlet.ServletRegistrationBean; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.filter.CharacterEncodingFilter; + +import cokr.xit.foundation.web.AccessFilter; + +/**서블릿 설정(기존 web.xml) 클래스 + * @author mjkhan + */ +@Configuration +public class ServletConfig { + protected static String[] URL_PATTERNS = {"/", "*.do"}; + + /**CharacterEncodingFilter를 등록한다. + * @return FilterRegistrationBean + */ + @Bean + public FilterRegistrationBean encodingFilter() { + FilterRegistrationBean registration = new FilterRegistrationBean<>(); + registration.setFilter(new CharacterEncodingFilter("utf-8")); + registration.addUrlPatterns(URL_PATTERNS); + registration.setOrder(-102); + return registration; + } + + /**AccessFilter를 등록한다. + * @return FilterRegistrationBean + */ + @Bean + public FilterRegistrationBean accessFilter() { + FilterRegistrationBean registration = new FilterRegistrationBean<>(); + registration.setFilter(new AccessFilter()); + registration.addUrlPatterns(URL_PATTERNS); + registration.setOrder(-101); + return registration; + } + + /**DefaultServlet를 등록한다. + * @return ServletRegistrationBean + */ + @Bean + public ServletRegistrationBean defaultServlet() { + ServletRegistrationBean bean = new ServletRegistrationBean<>(new DefaultServlet(), "/resources/*"); + bean.setLoadOnStartup(1); + + HashMap params = new HashMap<>(); + params.put("debug", "0"); + params.put("listings", "false"); + + bean.setInitParameters(params); + return bean; + } +} \ No newline at end of file diff --git a/src/main/java/cokr/xit/foundation/boot/TransactionConfig.java b/src/main/java/cokr/xit/foundation/boot/TransactionConfig.java new file mode 100644 index 0000000..8cc8ca0 --- /dev/null +++ b/src/main/java/cokr/xit/foundation/boot/TransactionConfig.java @@ -0,0 +1,70 @@ +package cokr.xit.foundation.boot; + +import java.util.Properties; + +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.annotation.EnableTransactionManagement; +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 + */ +@Configuration +@Aspect +@EnableTransactionManagement +@EnableAspectJAutoProxy(proxyTargetClass = true) +public class TransactionConfig { + @Resource(name = "dataSource") + private DataSource dataSource; + + @Bean + public DataSourceTransactionManager txManager() { + DataSourceTransactionManager bean = new DataSourceTransactionManager(); + bean.setDataSource(dataSource); + return bean; + } + + @Bean + public TransactionInterceptor txAdvice() { + RuleBasedTransactionAttribute write = new RuleBasedTransactionAttribute(); + write.getRollbackRules().add(new RollbackRuleAttribute(Exception.class)); + + Properties txAttrs = new Properties(); + txAttrs.setProperty("*", write.toString()); + + TransactionInterceptor bean = new TransactionInterceptor(); + bean.setTransactionManager(txManager()); + bean.setTransactionAttributes(txAttrs); + return bean; + } + + @Bean + public Advisor txAdvisor() { + String expression = "execution(* cokr.xit..service.bean..*ServiceBean.*(..))"; + + AspectJExpressionPointcut serviceMethod = new AspectJExpressionPointcut(); + serviceMethod.setExpression(expression); + + 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/Yml.java b/src/main/java/cokr/xit/foundation/boot/Yml.java new file mode 100644 index 0000000..b10a301 --- /dev/null +++ b/src/main/java/cokr/xit/foundation/boot/Yml.java @@ -0,0 +1,130 @@ +package cokr.xit.foundation.boot; + +import java.util.Collections; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import org.springframework.boot.env.YamlPropertySourceLoader; +import org.springframework.core.env.PropertySource; +import org.springframework.core.io.ClassPathResource; + +import cokr.xit.foundation.Assert; + +/**yml 파일 내용을 프로퍼티 형식으로 읽기를 지원하는 유틸리티. + *

+ * @author mjkhan + */ +public class Yml { + private Map source; + + /**새 Yml을 생성한다. + * @param rootName 프로퍼티 소스의 루트 이름 + * @param path 클래스패스에서 yml 파일의 경로 + */ + public Yml(String rootName, String path) { + load(rootName, path); + } + + /**지정하는 yml 파일의 프로퍼티들을 읽어들인다. + * @param rootName 프로퍼티 소스의 루트 이름 + * @param path 클래스패스에서 yml 파일의 경로 + * @return 현재 Yml + */ + public Yml load(String rootName, String path) { + source = null; + try { + List> sources = new YamlPropertySourceLoader() + .load(rootName, new ClassPathResource(path)); + if (!sources.isEmpty()) + source = (Map)sources.get(0).getSource(); + return this; + } catch (Exception e) { + throw Assert.runtimeException(e); + } + } + + /**지정하는 프로퍼티(아래 참고)의 값을 반환한다. + * @param key 키. 프로퍼티 이름 + *

 spring:
+	 *   application:
+	 *     name: my-application
+	 * 
+ * @return 지정하는 키의 프로퍼티 값 + */ + public String getValue(String key) { + if (source == null) return ""; + + Object obj = source.get(key); + return obj != null ? obj.toString() : ""; + } + + /**지정하는 문자열로 시작하는 프로퍼티(아래 참고) 값들을 반환한다. + *
 list:
+	 *   - item-0
+	 *   - item-2
+	 *   - item-3
+ * @param prefix 프로퍼티 접두어 + * @return 지정하는 문자열로 시작하는 프로퍼티 값 + */ + public List getValues(String prefix) { + if (source == null) return Collections.emptyList(); + + return getPrefixed(prefix).stream() + .map(entry -> entry.getValue().toString()) + .collect(Collectors.toList()); + } + + private List> getPrefixed(String prefix) { + return source.entrySet().stream() + .filter(entry -> entry.getKey().startsWith(prefix)) + .collect(Collectors.toList()); + } + + /**지정하는 문자열로 시작하는 프로퍼티(아래 참고) 값들을 Map으로 반환한다. + *
 parent:
+	 *   - property-0: value-0
+	 *   - property-1: value-1
+	 *   - property-2: value-2
+ * @param prefix 프로퍼티 접두어 + * @return 지정하는 문자열로 시작하는 프로퍼티로 된 Map + */ + public Map getMap(String prefix) { + if (source == null) return Collections.emptyMap(); + + LinkedHashMap map = new LinkedHashMap<>(); + getPrefixed(prefix).stream().forEach(entry -> putTo(map, entry)); + + return map; + } + + private void putTo(LinkedHashMap map, Map.Entry entry) { + String key = entry.getKey(); + key = key.substring(key.lastIndexOf(".") + 1); + String val = entry.getValue().toString(); + map.put(key, val); + } + + /**지정하는 문자열로 시작하는 프로퍼티들(아래 참고)을 Map 목록으로 반환한다. + *
 parent:
+	 *   - property-0: value-0.0
+	 *     property-1: value-0.1
+	 *   - property-0: value-1.0
+	 *     property-1: value-1.1
+ * @param prefix 프로퍼티 접두어 + * @return 지정하는 문자열로 시작하는 프로퍼티들의 Map 목록 + */ + public List> getMaps(String prefix) { + if (source == null) return Collections.emptyList(); + + return getPrefixed(prefix).stream() + .map(entry -> { + String str = entry.getKey(); + return str.substring(0, str.lastIndexOf(".")); + }) + .collect(Collectors.toSet()).stream() + .map(this::getMap) + .collect(Collectors.toList()); + } +} \ No newline at end of file diff --git a/src/main/java/cokr/xit/foundation/boot/package-info.java b/src/main/java/cokr/xit/foundation/boot/package-info.java new file mode 100644 index 0000000..01a6fda --- /dev/null +++ b/src/main/java/cokr/xit/foundation/boot/package-info.java @@ -0,0 +1,6 @@ +/**xit-foundation 모듈을 Spring Boot 애플리케이션에서 사용할 수 있도록 지원 + *
  • 배포 모듈: xit-foundation-starter-yy.mm.dd.jar
  • + *
  • 의존 모듈: {@link cokr.xit.foundation xit-foundation-yy.mm.dd.jar}
  • + *
+ */ +package cokr.xit.foundation.boot; \ No newline at end of file