💬
목차
< 뒤로가기
인쇄

오픈소스와 비교하여 캐모마일을 사용해야 하는 이유

제품소개서 내 오픈소스 프레임워크 비교

오픈소스의 경우 개발자 역량에 의존적이며 프로젝트 진행 외 향후 유지보수 관점에서도 문제 발생 시 대처가 어렵다는 단점이 있습니다. 캐모마일의 경우 Spring의 장점을 포함하여 그룹사 환경에 적합한, 기술지원이 가능한 전담인력, 지속가능한 프레임워크입니다.

image-20220331172324348

개발 라이선스와 운영 라이선스

캐모마일의 라이선스는 아래와 같은 종류를 가집니다.

중분류 설명 캐모마일
정식 라이선스 정식 라이선스 체결 후 배포되는 라이선스.
운영 환경에서 사용하며, 서버의 코어수 검증기간을 검증합니다.
✔ 운영 서버에 적용
개발 라이선스 개발 시 사용하기 위한 라이선스이며, 특정 기간동안 발급 된다. ✔ 2개월 (로컬 및 개발 서버에 적용)
체험 라이선스 초기 체험 을 위한 라이선스이며, 짧은 기간 동안 사용할 수 있는 라이선스이다. ✔ 2주 (기간이 만료되는 경우 동작하지 않음)

빌드 시 캐모마일의 라이브러리가 다운로드 되지 않아요

캐모마일에서 배포하는 개발환경에는 라이브러리를 다운로드 받기 위한 정보가 설정되어 있습니다.

  • maven의 settings.xml 파일
  • 프로젝트의 pom.xml 파일

maven의 설정 파일인 C:/Chamomile/maven/settings.xml에 mirror 정보가 설정되어져 있으며,

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

<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0 http://maven.apache.org/xsd/settings-1.0.0.xsd">

    <!-- ... -->
    <mirrors>
        <mirror>
            <id>chamomile</id>
            <mirrorOf>chamomile</mirrorOf>
            <name>Human Readable Name for this Mirror.</name>
            <url>https://chamomile.lotteinnovate.com/nexus/repository/maven-public/</url>
        </mirror>
    </mirrors>
</settings>

maven의 설정을 사용하지 않는 경우 프로젝트의 pom.xml에 아래와 같이 기록하여 사용가능합니다.

아래 방식으로 사용하기를 권장한다.

<project>
    <!-- ... -->
    <repositories>
        <repository>
            <id>chamomile</id>
            <name>chamomile</name>
            <url>https://chamomile.lotteinnovate.com/nexus/repository/maven-public/</url>
        </repository>
    </repositories>
</project>

간혹 서버에서 라이브러리를 다운로드가 되지 않고, 시간이 오래 걸리는 경우가 있는데, 그런 경우 종료 후 다시 다운로드를 수행합니다.

  • mvn -U clean package (Force Update of Snapshots/Release)
  • mvn -o clean package (offline 모드)

개발/운영 환경 별 설정 파일의 내용을 변경하고 싶어요

개발환경 혹은 운영환경 별 환경 설정(e.g. 데이터베이스 접속 정보)에 대한 내용이 다르며, 아래와 같은 형태로 환경별 배포가 가능하다.

  1. maven profile
  2. spring profile
  3. java 환경 변수 (vm arguments)

대부분의 요건은 코드 변경 없이 배포 실수 등 이슈 핸들링 목적이므로 Maven의 profile 을 사용해서 빌드 환경을 구성하는 것을 선택

  • maven profile *

local, development, test, staging, production 등 deploy 환경에 따라 달라져야할 정보와 패키징 될 리소스 파일을 maven profile을 이용하여 build 시에 구성할 수 있다.

제약사항: 배포 환경에 따라 새로 빌드 해야 한다.
jenkins 스크립트를 통해 빌드 자동화 및 빌드 파일을 관리

  1. pom.xml 파일에 profile 관련 properties 추가 및 기본 값 설정
<properties>
    <environment>dev</environment>
</properties>
  1. pom.xml 파일에 profile 선언

    배포 파일 및 리소스 파일 관리를 위한 id 를 지정하여 사용

<profiles>
    <profile>
        <id>dev</id>
        <properties>
            <environment>dev</environment>
        </properties>
    </profile>
    <profile>
        <id>test</id>
        <properties>
            <environment>test</environment>
        </properties>
    </profile>
    <profile>
        <id>prod</id>
        <properties>
            <environment>prod</environment>
        </properties>
    </profile>
    ...
    <!-- 환경에 맞는 pofile id 를 구성 -->
