이 글에서는 메이븐 프로젝트를 이클립스나 인텔리J에서 임포트하는 방법을 살펴보자.

이클립스에서 메이븐 프로젝트 임포트하기

이클립스에서 [File] -> [Import] 메뉴를 실행한다.

[그림1]

실행한 뒤 Import 대화창에서 Maven/Existing Maven Projects를 선택하고 [Next]를 클릭한다.

[그림2]

[그림2]에서 [Browse] 버튼을 클릭해서 pom.xml 파일이 위치한 폴더를 Root Directory로 선택하고 [Finish] 버튼을 클릭한다. 임포트가 끝나면 다음 그림처럼 이클립스에 프로젝트가 표시된다.

[그림3]

인텔리J에서 이클립스 프로젝트 임포트하기

인텔리J의 [File] -> [Open] 메뉴를 실행한다. Welcome 대화창에서는 Open 메뉴를 실행한다.

[그림4]

Open File or Project 대화창에서 메이븐 프로젝트 폴더를 선택하고 [OK] 버튼을 클릭한다. 잠시후 임포트가 끝나면 다음 그림처럼 프로젝트를 임포트한 결과를 확인할 수 있다.

[그림5]

 

모든 개발팀에 공유할 연동 모듈이 HttpClient를 사용한다고 하자. 이 모듈은 HttpClient 3 버전을 사용해서 개발하고 있다. 열심히 개발해서 이 모듈을 배포했다. 그런데 문제가 생겼다. 어떤 팀은 이미 HttpClient 4 버전을 사용했고 어떤 팀은 HttpClient 2 버전을 사용하는 것이었다. 그래서 버전 충돌로 인해 제대로 동작하지 않는 상황이 벌어졌다.


이런 일이 벌어질 때 사용하기 좋은 메이븐 플러그인이 있는데, 그 플러그인은 바로 maven-shade-plugin이다.


maven-shade-plugin


maven-shade-plugin은 다음의 두 기능을 제공한다.

  • 프로젝트의 타입뿐만 아니라 의존하는 jar에 포함된 모든 타입을 포함하는 한 개의 jar 파일을 만들어준다.
  • 패키지 구조를 변경해준다.
설명만 봐서 언뜻 이해가 안 될테니 설정 예를 보자.

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-shade-plugin</artifactId>
    <version>2.2</version>
    <executions>
        <execution>
            <phase>package</phase>
            <goals>
                <goal>shade</goal>
            </goals>
        </execution>
    </executions>
    <configuration>
        <outputFile>${project.build.directory}/${project.artifactId}-with-common-${project.version}.jar
        </outputFile>
        <minimizeJar>false</minimizeJar>
        <keepDependenciesWithProvidedScope>true</keepDependenciesWithProvidedScope>
        <artifactSet>
            <includes>
                <include>commons-httpclient:commons-httpclient</include>
                <include>commons-logging:commons-logging</include>
                <include>commons-lang:commons-lang</include>
            </includes>
        </artifactSet>
        <relocations>
            <relocation>
                <pattern>org.apache.commons.logging</pattern>
                <shadedPattern>madvirus.relocated.commons.logging</shadedPattern>
            </relocation>
            <relocation>
                <pattern>org.apache.commons.httpclient</pattern>
                <shadedPattern>madvirus.relocated.commons.httpclient</shadedPattern>
            </relocation>
        </relocations>
    </configuration>
</plugin>

이 예에서 artifactSet/includes는 생성할 jar 파일에 포함시킬 의존 대상을 지정한다. 위 코드는 commons-httpclient, commons-logging, commons-lang을 지정했는데, 이 경우 이 세 개의 아티팩트를 위한 jar 파일의 내용과 해당 프로젝트의 클래스/리소스를 모아 하나의 jar를 만든다. 생성할 jar 파일은 outputFile 태그로 지정한다.


relocations은 jar 파일에 담긴 타입의 패키지 구조를 변경한다. 위 예에서는 org.apache.commons.logging 패키지에 속한 타입을 madvirus.relocated.commons.logging 패키지로 바꿔준다. 또한, 변경한 패키지를 사용하는 타입은 바뀐 패키지를 사용하도록 변경한다.


maven-shade-plugin을 이용해서 생성한 jar 파일은 필요한 모든 외부 의존을 포함하고 있기 때문에 jar 파일 한 개만 배포하면 된다. 또한 패키지 구조도 변경했기 때문에, 이 jar 파일을 어디에 배포해도 클래스 충돌 문제가 발생하지 않는다. 위 코드의 경우 HttpClient의 패키지 구조를 변경했으므로, 다른 프로젝트에서 다른 버전의 HttpClient를 사용하더라도 같은 클래스를 사용해서 발생해서 버전 충돌 문제를 피할 수 있다.


이 외에도 몇 가지 기능을 더 제공하는데 이에 대한 내용은 https://maven.apache.org/plugins/maven-shade-plugin/ 페이지를 참고한다.

최근 수행한 프로젝트에서 스프링부트로 만든 어플리케이션의 최종 빌드 모습은 다음과 같았다.

  • myapp.war
  • myapp-run.sh
  • conf/application.properties
myapp을 yum으로 설치해야 한다는 요구사항이 생겨서 위 파일들을 rpm 파일로 만들어야 할 일이 생겼다. 다행히 메이븐의 rpm-maven-plugin 플러그인을 사용하면 쉽게 rpm 파일을 만들 수 있다.

* 참고로, rpm-maven-plugin은 rpmbuild를 사용하므로 rpmbuild를 먼저 설치해야 rpm-maven-plugin이 올바르게 동작한다.

rpm-maven-plugin 설정 예제


다음은 rpm-maven-plugin의 설정 예제이다.


<build>

    <plugins>

        <plugin>

            <groupId>org.codehaus.mojo</groupId>

            <artifactId>rpm-maven-plugin</artifactId>

            <version>2.0.1</version>

            <executions>

                <execution>

                    <phase>none</phase>

                    <goals>

                        <goal>rpm</goal>

                    </goals>

                </execution>

            </executions>

            <configuration>

                <copyright>2016, MyCompany</copyright>

                <group>Development</group>

                <description>Maven Recipe: RPM Package.</description>

                <version>${project.version}</version>

                <release>0</release>

                <autoRequires>false</autoRequires>

                <preinstallScriptlet>

                    <scriptFile>src/main/package/rpm/preinstall.sh</scriptFile>

                    <fileEncoding>utf-8</fileEncoding>

                </preinstallScriptlet>

                <defaultDirmode>755</defaultDirmode>

                <defaultFilemode>644</defaultFilemode>

                <defaultUsername>root</defaultUsername>

                <defaultGroupname>root</defaultGroupname>

                <mappings>

                    <mapping>

                        <directory>/usr/local/myapp</directory>

                        <sources>

                            <source>

                                <location>${project.basedir}/target/myapp-${project.version}.war</location>

                            </source>

                        </sources>

                    </mapping>

                    <mapping>

                        <directory>/usr/local/myapp</directory>

                        <filemode>755</filemode>

                        <sources>

                            <source>

                                <location>${project.basedir}/bin/myapp-run.sh</location>

                            </source>

                        </sources>

                    </mapping>

                    <mapping>

                        <directory>/usr/local/myapp/conf</directory>

                        <sources>

                            <source>

                                <location>${project.basedir}/conf</location>

                            </source>

                        </sources>

                    </mapping>

                </mappings>

            </configuration>

        </plugin>

    </plugins>

</build>


<mapping>에서 각 요소는 다음을 의미한다.

  • <directory> : 파일 복사 위치. RPM 설치 과정에서 생성한다.
  • <filemode> : 파일의 권한 모드
  • <sources> : 해당 복사 위치에 넣을 대상
예를 들어, /usr/local/myapp 폴더가 존재하지 않으면 이 폴더를 생성하고, myapp-버전.war 파일을 이 폴더에 복사한다. 또한, 같은 위치에 myapp-run.sh 파일을 755 모드로 복사한다. 별도로 모드를 지정하지 않은 경우 <defaultDirmode>와 <defaultFilemode>에서 지정한 모드를 사용한다. 비슷하게 소유 계정과 그룹을 지정하지 지정하지 않으면 <defaultUsername>와 <defaultGroupname>에서 지정한 계정과 그룹을 사용한다.

설치 전에 필요한 계정을 생성하거나 기존에 이미 설치된 파일의 경로를 변경하는 등의 작업이 필요할 경우 <preinstallScriptlet>을 이용해서 해당 작업을 실행할 스크립트를 지정한다.

메이븐 명령어

이제 RPM 생성을 위한 메이븐 명령어를 실행할 차례다. "rpm:rpm" 골을 이용해서 메이븐을 실행하면 된다.

mvn clean package rpm:rpm

RPM 파일은 target/rpm/myapp/RPMS/noarch/myapp-버전-0.noarch.rpm 경로에 생긴다.


  1. 김범준 2016.08.14 14:08

    안녕하세요, 맨날 도움만 받다가.. 어떻게 더 도움을 받을까 해서 글을 남깁니다.
    저 역시 rpm 으로 릴리즈를 진행하는데, 맥 (혹은 윈도우) 상의 이클립스에서만 문제가 있어서요..
    맥의 터미널이나 윈도우의 시그윈 상에서는 mvn install 로 문제 없이 빌드가 됩니다.
    맥/윈도우 상의 이클립스에서 Run As -> Maven Install 로 빌드하면 다음과 같은 에러가 발생합니다.

    [ERROR] Failed to execute goal org.codehaus.mojo:rpm-maven-plugin:2.1.4:rpm (generate-rpm) on project xxx: Unable to query for default vendor from RPM: Error while executing process. Cannot run program "rpm": error=2, No such file or directory -> [Help 1]

    (편의상 프로젝트 네임은 숨겼습니다..)

    맥에서의 rpm 은 brew install 로 설치했고, 윈도우는 시그윈에 바이너리가 포함되어 있습니다.
    환경변수 문제가 아닐까 하여 여러 시도를 다 해보았으나.. 해결되지 않네요.

    혹시 알고 계신 것이 있다면 말씀해 주실 수 있을까요?
    미리 감사드립니다.

    • 최범균 madvirus 2016.08.18 08:10 신고

      rpm이 실행 경로에 있어야 하니까, 이클립스에서 인식할 수 있게 시스템패스에 넣어주셔야 합니다. 터미널은 bash_profile과 같은 곳에서 설정해주지만, 거기에 설정한 환경 변수는 이클립스에 적용되지 않는 걸로 알고 있습니다.

      전 쉘 외에 다른 프로그램에서 사용해야 하는 환경변수는 http://cooldevlife.blogspot.kr/2014/01/os-x.html 이 글 보고 설정했습니다.

      더 좋은 방법은 아직 잘 모릅니다.

Eclipse Luna for JavaEE Developver 버전을 다운로드 받으면 메이븐 연동을 위한 m2e 플러그인이 기본으로 설치되어 있다.


이클립스는 Subversion 연동 플러그인이 기본 포함되어 있지 않기 때문에, 이클립스 마켓플레이스 Help -> Eclipse Marketplace 메뉴에서 Subclipse 플러그인을 찾아서 설치했다. 글 쓰는 시점 기준으로 이 Subclipse 플러그인 버전은 1.10.5다.


