페이지

2022년 8월 2일 화요일

Git 복제 + IntelliJ 열기 + Maven 빌드 자동화

Git 복제 + IntelliJ 열기 + Maven 빌드 자동화

1. 자동화 목표

문제 보고부터 시작해서 소프트웨어를 수정하고 JAR 파일을 테스트 위치로 보내기까지의 과정을 아래의 여섯 단계로 나눌 수 있습니다.

  1. 문제 보고

  2. Git 저장소 복제

    cd WORKING_DIR
    \path\to\repo-scripts\clone-and-cd-PROJECT_NAME.bat
    
  3. IntelliJ에서 프로젝트 임포트하여 열기

    .\scripts\launch-idea.bat
    
  4. 문제 해결을 위한 소스 수정

  5. Maven으로 프로젝트 빌드

    .\scripts\clean-and-build.bat
    
  6. JAR 파일을 테스트 위치로 보내기

    .\scripts\upload-jar.bat
    

위의 1번, 4번 과정을 제외한 나머지 과정들에 대해서 자동화 스크립트를 작성하고자 합니다.

2. 개발 환경

이 문서를 작성하기 위하여 사용한 개발 환경은 아래와 같습니다.

  1. 시스템 정보
    1. Windows 10
  2. 개발 도구
    1. JDK 1.8
    2. Maven 3.8.6
    3. IntelliJ 2021.2.2
    4. PuTTY 0.77 (원격 접속 및 파일 업로드 도구)

개발 도구의 실행 파일이 있는 경로들을 시스템 환경 변수 PATH에 등록합니다.

3. 스크립트 작성

3.1. Git 저장소 복제

  1. clone-and-cd-PROJECT_NAME.bat 파일의 내용을 아래와 같이 작성합니다.

    @echo off
    
    git clone https://YOUR_NAME@github.com/ACCOUNT_NAME/REPOSITORY_NAME.git
    cd REPOSITORY_NAME\PROJECT_NAME
    

3.2. IntelliJ에서 프로젝트 임포트하여 열기

  1. launch-idea.bat 파일의 내용을 아래와 같이 작성합니다.

    @echo off
    
    idea64.exe pom.xml
    

3.3. Maven으로 프로젝트 빌드

  1. clean-and-build.bat 파일의 내용을 아래와 같이 작성합니다.

    @echo off
    
    call mvn clean
    call mvn install
    

3.4. JAR 파일을 테스트 위치로 보내기

보안을 위해서는 비밀번호를 스크립트에 직접 지정하는 방식보다는 공개키 인증 방식을 권장합니다.

3.4.1. 비밀번호 직접 지정 방식

  1. upload-jar.bat 파일의 내용을 아래와 같이 작성합니다.

    @echo off
    
    psftp.exe USER@HOST -P PORT -pw PASSWORD -b upload-jar-batch.txt 
    
  2. upload-jar-batch.txt 파일의 내용을 아래와 같이 작성합니다.

    cd JAR_INSTALL_DIR
    put target/JAR_FILE
    

3.4.2. 공개키 인증 방식

공개키 인증 방식을 사용할 때 비밀번호 입력 과정 없이 진행하기 위해서는 PC에서 생성한 공개키를 테스트 서버에 등록해 두어야 합니다. 이에 대한 안내는 SSH로 암호 입력하지 않고 로그인하기 자료에서 제공하고 있습니다.

  1. upload-jar.bat 파일의 내용을 아래와 같이 작성합니다.

    @echo off
    
    psftp.exe USER@HOST -P PORT -i \PATH\TO\YOUR.ppk -b upload-jar-batch.txt
    

    psftp.exe가 사용하는 *.ppk 파일을 만드는 과정은 Using PuTTYgen, the PuTTY key generator 자료에서 설명하고 있습니다.

    참고로 OpenSSH의 sftp.exe의 경우 명령 줄에서 비밀번호를 지정하는 옵션을 제공하지 않기 때문에 비밀번호 직접 지정 방식으로는 자동화가 안되지만 공개키 인증 방식을 사용할 경우에는 아래와 같이 스크립트를 작성하여 자동화할 수 있습니다.

    @echo off
    
    sftp.exe -P PORT -b upload-jar-batch.txt USER@HOST
    
  2. upload-jar-batch.txt 파일의 내용을 아래와 같이 작성합니다.

    cd JAR_INSTALL_DIR
    put target/JAR_FILE
    

4. 기타

4.1. SSH 터미널 열고 연결하기

4.1.1. 비밀번호 직접 지정 방식

  1. open-ssh.bat 파일의 내용을 아래와 같이 작성합니다.

    @echo off
    
    start putty.exe -ssh USER@HOST -P PORT -pw PASSWORD 
    

4.1.2. 공개키 인증 방식

  1. open-ssh.bat 파일의 내용을 아래와 같이 작성합니다.

    @echo off
    
    start putty.exe -ssh USER@HOST -P PORT -i \PATH\TO\YOUR.ppk
    

5. 참고 자료

  1. Using public key authentication with PSFTP
  2. Using PuTTYgen, the PuTTY key generator
  3. The PuTTY command line
  4. SSH로 암호 입력하지 않고 로그인하기

Written with StackEdit.

2022년 7월 7일 목요일

Eclipse Java 프로젝트를 Maven 프로젝트로 변환하기

Eclipse Java 프로젝트를 Maven 프로젝트로 변환하기

1. 들어가는 말

이 글에서는 Eclipse Java 프로젝트Maven 프로젝트로 변환했을 때의 이점과 변환 방법을 소개합니다.

구분 설명 소스 폴더 위치
Eclipse Java 프로젝트 Eclipse에서 File -> New -> Project -> Java -> Java Project 메뉴를 통해서 생성한 프로젝트 src
Maven 프로젝트 Maven을 사용해서 빌드하는 프로젝트 (Eclipse의 File -> New -> Project -> Maven -> Maven Project 메뉴를 통해서 생성할 수도 있음) src/main/java
src/test/java

