Springboot에서 jar에서 war 파일을 만들게 설정 변경하기

JAR -> WAR로 배포파일 변경하기

간혹가다 프로젝트를 진행하면서 jar로 배포를 하려다가 war 파일을 톰캣에 올려서 배포하게 변경되는 경우가 생기기도 합니다.
그런 경우 프로젝트가 정말 작고, 시작한 지 얼마 안 된 경우라면 새로 프로젝트를 패키징 설정을 war로 해서 새로 만드는 방법도 있지만… 좋은 방법도 아니고 일정 이상 프로젝트를 진행해서 그러기 쉽지 않은 경우가 발생할 수 있습니다.

그럴 경우 jar 파일로 생성되게 만든 프로젝트를 war 파일을 생성하게 하는 방법에 대해서 알아봅시다.

추가로 스프링 부트 2.0.5 버전에서 진행 한 내용이며 실습 코드 자체는 아주 간단하게도 아래와 같이 우리에게 친숙한 hello world를 보여주는 웹 앱입니다.

성공_화면


일단 jar로 패키징 되게 프로젝트를 만들어 봅니다.

jar_프로젝트

일단 maven의 경우 pom.xml의 내용을 보시면 아래와 같이 packaging 의 내용에 jar 가 들어 있는 걸 확인할 수 있습니다.

<groupId>com.example</groupId>
<artifactId>maven</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>

gradle의 경우 별다른 내용이 없습니다…

buildscript {
	ext {
		springBootVersion = '2.0.5.RELEASE'
	}
	repositories {
		mavenCentral()
	}
	dependencies {
		classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
	}
}

apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'org.springframework.boot'
apply plugin: 'io.spring.dependency-management'

이 상태에서 프로젝트를 만든 다음 빌드를 해보면 당연하게도 xxx.jar 파일이 만들어집니다.

여기서 war 파일을 만드는 것은 아주 간단합니다. 메이븐의 경우

<groupId>com.example</groupId>
<artifactId>maven</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>war</packaging>

packaging의 내용을 war로 바꿔주기만 하면 됩니다…….

gradle의 경우 build.gradle을 보면

apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'org.springframework.boot'
apply plugin: 'io.spring.dependency-management'
apply plugin: 'war'

war {
	baseName = 'gradle'
	version = '0.0.1'
}

apply plugin: 'war'로 플러그인을 추가하고 war{}에 필요한 내용을 채워 넣으면 됩니다.

그러면 새로 빌드를 하면 xxx.war가 생성이 됩니다. gradle의 경우 위와 같이 설정해주면 gradle-0.0.1.war같이 파일명과 버젼링을 해줄 것이라 예상하시겠지만, 그렇지 않으신 분들도 계실 겁니다… (특히 부트 2버젼 대가 아니시라면) 그에 대해서는 차후 소개해드리도록 하겠습니다 :)


자 그러면 war 파일도 만들어 봤으니 톰캣을 이용해 배포해 보겠습니다!

실패_화면

?!

여기서 멘붕에 빠지는 경우들이 있으신데… 특히 저 같은 경우 aws에 엘라스틱빈스톡의 톰캣 환경에서 배포를 하기 위해 jar에서 war로 변경했던지라, 스프링 내에 설정을 잘 못 만든 것인지 빈스톡 설정을 잘 못 한 건지 엄청난 멘붕에 빠졌었던 기억이 나는군요…. 결국 당시엔 새로 프로젝트를 만들었습니다..


ServletInitializer

스프링부트를 통해 만든 웹 애플리케이션의 경우 embeded 톰켓을 이용한다면 @SpringBootApplication을 구현한 클래스만 있으면 되지만, 따로 톰켓을 통해 배포하는 경우 SpringBootServletInitializer를 상속받은 클래스가 필요합니다.

public class ServletInitializer extends SpringBootServletInitializer {

    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
        return application.sources(DemoWarApplication.class);
    }

}

아주 혹시나 알려드리면 DemoWarApplication.class 부분은 본인의 @SpringBootApplication 구현체를 넣으시면 됩니다. (스프링부트 생성시 존재하는 클래스)

경로1

ServletInitializer 추가

경로2

위와 같이 ServletInitializer를 추가해 주시면 됩니다.(war 패키징 되는 프로젝트로 생성하면 처음 초기화 시 위와 같이 ServletInitializer도 같이 생성되는 걸 볼 수 있습니다.)

그러고서 다시 war 파일을 빌드 해주시고 톰캣을 통해 배포하시면

성공_화면

정상적으로 배포되신 것을 확인하실 수 있습니다.

한 줄로 요약하면 maven, gradle에 해당하는 설정 파일에 war 관련 내용을 추가 한 후에, SpringBootServletInitializer을 상속 한 ServletInitializer를 만들어 주시면 됩니다.


참고 자료 : Spring Boot에서 배포환경 나누기, Spring Boot 웹 애플리케이션을 WAR로 배포할 때 왜 SpringBootServletInitializer를 상속해야 하는걸까?

(SpringBootServletInitializer에 대해 보다 자세히 알고 싶으시다면 두 번째 참고 자료를 추천드립니다.)