</profiles>
  1. pom.xml 파일에 build 엘리먼트에 resources 디렉토리 경로를 변경
<build>
    <resources>
        <resource>
            <directory>src/main/resources-${environment}</directory>
        </resource>
        <resource>
            <directory>src/main/resources</directory>
        </resource>
        <!--
        <testResource>
            <directory>src/test/resources-${envoronment}</directory>
        </testResource>
        -->
    </resources>
</build>

빌드 시 resources 적용 순서

  • src/main/resources-${environment} 디렉토리의 데이터의 내용이 target/classes로 복사

  • src/main/resources 의 내용이 target/classes로 복사

    동일한 이름의 파일이 존재하는 경우 복사되지 않음

    즉, src/main/resources-dev/application.properties의 파일이 복사된 경우 src/main/resources/application.properties 파일은 복사되지 않음.

  1. maven package 수행시 -P 옵션을 통해 프로파일로 패키징
  • mvn package -P dev

  • mvn package -P local

  • mvn package -P prod

  1. target의 출력물 (.war / .jar) 를 열어서 deploy 환경에 맞는 리소스가 포함되었는지 확인

캐모마일과 연관이 없는 기본적인 사용 예시로 구체적인 설정 파일 및 설정 값 등은 프로젝트에서 확인하여 사용
CI/CD 도구를 통해서 자동화하고 프로파일별 배포파일을 관리하는 것을 활용 (Jenkin 등)

부트로 개발 된 프로젝트를 war 로 패키징하여 WAS에 배포하고 싶습니다.

WAS로 배포가능한 war로 패키징 하려면 아래 링크 내용에 나와있는 것처럼 일부 소스 수정이 필요합니다.

https://mkyong.com/spring-boot/spring-boot-deploy-war-file-to-tomcat/

변경 내용

  • XXXApplication.java
  • pom.xml

사용자 인증 시 캐모마일 테이블이 아닌 다른 테이블을 사용하고 싶다.

기본적으로는 캐모마일의 사용자 테이블을 사용하기를 권장한다. 하지만 이미 사용자의 테이블이 존재하거나, 혹은 캐모마일의 사용자 테이블을 사용하지 못하는 경우 아래와 같이 설정을 변경하여 적용 가능하다.

src/main/resources/spring/context-security.xml 파일의 내용 중 JdbcUserDetailsService의 설정을 변경한다.

<beans:bean id="JdbcUserDetailsService" class="net.lotte.chamomile.security.userdetails.JdbcUserDetailsService" >
    <beans:property name="dataSource" ref="dataSourceFactoryBean" />
    <beans:property name="usersByUsernameQuery" value="sql query" /> <!-- optional -->
    <beans:property name="authoritiesByUsernameQuery" value="sql query" />  <!-- optional -->
    <beans:property name="groupAuthoritiesByUsernameQuery" value="sql query" />  <!-- optional -->
</beans:bean>
  • usersByUsernameQuery (optional) : 입력받은 사용자 아이디로 사용자를 조회하는 쿼리를 설정한다.

    • 쿼리의 결과는 기본적으로 6개의 항목을 조회하고 있다. (alias를 활용하여 아래 이름으로 반환한다.)
    • userId(아이디), userPassword(비밀번호), enabled(활성화여부), accountNonExpired(계정이만료되지 않았는지), accountNonLocked(계정이 잠겨있지 않았는지), credentialsNonExpired(비밀번호가 만료되지 않았는지): 순서는 변경되어서는 안된다.
    • 예) select userId, userPassword, enabled, accountNonExpired, accountNonLocked, credentialsNonExpired from {your table} where {start_date} < ? and {end_date} > ? and userId = ?
  • authoritiesByUsernameQuery (optional) : 입력받은 사용자 아이디에 부여 된 권한 목록을 조회하는 쿼리를 설정한다.

    • 쿼리의 결과는 기본적으로 2개의 항목을 조회하고 있다.
    • userId(아이디), roleId(권한): 순서가 변경되어서는 안된다.
  • groupAuthoritiesByUsernameQuery (optional) : 사용자가 속한 그룹의 권한 목록을 조회하는 쿼리를 설정한다.

    • 쿼리의 결과는 기본적으로 3개의 항목을 조회하고 있다.
    • userId(아이디), groupId(그룹), roleId(권한): 순서가 변경되어서는 안된다.

참고로 인가(접근제어)에 관한 정보도 동일하게 다른 곳에서 정보를 가져와 사용가능하다.


  
  
 