개발하고 있는 Java 응용프로그램 프로젝트의 규모가 복잡하지 않더라도 그 수가 수십 개에 이르고 IDE와 빌드 도구마저 제각각이라면 이로부터 발생하는 어려움들을 과소평가해서는 안됩니다. 대표적인 어려움 몇 가지를 적어보면 아래와 같습니다.

  • 이 프로젝트의 배포용 실행 파일을 어떻게 만들지?
    • 타겟 클래스 버전은?
    • 어떤 파일들이 실행 파일에 포함되어야 하지?
    • 리소스 파일은 어디에 복사해야 하지?
    • 외부 참조 파일은 어떤 방식으로 포함시키지?
    • 새롭게 빌드한 결과 파일의 크기가 왜 기존의 결과 파일 크기와 다르지?

IDE가 제공하는 자체 빌드 도구를 통해서 위의 어려움들을 어느 정도 완화시킬 수는 있지만 만족스러운 정도는 아니며 모든 개발자들이 동일한 IDE를 쓰도록 유도하는 것도 쉽지는 않습니다. 왜냐하면 각자 IDE를 선택하는 데에는 여러 가지 이유가 있을 것이기 때문입니다. 다행히도 위와 같은 문제를 해결하기 위해 탄생한 빌드 전문 도구인 Maven을 사용하면 프로젝트 정보를 pom.xml 파일에서 지정하고 mvn package 명령을 실행함으로써 배포용 실행 파일을 만들어 낼 수 있습니다.

어찌보면 당연해 보이는 이야기를 굳이 하는 이유는 IDE 제공 빌드 도구를 사용해서 빌드하는 프로젝트들이 생각보다 많기 때문입니다.

2. 변환했을 때의 이점

2.1. 의존성 관리 개선

2.1.1. Eclipse

  • 외부 라이브러리들을 특정 경로에 보관하고 이들을 참조하도록 빌드 구성을 수정합니다.
  • 사용할 라이브러리 버전을 바꾸고자 한다면 새로운 라이브러리 파일을 다운로드해서 저장하고 이 파일을 참조하도록 빌드 구성을 수정합니다.
  • 동일한 프로젝트 소스를 가지고 새로운 PC에서 개발 환경을 구성할 때 라이브러리 파일 저장 경로를 기존과 동일하게 유지하지 않으면 빌드 구성을 수정해 주어야 합니다.

2.1.2. Maven

  • 참조할 외부 라이브러리들에 대한 정보(groupId, artifactId, version)를 pom.xml 파일에서 지정합니다.
  • 사용할 라이브러리 버전을 바꾸고자 한다면 version 값만 수정하면 됩니다.
  • 새로운 PC에 개발 환경을 구성할 때 라이브러리 파일 저장 경로와 관련하여 수정할 사항은 없습니다.

2.2. 단위 테스트 개선

2.2.1. Eclipse

  • JUnit 라이브러리를 참조하도록 빌드 구성을 변경하고 테스트 코드를 작성하여 실행합니다. 복잡한 편은 아니지만 프로젝트가 많을 때, 사용하는 IDE가 서로 다를 때 불편할 수 있습니다.

2.2.2. Maven

  • JUnit 의존성을 추가하고 테스트 코드를 작성하여 실행하는 과정이 간편합니다.

2.3. JAR 파일 묶기 개선

2.3.1. Eclipse

  • Export -> Runnable JAR file 메뉴로 실행 가능한 JAR 파일을 만듭니다. 하나의 프로젝트에 대해 작업을 반복해야 하거나 여러 프로젝트들에 대해서 작업을 수행해야 할 때 매우 번거로운 과정이 될 수 있습니다.

2.3.2. Maven

  • pom.xml 파일에 shader 플러그인을 추가하고 mvn package 명령으로 실행 가능한 JAR 파일을 만듭니다. 한 줄 명령을 실행하는 것으로 원하는 결과를 얻을 수 있습니다.

3. 변환 방법

3.1. Eclipse에서 변환

Eclipse 내에서 아래의 과정을 수행합니다.

  1. 프로젝트를 선택한 상태에서 마우스 오른쪽 버튼을 클릭합니다.
  2. 컨텍스트 메뉴 Configure -> Convert to Maven Project를 클릭합니다.
  3. Create new POM 대화상자에서 입력 값을 그대로 두거나 변경한 후 Finish 버튼을 클릭합니다.
  4. Eclipse를 종료합니다.

위 작업의 결과로 Eclipse가 사용하는 .project 파일과 .classpath 파일이 변경되고 Maven이 사용하는 pom.xml 파일이 생성됩니다.

  • 변환 전 .project 파일

    <?xml version="1.0" encoding="UTF-8"?>
    <projectDescription>
        <name>HelloWorld</name>
        <comment></comment>
        <projects>
        </projects>
        <buildSpec>
            <buildCommand>
                <name>org.eclipse.jdt.core.javabuilder</name>
                <arguments>
                </arguments>
            </buildCommand>
        </buildSpec>
        <natures>
            <nature>org.eclipse.jdt.core.javanature</nature>
        </natures>
    </projectDescription>
    
  • 변환 전 .classpath 파일

    <?xml version="1.0" encoding="UTF-8"?>
    <classpath>
        <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>
        <classpathentry kind="src" path="src"/>
        <classpathentry kind="output" path="bin"/>
    </classpath>
    
  • 변환 후 .project 파일

    <?xml version="1.0" encoding="UTF-8"?>
    <projectDescription>
        <name>HelloWorld</name>
        <comment></comment>
        <projects>
        </projects>
        <buildSpec>
            <buildCommand>
                <name>org.eclipse.jdt.core.javabuilder</name>
                <arguments>
                </arguments>
            </buildCommand>
            <buildCommand>
                <name>org.eclipse.m2e.core.maven2Builder</name>
                <arguments>
                </arguments>
            </buildCommand>
        </buildSpec>
        <natures>
            <nature>org.eclipse.m2e.core.maven2Nature</nature>
            <nature>org.eclipse.jdt.core.javanature</nature>
        </natures>
    </projectDescription>
    
  • 변환 후 .classpath 파일

    <?xml version="1.0" encoding="UTF-8"?>
    <classpath>
        <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8">
            <attributes>
                <attribute name="maven.pomderived" value="true"/>
            </attributes>
        </classpathentry>
        <classpathentry kind="src" output="target/classes" path="src">
            <attributes>
                <attribute name="optional" value="true"/>
                <attribute name="maven.pomderived" value="true"/>
            </attributes>
        </classpathentry>
        <classpathentry kind="con" path="org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER">
            <attributes>
                <attribute name="maven.pomderived" value="true"/>
            </attributes>
        </classpathentry>
        <classpathentry kind="output" path="target/classes"/>
    </classpath>
    
  • 생성된 pom.xml 파일

    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
      <modelVersion>4.0.0</modelVersion>
      <groupId>HelloWorld</groupId>
      <artifactId>HelloWorld</artifactId>
      <version>0.0.1-SNAPSHOT</version>
      <build>
        <sourceDirectory>src</sourceDirectory>
        <plugins>
          <plugin>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>3.8.0</version>
            <configuration>
              <source>1.8</source>
              <target>1.8</target>
            </configuration>
          </plugin>
        </plugins>
      </build>
    </project>
    

