CLOVER🍀

That was when it all began.

Apache MavenでWebアプリにトライ

今回は、Apache Mavenを使ったWebアプリ作成にトライしてみます。以下のページを参考に、Webアプリ用のプロジェクトを作成。

http://maven.apache.org/guides/mini/guide-webapp.html

$ mvn archetype:generate -DgroupId=myapp.web -DartifactId=myapp-web -DarchetypeArtifactId=maven-archetype-webapp
[INFO] Scanning for projects...
[INFO]                                                                         
[INFO] ------------------------------------------------------------------------
[INFO] Building Maven Stub Project (No POM) 1
[INFO] ------------------------------------------------------------------------
[INFO] 
[INFO] >>> maven-archetype-plugin:2.0:generate (default-cli) @ standalone-pom >>>
[INFO] 
[INFO] <<< maven-archetype-plugin:2.0:generate (default-cli) @ standalone-pom <<<
[INFO] 
[INFO] --- maven-archetype-plugin:2.0:generate (default-cli) @ standalone-pom ---
[INFO] Generating project in Interactive mode
Downloading: http://repo1.maven.org/maven2/org/apache/maven/archetypes/maven-archetype-webapp/1.0/maven-archetype-webapp-1.0.jar
Downloaded: http://repo1.maven.org/maven2/org/apache/maven/archetypes/maven-archetype-webapp/1.0/maven-archetype-webapp-1.0.jar (4 KB at 8.9 KB/sec)
Downloading: http://repo1.maven.org/maven2/org/apache/maven/archetypes/maven-archetype-webapp/1.0/maven-archetype-webapp-1.0.pom
Downloaded: http://repo1.maven.org/maven2/org/apache/maven/archetypes/maven-archetype-webapp/1.0/maven-archetype-webapp-1.0.pom (533 B at 1.1 KB/sec)
[INFO] Using property: groupId = myapp.web
[INFO] Using property: artifactId = myapp-web
Define value for property 'version':  1.0-SNAPSHOT: : 
[INFO] Using property: package = myapp.web
Confirm properties configuration:
groupId: myapp.web
artifactId: myapp-web
version: 1.0-SNAPSHOT
package: myapp.web
 Y: : Y
[INFO] ----------------------------------------------------------------------------
[INFO] Using following parameters for creating project from Old (1.x) Archetype: maven-archetype-webapp:1.0
[INFO] ----------------------------------------------------------------------------
[INFO] Parameter: groupId, Value: myapp.web
[INFO] Parameter: packageName, Value: myapp.web
[INFO] Parameter: package, Value: myapp.web
[INFO] Parameter: artifactId, Value: myapp-web
[INFO] Parameter: basedir, Value: /xxxxx
[INFO] Parameter: version, Value: 1.0-SNAPSHOT
[INFO] ********************* End of debug info from resources from generated POM ***********************
[INFO] project created from Old (1.x) Archetype in dir: /xxxxx/myapp-web
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 16.802s
[INFO] Finished at: Fri May 20 20:53:48 JST 2011
[INFO] Final Memory: 8M/107M
[INFO] ------------------------------------------------------------------------

archetypeプラグインのgenerateゴール実行時に、「archetypeArtifactId=maven-archetype-webapp」を指定します。

できあがったディレクトリ。

$ find ./myapp-web
./
./myapp-web
./myapp-web/src
./myapp-web/src/main
./myapp-web/src/main/resources
./myapp-web/src/main/webapp
./myapp-web/src/main/webapp/WEB-INF
./myapp-web/src/main/webapp/WEB-INF/web.xml
./myapp-web/src/main/webapp/index.jsp
./myapp-web/pom.xml

…srcディレクトリに、javaディレクトリがありません。どうも、Webアプリプロジェクト作成時には、Javaソースディレクトリは作ってくれないらしいです。なんで?

仕方がないので、ディレクトリを作成します。

$ mkdir src/main/java

んで、手順を見ると「mvn clean package」と書いてあるので、とりあえず実行してみます。

mvn clean package
[INFO] Scanning for projects...
[INFO]                                                                         
[INFO] ------------------------------------------------------------------------
[INFO] Building myapp-web Maven Webapp 1.0-SNAPSHOT
[INFO] ------------------------------------------------------------------------
Downloading: http://repo1.maven.org/maven2/org/apache/maven/plugins/maven-war-plugin/2.1.1/maven-war-plugin-2.1.1.pom
Downloaded: http://repo1.maven.org/maven2/org/apache/maven/plugins/maven-war-plugin/2.1.1/maven-war-plugin-2.1.1.pom (7 KB at 5.8 KB/sec)
Downloading: http://repo1.maven.org/maven2/org/apache/maven/plugins/maven-war-plugin/2.1.1/maven-war-plugin-2.1.1.jar
Downloaded: http://repo1.maven.org/maven2/org/apache/maven/plugins/maven-war-plugin/2.1.1/maven-war-plugin-2.1.1.jar (76 KB at 53.5 KB/sec)
[INFO] 
[INFO] --- maven-clean-plugin:2.4.1:clean (default-clean) @ myapp-web ---
[INFO] 
[INFO] --- maven-resources-plugin:2.4.3:resources (default-resources) @ myapp-web ---
[WARNING] Using platform encoding (UTF-8 actually) to copy filtered resources, i.e. build is platform dependent!
[INFO] Copying 0 resource
…毎度おなじみ、ダウンロード処理
[INFO] Webapp assembled in [34 msecs]
[INFO] Building war: /xxxxx/myapp-web/target/myapp-web.war
[INFO] WEB-INF/web.xml already added, skipping
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 15.700s
[INFO] Finished at: Fri May 20 21:00:21 JST 2011
[INFO] Final Memory: 7M/169M
[INFO] ------------------------------------------------------------------------