Subclipse 플러그인을 설치하고, 이클립스를 재시작한 뒤에 Subclipse와 메이븐 연동을 위해 Window -> Preferences -> Maven ->Discovery -> [Open Catalog]를 실행해서 Subclipse 연동을 위한 m2e-subclipse 를 선택하고 [Finish] 버튼을 클릭했다. 그런데, 잠시 후에 다음과 같은 오류가 발생한다.




Operation details

Cannot complete the install because of a conflicting dependency.

Software being installed: Maven SCM handler for Subclipse 0.13.0.201303011221 (org.sonatype.m2e.subclipse.feature.feature.group 0.13.0.201303011221)

Software currently installed: Subclipse (Required) 1.10.5 (org.tigris.subversion.subclipse.feature.group 1.10.5)

Only one of the following can be installed at once: 

SVN Team Provider Core 1.8.22 (org.tigris.subversion.subclipse.core 1.8.22)

SVN Team Provider Core 1.10.5 (org.tigris.subversion.subclipse.core 1.10.5)

Cannot satisfy dependency:

From: Maven SCM Handler for Subclipse 0.13.0.201303011221 (org.sonatype.m2e.subclipse 0.13.0.201303011221)

To: bundle org.tigris.subversion.subclipse.core [1.6.0,1.9.0)

Cannot satisfy dependency:

From: Maven SCM handler for Subclipse 0.13.0.201303011221 (org.sonatype.m2e.subclipse.feature.feature.group 0.13.0.201303011221)

To: org.sonatype.m2e.subclipse [0.13.0.201303011221]

Cannot satisfy dependency:

From: Subclipse (Required) 1.10.5 (org.tigris.subversion.subclipse.feature.group 1.10.5)

To: org.tigris.subversion.subclipse.core [1.10.5]


이런 오류가 발생하는 이유는 m2e의 Subclipse Connector가 필요로 하는 Subclipse 버전과 실제 설치된 Subclipse 버전이 맞지 않기 때문이다.


이를 해결하려면 Marketplace에 설치한 Subclipse 1.10 버전을 제거하고, 1.8 버전을 설치하면 된다. Help -> Install New Software 를 이용해서 1.8 버전 설치를 진행한다. 업데이트 URL(work with...)은 다음 주소를 입력하면 된다.

  • http://subclipse.tigris.org/update_1.8.x

1.8 버전 Subclipse를 설치한 뒤에 다시 m2e Subclipse Connector를 설치하면 된다. 끝!



메이븐을 사용하다보면 오라클 JDBC 드라이버처럼 라이선스 문제로 메이븐 중앙 리포지토리나 다른 공개 리포지토리에 존재하지 않는 jar 파일이 존재한다. 이런 경우에는 다음과 같이 maven-install 플러그인을 사용해서 jar 파일을 로컬 메이븐 리포지토리에 등록해주면 된다. (공간상 두 줄로 표시했으며, 실제로는 한 줄로 입력한 것이다.)


mvn install:install-file -Dfile=ojdbc14.jar -DgroupId=com.oracle

  -DartifactId=ojdbc14 -Dversion=10.2.0.2.0 -Dpackaging=jar


여력이 된다면, 로컬 리포지토리에 일일이 등록하는 것 보다는, 내부에 Nexus를 이용해서 메이븐 리포지토리를 구축하는 것이 더 좋다. Nexus에 대한 내용은 "Maven 내부용 리포지토리 만들고 Maven 설정하기" 글을 참고하기 바란다.

배치 프로그램이나 명령행에서 실행할 간단한 자바 프로그램을 만들 때가 있는데, 이 프로그램이 스프링 프레임워크를 이용한 경우 관련된 jar 파일들을 함께 배포하고 실행 스크립트에 클래스패스를 설정해주고 하는 것이 귀찮을 때가 있다. 내가 만든 클래스 파일/자원 파일뿐만 아니라 스프링 jar 파일에 포함된 클래스/메타 파일들을 모두 하나의 jar 파일로 만들어서 배포하면 프로그램을 실행하는 스크립트가 매우 간단해질텐데, 메이븐의 어셈블리 플러그인이 제공하는 jar-with-dependencies 기능을 사용하면 이 작업을 매우 쉽게 할 수 있다.


maven-assembly-plugin은 jar-with-dependencies 설정을 제공하는데, 이 설정을 사용하면 내가 만든 클래스 및 자원 파일과 의존하는 jar 파일에 포함된 모든 파일을 묶어서 하나의 jar 파일로 만들어준다. 다음은 설정 예이다.



<build>

        <plugin>

            <groupId>org.apache.maven.plugins</groupId>

            <artifactId>maven-assembly-plugin</artifactId>

            <executions>

                <execution>

                    <id>create-jar</id>

                    <phase>package</phase>

                    <goals>

                        <goal>single</goal>

                    </goals>

                    <configuration>

                        <descriptorRefs>

                            <descriptorRef>

                                jar-with-dependencies

                            </descriptorRef>

                        </descriptorRefs>

                    </configuration>

                </execution>

            </executions>

        </plugin>


        <plugin>

            <groupId>org.apache.maven.plugins</groupId>

            <artifactId>maven-shade-plugin</artifactId>

            <executions>

                <execution>

                    <phase>package</phase>

                    <goals>

                        <goal>shade</goal>

                    </goals>

                    <configuration>

                        <transformers>

                            <transformer

                                implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">

                                <mainClass>com.prototype.springintegration.AppBootstrapper</mainClass>

                            </transformer>

                            <transformer

                                implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">

                                <resource>META-INF/spring.handlers</resource>

                            </transformer>

                            <transformer

                                implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">

                                <resource>META-INF/spring.schemas</resource>

                            </transformer>

                            <transformer

                                implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">

                                <resource>META-INF/spring.factories</resource>

                            </transformer>

                            <transformer

                                implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">

                                <resource>META-INF/spring.factories</resource>

                            </transformer>

                            <transformer

                                implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">

                                <resource>META-INF/spring.tooling</resource>

                            </transformer>

                        </transformers>

                    </configuration>

                </execution>

            </executions>

        </plugin>

    </plugins>

</build>


위 코드에서 maven-shade-plugin 을 사용했는데, 이 플러그인을 사용한 이유는 스프링의 각 jar 파일에 포함되어 있는 메타 파일들을 하나의 파일로 합치기 위함이다. 이 플러그인을 사용하지 않으면 스프링의 각 jar 파일에 포함된 메타 파일을 한 개 jar 파일에 모으는 과정에서 합쳐지지 않고 뎝어쓰기때문에 XML 확장 스키마 등의 설정이 올바르게 동작하지 않게 된다.


위와 같이 설정을 했다면 mvn package 명령어로 의존하는 jar 파일에 속한 모든 내용과 내가 만든 클래스/자원 파일들이 포함된 한 개의 jar 파일을 얻을 수 있다.

아래 링크에 걸려 있는 정보를 이용해서 Github을 리포지토리로 사용을 해 보았다.


http://stackoverflow.com/questions/14013644/hosting-a-maven-repository-on-github/14013645#14013645


위 글을 보고 열심히 따라서 Maven pom.xml 파일을 작성한 뒤에 흥분되는 마음으로 mvn deploy 명령어를 실행하자, 아래와 같은 오류 메시지가 출력되었다.


[ERROR] Failed to execute goal com.github.github:site-maven-plugin:0.7:site (default) on project jasmine-maven-plugin: Error creating blob: Missing or invalid User Agent string. See http://developer.github.com/v3/#user-agent-required (403) -> [Help 1]