3.2. 소스 폴더 변경

  1. Maven이 사용하는 pom.xml 파일을 열고 <build> 아래에 있는 <sourceDirectory> 항목을 제거합니다. 이렇게 하면 Maven은 src/main/javasrc/test/java을 기본 소스 폴더 위치로 사용하게 됩니다.
  2. Eclipse가 사용하는 .classpath 파일을 열고 kind="src" 항목을 아래와 같이 편집합니다.
    <!--
    <classpathentry kind="src" output="target/classes" path="src">...</classpathentry>
    -->
    <classpathentry kind="src" output="target/classes" path="src/main/java">
        <attributes>
    		<attribute name="optional" value="true"/>
    		<attribute name="maven.pomderived" value="true"/>
    	</attributes>
    </classpathentry>
    <classpathentry kind="src" output="target/test-classes" path="src/test/java">
        <attributes>
    		<attribute name="optional" value="true"/>
    		<attribute name="maven.pomderived" value="true"/>
    		<attribute name="test" value="true"/>
    	</attributes>
    </classpathentry>
    
  3. src 폴더 아래의 파일들을 src/main/java 폴더 아래로 옮깁니다.

3.3. Eclipse 시작하고 새로고침

  1. Eclipse를 시작합니다.
  2. 프로젝트 이름에서 마우스 오른쪽 버튼을 클릭하고 컨텍스트 메뉴 Refresh를 클릭합니다.

3.4. 의존성 추가

  1. pom.xml 파일을 열고 마우스 오른쪽 버튼을 클릭합니다.
  2. 컨텍스트 메뉴 Maven -> Add Dependency를 클릭합니다.
  3. 추가할 라이브러리에 대한 Group Id, Artifact Id 등을 입력하고 OK 버튼을 클릭합니다.

직접 다운로드한 JAR 파일에 대한 의존성을 pom.xml에 추가하려면 아래와 같은 방법으로 먼저 Maven 로컬 저장소에 설치해야 합니다.

  1. Maven의 install:install-file 명령을 사용하여 JAR 파일을 Maven 로컬 저장소에 저장합니다.
    mvn install:install-file -Dfile=.\ojdbc6.jar -DgroupId=com.oracle -DartifactId=ojdbc6 -Dversion=11.2.0.3 -Dpackaging=jar
    
  2. 의존성을 추가합니다.
    <dependency>  
        <groupId>com.oracle</groupId>  
        <artifactId>ojdbc6</artifactId>  
        <version>11.2.0.3</version>  
    </dependency>
    

4. 단위 테스트 추가하기

4.1. pom.xml

  1. JUnit 의존성을 추가합니다.

    <dependency>  
        <groupId>junit</groupId>  
        <artifactId>junit</artifactId>  
        <version>4.13.2</version>  
        <scope>test</scope>  
    </dependency>
    
  2. pom.xml 파일에서 마우스 오른쪽 버튼을 클릭하고 컨텍스트 메뉴 Maven -> Update Project를 클릭합니다.

4.2. src/test/java/com/example/DateTimeUtilTest.java

  1. 아래와 같은 단위 테스트 코드를 추가합니다.

    package com.example;
    
    import org.junit.Assert;
    import org.junit.Test;
    
    public class DateTimeUtilTest {
    	@Test
    	public void testGetFormattedShortDateTimeNow() {
    		String s = DateTimeUtils.getFormattedShortDateTimeNow();
    		System.out.println(s);
    		Assert.assertTrue(s != null);
    	}
    }
    

4.3. 테스트 실행

  • 모든 단위 테스트 실행

    mvn test
    
  • 특정 클래스의 단위 테스트 실행

    mvn -Dtest=TestMapper test
    
  • 특정 메쏘드의 단위 테스트 실행

    mvn -Dtest=TestMapper#testCheckTable test
    

5. JAR 파일 묶기

5.1. pom.xml

shader 플러그인 추가

<build>
    <finalName>example</finalName>
    <plugins>
        <plugin>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>3.8.0</version>
            <configuration>
                <source>1.8</source>
                <target>1.8</target>
            </configuration>
        </plugin>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-shade-plugin</artifactId>
            <version>3.3.0</version>
            <executions>
                <execution>
                    <phase>package</phase>
                    <goals>
                        <goal>shade</goal>
                    </goals>
                    <configuration>
                        <transformers>
                            <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
                                <mainClass>com.example.ExampleMain</mainClass>
                            </transformer>
                        </transformers>
                    </configuration>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>

5.2. 패키징 실행

mvn package

6. 기타

6.1. 소스 파일 문자셑 지정

문자셑으로 MS949를 쓰는 명령 프롬프트에서 mvn 명령을 사용하여 컴파일할 때 아래의 경우 문자 인코딩 오류가 발생할 것입니다.

  • 소스 파일의 문자셑이 UTF-8이고 소스 파일 내에서 한글을 사용