最終的に、WARファイルができあがります。ちょっとpom.xmlを見てみましょう。

$ cat 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>myapp.web</groupId>
  <artifactId>myapp-web</artifactId>
  <packaging>war</packaging>
  <version>1.0-SNAPSHOT</version>
  <name>myapp-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>myapp-web</finalName>
  </build>
</project>

packagingが「war」になっています。あと、さっきのパッケージング結果だと、WARファイルの名前が「myapp-web.war」となっていましたが、build/finalNameで指定下名前がWARファイルの名前になるっぽいですね。前回のコマンドラインアプリの時はバージョンまで名前に入っていましたが、Webアプリの場合はバージョンを入れるとバージョンが変わるとURLが変わってしまうからでしょう…。

続いて、サーブレットを書いてみましょう。pom.xmlに依存関係を追加します。

    <dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>servlet-api</artifactId>
      <version>2.5</version>
      <scope>provided</scope>
    </dependency>

ディレクトリとサーブレットの作成。

$ mkdir -p src/main/java/myapp/web
$ emacs src/main/java/myapp/web/HelloServlet.java &

今回のサーブレット

package myapp.web;

import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class HelloServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request,
                         HttpServletResponse response) throws ServletException, IOException {
        response.setCharacterEncoding("UTF-8");
        PrintWriter writer = response.getWriter();
        writer.write("Hello Web App!");
    }
}

デプロイメントディスクリプタ(web.xml)。

<web-app xmlns="http://java.sun.com/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
         version="2.5">
  <display-name>Archetype Created Web Application</display-name>

  <servlet>
    <servlet-name>HelloServlet</servlet-name>
    <servlet-class>myapp.web.HelloServlet</servlet-class>
  </servlet>
  <servlet-mapping>
    <servlet-name>HelloServlet</servlet-name>
    <url-pattern>/hello</url-pattern>
  </servlet-mapping>
</web-app>

archetypeプラグインで用意されたデフォルトのweb.xmlを修正。ちょっとDTDが古かったので、サーブレット2.5まで引き上げました。

パッケージングします。

$ mvn clean package
[INFO] Scanning for projects...
[INFO]                                                                         
[INFO] ------------------------------------------------------------------------
[INFO] Building myapp-web Maven Webapp 1.0-SNAPSHOT
[INFO] ------------------------------------------------------------------------
[INFO] 
[INFO] --- maven-clean-plugin:2.4.1:clean (default-clean) @ myapp-web ---
[INFO] Deleting /xxxxx/myapp-web/target
[INFO] 
[INFO] --- maven-resources-plugin:2.4.3:resources (default-resources) @ myapp-web ---
[WARNING] Using platform encoding (UTF-8 actually) to copy filtered resources, i.e. build is platform dependent!
[INFO] Copying 0 resource
[INFO] 
[INFO] --- maven-compiler-plugin:2.3.2:compile (default-compile) @ myapp-web ---
[WARNING] File encoding has not been set, using platform encoding UTF-8, i.e. build is platform dependent!
[INFO] Compiling 1 source file to /xxxxx/myapp-web/target/classes
[INFO] 
[INFO] --- maven-resources-plugin:2.4.3:testResources (default-testResources) @ myapp-web ---
[WARNING] Using platform encoding (UTF-8 actually) to copy filtered resources, i.e. build is platform dependent!
[INFO] skip non existing resourceDirectory /xxxxx/myapp-web/src/test/resources
[INFO] 
[INFO] --- maven-compiler-plugin:2.3.2:testCompile (default-testCompile) @ myapp-web ---
[INFO] No sources to compile
[INFO] 
[INFO] --- maven-surefire-plugin:2.7.2:test (default-test) @ myapp-web ---
[INFO] No tests to run.
[INFO] Surefire report directory: /xxxxx/myapp-web/target/surefire-reports

-------------------------------------------------------
 T E S T S
-------------------------------------------------------
There are no tests to run.

Results :

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