우분투는 기본적으로 utf-8 인코딩을 사용하고, 윈도우는 다른 인코딩을 사용해서 생기는 문제입니다. 무슨 프로그램으로 파일을 열어 보셨는지 모르지만, gedit나 vi 에디터 등의 프로그램에서는 encoding을 설정해서 볼 수 있습니다. 해당 프로그램의 메뉴에서 encoding을 euc-kr 등의 다른 한글 인코딩 방법으로 선택하면 보일 겁니다.

우분투는 기본적으로 utf-8 인코딩을 사용하고 있어 윈도우 등 다른 인코딩 방식을 사용하고 있는 방식서 만들어진 파일을 열면 글자가 깨지는 경우가 발생 합니다. 이런 경우 해결 하는 방법을 알아 보도록 하겠습니다.

iconv1


1.파일 인코딩 확인

file -bi 파일명

text/plain; charset=iso-8859-1

iconv2

iso-8859-1라고 나오고 있긴 하지만 변환 할 때는 euc-kr로 생각하고 진행 해야 합니다. 자료를 찾다보니 같은 경우들이 나오긴 하는데 euc-kr로 진행 해보라는 것 말곤 아직 정확한 원인은 찾진 못했습니다만 이게 당장 중요한 부분은 아니니…
(해당 부분은 좀 알아 보는 중으로 차후 정확히 알게 되면 추가를 하도록 하겠습니다.)

2.파일 인코딩 변환

파일 인코딩을 변환 하려면 추가로 무엇을 설치 할 필요 없이 iconv 명령어를 사용하면 됩니다.

위에서 예시를 보인 파일의 인코딩을 변경하는 것을 보도록 하겠습니다.

iconv -c -f 기존 인코딩 -t 새로운 인코딩 원본 파일명 > 새로운 파일명
iconv -c -f euc-kr -t utf-8 원본 파일명 > 새로운 파일명
iconv -c -f euc-kr -t utf-8 ko_add_keyword_template.csv > aa.csv

iconv3

file로 위에서 생성한 aa.csv 파일을 확인 해보면 인코딩이 변한걸 볼 수 있습니다.

iconv4

그래면 아래와 같이 한글이 깨짐 없이 잘 보입니다!!

iconv5

-t 옵션 사용하기

git checkout -t 브랜치
git checkout -t origin/develop

-t 옵션은 원격 저장소의 branch를 로컬에 동일한 이름의 branch를 생성하면서 해당 branch로 checkout을 합니다.

위에서는 origin으로 예시를 보여줬지만 추가로 등록한 upstream이나 다른 원격 저장소의 브랜치 또한 같은 방법으로 사용이 가능합니다.

혹시, 자신이 clone한 저장소의 어떤 브랜치들이 있어 모르시면

git branch -a

위의 명령어로 모든 브랜치를 보실 수 있습니다.

원격의 push 내용 되돌리기

로컬에서 작업을 끝내고 원격에다가 push까지 하고 난 다음 로컬의 커밋을 다시 이전으로 되돌려야 되는 상황이 발생 하기도 합니다. 로컬이야 간단히 돌릴 수 있지만, 원격에 경우 어떻게 돌려야 할지 난감한 경우가 있습니다. 그런 경우 아래의 명령어를 이용하면 간단히 해결 가능 합니다.

git push origin +"branch"
git push origin +master

오픈소스를 발견하고 fork를 한 다음 묵혀두고 있다가 차후 commit할 꺼리를 발견해서 작업을 하려고 하는 경우가 있습니다.

그런데 문제는 3개월 전에 fork한 내 저장소와 현재 해당 오픈소스 저장소와 sync가 맞지 않는 상황일 확률이 높습니다.

그렇다면 commit을 할 사항을 작업 하기 전에 오픈소스의 원본 저장소와 같은 상태로 만들어 놓고 작업을 해야 문제가 발생 하지 않습니다.

위의 상황은 제가 이 포스팅을 정리하게 된 이유를 예로 들었지만, 꼭 오픈소스에 대한 상황이 아니라도 같은 경우가 발생 할 수 있습니다.

그럼 이런 경우 해결 하는 방법에 대해 알아 보도록 하겠습니다.


일단 remote 저장소 목록을 확인 해 봅니다.

git remote -v

git_fork_sync1

일반적이라면 위의 사진처럼 fork해서 생성된 자신의 저장소만 origin으로 등록이 되어 있을겁니다.

git remote add upstream 원본 저장소
git remote add upstream https://github.com/scouter-project/scouter

git_fork_sync1

git fetch upstream

원본 저장소 master branch에 있는 추가된 내용들이 현재 내 로컬의 upstream/master로 복사가 됩니다.

git checkout master

master baranch로 체크아웃

git merge upstream/master

위의 fetch를 통해 가져온 원본 저장소의 master branch의 내용을 내 master로 머지합니다.

이 과정까지 거치고 나면 로컬에 한해서는 원본 저장소의 master와 로컬의 master와의 동기화는 성공적으로 끝마치게 됩니다.

이후 자신의 원격 레파지토리도 갱신을 하기 원하면 기존 작업하던 방식 그대로

git push origin

push를 해주면 됩니다.

간단히 위의 과정들을 통해 로컬 및 자신의 원격 저장소를 원본 저장소에 맞추어 동기화를 마무리 할 수 있습니다.