이 문제는 pom.xml에서 문자셑을 UTF-8로 지정하면 해결됩니다.

<properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
</properties>

6.2. Java 컴파일러 버전

<properties>
    <maven.compiler.target>1.8</maven.compiler.target>
    <maven.compiler.source>1.8</maven.compiler.source>
</properties>

또는

<plugins>
    <plugin>
        <artifactId>maven-compiler-plugin</artifactId>
        <configuration>
            <source>1.8</source>
            <target>1.8</target>
        </configuration>
    </plugin>
</plugins>

위 두 속성의 기본값은 1.6이다.

7. 참고 자료

  1. Apache Maven Shade Plugin
  2. How to convert an existing Java Project to Maven in Eclipse?
  3. Setting the Java Version in Maven

Written with StackEdit.

2022년 5월 2일 월요일

Maven 사용 기초

Maven 사용 기초

Maven을 자주 사용하지 않는 상황에서 필요할 때 참조하기 위하여 이 문서를 작성합니다.

Maven 설치

프로젝트 생성 및 빌드 기본 과정

  1. 프로젝트 생성

    > mvn archetype:generate -DgroupId=com.mycompany.app -DartifactId=my-app -DarchetypeArtifactId=maven-archetype-quickstart -DarchetypeVersion=1.4 -DinteractiveMode=false
    
  2. 프로젝트 폴더로 이동

    > cd my-app
    
  3. 프로젝트 빌드

    > mvn package
    

    테스트 과정을 빼고 빌드를 하고자 한다면 maven.test.skip=true 옵션을 추가합니다.

    > mvn -Dmaven.test.skip=true package
    
  4. 응용프로그램 실행

    > mvn exec:java -Dexec.mainClass=com.mycompany.app.App
    

    응용프로그램에 인자를 전달하고자 한다면 아래와 같이 실행하면 됩니다.

    > mvn exec:java -Dexec.mainClass=com.mycompany.app.App -Dexec.args="foo bar"
    

    또는

    > java -cp target/my-app-1.0-SNAPSHOT.jar com.mycompany.app.App
    

자주 사용하는 archetype들

  • maven-archetype-quickstart
  • maven-archetype-simple
  • maven-archetype-webapp

자주 사용하는 단계들

기본에 해당하는 단계들

  1. compile - 소스 코드 컴파일
  2. package - 컴파일 결과를 JAR 파일과 같은 형태로 묶기
  3. install - 패키지 결과물을 지역 저장소로 복사
  4. deploy - 최종 결과물을 원격 저장소로 복사

기타 자주 사용하는 단계들

  1. clean - 빌드를 통해 생성한 결과물들을 삭제
  2. site - 사이트 문서 생성

참고 자료

Written with StackEdit.

2022년 4월 18일 월요일

JDK 1.6 + Spring Framework 4 + MyBatis 3 사용 기초

JDK 1.6 + Spring Framework 4 + MyBatis 3 사용 기초

1. 개요

다음과 같은 환경에서 Spring Framework 4 기반의 MyBatis 3 사용 프로그램을 작성하고 빌드하여 실행할 수 있도록 안내합니다.

도구 버전 설명
Windows 10 운영체제
JDK 1.6 Java 컴파일러 및 실행 환경
IntelliJ IDEA 2021.2.2 (Community Edition) 통합 개발 환경
Maven 3.2.5 (JDK 1.6에서 동작하는 마지막 버전) 빌드 도구
Spring Framework 4.3.30.RELEASE 응용 프레임워크
MyBatis 3.4.6 DB 사용 프레임워크

2. 준비

아래 블로그 글을 참고하여 프로젝트를 생성하고 Spring Framework 4 기반 응용프로그램을 작성합니다.

3. JDBC 설정 파일 추가

3.1. jdbc.conf

#############################  
##         MySQL           ##  
#############################  
jdbc.type=1  
jdbc.driver=com.mysql.jdbc.Driver  
jdbc.url=jdbc:mysql://DB_IP:DB_PORT/DB_NAME?serverTimezone=UTC&useSSL=false  
jdbc.username=DB_USERNAME  
jdbc.password=DB_PASSWORD 
jdbc.validation.query=SELECT 1  
mybatis.mapper.location=../conf/mapper/app-mysql.xml  
  
#===========================================================  
# DATABASE SESSION CONFIG ( init; max; min )  
#===========================================================  
jdbc.init.pool.size=5  
jdbc.max.pool.size=20  
jdbc.min.pool.size=5

3.2. applicationContext.xml

<beans ...
       xmlns:context="http://www.springframework.org/schema/context"
       ...
       xsi:schemaLocation="
       ...
       http://www.springframework.org/schema/context  
       http://www.springframework.org/schema/context/spring-context.xsd
       ...>

    <context:property-placeholder properties-ref="properties" />  
  
    <bean id="properties" class="org.springframework.beans.factory.config.PropertiesFactoryBean">  
        <property name="locations">  
            <list>  
                <value>file:../conf/jdbc.conf</value>  
            </list>  
        </property>  
    </bean>
    ...

4. MyBatis 사용

4.1. pom.xml

<properties>  
    <spring.version>4.3.30.RELEASE</spring.version>  
    <mybatis.version>3.4.6</mybatis.version>  
    <mybatis.spring.version>1.3.3</mybatis.spring.version>  
    <hikaricp.version>2.3.13</hikaricp.version>  
    <mysql.connector.version>5.1.49</mysql.connector.version>
</properties>