rolesQuery : URL 리소스에 대한 권한 정보를 조회하는 쿼리를 설정한다.

  • 기본적으로 url(리소스 url 정보), authority(권한)을 조회하게 되어 있다.
  • 순서와 명칭이 동일해야 한다.

부트에서는 아래와 같이 변경가능하다.

@Configuration
protected static class CustomizingSuccessAndFailureHandlerConfiguration
 extends net.lotte.chamomile.autoconfiguration.SecurityAutoConfiguration {

 @Bean
 @Override
 public JdbcUserDetailsService jdbcUserDetailsService(DataSource dataSourceFactoryBean) throws Exception {
     JdbcUserDetailsService jdbcUserDetailsService = new JdbcUserDetailsService();
     jdbcUserDetailsService.setDataSource(dataSourceFactoryBean);
     jdbcUserDetailsService.setUsersByUsernameQuery("sql query");
     jdbcUserDetailsService.setAuthoritiesByUsernameQuery("sql query");
     jdbcUserDetailsService.setGroupAuthoritiesByUsernameQuery("sql query");
     return jdbcUserDetailsService;
 }

 @Bean
 @Override
 public SecuredUrlResourceService securedUrlResourceService(DataSource dataSourceFactoryBean) {
     SecuredUrlResourceService securedUrlResourceService = new SecuredUrlResourceService();
     securedUrlResourceService.setDataSource(dataSourceFactoryBean);
     securedUrlResourceService.setRolesQuery("sql query");
     return securedUrlResourceService;
 }

 // ...
}

넥사크로와의 연동은 어떻게 되는지

타 프레임워크에서 상용 UI 솔루션과 연동을 위한 모듈을 제공하나, 해당 프레임워크에 종속적인 형태로 개발이 된다.

Chamomile에서는 프레임워크에 대한 종속성을 탈피하기 위해 Spring MVC에서 제공하는 기술들을 이용하여 상용 UI 솔루션과 연동할 수 있는 방법을 제시한다.

즉, 다시말해 백엔드에서 개발되어지는 코드 자체가 프레임워크에 대한 종속성, 상용 UI 솔루션에 대한 종속성이 제거된다. 상용 UI 솔루션을 사용하지 않는 경우에도 동일한 코드로 서비스를 제공할 수 있다. (단, 예외적인 경우도 존재한다.)

지원하는 상용 UI 솔루션은 아래와 같다.

  1. nexacro (투비소프트)
  2. xplatform (투비소프트)
  3. websquare (인스웨이브시스템즈)

Spring MVC에서 제공하는 기술들을 그대로 사용할 수 있도록 구성된다.

image-20200911093232320

서버에서의 개발 방식은 기존 웹 개발과 동일한 형태로 개발을 할 수 있으며, 벤더사의 데이터 타입에 맞게 primitive 타입 혹은 pojo 형태의 데이터로 자동 변환된다.

상세한 내용은 Web_개발가이드UI어댑터 부분을 참고한다.

  • 간단한 실습 *

프로젝트 생성

먼저 File -> New -> Project를 선택한 후 Chamomile Framework -> Create Chamomile Project를 선택한 후 Next를 클릭한다.

아래와 같이 창이 생성되면 값을 입력해준다.

image-20220404172655404

Base package를 net.lotte.sample로 지정한다.

이후 버전에서 변경되지 않는 부분은 패치될 예정입니다.

생성 된 프로젝트는 화면 예제를 포함하고 있으며, 컴파일 된 넥사크로 소스도 포함한다.

기본적으로 생성 된 소스는 http://localhost:8088/chamomile-samples-nexacro17 로 구성되어 있기 때문에 서버에 배포 시 portcontext를 변경하여 적용한다.

image-20220404172743203

eclipse의 servers 뷰에서 image-20220404172905594 를 더블클릭하면 서버 설정 화면이 나오고, port8088로 변경한다.

image-20220404173014540

이후 servers 뷰에서 tomcat을 선택하여 우클릭 하여 Add and Remove...를 선택하여 서버에 프로젝트를 추가한다.

image-20220404173102240

좀전에 만든 edu-nexacro를 추가한 후

image-20220404173204411

서버를 실행한다.

image-20220404173249349

혹시나 아래와 같은 오류가 발생하는 경우