이런! 구글링을 해 보니, 깃헙의 site-maven-plugin 설정에 아래와 같은 내용을 추가해야 함을 알 수 있었다.


            <plugin>

                <groupId>com.github.github</groupId>

                <artifactId>site-maven-plugin</artifactId>

                <version>0.7</version>

                <configuration>

                    <message>Maven artifacts for ${project.version}</message>

                    <noJekyll>true</noJekyll>

                    <outputDirectory>${project.build.directory}/mvn-repo</outputDirectory>

                    <branch>refs/heads/mvn-repo</branch>

                    <merge>true</merge> <!-- 이것도 추가 -->

                    <includes>

                        <include>**/*</include>

                    </includes>

                    <repositoryName>깃헙리포지토리이름</repositoryName>

                    <repositoryOwner>깃헙ID</repositoryOwner>

                </configuration>

                <executions>

                    <execution>

                        <goals>

                            <goal>site</goal>

                        </goals>

                        <phase>deploy</phase>

                    </execution>

                </executions>

                <!-- site-maven-plugin 0.7 버전에서 에러 안 나도록, 아래 내용 추가 -->

                <dependencies>

                    <dependency>

                        <groupId>org.eclipse.mylyn.github</groupId>

                        <artifactId>org.eclipse.egit.github.core</artifactId>

                        <version>2.0.3</version>

                    </dependency>

                </dependencies>

            </plugin>


그리고, <merge> 속성의 값을 true로 지정해 주었다. <merge>가 false일 경우 기존 내용이 삭제되기 때문에, 이전 버전이 유지가 되지 않는다. 이전 버전을 유지하고 싶지 않더라도 Maven 멀티 모듈을 사용하고 있다면 이 속성을 true로 지정해 주어야 한다. 그렇지 않을 경우, 멀티 모듈의 각 모듈이 리포지토리에 배포될 때 마다 이전에 올라간 것들을 지우기 때문에, 최종적으로 한 개의 서브 모듈만 리포지토리에 올라가게 된다.

필자는 Maven을 너무 좋아하기에 안드로이드 개발도 Maven 프로젝트로 관리하고 싶었다. 그래서 구글링을 좀 했고, 영어로 된 걸 매번 보고 싶지 않아 나중을 위해 한글로 정리해둔다.


M2E를 위한 Android Connector 설치


먼저 할 일은 이클립스에 설치한 Maven 플러그인과 ADT를 연결하는 위해 Android Connector를 설치하는 것이다. 설치를 하려면 Preferences > Android/Discovery > Open Catalog 메뉴를 실행한 뒤, 아래 그림이 나올 때 android로 검색하면 된다.



검색 결과로 나온 Android Connector를 선택한 뒤 설치하자.


Android용 Archetype 추가 (옵션)


Android Connector를 설치 후, pom.xml 파일에 maven-android-plugin을 설정하면 해당 프로젝트를 ADT와 연동해 준다. 하지만, pom.xml 파일을 처음부터 만들면 (다소) 귀찮을 수 있는데, 그걸 대신 해주는 archetype을 추가해주면 좀 더 편하게 pom.xml 파일을 생성할 수 있다.


Archetype 타입을 추가해주는 방법은 간단하다. New > Maven Project > Next > Select an Archetype 화면에서 [Add Archetype...] 버튼을 클릭한다. 그런 다음 아래와 같이 정보를 입력하고 [OK] 버튼을 클릭하면 해당 Archetype이 추가된다.


* Group Id: de.akquinet.android.archetypes

* Artifact Id: android-quickstart

* Version: 1.0.8


안드로이드 프로젝트 생성하기


안드로이드 프로젝트를 생성하는 방법은 간단하다. 앞서 생성한 android-quickstart Archetype을 이용해서 안드로이드 프로젝트를 생성하면 된다. android-quickstart Archetype을 선택하면 아래 그림과 같은 화면이 나온다. platform의 값에 사용할 안드로이드 플랫폼 버전을 입력해주면 된다.



프로젝트를 생성하면 잠시 후 아래 그림과 같이 Maven 프로젝트가 ADT와 연동된 것을 확인할 수 있다. 아래 그림을 보면 자원 관리를 위한 res 폴더, 자동 생성되는 파일을 위한 gen 폴더 등이 생성된 것을 확인할 수 있다.



생성된 pom.xml 파일을 maven-android-plugin 설정 및 플랫폼 버전 정보 등이 포함된 것을 확인할 수 있다.


<?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/maven-v4_0_0.xsd">

    <modelVersion>4.0.0</modelVersion>

    <groupId>com.madvirus</groupId>

    <artifactId>NetworkExplorer</artifactId>

    <version>0.0.1-SNAPSHOT</version>

    <packaging>apk</packaging>

    <name>NetworkExplorer</name>


    <properties>

        <platform.version>2.3.2</platform.version>

    </properties>


    <dependencies>

        <dependency>

            <groupId>com.google.android</groupId>

            <artifactId>android</artifactId>

            <version>${platform.version}</version>

            <scope>provided</scope>

        </dependency>

    </dependencies>


    <build>

        <plugins>

            <plugin>

                <groupId>com.jayway.maven.plugins.android.generation2</groupId>

                <artifactId>android-maven-plugin</artifactId>

                <version>3.1.1</version>

                <configuration>

                    <androidManifestFile>${project.basedir}/AndroidManifest.xml</androidManifestFile>

                    <assetsDirectory>${project.basedir}/assets</assetsDirectory>

                    <resourceDirectory>${project.basedir}/res</resourceDirectory>

                    <nativeLibrariesDirectory>${project.basedir}/src/main/native</nativeLibrariesDirectory>

                    <sdk>

                        <platform>10</platform>

                    </sdk>

                    <undeployBeforeDeploy>true</undeployBeforeDeploy>

                </configuration>

                <extensions>true</extensions>

            </plugin>


            <plugin>

                <artifactId>maven-compiler-plugin</artifactId>

                <version>2.3.2</version>

                <configuration>

                    <source>1.6</source>

                    <target>1.6</target>

                </configuration>

            </plugin>

        </plugins>

    </build>

</project>




참고로, Android Connector와 android-maven-plugin인에 대한 보다 자세한 내용이 궁금하면 아래 사이트를 방문해서 확인하면 된다.


  1. 예감 2013.07.29 12:09

    Maven관련 자료 잘보고 갑니다^^

  2. 소액결제 현금 2017.12.10 04:09

    감솨합니다 ~~~

Scala 언어가 재미있지만 실제 프로젝트에 적용하려면 콘솔에서 컴파일하거나 실행해 볼 수는 없다. 실제 프로젝트에 Scala를 적용하려면 먼저 편리한 개발 환경을 구축해 주어야 한다. 필자의 경우 개발시 주로 이클립스와 메이븐을 사용하기 때문에, Scala를 이 환경에서 개발하기 위한 내용을 찾아보았으며, 각 내용들은 한 곳에 모아 보았다. (나중에 또 돌아다니면서 찾는 건 귀찮기에 이곳에 정리한다.)


이클립스와 메이븐(m2e 플러그인) 환경을 이용해서 Scala를 적용하려면 다음과 같은 준비를 하면 된다.

  • Scala IDE 설치
  • M2Eclipse Scala 플러그인 설치
  • Maven 프로젝트에 pom.xml 파일에 maven-scala-plugin 설정

Scala IDE 설치하기


먼저 Scala IDE를 설치한다. 이클립스 업데이트 사이트는 아래와 같다. 참고로 아래 주소는 Scala 2.9 버전 기준이다. (참고 사이트는 http://scala-ide.org/index.html 이다.)

  • http://download.scala-ide.org/releases-29/stable/site

M2Eclipse Scala 플러그인 설치


그 다음 할 작업은 Maven 프로젝트와 Scala IDE를 연결해 줄 플러그인을 설치해주는 것이다. 업데이트 주소는 아래와 같다. (참고 사이트는 https://github.com/sonatype/m2eclipse-scala 이다.)


  • http://alchim31.free.fr/m2e-scala/update-site/

pom.xml 파일에 maven-scala-plugin 설정하기


이제 남은 작업은 이클립스에서 실행할 메이븐 프로젝트의 pom.xml 파일에 maven-scala-plugin 설정을 하는 것이다. pom.xml 파일의 설정 예는 https://github.com/sonatype/m2eclipse-scala 사이트에서 찾아볼 수 있다. pom.xml 파일을 알맞게 작성한 뒤에 Scala 소스 코드를 작성하면, 알맞게 컴파일되고, 실행해 볼 수 있고,  자바 코드에서 Scala가 생성한 클래스를 사용하는 등의 작업을 할 수 있다.


참고로, 그럼 내가 왜 Scala를 사용해보려고 하느냐? 여러 이유가 있겠지만 다음이 주요 이유다.

  • 언어 자체의 재미: 언어가 다소 복잡하지만 재미는 있다.
  • Combinator Parser: 뭔가 규칙에 기반해서 텍스트를 파싱해야 할 때, 언어 차원에서 Parser를 지원하기 때문에, ANTLR 등을 사용하지 않아도 쉽게 파싱할 수 있다.
  • DSL(Domain Specific Language): 위의 내용과 더불어 DSL을 만들기에 Ruby나 Groovy 등의 언어들 만큼 좋다.
  • 자바와의 호환성: JVM 기반으로 동작하며 자바와의 호환이 당연히 잘 된다.
  • 함수형 언어이고 Clousure 등을 지원하기에 테스트 코드에 적용하면 테스트 코드에서 발생하는 중복을 많이 줄일 수 있으므로, 그것만으로도 가치가 있다.



회사를 옮길 때 마다 Maven 리포지토리와 관련된 비슷한 짓거리를 하고 그 내용을 동료들에게 알려주어야 하는 귀찮음을 줄이고자 정리해 보았다.


회사에서 내부적으로 사용할 Maven 리포지토리가 필요한 경우가 있다. 예를 들어, 오라클 JDBC 드라이버는 Maven 중앙 리포지토리에 존재하지 않기 때문에 모든 개발자들이 로컬 리포지토리에 따로 등록해주는 수고를 해야 하는데, 내부용 Maven 리포지토리를 만들어서 그곳에 오라클 JDBC 드라이버를 등록하면 한 사람만 내부용 리포지토리에 등록해주는 수고를 해 주면 나머지 개발자는 편하게 오라클 JDBC 드라이버를 Maven의 depedency로 등록해서 사용할 수 있게 된다. (한 사람이 노력으로 많은 개발자들의 중복 작업이 사라진다. DRY!!) 외부의 jar 파일 뿐만 아니라 내부에서 사내의 다수 프롤젝트에서 사용될 모듈을 만드는 경우에도 내부용 리포지토리를 만들면 쉽게 관련 모듈을 사용/관리할 수 있게 된다.

내부용 리포지토리 구축을 쉽게 하고 싶을 때에는 Nexus(http://www.sonatype.org/nexus/)를 사용하면 된다. Nexus는 자바로 만들어져 있으며, WAR로도 배포되기 때문에 손쉽게 설치할 수 있다는 장점이 있다. 설치에 대한 정보는 Nexus 홈페이지를 참고하기 바란다.

Nexus를 설치하면 최초에 다음의 리포지토리를 제공해준다.
  • Releases: 내부에서 만들어진 모듈의 정식 버전을 등록할 때 사용 (releases)
  • Snapshots: 내부에서 만들어진 모듈의 스냅샵 버전을 등록할 때 사용 (snapshots)
  • 3rd party: 외부 업체 제공 모듈을 등록할 때 사용 (예를 들어, 오라클 JDBC 드라이버 등) (thirdparty)
  • 기타 Central, Apache Snapshots, Codehaus Snapshots 등 외부 리포지토리 연결 (central 등)
  • 그리고, 이들을 하나처럼 보이게 해 주는 Public Repositories (public)
위 목록에서 뒤의 괄호안에 있는 이름이 리포지토리 주소에서 사용되는 경로인데, 예를 들어, Releases 리포지토리의 주소는 http://host/nexus-ver/content/repositories/releases/ 의 형식을 가지며, 그룹의 경우는 http://host/nexus-ver/content/groups/public의 형식을 갖는다.

릴리즈하기 위한 Maven 설정

내가 만든 Maven 프로젝트를 리포지토리에 배포하려면 다음의 세 가지 작업을 해 주어야 한다.
  • pom.xml 파일에 배포 대상 리포지토리 설정하기
  • settings.xml 파일에 배포 대상 리포지토리 연결 정보 설정하기
  • 배포하기
먼저 pom.xml 파일에 다음과 같이 <distributionManagement> 태그를 등록한다.

pom.xml 파일

<distributionManagement>
<repository>
<id>mycompany.internal.release</id>
<name>MyCompany Internal Repository</name>
<url>http://host/nexus/content/repositories/releases/</url>
</repository>
</distributionManagement>

두 번째로 settings.xml 파일에 pom.xml 파일에 설정한 리포지토리에 연결할 때 사용할 정보를 추가해주는 것이다. settings.xml 파일은 여러 위치에 만들 수 있는데 필자의 경우 [홈디렉토리]/.m2 디렉토리에 주로 만들어준다. 아래 코드는 settings.xml 파일의 작성 예이다.

settings.xml 파일

<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">
<servers>
<server>
<id>mycompany.internal.release</id>
<username>deployment</username>
<password>deployment123</password>
</server>
</servers>

</settings>

<server> 태그는 특정 서버에 연결할 때 사용할 아이디/암호를 입력하는데 이때 <id>의 값은 pom.xml에 등록한 리포지토리의 <id> 값과 일치해야 한다.

위와 같이 작업이 끝났다면 이제 배포만 하면 된다. Maven 프로젝트 디렉토리에서 다음과 같이 deploy 명령어를 실행하면 pom.xml 파일에 등록했던 배포 대상 리포지토리에 프로젝트의 artifact가 배포된다.

mvn deploy

등록된 것 사용하기

배포된 artifact를 다른 프로젝트에서 사용하려면 다음과 같이 앞서 구축한 내부용 리포지토리를 등록해주고 depedency를 추가해주면 된다.


<repositories>

<repository>

<id>mycompany.internal.repo</id>

<url>http://host/nexus/content/repositories/releases/</url>

<releases>

<enabled>true</enabled>

</releases>

</repository>

</repositories>


<dependencies>

<dependency>

<groupId>com.mycompany</groupId>

<artifactId>my-common-module</artifactId>

<version>3.0</version>

</dependency>

</dependencies>


Snapshot 등도 동일한 방식으로 등록 및 사용할 수 있다.



  1. moonv11 2014.07.17 13:49

    좋은 글 잘 보았습니다. 출처 명시하고 퍼가겠습니다.

  2. 카루딘 2016.07.06 11:12

    감사합니다. 출처 명시하고 담아가겠습니다. ^^

  3. 라이더 2017.04.19 18:55

    감사합니다. 정리 깔끔하시네요 ^^

  4. Ironcow 2018.07.06 09:27

    좋은 글 감사합니다.
    공부중에 필요한 정보였는데 출처 명시하고 담아가겠습니다!!

이 글은 Jetty 6 버전 기준이긴 하지만, 플러그인 버전이나 의존 라이브러리에서 차이가 날 뿐 Jetty 7 버전에서도 크게 다르지 않다.

Jetty 서버를 임베딩하기 위한 pom.xml 설정

Maven 프로젝트에서 Jetty 서버를 임베딩하려면 먼저 Jetty 관련 클래스들을 사용할 수 있어야 하므로, 아래와 같이 의존 라이브러리에 Jetty 관련 artifact를 추가해 준다.

<dependencies>
    <dependency>
        <groupId>org.mortbay.jetty</groupId>
        <artifactId>jsp-api-2.1</artifactId>
        <version>6.1.14</version>
        <scope>provided</scope>
    </dependency>
    <dependency>
        <groupId>org.mortbay.jetty</groupId>
        <artifactId>servlet-api-2.5</artifactId>
        <version>6.1.14</version>
        <scope>provided</scope>
    </dependency>
    <dependency>
        <groupId>org.mortbay.jetty</groupId>
        <artifactId>jetty</artifactId>
        <version>6.1.14</version>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>org.mortbay.jetty</groupId>
        <artifactId>jsp-2.1</artifactId>
        <version>6.1.14</version>
        <scope>test</scope>
    </dependency>
    ...

위 설정에서 눈여겨 볼 점은 서블릿/JSP API를 위한 artifact는 provided 범위를 갖는 반면에 Jetty 자체를 임베딩해서 실행하기 위한 artifact는 test 범위를 갖는다는 것이다. test 범위를 갖도록 한 이유는 Jetty 임베딩을 ATDD를 위한 용도로만 사용하기 때문이다.

Jetty 서버 임베딩으로 실행하기

Maven 프로젝트 구조에서 Jetty 서버를 임베딩으로 실행하고 종료하는데 사용된 코드는 다음과 같다.

public class JettyServer {

    private static Server server;
   
    public static void start() throws Exception {
        server = new Server(9090);

        WebAppContext context = new WebAppContext();
        context.setResourceBase("src/main/webapp");
        context.setContextPath("/goodjob");
        context.setParentLoaderPriority(true);

        server.setHandler(context);
       
        server.start();
    }

    public static void stop() throws Exception {
        server.stop();
    }
}

ATDD를 수행하는 코드에서는 다음과 같이 픽스처 구성시 JettyServer.start() 메서드를 이용해서 Jetty 서버를 임베딩해서 실행하고, 테스트 완료 후 JettyServer.stop() 메서드를 이용해서 Jetty 서버를 중지시켜주면 된다.

public class EndToEndTestBase {

    @BeforeClass
    public static void init() throws Exception {
        JettyServer.start();
    }

    @AfterClass
    public static void close() throws Exception {
        JettyServer.stop();
    }

}

일단, Jetty 서버를 임베딩으로 실행하면 http://localhost:9090/goodjob/authentication/login 과 같은 URL을 이용해서 실제 기능 테스트를 수행할 수 있다. 예를 들어, 웹 기능 테스트를 위한 코드는 아래와 같은 구성을 갖게 된다.

public class AllTeamsSummaryReportEndToEndTest extends EndToEndTestBase {

    @BeforeClass
    public static void initData() throws Exception {
        // 테스트 목적을 위한 데이터 초기화
        ...
    }

    @Test
    public void queryAllTeamsWeekSummaryReport() throws Throwable {
        // HtmlUnit이나 HttpClient와 같은 라이브러리를 이용해서
        // http://localhost:9090/goodjob/testurl 등 테스트 URL에 연결하고
        // 그 결과를 검증하는 코드 삽입
    }

}




필자가 Maven에서 가장 좋아하는 기능 중의 하나를 꼽으라면? Maven과 Jetty를 연동하여 웹 어플리케이션을 테스트할 수 있다는 것이다. 이클립스에서 톰캣이나 다른 WAS를 연동해서 테스트 해 본 개발자라면 프로젝트 별로 톰캣 연동 설정을 하는 게 얼마나 귀찮은 일인지 알 것이다. 동일한 프로젝트가 여러 브랜치에서 개발되고 있고, 각 브랜치를 하나의 이클립스에서 동시에 테스트 해야 할 경우 이클립스에서 WAS를 연동해서 테스트 하는 건 더욱 더 성가신 작업이 될 수 있다.

Maven은 웹 어플리케이션을 위한 프로젝트 타입을 제공하고 있을 뿐만 아니라 maven-jetty-plugin을 이용해서 프로젝트 별로 간단한 설정만으로 Jetty를 이용해서 웹 어플리케이션 테스트를 진행할 수 있다. 본 글에서는 Maven을 이용해서 웹 프로젝트를 생성하는 방법과 Jetty를 연동해서 웹 어플리케이션을 실행하고 테스트하는 방법을 살펴보도록 하겠다.

웹 어플리케이션 프로젝트 생성하기

웹 어플리케이션을 생성할 때에는 'archetype:generate' 플러그인 골을 실행한 뒤, Archetype으로 'maven-archetype-webapp'을 선택하면 된다. (archetype:generate 플러그인 골을 실행하는 방법은 필자가 쓴 'Maven 기초 사용법'을 참고하기 바란다.)

maven-archetype-webapp Arcetype을 이용해서 Maven 프로젝트를 생성하면 다음과 같이 디렉터리 구조가 생성된다.

simple-web
└─src
    └─main
        ├─resources
        └─webapp
            └─WEB-INF (web.xml 파일 포함)

src/main/webapp 디렉터리는 웹 어플리케이션에서 필요로 하는 HTML, 이미지, JSP 등의 파일이 위치한다. 웹 어플리케이션에서 필요로 하는 클래스를 추가해야 할 경우 src/main/java 디렉터리를 생성한 뒤 이 디렉터리에 자바 소스 코드를 위치시키면 된다.

maven-archetype-webapp을 통해서 생성된 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/maven-v4_0_0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>net.daum.cafe</groupId>
    <artifactId>simple-web</artifactId>
    <packaging>war</packaging>
    <version>1.0-SNAPSHOT</version>
    <name>simple-web Maven Webapp</name>
    <url>http://maven.apache.org</url>
    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>3.8.1</version>
            <scope>test</scope>
        </dependency>
    </dependencies>
    <build>
        <finalName>simple-web</finalName>
    </build>
</project>

위 코드를 보면 <packaging>의 값이 war인 것을 알 수 있는데, 이는 mvn package 명령어를 실행할 때 생성되는 결과물이 war 파일이라는 것을 의미하며, 이때 생성되는 war 파일의 이름은 <build>/<finalName>의 값을 사용한다. 위 예의 경우에는 simple-web.war 파일이 생성된다. mvn package 명령어로 생성되는 war 파일의 이름을 변경하고 싶다면 <finalName>에 원하는 값을 입력해 주면 된다.

웹 어플리케이션 개발시 주로 사용되는 의존 프로젝트 목록

웹 기반의 엔터프라이즈 어플리케이션을 개발할 때에는 서블릿 API, JSP API, JTA API 등 Sun에서 정의한 API가 필요하다. 문제는 라이센스 때문에 Sun이 제공하는 API를 Maven 중앙 리포지토리에서 다운로드 받을 수 없다는 점이다. 중앙 리포지토리에 없는 라이브러리는 직접 다운로드 받아 로컬 리포지토리에 등록해주어야 하는데, 다행히 Geronimo 프로젝트에서 Sun의 주요 API를 만들어 Maven 리포지토리에 등록하고 있다. 따라서, 서블릿 API나 JSP API 가 필요한 경우 Geronimo에서 제공하는 프로젝트를 pom.xml 파일의 <dependency>에 추가해주면 된다.

아래 표는 Geronimo가 제공하는 Sun의 주요 표준 API 목록을 정리한 것이다. 참고로 아래 표에 정리된 Artifact 들의 groupId는 org.apache.geronimo.specs 이다.

표준 표준 버전 Artifact ID  Artifact 최신 버전
Activation 1.0.2  geronimo-activation_1.0.2_spec 1.2 
Activation 1.1 geronimo-activation_1.1_spec 1.0.2
EJB 2.1 geronimo-ejb_2.1_spec 1.1 
EJB 3.0 geronimo-ejb_3.0_spec 1.0 .1
J2EE Connector 1.5 geronimo-j2ee-connector_1.5_spec  2.0.0
J2EE JACC 1.0  geronimo-j2ee-jacc_1.0_spec  1.1.1 
JACC 1.1  geronimo-jacc_1.1_spec  1.0.1
JavaMail  1.3.1  geronimo-javamail_1.3.1_spec  1.3 
JavaMail 1.4  geronimo-javamail_1.4_spec 1.5
JMS 1.1 geronimo-jms_1.1_spec  1.1.1
JPA 3.0  geronimo-jpa_3.0_spec  1.1.1
JSP 2.0  geronimo-jsp_2.0_spec 1.1
JSP 2.1  geronimo-jsp_2.1_spec 1.0.1
JTA 1.0.1B geronimo-jta_1.0.1B_spec  1.1.1 
JTA 1.1  geronimo-jta_1.1_spec 1.1.1
Servlet 2.4  geronimo-servlet_2.4_spec 1.1.1 
Servlet 2.5  geronimo-servlet_2.5_spec 1.2

예를 들어, 개발 과정에서 서블릿 2.5 API가 필요할 경우 pom.xml에 다음과 같이 <dependency>를 추가해주면 된다.

<dependency>
    <groupId>org.apache.geronimo.specs</groupId>
    <artifactId>geronimo-servlet_2.5_spec</artifactId>
    <version>1.2</version>
    <scope>provided</scope>
</dependency>

위 코드에서 scope가 provided인 이유는 서블릿이나 JSP API의 경우 컨테이너에 제공하기 때문이다.

Maven과 Jetty 연동을 통한 웹 테스트

Maven을 이용해서 웹 어플리케이션을 개발할 때 필자 개인적으로 가장 매력적인 점은 pom.xml 파일에 maven-jetty-plugin 설정만 추가해주면 Jetty를 이용해 웹 어플리케이션을 테스트 할 수 있다는 점이다. 즉, 톰캣과 같은 WAS를 설치하거나 추가적으로 설정할 필요 없이 웹 어플리케이션에 대한 기능 테스트가 가능하다는 점이다.

maven-jetty-plugin의 설정 방법은 매우 간단한데, 아래와 같이 pom.xml 파일에 설정해주면 된다.

<?xml version="1.0" encoding="UTF-8"?>
<project ...>
    ...
    <build>
        <finalName>main</finalName>
        <plugins>
            <plugin>
                <groupId>org.mortbay.jetty</groupId>
                <artifactId>maven-jetty-plugin</artifactId>
                <version>6.1.11</version>
                <configuration>
                    <contextPath>/main</contextPath>
                    <scanIntervalSeconds>3</scanIntervalSeconds>
                    <!-- 포트를 변경하고 싶은 경우 connectors 설정 이용 -->
                    <connectors>
                        <connector implementation="org.mortbay.jetty.nio.SelectChannelConnector">
                            <port>80</port>
                            <maxIdleTime>60000</maxIdleTime>
                        </connector>
                    </connectors>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

<configuration>에서 주요 설정 값은 다음과 같다.
  • <contextPath> - 웹 어플리케이션 컨텍스트 경로. 예를 들어, 위 설정의 경우 http://localhost:8080/main 이 웹 어플리케이션의 접근 URL이 된다.
  • <scanIntervalSeconds> - 웹 어플리케이션 컨텍스트의 클래스가 변경되는 지의 여부를 검사하는 시간 간격을 초 단위로 입력한다. 이 값을 0보다 크게 주면, 클래스가 변경될 때 마다 리로드 된다.
<scanTargets>나 <scanTargetPatterns>를 설정하면 클래스 뿐만 아니라 특정 디렉터리나 파일이 변경되는 지의 여부를 검사하도록 설정할 수 있다. 스캔 설정을 비롯한 maven-jetty-plugin의 다양한 설정 옵션을 확인하고 싶다면 'Maven Jetty Plugin Configuration Guide' 문서를 참고하기 바란다.

포트 번호를 지정하지 않을 경우 기본 값은 8080 이다. 따라서 8080 이 아닌 다른 포트를 사용하고 싶다면 위 설정에서 처럼 <connector>를 알맞게 설정해 주어야 한다.

jetty:run을 이용한 실행

maven-jetty-plugin이 제공하는 골에는 run, run-exploaded, run-war, start, stop 등 몇 가지가 존재하는데, 가장 많이 사용되는 건 run 골이다. run 골을 실행하는 방법은 다음과 같다.

$ mvn jetty:run
[INFO] Scanning for projects...
[INFO] Searching repository for plugin with prefix: 'jetty'.
[INFO] ------------------------------------------------------------------------
[INFO] Building javacan3
[INFO]    task-segment: [jetty:run]
[INFO] ------------------------------------------------------------------------
[INFO] Preparing jetty:run
[INFO] [resources:resources]
...
[INFO] [jetty:run]
[INFO] Configuring Jetty for project: javacan3
[INFO] Webapp source directory = C:\work\JavaCan3_maven\src\main\webapp
[INFO] web.xml file = C:\work\JavaCan3_maven\src\main\webapp\WEB-INF\web.xml
[INFO] Classes = C:\work\JavaCan3_maven\target\classes
2008-12-19 15:49:19.210::INFO:  Logging to STDERR via org.mortbay.log.StdErrLog
[INFO] Context path = /main
[INFO] Tmp directory =  determined at runtime
[INFO] Web defaults = C:\work\JavaCan3_maven\src\jetty\webdefault.xml
[INFO] Web overrides =  none
[INFO] Webapp directory = C:\work\\JavaCan3_maven\src\main\webapp
[INFO] Starting jetty 6.1.11 ...
...
2008-12-19 15:48:38.584::INFO:  Started SelectChannelConnector@0.0.0.0:8080
[INFO] Started Jetty Server

jetty:run을 실행하면 잠시 뒤에 Jetty가 실행되고 이 후로 웹 브라우저를 이용해서 기능 테스트를 진행할 수 있게 된다.


관련 링크:
  • Archetype 플러그인 사용법: http://maven.apache.org/plugins/maven-archetype-plugin/usage.html
  • Maven Jetty Plugin Configuration Guide: http://docs.codehaus.org/display/JETTY/Maven+Jetty+Plugin
  • Jetty 서블릿/JSP 컨테이너 기초 사용: http://javacan.tistory.com/entry/136

  1. 감사용 2011.07.28 11:35

    정보 감사합니다 퍼갈게요~문제된다면 삭제하겠습니다.!

    • 최범균 madvirus 2011.07.28 16:25 신고

      반드시 출처 밝혀 주시기 바랍니다.
      그리고, 퍼가시는 것 보다는 트랙백이나 링크 정도만 거는 수준으로 해 주셨으면 합니다.

Maven의 기본 라이프사이클에서 compile 시기에 실행되는 compiler 플러그인은 별도 설정이 없을 경우, 자바 1.3 버전 기준으로 컴파일 할 소스 코드를 파싱하고 자바 1.1 버전에 호환되도록 클래스 파일을 생성한다. 따라서, 제너릭(generic)이나 어노테이션(annotation)과 같이 자바 5 이상 버전에서만 유효한 문법이 코드에 포함되어 있을 경우 컴파일 과정에서 문법 에러가 발생하게 된다.

maven-compiler-plugin 설정하기

Maven이 기본적으로 사용하는 소스 및 생성 클래스의 자바 버전을 변경하려면 pom.xml 파일에서 maven-compiler-plugin의 <configuration> 영역에서 <source>와 <target>을 이용해서 소스 코드 및 생성 대상 자바 버전을 지정할 수 있다. 아래 코드는 설정 예를 보여주고 있다.

<project>
    ....
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>1.5</source>
                    <target>1.5</target>
                    <encoding>UTF-8</encoding>
                </configuration>
            </plugin>
            ...
        </plugins>
    </build>
</project>

만약 소스 코드의 인코딩이 운영체제의 기본 인코딩과 다르다면 <encoding> 속성을 이용해서 소스 코드의 인코딩을 지정해주면 된다.

위와 같이 maven-compiler-plugin 에서 소스 및 대상 자바 버전을 명시하면 eclipse:eclipse를 이용해서 생성한 이클립스 프로젝트도 설정한 자바 버전을 사용하도록 설정된다.

관련 자료:



 

  1. 고이 고이 퍼 갑니다. 잘 활용하도록 하겠습니다. ^^/

Maven을 이용해서 생성한 프로젝트를 이클립스에서 바로 사용할 수는 없다. 대신, Maven은 maven-eclipse-plugin을 이용해서 Maven 프로젝트를 이클립스에서 import 해서 사용할 수 있도록 지원해 주고 있다. 본 글에서는 Maven 프로젝트를 이클립스에서 사용하기 위한 기본 절차를 설명하고, 생성할 이클립스 프로젝트 정보를 커스터마이징 하는 방법을 살펴보도록 하겠다.

이 글을 최초로 썼던 2008년 시점과 달리, 현재는 이클립스의 메이븐 연동 플러그인(m2e 플러그인)이 잘 동작하기 때문에, 이 글의 방법을 사용해서 메이븐 프로젝트를 이클립스에 임포트 할 일이 없다. m2e 플러그인을 설치하면 이클립스에서 메이븐 프로젝트를 바로 임포트 할 수 있고, 또 메이븐 프로젝트를 생성할 수도 있다. 특히 이클립스 4.3 / 4.4 버전부터는 m2e 플러그인이 기본으로 포함되어 나오기 때문에, 플러그인을 따로 설치할 필요도 없어졌다. - 2014년 7월

최신 이클립스에서 메이븐 프로젝트를 임포트하는 방법은 https://javacan.tistory.com/entry/import-maven-project 글을 참고한다.


Maven 프로젝트에서 이클립스 프로젝트 정보 생성하는 방법

Maven 프로젝트를 이클립스에서 import 할 수 있도록 하기 위해 이클립스 프로젝트 정보를 생성하려면 아래 절차에 따라 필요한 작업을 수행하면 된다.

  1. 이클립스 워크스페이스에 Maven 관련 클래스패스 변수 추가하기. 이는 아래 명령어를 이용해서 실행하면 된다. (이 과정은 워크스페이스에 대해 한번만 실행해주면 된다.) 이 작업을 수행하면 해당 워크스페이스와 관련해서

    mvn -Declipse.workspace=<path-to-eclipse-workspace> eclipse:add-maven-repo

  2. 프로젝트 루트 디렉터리에서 eclipse:eclipse 플러그인 골을 실행해서 이클립스 프로젝트 정보를 생성한다.

    mvn eclipse:eclipse

    위 명령어가 성공적으로 실행되면 .project, .classpath, .settings/ 등 이클립스 프로젝트와 관련된 설정 파일이 생성된다.
  3. 이클립스를 실행한 뒤, File > Import > Existing Projects into Workspace 메뉴를 이용해서 생성된 이클립스 프로젝트를 import 한다.

1번 작업은 이클립스 워크스페이스 별로 한번씩 해 주면 된다. 2번 작업의 경우 POM 파일의 의존 설정 부분이 수정될 때 마다 eclipse:eclipse 플러그인 골을 실행해서 새로운 이클립스 프로젝트 설정 파일을 생성해 주어야 한다. 또한, 이클립스 설정이 변경된 프로젝트에 대해 'Refresh'를 실행해서 프로젝트 정보를 다시 읽어오도록 해 주어야 한다.

의존 라이브러리 소스 다운로드 설정

개발하다보면 디버그 과정에서 외부 라이브러리의 코드를 참조하고 싶을 때가 있다. maven-eclipse-plugin 플러그인은 프로젝트 정보를 생성할 때 관련 소스 코드 정보를 함께 생성해주는 기능을 제공하고 있다. 간단한 방법은 다음과 같이 eclipse:eclipse 플러그인 골을 실행할 때 donwloadSources 시스템 프로퍼티 값을 true로 주는 것이다.

mvn eclipse:eclipse -DdownloadSources=true

이 경우 Maven은 Maven 중앙 리포지토리에서 소스 코드를 포함하는 jar 파일을 다운로드 받아 로컬 리포지토리에 저장한 뒤, 이클립스 프로젝트 설정 파일에 소스 첨부 정보를 추가한다.

소스 코드를 다운로드 받도록 하는 또 다른 방법은 pom.xml 파일에서 maven-eclipse-plugin 플러그인 설정 정보를 직접 명시해주는 것이다. 아래는 pom.xml 파일 설정 예를 보여주고 있다.

<project>
  ...
  <dependencies>...</dependencies>
  <build>
    ...
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-eclipse-plugin</artifactId>
        <configuration>
          <downloadSources>true</downloadSources>
          <downloadJavadocs>true</downloadJavadocs>
        </configuration>
      </plugin>
    </plugins>
  </build>
</project>

위 코드와 같이 pom.xml 파일에 maven-eclipse-plugin의 설정 정보에서 downloadSources 설정 값을 true로 주면 eclipse:eclipse 골을 실행할 때 마다 소스 코드 다운로드를 시도하게 된다.

생성되는 프로젝트의 캐릭터 셋 설정하기

'mvn eclipse:eclipse' 명령어를 사용해서 이클립스 프로젝트 정보를 생성할 때, 생성되는 프로젝트의 인코딩은 이클립스에서 기본값으로 설정한 캐릭터 인코딩으로 설정된다. 그런데, 현재 이클립스의 기본 인코딩은 MS949인데, 새로 진행되는 프로젝트의 인코딩이 UTF-8 이라면 어떻게 해야 할까? 이미 다른 프로젝트들이 MS949 인코딩을 이용해서 개발되었기 때문에 이클립스의 기본 인코딩을 UTF-8로 변경할 수는 없을 것이다.

이렇게 프로젝트 별로 인코딩을 지정해주어야 하는 경우에는 pom.xml 파일에서 다음과 같이 maven-eclipse-plugin 플러그인의 <additionalConfig> 설정 정보를 추가해주면 된다.

    <plugin>
      <groupId>org.apache.maven.plugins</groupId>
      <artifactId>maven-eclipse-plugin</artifactId>
      <configuration>
        <additionalConfig>
          <file>
            <name>.settings/org.eclipse.core.resources.prefs
            </name>
            <content>
     <![CDATA[eclipse.preferences.version=1
encoding/<project>=UTF-8
]]>
            </content>
          </file>
        </additionalConfig>

      </configuration>
    </plugin>

<addionalConfig>/<file>을 설정하면 이클립스 프로젝트 생성시 추가적으로 <name>에 설정한 파일을 생성해준다. 위 코드의 경우 이클립스에서 인코딩 설정 정보를 저장할 때 사용되는 파일을 생성해 주도록 하였다. 생성되는 설정 파일(org.eclipse.core.resources.prefs)에서 encoding/<project> 설정 값을 UTF-8로 줌으로써, 이클립스에서 생성된 프로젝트의 인코딩을 UTF-8로 지정해 줄 수 있게 된다.


관련링크:


  1. 구구구구우 2017.03.03 09:49

    eclipse:configure-workspace 는 deprecated 되었다고 하네요
    eclipse:configure-workspace - > eclipse:configure-workspace 이걸 쓰면 된다고 합니다.

본 글에서는 Maven을 이용해서 프로젝트를 생성하는 방법과, 디렉토리 구조, POM 파일 기본 구성, Maven 라이프 사이클 그리고 Maven 프로젝트를 이클립스 프로젝트로 생성하는 방법을 살펴보도록 하겠다.


본 글의 내용 중 일부를 현재 메이븐 버전인 3.5에 맞게 수정했다. - 2017년 12월


Maven 설치

http://maven.apache.org/ 사이트를 방문하면, 최신 버전의 메이븐을 다운로드 받을 수 있다. 이 글을 쓰는 시점에서 메이븐 최신 버전은 3.5.2이다. 바이너리 배포판을 다운로드 받은 아무 곳이나 원하는 디렉토리에 압축을 푼다. 설치 과정은 다음과 같다.

  1. 다운로드 받은 파일의 압축을 푼다. 예, apache-maven-3.5.2.zip 파일의 압축을 C:에 풀면 c:\apache-maven-3.5.2 디렉토리가 생성된다.
  2. PATH 환경 변수에서 메이븐 bin 디렉토리를 추가한다. 
  3. 예) PATH=c:\apache-maven-3.5.2\bin;%PATH%
  4. JAVA_HOME 환경 변수가 올바르게 설정되어 있는지 확인한다. 참고로, 메이븐 3.3 이후부터는 자바 1.7 이상을 요구한다.
  5. 설치를 끝냈으면, 다음 명령어를 실행해서 메이븐이 올바르게 동작하는지 확인한다.
환경 변수를 모두 설정해 주었다면 아래의 명령어를 사용해서 Maven이 제대로 실행되는 지 확인해보자.

$ mvn -version
Apache Maven 3.5.2 (138edd61fd100ec658bfa2d307c43b76940a5d7d; 2017-10-18T16:58:13+09:00)
Maven home: /Users/madvirus/apache-maven-3.5.2
Java version: 9.0.1, vendor: Oracle Corporation
Java home: /Library/Java/JavaVirtualMachines/jdk-9.0.1.jdk/Contents/Home
Default locale: ko_KR, platform encoding: UTF-8
OS name: "mac os x", version: "10.13.1", arch: "x86_64", family: "mac"

Maven 프로젝트 생성하기

설치가 끝났다면 Maven 프로젝트를 생성해 보자. 명령 프롬프트에서 아래 명령어를 실행하면 된다. (아래 명령어를 처음 실행할 경우 꽤 오랜 시간이 걸리는데, 그 이유는 Maven이 필요한 플러그인과 모듈을 다운로드 받기 때문이다. Maven 배포판은 최초로 Maven을 사용하는 데 필요한 모듈만 포함하고 있고, 그 외에 archetype 플러그인, compiler 플러그인 등 Maven을 사용하는 데 필요한 모듈은 포함하고 있지 않다. 이들 모듈은 실제로 필요할 때 Maven 중앙 리포지토리에서 로딩된다.)


mvn archetype:generate


위 명령어를 실행하면 Maven 프로젝트를 생성하는 데 필요한 정보를 입력하라는 메시지가 단계적으로 뜨고, 각 항목별로 알맞은 값을 입력해주면 된다. 아래는 실행 화면 예이다. 붉은색으로 표시한 것은 입력한 값이다.


C:\Users\madvirus>mvn archetype:generate

[INFO] Scanning for projects...

[INFO] 

[INFO] ------------------------------------------------------------------------

[INFO] Building Maven Stub Project (No POM) 1

[INFO] ------------------------------------------------------------------------

...생략

Choose archetype:

1: remote -> am.ik.archetype:maven-reactjs-blank-archetype (Blank Project for React.js)

2: remote -> am.ik.archetype:msgpack-rpc-jersey-blank-archetype (Blank Project for Spring Boot + Jersey)

...생략

1090: remote -> org.apache.maven.archetypes:maven-archetype-portlet (An archetype which contains a sample JSR-268 Portlet.)

1091: remote -> org.apache.maven.archetypes:maven-archetype-profiles (-)

1092: remote -> org.apache.maven.archetypes:maven-archetype-quickstart (An archetype which contains a sample Maven project.)

...생략

Choose a number or apply filter (format: [groupId:]artifactId, case sensitive contains): 1092: [엔터]

Choose version:

1: 1.0-alpha-1

2: 1.0-alpha-2

3: 1.0-alpha-3

4: 1.0-alpha-4

5: 1.0

6: 1.1

Choose a number: 6: [엔터]

Define value for property 'groupId': : net.madvirus

Define value for property 'artifactId': : sample

Define value for property 'version':  1.0-SNAPSHOT: : [엔터]

Define value for property 'package':  net.madvirus: :  [엔터]

Confirm properties configuration:

groupId: net.madvirus

artifactId: sample

version: 1.0-SNAPSHOT

package: net.madvirus

 Y: : [엔터]

 [INFO] ----------------------------------------------------------------------------

[INFO] Using following parameters for creating project from Old (1.x) Archetype: maven-archetype-quickstart:1.1

[INFO] ----------------------------------------------------------------------------

[INFO] Parameter: groupId, Value: net.madvirus

[INFO] Parameter: packageName, Value: net.madvirus

[INFO] Parameter: package, Value: net.madvirus

[INFO] Parameter: artifactId, Value: sample

[INFO] Parameter: basedir, Value: C:\Users\madvirus

[INFO] Parameter: version, Value: 1.0-SNAPSHOT

[INFO] project created from Old (1.x) Archetype in dir: C:\Users\madvirus\sample


[INFO] ------------------------------------------------------------------------

[INFO] BUILD SUCCESS

[INFO] ------------------------------------------------------------------------

[INFO] Total time: 25:52 min

[INFO] Finished at: 2014-07-02T15:17:56+09:00

[INFO] Final Memory: 12M/111M

[INFO] ------------------------------------------------------------------------


과정에서 실제로 입력하는 값은 다음과 같다.

  • groupId - 프로젝트 속하는 그룹 식별 값. 회사, 본부, 또는 단체를 의미하는 값이 오며, 패키지 형식으로 계층을 표현한다. 위에서는 net.madvirus를 groupId로 이용하였다.
  • artifactId - 프로젝트 결과물의 식별 값. 프로젝트나 모듈을 의미하는 값이 온다. 위에서는 sample을 artifactId로 이용하였다.
  • version - 결과물의 버전을 입력한다. 위에서는 기본 값인 1.0-SNAPSHOT을 사용하였다.
  • package - 기본적으로 생성할 패키지를 입력한다. 별도로 입력하지 않을 경우 groupId와 동일한 구조의 패키지를 생성한다.
Maven 프로젝트의 기본 디렉토리 구조


archetype:generate 골이 성공적으로 실행되면, artifactId에 입력한 값과 동일한 이름의 폴더가 생성된다. 위 경우에는 현재 폴더에 sample 이라는 하위 폴더가 생성된다. 위 과정에서 선택한 archetype은 maven-archetype-quickstart 인데, 이 archetype을 선택했을 때 생성되는 폴더 구조는 다음과 같다.


sample
├─src
│   ├─main
│   │  └─java
│   │      └─net
│   │          └─madvirus
│   │              └─App.java
│   ├─test
│       └─java
│           └─net
│               └─madvirus
│                   └─AppTest.java
└─pom.xml


기본적으로 생성되는 폴더를 포함한 Maven 프로젝트의 주요 폴더는 다음과 같다.

  • src/main/java - 자바 소스 파일이 위치한다.
  • src/main/resources - 프로퍼티나 XML 등 리소스 파일이 위치한다. 클래스패스에 포함된다.
  • src/main/webapp - 웹 어플리케이션 관련 파일이 위치한다. (WEB-INF 폴더, JSP 파일 등)
  • src/test/java - 테스트 자바 소스 파일이 위치한다.
  • src/test/resources - 테스트 과정에서 사용되는 리소스 파일이 위치한다. 테스트 시에 사용되는 클래스패스에 포함된다.

기본적으로 생성되지 않은 폴더라 하더라도 직접 생성해주면 된다. 예를 들어 src/main 폴더에 resources 폴더를 생성해주면 Maven은 리소스 폴더로 인식한다.


자바 버전 수정


pom.xml 파일을 열어서 아래 코드를 추가하자. 이 설정은 컴파일 자바 버전을 1.8로 설정한다.



    ...생략


    <build>

        <plugins>

            <plugin>

                <groupId>org.apache.maven.plugins</groupId>

                <artifactId>maven-compiler-plugin</artifactId>

                <configuration>

                    <source>1.8</source>

                    <target>1.8</target>

                    <encoding>UTF-8</encoding>

                </configuration>

            </plugin>

        </plugins>

    </build>


</project>



컴파일 해보기/테스트 실행 해보기/패키지 해보기

이제 간단하게 컴파일과 테스트를 실행해보자. 소스 코드를 컴파일 하려면 다음과 같은 명령어를 실행해주면 된다.


C:\Users\madvirus\sample>mvn compile
[INFO] Scanning for projects...
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] Building sample 1.0-SNAPSHOT
[INFO] ------------------------------------------------------------------------
[INFO]
[INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ sample ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] skip non existing resourceDirectory C:\Users\madvirus\sample\src\main\resources
[INFO]
[INFO] --- maven-compiler-plugin:3.1:compile (default-compile) @ sample ---
[INFO] Compiling 1 source file to C:\Users\madvirus\sample\target\classes
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 2.205 s
[INFO] Finished at: 2014-07-03T09:51:15+09:00
[INFO] Final Memory: 11M/110M
[INFO] ------------------------------------------------------------------------


컴파일 된 결과는 target/classes 폴더에 생성된다.


테스트 클래스를 실행해보고 싶다면, 다음과 같은 명령어를 사용하면 된다.


$ mvn test

[INFO] Scanning for projects...

[INFO]                                                                         

[INFO] ------------------------------------------------------------------------

[INFO] Building sample 1.0-SNAPSHOT

[INFO] ------------------------------------------------------------------------

[INFO] 

[INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ sample ---

[INFO] Using 'UTF-8' encoding to copy filtered resources.

[INFO] skip non existing resourceDirectory /Users/madvirus/sample/src/main/resources

[INFO] 

[INFO] --- maven-compiler-plugin:3.1:compile (default-compile) @ sample ---

[INFO] Compiling 1 source file to /Users/madvirus/sample/target/classes

[INFO] 

[INFO] --- maven-resources-plugin:2.6:testResources (default-testResources) @ sample ---

[INFO] Using 'UTF-8' encoding to copy filtered resources.

[INFO] skip non existing resourceDirectory /Users/madvirus/sample/src/test/resources

[INFO] 

[INFO] --- maven-compiler-plugin:3.1:testCompile (default-testCompile) @ sample ---

[INFO] Compiling 1 source file to /Users/madvirus/sample/target/test-classes

[INFO] 

[INFO] --- maven-surefire-plugin:2.12.4:test (default-test) @ sample ---

...최초 실행시 관련 플러그인 파일 다운로드

-------------------------------------------------------

 T E S T S

-------------------------------------------------------

Running net.madvirus.AppTest

Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.005 sec


Results :


Tests run: 1, Failures: 0, Errors: 0, Skipped: 0


[INFO] ------------------------------------------------------------------------

[INFO] BUILD SUCCESS

[INFO] ------------------------------------------------------------------------

[INFO] Total time: 10.238 s

[INFO] Finished at: 2014-07-03T22:20:08+09:00

[INFO] Final Memory: 13M/228M

[INFO] ------------------------------------------------------------------------


그러면, 테스트 코드를 컴파일한 뒤 테스트 코드를 실행한다. 그리고 테스트 성공 실패 여부를 화면에 출력한다. 컴파일 된 테스트 클래스들은 target/test-classes 폴더에 생성되고, 테스트 결과 리포트는 target/surefire-reports 폴더에 저장된다.


(아무것도 한게 없으니 당연하지만) 모든 코드가 정상적으로 만들어지고 테스트도 통과했으니, 이제 배포 가능한 jar 파일을 만들어보자. 아래 명령어를 실행하면 프로젝트를 패키징해서 결과물을 생성한다.


$ mvn package

[INFO] Scanning for projects...

[INFO]                                                                         

[INFO] ------------------------------------------------------------------------

[INFO] Building sample 1.0-SNAPSHOT

[INFO] ------------------------------------------------------------------------

[INFO] 

[INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ sample ---

[INFO] Using 'UTF-8' encoding to copy filtered resources.

[INFO] skip non existing resourceDirectory /Users/madvirus/sample/src/main/resources

[INFO] 

[INFO] --- maven-compiler-plugin:3.1:compile (default-compile) @ sample ---

[INFO] Nothing to compile - all classes are up to date

[INFO] 

[INFO] --- maven-resources-plugin:2.6:testResources (default-testResources) @ sample ---

[INFO] Using 'UTF-8' encoding to copy filtered resources.

[INFO] skip non existing resourceDirectory /Users/madvirus/sample/src/test/resources

[INFO] 

[INFO] --- maven-compiler-plugin:3.1:testCompile (default-testCompile) @ sample ---

[INFO] Nothing to compile - all classes are up to date

[INFO] 

[INFO] --- maven-surefire-plugin:2.12.4:test (default-test) @ sample ---

[INFO] Surefire report directory: /Users/madvirus/sample/target/surefire-reports


-------------------------------------------------------

 T E S T S

-------------------------------------------------------

Running net.madvirus.AppTest

Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.005 sec


Results :


Tests run: 1, Failures: 0, Errors: 0, Skipped: 0


[INFO] 

[INFO] --- maven-jar-plugin:2.4:jar (default-jar) @ sample ---

[INFO] Building jar: /Users/madvirus/sample/target/sample-1.0-SNAPSHOT.jar

[INFO] ------------------------------------------------------------------------

[INFO] BUILD SUCCESS

[INFO] ------------------------------------------------------------------------

[INFO] Total time: 1.783 s

[INFO] Finished at: 2014-07-03T22:21:59+09:00

[INFO] Final Memory: 8M/156M

[INFO] ------------------------------------------------------------------------


mvn package가 성공적으로 실행되면, target 폴더에 프로젝트 이름과 버전에 따라 알맞은 이름을 갖는 jar 파일이 생성된다. 위 예제의 경우에는 sample-1.0-SNAPSHOT.jar 파일이 생성된 것을 확인할 수 있다.


POM 파일 기본

Maven 프로젝트를 생성하면 pom.xml 파일이 프로젝트 루트 폴더에 생성된다. 이 pom.xml 파일은 Project Object Model 정보를 담고 있는 파일로서, 이 파일에서 다루는 주요 설정 정보는 다음과 같다.

  • 프로젝트 정보 - 프로젝트의 이름, 개발자 목록, 라이센스 등의 정보를 기술
  • 빌드 설정 - 소스, 리소스, 라이프 사이클 별 실행할 플러그인 등 빌드와 관련된 설정을 기술
  • 빌드 환경 - 사용자 환경 별로 달라질 수 있는 프로파일 정보를 기술
  • POM 연관 정보 - 의존 프로젝트(모듈), 상위 프로젝트, 포함하고 있는 하위 모듈 등을 기술

archetype:create 골 실행시 maven-archetype-quickstart Archetype을 선택한 경우 생성되는 pom.xml 파일은 다음과 같다.

[기본으로 생성되는 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>net.madvirus</groupId>

  <artifactId>sample</artifactId>

  <version>1.0-SNAPSHOT</version>

  <packaging>jar</packaging>


  <name>sample</name>

  <url>http://maven.apache.org</url>


  <properties>

    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>

  </properties>


  <dependencies>

    <dependency>

      <groupId>junit</groupId>

      <artifactId>junit</artifactId>

      <version>3.8.1</version>

      <scope>test</scope>

    </dependency>

  </dependencies>

</project>


위 POM 파일에서 프로젝트 정보를 기술하는 태그는 다음과 같다.

  • <name> - 프로젝트 이름
  • <url> - 프로젝트 사이트 URL

POM 연관 정보는 프로젝트간 연관 정보를 기술하는데, 관련 태그는 다음과 같다.

  • <groupId> - 프로젝트의 그룹 ID 설정
  • <artifactId> - 프로젝트의 Artifact ID 설정
  • <version> - 버전 설정
  • <packaging> - 패키징 타입 설정. 위 코드의 경우 프로젝트의 결과 Artifact가 jar 파일로 생성됨을 의미한다. jar뿐만 아니라 웹 어플리케이션을 위한 war나 JEE를 위한 ear 등의 패키징 타입이 존재한다.
  • <dependencies> - 이 프로젝트에서 의존하는 다른 프로젝트 정보를 기술한다.
    • <dependency> - 의존하는 프로젝트 POM 정보를 기술
      • <groupId> - 의존하는 프로젝트의 그룹 ID
      • <artifactId> - 의존하는 프로젝트의 artifact ID
      • <version> - 의존하는 프로젝트의 버전
      • <scope> - 의존하는 범위를 설정

의존 설정

<dependency> 부분의 설정에 대해서 좀 더 살펴보도록 하자.

Maven을 사용하지 않을 경우 개발자들은 코드에서 필요로 하는 라이브러리를 각각 다운로드 받아야 한다. 예를 들어 아파치 commons DBCP 라이브러리를 사용하기 위해서는 DBCP뿐만 아니라 common pool 라이브러리도 다운로드 받아야 한다. 물론 commons logging을 비롯한 라이브러리도 모두 추가로 다운로드 받아 설치해 주어야 한다. 즉 코드에서 필요로 하는 라이브러리뿐만 아니라 그 라이브러리가 필요로 하는 또 다른 라이브러리도 직접 찾아서 설치해 주어야 한다.

하지만, Maven을 사용할 경우에는 코드에서 직접적으로 사용하는 모듈에 대한 의존만 추가해주면 된다. 예를 들어 commons-dbcp 모듈을 사용하고 싶은 경우 다음과 같은 <dependency> 코드만 추가해주면 된다.


<dependency>
    <groupId>commons-dbcp</groupId>
    <artifactId>commons-dbcp</artifactId>
    <version>1.2.1</version>
</dependency>


그러면, Maven은 commons-dbcp 뿐만 아니라 commons-dbcp가 의존하는 라이브러리를 자동으로 처리해준다. 실제로 1.2.1 버전의 commons-dbcp 모듈의 pom.xml 파일을 보면 의존 부분이 다음과 같이 설정되어 확인할 수 있다.


  <dependencies>
    <dependency>
      <groupId>commons-collections</groupId>
      <artifactId>commons-collections</artifactId>
      <version>2.1</version>
    </dependency>
    <dependency>
      <groupId>commons-pool</groupId>
      <artifactId>commons-pool</artifactId>
      <version>1.2</version>
    </dependency>
    <dependency>
      <groupId>javax.sql</groupId>
      <artifactId>jdbc-stdext</artifactId>
      <version>2.0</version>
      <optional>true</optional>
    </dependency>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>3.8.1</version>
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>xml-apis</groupId>
      <artifactId>xml-apis</artifactId>
      <version>2.0.2</version>
    </dependency>
    <dependency>
      <groupId>xerces</groupId>
      <artifactId>xerces</artifactId>
      <version>2.0.2</version>
    </dependency>
  </dependencies>


Maven은 commons-dbcp 모듈을 다운로드 받을 때 관련 POM 파일도 함께 다운로드 받는다. (다운로드 받은 파일은 로컬 리포지토리에 저장되는데 이에 대한 내용은 뒤에서 다시 설명하겠다.) 그리고 POM 파일에 명시한 의존 모듈을 함께 다운로드 받는다. 즉 commons-dbcp 1.2.1 버전의 경우 commons-collections 2.1 버전과 commons-pool 1.2 버전 등을 함께 다운로드 받는다. 이런 식으로 반복해서 다운로드 받은 모듈이 필요로 하는 모듈을 다운로드 받고 이들 모듈을 현재 프로젝트에서 사용할 클래스패스에 추가해준다.

따라서, 개발자는 일일이 필요한 모듈을 다운로드 받을 필요가 없으며, 현재 코드에서 직접적으로 필요로 하는 모듈에 대해서만 <dependency>로 추가해주면 된다. 나머지 의존은 모두 Maven이 알맞게 처리해준다.


search.maven.org 사이트에서 POM 정보 찾기

Maven을 사용할 때 자주 찾게 되는 사이트가 search.maven.org 이다. search.maven.org는 Maven 중앙 리포지토리에 등록된 POM 정보를 검색해주는 기능을 제공해준다. 이 사이트를 통해서 추가할 라이브러리의 <dependency> 설정 정보를 구할 수 있다.


의존의 scope: compile, runtime, provided, test

앞의 pom.xml 파일에서 <dependency> 부분을 보면 <scope>를 포함하고 있는 것과 그렇지 않은 것이 존재한다는 것을 알 수 있다. <scope>는 의존하는 모듈이 언제 사용되는 지를 설정할 때 사용되며, <scope>에 올 수 있는 값은 다음의 네 가지가 존재한다.

  • compile - 컴파일 할 때 필요. 테스트 및 런타임에도 클래스패스에 포함된다. <scope>를 설정하지 않을 경우 기본 값은 compile 이다.
  • runtime - 런타임에 필요. JDBC 드라이버 등이 예가 된다. 프로젝트의 코드를 컴파일 할 때는 필요하지 않지만, 실행할 때 필요하다는 것을 의미한다. 배포시 포함된다.
  • provided - 컴파일 할 때 필요하지만, 실제 런타임 때에는 컨테이너 같은 것에서 기본으로 제공되는 모듈임을 의미한다. 예를 들어 서블릿이나 JSP API 등이 이에 해당한다. 배포시 제외된다.
  • test - 테스트 코드를 컴파일 할 때 필요. Mock 테스트를 위한 모듈이 예이다. 테스트 시에 클래스패스에 포함되며, 배포시 제외된다.


원격 리포지토리와 로컬 리포지토리

Maven은 컴파일이나 패키징 등 작업을 실행할 때 필요한 플러그인이나 pom.xml 파일의 <dependency> 등에 설정한 모듈을 Maven 중앙 리포지토리에서 다운로드 받는다. 현재 중앙 리포지토리의 주소는 http://repo1.maven.org/maven2/ 이다.

원격 리포지토리에서 다운로드 받은 모듈은 로컬 리포지토리에 저장된다. 로컬 리포지토리는 [USER_HOME]/.m2/repository 폴더에 생성되며, 로컬 리포지토리에는 다음과 같은 형식의 폴더를 생성한 뒤 다운로드 받은 모듈을 저장한다.


[groupId]/[artifactId]/[version]


예를 들어 commons-dbcp 1.2.1 버전의 경우, 모듈 및 관련 POM 파일이 저장되는 폴더는 다음과 같다.


[USER_HOME]/.m2/repository/commons-dbcp/commons-dbcp/1.2.1


위 폴더에 저장되는 파일은 패키징 된 모듈 파일, pom 파일, 그리고 소스 코드 다운로드 옵션을 실행한 경우에는 소스 코드를 포함한 jar 파일이 포함된다.

일단 원격 리포지토리로부터 파일을 다운로드해서 로컬 리포지토리에 저장하면, 그 뒤로는 로컬 리포지토리에 저장된 파일을 사용하게 된다.

Maven 라이프사이클(Lifecycle)과 플러그인 실행

본 글의 서두에 Maven은 프로젝트의 라이프사이클 기반 프레임워크를 제공한다고 했다. 앞서 프로젝트를 생성한 뒤 컴파일하고(mvn compile), 테스트 하고(mvn test), 패키징 하는(mvn package) 과정을 정해진 명령어를 이용해서 실행했는데, 이때 compile, test, package는 모두 빌드 라이프사이클에 속하는 단계이다.

Maven은 clean, build (default), site의 세 가지 라이프사이클을 제공하고 있다. 각 라이프사이클은 순서를 갖는 단계(phase)로 구성된다. 또한, 각 단계별로 기본적으로 실행되는 플러그인(plugin) 골(goal)이 정의되어 있어서 각 단계마다 알맞은 작업이 실행된다. 아래 표는 디폴트 라이프사이클을 구성하고 있는 주요 실행 단계를 순서대로 정리한 것이다.

[표] 디폴트 라이프사이클의 주요 단계(phase)

 단계 설명  단계에 묶인 플러그인 실행
generate-sources 컴파일 과정에 포함될 소스를 생성한다. 예를 들어 DB 테이블과 매핑되는 자바 코드를 생성해주는 작업이 이 단계에서 실행된다.
process-sources 필터와 같은 작업을 소스 코드에 처리한다.  
generate-resources 패키지에 포함될 자원을 생성한다.   
process-resources 필터와 같은 작업을 자원 파일에 처리하고, 자원 파일을 클래스 출력 디렉토리에 복사한다. resources:resources 
compile 소스 코드를 컴파일해서 클래스 출력 폴더에 클래스를 생성한다. compiler:compile
generate-test-sources 테스트 소스 코드를 생성한다. 예를 들어 특정 클래스에서 자동으로 테스트 케이스를 만드는 작업이 이 단계에서 실행된다.
process-test-sources 필터와 같은 작업을 테스트 소스 코드에 처리한다. resources:testResources 
generate-test-resources 테스트를 위한 자원 파일을 생성한다.   
process-test-resources 필터와 같은 작업을 테스트 자원 파일에 처리하고, 테스트 자원 파일을 테스트 클래스 출력 폴더에 복사한다.  
test-compile 테스트 소스 코드를 컴파일해서 테스트 클래스 추력 폴더에 클래스를 생성한다. compiler:testCompile
test 테스트를 실행한다. surefire:test
package 컴파일 된 코드와 자원 파일들을 jar, war와 같은 배포 형식으로 패키징한다. 패키징에 따라 다름
jar - jar:jar
war - war:war
pom - site:attach-descriptor
ejb - ejb:ejb
install 로컬 리포지토리에 패키지를 복사한다. install:install
deploy 생성된 패키지 파일을 원격 리포지토리에 등록하여, 다른 프로젝트에서 사용할 수 있도록 한다. deploy:deploy

라이프사이클의 특정 단계를 실행하려면 다음과 같이 mvn [단계이름] 명령어를 실행하면 된다.


mvn test
mvn deploy


라이프사이클의 특정 단계를 실행하면 그 단계의 앞에 위치한 모든 단계가 실행된다. 예를 들어 test 단계를 실행하면 test 단계를 실행하기에 앞서 'generate-sources' 단계부터 'test-compile' 단계까지 각 단계를 순서대로 실행한다. 각 단계가 실행될 때는 각 단계에 묶인 골(goal)이 실행된다.

플러그인을 직접 실행할 수도 있다. mvn 명령어에 단계 대신 실행할 플러그인을 지정하면 된다.


mvn surefire:test


단, 플러그인 골을 직접 명시한 경우에는 해당 플러그인만 실행되기 때문에 라이프사이클의 단계가 실행되지는 않는다.


플러그인 골(Plugin Goal)

Maven에서 플러그인을 실행할 때에는 '플러그인이름:플러그인지원골'의 형식으로 실행할 기능을 선택한다. 예를 들어 compiler:compile은 'compiler'는 플러그인에서 'compile' 기능(goal)을 실행한다는 것을 뜻한다.


맺음말

이번 글에서는 Maven의 기본 사용법을 살펴봤다. Maven이 제공하는 의존 관리는 개발자를 jar 지옥(?)에서 구해준다는 것을 알 수 있었다. 또한, Maven은 표준화된 라이프사이클을 제공하고 있기 때문에 개발자가 컴파일-테스트-패키징 등의 과정을 손으로 정의하지 않아도 되며, 개발자는 Maven이 제공하는 단계 중 필요한 단계만 실행하면 된다. 그럼, 나머지 작업(컴파일, 테스트 실행, jar 파일 생성)은 모두 Maven이 처리해준다.

다음 글에서는 많이 사용되고 있는 개발툴인 이클립스에서 Maven 프로젝트를 import하는 방법과 컴파일러 버전을 명시하는 방법을 살펴보도록 하겠다.

관련 자료:





 

  1. 쿠하하하 2009.05.29 15:49

    아.. 정말 찾던 정보예요~
    ㅠㅠ 감사합니다.
    담아가도 될까요???
    허락 후에 담아갈게요 ^^

  2. 지피지기 2010.01.14 11:06

    좋은글 감사합니다.
    허락하시면 담아가도 될까요?
    좋은 하루되세요

  3. 옴그루 2010.09.13 20:17

    도움이 많이 되었습니다.
    정말 감사합니다. ^^

  4. rootkim 2012.07.08 16:13

    공부하는 학생입니다.
    Maven에 대해서 환경을 만들어주는데 어려움을 많이 겪었는데,
    정말 많은 도움이 됐습니다. 감사합니다.

  5. 궁금 2014.01.09 16:01

    Path 환경변수 등록할때 맨 뒤에%PATH% 이건 왜 붙는거죠?

    • 최범균 madvirus 2014.01.11 00:13 신고

      윈도우7에선 사실 그걸 안 붙여줘도 되는데, 완전 습관적으로 붙였네요. (윈XP는 어땟는지 기억이 가물가물합니다.)

  6. 김승광 2014.02.05 16:21

    아마도 기존 환경변수 PATH 에 저장된 경로들에 신규 M2_HOME PATH를 더한(+) 다는 의미 인듯 합니다. 적어도 리눅스에서는요 .
    항상 감사하게 잘 읽고 있습니다.
    새해 복 많이 받으세요!

  7. 표희민 2014.04.01 07:34

    덕분에 도움 많이 되었습니다. 감사합니다!

  8. 고명재 2015.05.06 06:51

    window8에서도 똑같이 설정하면 되는건가요?
    같은 방법으로 했는데 명령프롬프트 창에 mvn -version 쓰면
    mvn은 내부 또는 외부 명령, 실행할수 있는 프로그램, 또는 배치 파일이 아닙니다.
    라는 에러메세지가 나와서요.

    • 최범균 madvirus 2015.05.06 14:22 신고

      PATH 환경변수 설정해 주셨나요?
      PATH 환경변수를 설정한 뒤에는 명령프롬프트를 다시 실행해주셔야 합니다.

  9. 고명재 2015.05.08 03:15

    네, 설명해 주신대로 설정했는데도 같은 에러 메세지가 나와서요.
    eclipse에서의 다른 작동도 문제가 없고, 명령프롬프트 창에 java 또는 javac를 적을 경우에 잘 작동합니다.
    java version 1.7.0_79를 설치했는데요. 혹시 버전에 문제가 있는 것일까요?

    • 최범균 madvirus 2015.05.08 10:12 신고

      PATH 환경 변수에 [메이븐설치폴더]\bin 이 추가되었는지 확인해보세요.
      java나 javac는 [JAVA설치폴더]\bin 폴더이고, mvn 명령어는 [메이븐설치폴더]\bin 폴더입니다.

  10. 고명재 2015.05.11 08:45

    안녕하세요. 벌써 세번째 댓글이네요. JAVA_HOME 경로 설정에 문제가 또 생겼었는데. 잘 해결 됐습니다. 감사합니다. 앞으로도 좋은 정보 많이 부탁드릴게요.

  11. 일본외국인노동자 2017.03.30 14:36

    안녕하세요 프론트쪽일하다가 서버쪽에서 API를 메이븐으로 해달라 어쩌구저쩌구 하나도 모르는거를 해달라고 해서 너무 힘들었는데 자바캔님 설명글듣고 칭찬도 듣고 잘 해결되서 너무나도 고마워서 댓글답니다. 이렇게 또 하나의 지식이 느는것같아서 기쁘네요 ㅋ
    좋은하루되세효 ^^

+ Recent posts