<dependencies>
    <dependency>  
        <groupId>org.springframework</groupId>  
        <artifactId>spring-tx</artifactId>  
        <version>${spring.version}</version>  
    </dependency>  
    <dependency>  
        <groupId>org.springframework</groupId>  
        <artifactId>spring-jdbc</artifactId>  
        <version>${spring.version}</version>  
    </dependency>  
    <dependency>  
        <groupId>org.mybatis</groupId>  
        <artifactId>mybatis</artifactId>  
        <version>${mybatis.version}</version>  
    </dependency>  
    <dependency>  
        <groupId>org.mybatis</groupId>  
        <artifactId>mybatis-spring</artifactId>  
        <version>${mybatis.spring.version}</version>  
    </dependency>  
    <dependency>  
        <groupId>com.zaxxer</groupId>  
        <artifactId>HikariCP-java6</artifactId>  
        <version>${hikaricp.version}</version>  
    </dependency>  
    <dependency>  
        <groupId>mysql</groupId>  
        <artifactId>mysql-connector-java</artifactId>  
        <version>${mysql.connector.version}</version> 
    </dependency>
</dependencies>

4.2. applicationContext-dataSource.xml

<?xml version="1.0" encoding="UTF-8"?>  
<beans xmlns="http://www.springframework.org/schema/beans"  
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
       xmlns:tx="http://www.springframework.org/schema/tx"  
       xsi:schemaLocation="
       http://www.springframework.org/schema/beans  
       http://www.springframework.org/schema/beans/spring-beans.xsd 
       http://www.springframework.org/schema/tx 
       http://www.springframework.org/schema/tx/spring-tx-3.0.xsd">  
  
    <bean id="dataSource" class="com.example.helper.CryptoHikariDataSource" >  
        <constructor-arg index="0" ref="properties"/>  
        <property name="driverClassName" value="${jdbc.driver}"/>  
        <property name="jdbcUrl" value="${jdbc.url}"/>  
        <property name="username" value="${jdbc.username}"/>  
        <property name="password" value="${jdbc.password}"/>  
        <property name="minimumIdle" value="${jdbc.min.pool.size}"/>  
        <property name="maximumPoolSize" value="${jdbc.max.pool.size}"/>  
        <property name="connectionTestQuery" value="${jdbc.validation.query}"/>  
        <property name="leakDetectionThreshold" value="3000"/>  
    </bean>  
  
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">  
        <property name="dataSource" ref="dataSource"/>  
        <property name="configurationProperties" ref="properties"/>  
        <property name="mapperLocations">  
            <array>  
                <value>file:${mybatis.mapper.location}</value>  
            </array>  
        </property>  
        <property name="typeAliasesPackage" value="com.example.beans"/>  
    </bean>  
  
    <bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">  
        <constructor-arg index="0" ref="sqlSessionFactory"/>  
    </bean>  
  
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">  
        <property name="dataSource" ref="dataSource" />  
    </bean>  
  
    <tx:annotation-driven transaction-manager="transactionManager" />  
  
</beans>

4.3. app-mysql.xml

<?xml version="1.0" encoding="UTF-8" ?>  
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">  
<mapper namespace="app">  
  
    <select id="checkTable" parameterType="String" resultType="String">  
        SHOW TABLES LIKE #{tableName}  
    </select>  
  
</mapper>

4.4. ConsoleExecutor.java

protected void initBeanFactory() {  
    beanFactory = new ClassPathXmlApplicationContext(  
            "classpath:applicationContext.xml",  
            "classpath:applicationContext-dataSource.xml"  
    );  
}

5. App DAO 추가

5.1. applicationContext.xml

<?xml version="1.0" encoding="UTF-8"?>  
<beans xmlns="http://www.springframework.org/schema/beans"  
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
       xmlns:context="http://www.springframework.org/schema/context"  
       xmlns:task="http://www.springframework.org/schema/task"  
       xsi:schemaLocation="  
       http://www.springframework.org/schema/beans 
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/context 
       http://www.springframework.org/schema/context/spring-context.xsd 
       http://www.springframework.org/schema/task 
       http://www.springframework.org/schema/task/spring-task.xsd">  
  
    <context:property-placeholder properties-ref="properties" />  
  
    <bean id="properties" class="org.springframework.beans.factory.config.PropertiesFactoryBean">  
        <property name="locations">  
            <list>  
                <value>file:../conf/jdbc.conf</value>  
            </list>  
        </property>  
    </bean>  
  
    <bean id="appDao" class="com.example.dao.AppDao">  
        <property name="sqlSession" ref="sqlSession"/>  
    </bean>  
  
    <bean id="messageHandler" class="com.example.handler.DefaultMessageHandler">  
        <property name="appDao" ref="appDao"/>  
    </bean>  
  
    <bean id="serviceExecutor" class="com.example.executor.ServiceExecutor">  
        <property name="messageHandler" ref="messageHandler"></property>  
    </bean>  
  
    <bean id="appScheduler" class="com.example.scheduler.AppScheduler">  
    </bean>  
  
    <task:scheduler id="scheduler" pool-size="10"/>  
    <task:scheduled-tasks scheduler="scheduler">  
        <task:scheduled ref="appScheduler" method="sayHello" fixed-delay="10000"/>  
    </task:scheduled-tasks>  
  
</beans>

5.2. AppDao.java

package com.example.dao;  
  
import org.apache.commons.lang3.StringUtils;  
import org.mybatis.spring.SqlSessionTemplate;  
  
public class AppDao {  
  
    private SqlSessionTemplate sqlSession;  
  
    public void setSqlSession(SqlSessionTemplate sqlSession) {  
        this.sqlSession = sqlSession;  
    }  
  
    public boolean checkTable(String tableName) {  
        String table = sqlSession.selectOne("app.checkTable", tableName);  
  
        return !StringUtils.isEmpty(table);  
    }  
  
}

6. App DAO 사용

6.1. DefaultMessageHandler.java

package com.example.handler;  
  
import org.slf4j.Logger;  
import org.slf4j.LoggerFactory;  
import com.example.dao.AppDao;  
  
public class DefaultMessageHandler implements MessageHandler {  
  
    private static Logger LOGGER = LoggerFactory.getLogger(DefaultMessageHandler.class);  
  
    private AppDao appDao;  
  
    public void setAppDao(AppDao appDao) {  
        this.appDao = appDao;  
    }  
  
    @Override  
  public void handle(String message) {  
        LOGGER.info("handle: " + message);  
        boolean result = appDao.checkTable("SERVER_INFO");  
        LOGGER.info("checkTable: " + result);  
    }  
  
}