Caused by: java.lang.IllegalArgumentException: Pointcut is not well-formed: expecting 'illegal identifier start (#)' at character position 29
(execution(* ###BASEPACKAGE###..*ServiceImpl.*(..)) || execution(* net.lotte.chamomile.core.servlet.mvc.method.RequestMappingInfoSynchronization.*(..)))

chmm.txPointcut.expression=(execution(* net.lotte.sample..*ServiceImpl.*(..)) or execution(* net.lotte.chamomile.core.servlet.mvc.method.RequestMappingInfoSynchronization.*(..)))

src/main/resources/application.properties 파일의 jdbc 설정 값과 txPointcut의 값을 변경해 준다. (기존 프로젝트에서 복사)

chmm.jdbc.driverClassName=net.sf.log4jdbc.DriverSpy
chmm.jdbc.jdbc-url=jdbc:log4jdbc:mariadb://127.0.0.1:3306/chamomile?autoReconnect=true&serverTimezone=UTC
chmm.jdbc.username=root
chmm.jdbc.password=ldcc!2626
chmm.jdbc.maximumPoolSize=8
chmm.jdbc.connectionTimeout=30000
chmm.jdbc.maxLifetime=1800000

chmm.txPointcut.expression=(execution(* net.lotte.sample..*ServiceImpl.*(..)) or execution(* net.lotte.chamomile.core.servlet.mvc.method.RequestMappingInfoSynchronization.*(..)))

이 후 버전에는 패치가 됩니다.

서버가 정상적으로 로드 된 후 http://localhost:8088/chamomile-samples-nexacro17 접속하여 넥사크로와의 데이터 연동이 정상적으로 이루어 지는지 테스트를 수행한다.

image-20220404173948219

requestParam 테스트는 실패하도록 구성되어져 있습니다. @RequestParam을 사용할 때에는 primitive 타입만 선언하여 사용할 수 있습니다.

//fail
@RequestMapping(value="/handleRequestParam")
public ModelAndView handleRequestParam(
 @RequestParam("addr") Address addr
 , @RequestParam("infoList") List
infoList) {

넥사크로 기반으로 프로젝트를 진행하는 경우 투비소프트에서 진행하는 교육 수강하기를 권장한다.

넥사크로에서의 예외 처리는 어떻게 하나요?

캐모마일은 UiAdapter를 통해 기본적인 예외를 처리하고 있으며,

nexacro 연동 시 에러 코드는 -1로 고정 된 값을 반환하고 있습니다.

<Parameter id="ErrorCode" type="string">-1</Parameter> 
<Parameter id="ErrorMsg" type="string">An Error Occured.... 

인증 및 인가 오류 시

  • http status 200, ErrorCode에 -401, -403으로 응답하고 있습니다.

벤더사의 ErrorCode 값을 변경하여 UI에서 추가적인 처리를 하고자 하는 경우 NexacroException을 이용하여 ErrorCode와 ErrorMsg를 변경할 수 있습니다.

추가적으로 nexacro platform에서의 예외 처리는 아래 2군데에서 처리 가능합니다.

  • transaction의 callback (ErrorCode 처리)
  • ADL의 onError (http status에 대한 처리)

admin에서 설정 혹은 DB에서 직접 데이터를 변경하였는데, 잘 동작하지 않습니다.

캐모마일은 기본적으로 데이터를 캐시하여 사용중에 있습니다. (어드민에서 관리되는 데이터들이 캐시 된다.)

예를 들어, 공통코드에 대한 정보, 다국어에 대한 정보, 리소스 보안에 관련한 정보 등

DB에서 데이터를 직접 변경하거나, 내장 Redis와의 연결이 원활하지 않을 경우 변경 된 데이터가 반영되지 않는 현상이 가끔 발생합니다.

그럴때에는 캐모마일 어드민의 시스템 설정 > 캐시관리 영역에서 캐시 초기화를 해주시면 정상적으로 동작합니다.

에러가 났을때 에러는 어떻게 봐야 하는가?

어플리케이션을 개발하는 경우 다양한 예외를 만날 수 있습니다.

에러가 발생하는 경우 로그 내역을 확인해야 합니다.

에러의 정보는 console 혹은 파일에 기록 되며 아래와 같은 형태로 구성됩니다.


; bad SQL grammar []; nested exception is java.sql.SQLSyntaxErrorException: (conn=375) Unknown column ‘DOC_IDs’ in ‘field list’
at org.springframework.jdbc.support.SQLErrorCodeSQLExceptionTranslator.doTranslate(SQLErrorCodeSQLExceptionTranslator.java:235) ~[spring-jdbc-5.2.8.RELEASE.jar:5.2.8.RELEASE]
at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:72) ~[spring-jdbc-5.2.8.RELEASE.jar:5.2.8.RELEASE]
at org.mybatis.spring.MyBatisExceptionTranslator.translateExceptionIfPossible(MyBatisExceptionTranslator.java:88) ~[mybatis-spring-2.0.4.jar:2.0.4]
at org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:440) ~[mybatis-spring-2.0.4.jar:2.0.4]

at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) [tomcat-embed-core-9.0.37.jar:9.0.37]
at java.lang.Thread.run(Thread.java:748) [?:1.8.0_265]
Caused by: java.sql.SQLSyntaxErrorException: (conn=375) Unknown column 'DOC_IDs' in 'field list'
at org.mariadb.jdbc.internal.util.exceptions.ExceptionMapper.get(ExceptionMapper.java:242) ~[mariadb-java-client-2.4.4.jar:?]
at org.mariadb.jdbc.internal.util.exceptions.ExceptionMapper.getException(ExceptionMapper.java:171) ~[mariadb-java-client-2.4.4.jar:?]