[INFO] 
[INFO] --- maven-war-plugin:2.1.1:war (default-war) @ myapp-web ---
[INFO] Packaging webapp
[INFO] Assembling webapp [myapp-web] in [/xxxxx/myapp-web/target/myapp-web]
[INFO] Processing war project
[INFO] Copying webapp resources [/xxxxx/myapp-web/src/main/webapp]
[INFO] Webapp assembled in [42 msecs]
[INFO] Building war: /xxxxx/myapp-web/target/myapp-web.war
[INFO] WEB-INF/web.xml already added, skipping
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 3.807s
[INFO] Finished at: Fri May 20 21:21:30 JST 2011
[INFO] Final Memory: 9M/170M
[INFO] ------------------------------------------------------------------------

servlet-api.jarのダウンロードは、今回は割愛。

では、動かしてみましょう。どうもこのところ、MavenとかsbtでWebアプリを動かすのはJettyが主流っぽいので、その流れに乗ることにします。pom.xmlを、以下のように修正。

  <build>
    <finalName>myapp-web</finalName>
    <plugins>
      <plugin>
        <groupId>org.mortbay.jetty</groupId>
        <artifactId>jetty-maven-plugin</artifactId>
        <version>8.0.0.M2</version>
        <configuration>
          <webAppConfig>
            <contextPath>/</contextPath>
          </webAppConfig>
          <scanIntervalSeconds>10</scanIntervalSeconds>
        </configuration>
      </plugin>
    </plugins>
  </build>

そして、「mvn jetty:run」でJettyに起動してもらいます。

$ mvn jetty:run
[INFO] Scanning for projects...
[INFO]                                                                         
[INFO] ------------------------------------------------------------------------
[INFO] Building myapp-web Maven Webapp 1.0-SNAPSHOT
[INFO] ------------------------------------------------------------------------
[INFO] 
[INFO] >>> jetty-maven-plugin:8.0.0.M2:run (default-cli) @ myapp-web >>>
[INFO] 
[INFO] --- maven-resources-plugin:2.4.3:resources (default-resources) @ myapp-web ---
[WARNING] Using platform encoding (UTF-8 actually) to copy filtered resources, i.e. build is platform dependent!
[INFO] Copying 0 resource
[INFO] 
[INFO] --- maven-compiler-plugin:2.3.2:compile (default-compile) @ myapp-web ---
[INFO] Nothing to compile - all classes are up to date
[INFO] 
[INFO] --- maven-resources-plugin:2.4.3:testResources (default-testResources) @ myapp-web ---
[WARNING] Using platform encoding (UTF-8 actually) to copy filtered resources, i.e. build is platform dependent!
[INFO] skip non existing resourceDirectory /xxxxx/myapp-web/src/test/resources
[INFO] 
[INFO] --- maven-compiler-plugin:2.3.2:testCompile (default-testCompile) @ myapp-web ---
[INFO] No sources to compile
[INFO] 
[INFO] <<< jetty-maven-plugin:8.0.0.M2:run (default-cli) @ myapp-web <<<
[INFO] 
[INFO] --- jetty-maven-plugin:8.0.0.M2:run (default-cli) @ myapp-web ---
[INFO] Configuring Jetty for project: myapp-web Maven Webapp
[INFO] webAppSourceDirectory /xxxxx/myapp-web/src/main/webapp does not exist. Defaulting to /home/ippei/study/java/maven/myapp-web/src/main/webapp
[INFO] Reload Mechanic: automatic
[INFO] Classes = /xxxxx/myapp-web/target/classes
[INFO] Context path = /
[INFO] Tmp directory = /xxxxx/myapp-web/target/tmp
[INFO] Web defaults = org/eclipse/jetty/webapp/webdefault.xml
[INFO] Web overrides =  none
[INFO] web.xml file = file:/xxxxx/myapp-web/src/main/webapp/WEB-INF/web.xml
[INFO] Webapp directory = /xxxxx/myapp-web/src/main/webapp
[INFO] Starting jetty 8.0.0.M2 ...
2011-05-20 21:35:31.369:INFO::jetty-8.0.0.M2
2011-05-20 21:35:31.568:INFO::No Transaction manager found - if your webapp requires one, please configure one.
2011-05-20 21:35:31.768:INFO::Started SelectChannelConnector@0.0.0.0:8080
[INFO] Started Jetty Server

ダウンロードはやっぱり割愛。先ほど作成したディレクトリを読み取り、起動しているようです。つか、この表示を見るとパッケージングまでの必要はなさそうですね…。
※WARファイルから起動する場合は、「mvn jetty:run-war」を実行します

最後に稼働確認。

$ telnet localhost 8080
Trying 127.0.0.1...
Connected to localhost.localdomain (127.0.0.1).
Escape character is '^]'.
GET /hello
Hello Web App!Connection closed by foreign host.

動いたー。止める時は、Ctrl-Cで。設定すれば、stopゴールで止められるっぽい。

jetty-maven-pluginのその他の設定内容は、こちらを参照。
http://wiki.eclipse.org/Jetty/Feature/Jetty_Maven_Plugin