6.2. applicationContext.xml

<?xml version="1.0" encoding="UTF-8"?>  
<beans xmlns="http://www.springframework.org/schema/beans"  
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
    xmlns:task="http://www.springframework.org/schema/task"  
    xsi:schemaLocation="  
    http://www.springframework.org/schema/beans  
    http://www.springframework.org/schema/beans/spring-beans.xsd 
    http://www.springframework.org/schema/task 
    http://www.springframework.org/schema/task/spring-task.xsd">  
  
    <bean id="messageHandler" class="com.example.handler.DefaultMessageHandler">  
    </bean>  
  
    <bean id="serviceExecutor" class="com.example.executor.ServiceExecutor">  
        <property name="messageHandler" ref="messageHandler"></property>  
    </bean>  
  
    <bean id="appScheduler" class="com.example.scheduler.AppScheduler">  
    </bean>  
  
    <task:scheduler id="scheduler" pool-size="10"/>  
    <task:scheduled-tasks scheduler="scheduler">  
        <task:scheduled ref="appScheduler" method="sayHello" fixed-delay="10000"/>  
    </task:scheduled-tasks>  
  
</beans>

Written with StackEdit.

2022년 4월 17일 일요일

JDK 1.6 + Spring Framework 4 사용 기초

JDK 1.6 + Spring Framework 4 사용 기초

1. 개요

다음과 같은 환경에서 Spring Framework 4 기반의 Hello World 프로그램을 작성하고 빌드하여 실행할 수 있도록 안내합니다.

도구 버전 설명
Windows 10 운영체제
JDK 1.6 Java 컴파일러 및 실행 환경
IntelliJ IDEA 2021.2.2 (Community Edition) 통합 개발 환경
Maven 3.2.5 (JDK 1.6에서 동작하는 마지막 버전) 빌드 도구
Spring Framework 4.3.30.RELEASE 응용 프레임워크

2. 준비

아래 블로그 글을 참고하여 프로젝트를 생성합니다.

3. Spring Framework 사용

3.1. pom.xml

<?xml version="1.0" encoding="UTF-8"?>  
<project xmlns="http://maven.apache.org/POM/4.0.0"  
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">  
    <modelVersion>4.0.0</modelVersion>  
  
    <groupId>org.example</groupId>  
    <artifactId>springframework4-study</artifactId>  
    <version>1.0-SNAPSHOT</version>  
    <dependencies>  
        <dependency>  
            <groupId>org.slf4j</groupId>  
            <artifactId>slf4j-api</artifactId>  
            <version>1.7.32</version>  
        </dependency>  
        <dependency>  
            <groupId>ch.qos.logback</groupId>  
            <artifactId>logback-classic</artifactId>  
            <version>1.2.10</version>  
        </dependency>  
        <dependency>  
            <groupId>org.springframework</groupId>  
            <artifactId>spring-beans</artifactId>  
            <version>${spring.version}</version>  
        </dependency>  
        <dependency>  
            <groupId>org.springframework</groupId>  
            <artifactId>spring-context</artifactId>  
            <version>${spring.version}</version>  
        </dependency>  
        <dependency>  
            <groupId>org.springframework</groupId>  
            <artifactId>spring-core</artifactId>  
            <version>${spring.version}</version>  
        </dependency>  
    </dependencies>  
  
    <properties>  
        <maven.compiler.source>6</maven.compiler.source>  
        <maven.compiler.target>6</maven.compiler.target>
        <spring.version>4.3.30.RELEASE</spring.version>
    </properties>  
  
</project>

3.2. applicationContext.xml

<?xml version="1.0" encoding="UTF-8"?>  
<beans xmlns="http://www.springframework.org/schema/beans"  
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
  xsi:schemaLocation="  
 http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">  
  
    <bean id="serviceExecutor" class="com.example.ServiceExecutor">  
    </bean>
    
</beans>

3.3. ServiceExecutor.java

package com.example;  
  
import org.slf4j.Logger;  
import org.slf4j.LoggerFactory;  
  
public class ServiceExecutor {  
    private static Logger LOGGER = LoggerFactory.getLogger(ServiceExecutor.class);  
  
    private boolean keepRunning = true;  
  
    public void start() throws Exception {  
        LOGGER.info("Service is starting...");  
        LOGGER.info("Service started.");  
  
        int count = 0;  
        while (keepRunning) {  
            Thread.sleep(1000);  
            LOGGER.info("count " + ++count);  
        }  
    }  
  
    public void stop() throws Exception {  
        LOGGER.info("Service is stopping...");  
        keepRunning = false;  
        LOGGER.info("Service stopped.");  
    }  
}

3.4. HelloWorld.java

package com.example;  
  
import org.slf4j.Logger;  
import org.slf4j.LoggerFactory;  
import org.springframework.beans.factory.BeanFactory;  
import org.springframework.context.support.ClassPathXmlApplicationContext;  
  
public class HelloWorld {  
    private static Logger LOGGER = LoggerFactory.getLogger(HelloWorld.class);  
  
    private BeanFactory beanFactory;  
  
    protected HelloWorld() {  
        initBeanFactory();  
    }  
  
    protected void initBeanFactory() {  
        beanFactory = new ClassPathXmlApplicationContext(  
                "classpath:applicationContext.xml"  
  );  
    }  
  
    protected void start() {  
        final ServiceExecutor serviceExecutor = beanFactory.getBean("serviceExecutor", ServiceExecutor.class);  
  
        Runtime.getRuntime().addShutdownHook(new Thread() {  
            @Override  
  public void run() {  
                try {  
                    LOGGER.info("Application is stopping...");  
                    serviceExecutor.stop();  
                    LOGGER.info("Application stopped.");  
                } catch (Exception e) {  
                    LOGGER.error(e.getMessage(), e);  
                }  
            }  
        });  
  
        try {  
            LOGGER.info("Application is starting...");  
            serviceExecutor.start();  
            LOGGER.info("Application started.");  
        } catch (Exception e) {  
            LOGGER.error(e.getMessage(), e);  
            System.exit(1);  
        }  
    }  
  