at java.lang.reflect.Method.invoke(Method.java:498) ~[?:1.8.0_265]
at org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:426) ~[mybatis-spring-2.0.4.jar:2.0.4]
… 185 more
Caused by: java.sql.SQLException: Unknown column 'DOC_IDs' in 'field list'
at org.mariadb.jdbc.internal.protocol.AbstractQueryProtocol.readErrorPacket(AbstractQueryProtocol.java:1594) ~[mariadb-java-client-2.4.4.jar:?]
at org.mariadb.jdbc.internal.protocol.AbstractQueryProtocol.readPacket(AbstractQueryProtocol.java:1453) ~[mariadb-java-client-2.4.4.jar:?]
at org.mariadb.jdbc.internal.protocol.AbstractQueryProtocol.getResult(AbstractQueryProtocol.java:1415) ~[mariadb-java-client-2.4.4.jar:?]
at org.mariadb.jdbc.internal.protocol.AbstractQueryProtocol.executeQuery(AbstractQueryProtocol.java:289) ~[mariadb-java-client-2.4.4.jar:?]
at org.mariadb.jdbc.ClientSidePreparedStatement.executeInternal(ClientSidePreparedStatement.java:221) ~[mariadb-java-client-2.4.4.jar:?]

at org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:426) ~[mybatis-spring-2.0.4.jar:2.0.4]
… 185 more

간단하게 OKKY – 초보 개발자를 위한 스택트레이스 읽는 법를 참고

예외의 정보를 바탕으로 어디에서, 어떠한 예외가 발생했고, 예외의 내용은 무엇인지 찾을 수 있어야 한다.

로그 설정은 어떻게 변경할 수 있는가

캐모마일에서 로그는 log4j2를 이용하여 처리되고 있습니다.

이력 데이터 적재 시 성능 문제로 비동기로거를 사용하여 데이터를 적재합니다.

로그 파일은 src/main/resources/log4j2.xml 파일에 기록되어져 있으며, Rewrite Appender를 이용하여 로그 마스킹 기능을 제공합니다.

로컬 개발환경에서는 아래와 같이 Loggers의 Root 레벨을 DEBUG로 설정하여 사용하시길 권장드리며, 개발서버 및 운영 서버에서는 INFO로 변경하여 사용하시길 권장 드립니다.

<Configuration status="error" packages="net.lotte.chamomile.core.log.mask.filter" monitorInterval="1">

    <Loggers>
        <Root level="INFO">
            <AppenderRef ref="maskDailyRollingFile" /> 
        </Root>
    </Loggers>
</Configuration>

Root의 레벨은 명시 된 Logger를 제외한 로거들에 대한 레벨을 설정한다.

그리고 세부적으로 Logger 들에 대한 레벨을 변경하고자 하는 경우 아래와 같이 각 로거들의 레벨을 변경하여 사용할 수 있습니다.

<!-- Application Loggers -->
<Logger name="net.lotte.chamomile" level="DEBUG" additivity="false">
    <AppenderRef ref="maskDailyRollingFile" />
</Logger>
<Logger name="net.lotte.chamomile.security.util.matcher.SerializableAntPathRequestMatcher" level="INFO" additivity="false">
    <AppenderRef ref="maskDailyRollingFile" />
</Logger>

<!-- 3rdparty Loggers -->
<Logger name="org.springframework.security" level="DEBUG" additivity="false">
    <AppenderRef ref="maskDailyRollingFile" />
</Logger>

아래 로거들은 이력데이터를 DB에 적재하기 위한 용도로 사용되며, TRACE인 경우에만 데이터가 적재 된다.





다음 캐모마일 소개