    public static void main(String[] args) {  
        LOGGER.info("Hello World!!!");  
  
        HelloWorld executor = new HelloWorld();  
        executor.start();  
    }  
}

4. 참고 자료

  1. Spring Framework Versions - JDK Version Range

Written with StackEdit.

2022년 4월 2일 토요일

JDK 1.6 + Maven + IntelliJ 사용 기초

JDK 1.6 + Maven + IntelliJ 사용 기초

1. 개요

다음과 같은 환경에서 Hello World 프로그램을 작성하고 빌드하여 실행할 수 있도록 안내합니다.

도구 버전 설명
Windows 10 운영체제
JDK 1.6 Java 컴파일러 및 실행 환경
IntelliJ IDEA 2021.2.2 (Community Edition) 통합 개발 환경
Maven 3.2.5 (JDK 1.6에서 동작하는 마지막 버전) 빌드 도구

2. 사용 기초

2.1. IntelliJ IDEA에서 프로젝트 생성

  1. Windows 시작 메뉴에서 JetBrains 아래의 IntelliJ IDEA Community Edition 2021.2.2를 클릭합니다.

  2. Welcome to IntelliJ IDEA 대화상자에서 Projects 탭 화면의 New Project 버튼을 클릭합니다.

  3. New Project 대화상자에서 Maven 탭 화면의 Project SDK1.6으로 지정하고 Next 버튼을 클릭합니다.

  4. New Project 대화상자에서 다음과 같이 입력하고 Finish 버튼을 클릭합니다.

    • Name: HelloWorld
    • Location: C:\DevTest\220402_HelloWorld

    생성된 pom.xml 파일의 내용은 아래와 같습니다.

    <?xml version="1.0" encoding="UTF-8"?>  
    <project xmlns="http://maven.apache.org/POM/4.0.0"  
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
      xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">  
        <modelVersion>4.0.0</modelVersion>  
      
        <groupId>org.example</groupId>  
        <artifactId>HelloWorld</artifactId>  
        <version>1.0-SNAPSHOT</version>  
      
        <properties>  
            <maven.compiler.source>6</maven.compiler.source>  
            <maven.compiler.target>6</maven.compiler.target>  
        </properties>  
      
    </project>
    

2.2. 사용할 Maven 지정

  1. IntelliJ IDEA에서 File - Settings… 메뉴를 클릭합니다.

  2. Settings 대화상자에서 Build, Execution, Deployment - Build Tools - Maven 탭을 선택하고 아래와 같이 Maven 경로를 지정한 후 OK 버튼을 클릭합니다.

    • Maven home path: Maven 3.2.5 설치 경로

2.3. HelloWorld.java 추가

  1. IntelliJ IDEA에서 Project 창의 src - main - java 항목을 선택하고 마우스 오른쪽 버튼을 클릭합니다.

  2. 컨텍스트 메뉴에서 New - Package 항목을 클릭하고 아래와 같이 입력한 후 엔터를 칩니다.

    • New Package: com.example
  3. com.example 패키지를 선택하고 마우스 오른쪽 버튼을 클릭합니다.

  4. 컨텍스트 메뉴에서 New - Java Class 항목을 클릭하고 아래와 같이 입력한 후 엔터를 칩니다.

    • New Java Class: HelloMain

    생성된 클래스는 아래와 같습니다.

    package com.example;  
    
    public class HelloMain {  
    }
    
  5. HelloMain 클래스에 아래와 같이 main 메쏘드를 추가합니다.

    package com.example;  
    
    public class HelloMain {  
        public static void main(String[] args) {
            System.out.println("Hello World!!!");
        }
    }
    

2.4. HelloWorld 실행

  1. Project 창에서 HelloWorld 클래스를 선택하고 마우스 오른쪽 버튼을 클릭합니다.

  2. 컨텍스트 메뉴에서 Run ‘HelloWorld.main()’ 항목을 클릭합니다.

  3. 콘솔 창에 아래와 같은 결과가 표시되는지 확인합니다.

    "C:\Program Files\Java\jdk1.6.0_45\bin\java.exe" ...
    Hello World!!!
    
    Process finished with exit code 0
    

2.5. Maven으로 빌드

  1. IntelliJ IDEA에서 Maven 창을 열고 상단 메뉴바에 있는 Toggle ‘Skip Tests’ Mode 버튼을 클릭하여 테스트 단계를 수행하지 않도록 합니다.

  2. Maven 창의 HelloWorld - Lifecycle 항목을 펼치고 cleaninstall을 더블클릭합니다.

3. Logback 사용

3.1. logback-classic 의존성 추가

  1. Project 창에서 pom.xml 파일을 더블클릭하여 엽니다.

  2. pom.xml 파일에 커서를 두고 Alt + Insert 버튼을 클릭합니다.

  3. Generate 창에서 Dependency 항목을 클릭합니다.

  4. Maven Artifact Search 대화상자의 Search For Artifact 입력창에 logback-classic을 입력합니다.

  5. ch.qos.logback:logback-classic을 펼친 후 1.2.10을 선택하고 Add 버튼을 클릭합니다.

  6. Maven 창에서 HelloWorld를 선택하고 마우스 오른쪽 버튼을 누릅니다. 이어서 나타나는 컨텍스트 메뉴의 Reload project 항목을 클릭합니다.

3.2. slf4j-api 의존성 추가

Logback은 SLF4J API를 구현하고 있기 때문에 아래와 같이 의존성을 추가해 주어야 합니다.

  1. Project 창에서 pom.xml 파일을 더블클릭하여 엽니다.

  2. pom.xml 파일에 커서를 두고 Alt + Insert 버튼을 클릭합니다.

  3. Generate 창에서 Dependency 항목을 클릭합니다.

  4. Maven Artifact Search 대화상자의 Search For Artifact 입력창에 slf4j-api를 입력합니다.

  5. org.slf4j:slf4j-api를 펼친 후 1.7.32를 선택하고 Add 버튼을 클릭합니다.

  6. Maven 창에서 HelloWorld를 선택하고 마우스 오른쪽 버튼을 누릅니다. 이어서 나타나는 컨텍스트 메뉴의 Reload project 항목을 클릭합니다.

3.3. Logback으로 로그 남기기

  1. HelloWorld 클래스를 아래와 같이 수정합니다.

    package com.example;
    
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    
    public class HelloMain {
        private static Logger LOGGER = LoggerFactory.getLogger(HelloMain.class);
    
        public static void main(String[] args) {
            LOGGER.info("Hello World!!!");
        }
    }
    

3.4. HelloWorld 실행

  1. Project 창에서 HelloWorld 클래스를 선택하고 마우스 오른쪽 버튼을 클릭합니다.

  2. 컨텍스트 메뉴에서 Run ‘HelloWorld.main()’ 항목을 클릭합니다.

  3. 콘솔 창에 아래와 같은 결과가 표시되는지 확인합니다.

    "C:\Program Files\Java\jdk1.6.0_45\bin\java.exe" ...
    14:14:42.815 [main] INFO com.example.HelloMain - Hello World!!!
    
    Process finished with exit code 0
    

참고 자료

Written with StackEdit.

2022년 2월 22일 화요일

PlantUML 간단하게 사용하기

PlantUML 간단하게 사용하기

UML 다이어그램을 그릴 때 사용할 수 있는 PlantUML을 PC에 설치하고 이미지 파일을 생성하는 방법을 소개합니다.

1. 설치하기

  1. Java 설치
  2. plantuml.jar 다운로드

2. 실행하기

2.1. 텍스트 파일 작성

텍스트 파일 sequenceDiagram.txt을 만들고 PlantUML 문법으로 아래와 같이 내용을 작성하여 저장합니다.

@startuml
Alice -> Box: test
@enduml

2.2. 이미지 파일 생성

위에서 작성한 텍스트파일로 다이어그램 파일을 생성하는 방법 두 가지를 소개합니다.

2.2.1. 명령 프롬프트에서 생성하는 방법

java -jar plantuml.jar sequenceDiagram.txt

텍스트 파일에서 한글을 사용하였고 UTF-8로 저장하였다면 아래와 같이 파일 인코딩 형식을 지정하여 실행하면 다이어그램에서 한글이 정상적으로 표시됩니다.

java -Dfile.encoding=UTF-8 -jar plantuml.jar sequenceDiagram.txt

위 명령을 수행하면 해당 디렉토리에 sequenceDiagram.png 이미지 파일이 생성됩니다.

2.2.2 GUI에서 생성하는 방법

java -jar plantuml.jar -gui

GUI 프로그램은 작업 디렉토리의 변경을 자동으로 감지하고 이미지 파일을 생성해 줍니다.

참고 자료

Written with StackEdit.

2022년 2월 3일 목요일

진단 성능 평가 지표

진단 성능 평가 지표

혼동행렬(Confusion Matrix)

진단 장비의 성능을 파악하기 위하여 질병의 유무를 알고 있는 사람들을 대상으로 진단을 수행하고 아래와 같이 혼동행렬을 작성합니다.

  • A: 진양성(True Positive) 수
  • B: 위양성(False Positive) 수
  • C: 위음성(False Negative) 수
  • D: 진음성(True Negative) 수

성능 평가

민감도(Sensitivity)

질병이 있는 사람을 양성으로 판정하는 정도를 민감도(sensitivity)라고 하며 아래와 같이 구합니다.

  • 민감도 = AA+C\frac{ A } { A+C }

특이도(Specificity)

질병이 없는 사람을 음성으로 판정하는 정도를 특이도(specificity)라고 하며 아래와 같이 구합니다.

  • 특이도 = DB+D\frac{ D }{ B+D }

재현율(Recall)

민감도와 같습니다.

  • 재현율 = AA+C\frac{ A }{ A+C }

정밀도(Precision)

  • 정밀도 = AA+B\frac{ A }{ A+B }

정확도(Accuracy)

  • 정확도 = A+DA+B+C+D\frac{ A+D }{ A+B+C+D }

성능 지표

AUC ROC

양성, 음성 판단 기준을 변경하면 혼동행렬에서 A, B, C, D의 값이 달라지고 이것은 민감도와 특이도가 변한다는 것을 의미합니다. 그래서 양성, 음성 판단 기준을 조정해 가면서 아래와 같은 민감도, 특이도 그래프를 그릴 수 있습니다.

  • TP 비율(True Positive Rate) = 민감도
  • FP 비율(False Positive Rate) = 1 - 특이도

그래프 곡선 아래의 면적을 구함으로써 성능 평가 지표인 AUC(Area Under the Curve) ROC(Receiver Operating Characteristic)를 구합니다. 아래 그림의 그래프를 살펴 보면 AUC가 클수록 낮은 FP 비율을 유지하면서도 더 높은 TP 비율을 보여줍니다. 즉 서로 다른 두 장비의 진단 성능을 비교할 때 AUC가 큰 쪽의 진단 성능이 더 좋다고 말할 수 있습니다.

F1 Score

양성, 음성 판단 기준을 변경하면 혼동행렬에서 A, B, C, D의 값이 달라지고 이것은 Recall과 Precision이 변한다는 것을 의미합니다. 위양성과 위음성을 모두 고려하여 성능을 평가할 때 아래와 같이 계산한 F1 Score를 사용할 수 있습니다.

  • F1 Score = 2×Recall×PrecisionRecall+Precision2 \times \frac{ Recall \times Precision }{ Recall+Precision }

이것은 재현율과 정밀도의 조화평균과 같습니다.

Written with StackEdit.

차등 정보보호 - 소개

차등 정보보호 - 소개 환자 질병 유무 데이터를 공개할 때 데이터셋에 불확실성을 추가함으로써 개별 환자의 질병 유무를 확정할 수 없도록 만들 수 있습니다. 예를 들어 어떤 병원이 데이터 분석을 목적으로 10,00...