Java MavenでWeb Applicationを作成する

code html digital coding web 1076536

MavenでHello Worldを出力するWeb Applicationを作成するチュートリアルです.数年前に書かれた本を参考にしたため素直に動かずトライアンドエラーで修正を繰り返してようやく動くようになりました.

目次

Mavenプロジェクトを作成する

mkdir mvn-web-app
cd mvn-web-app
% mvn archetype:generate -DarchetypeGroupId=org.apache.maven.archetypes -DarchetypeArtifactId=maven-archetype-webapp

Interactiveセッションで色々聞かれるので,以下のように回答します.

Define value for property 'groupId': org.example
Define value for property 'artifactId': mvn-web-app
Define value for property 'version' 1.0-SNAPSHOT: :
Define value for property 'package' org.example: : org.example.web
Confirm properties configuration:
groupId: org.example
artifactId: mvn-web-app
version: 1.0-SNAPSHOT
package: org.example.web

パラメータを確認します.

[INFO] ----------------------------------------------------------------------------
[INFO] Using following parameters for creating project from Archetype: maven-archetype-webapp:1.4
[INFO] ----------------------------------------------------------------------------
[INFO] Parameter: groupId, Value: org.example
[INFO] Parameter: artifactId, Value: mvn-web-app
[INFO] Parameter: version, Value: 1.0-SNAPSHOT
[INFO] Parameter: package, Value: org.example.web
[INFO] Parameter: packageInPathFormat, Value: org/example/web
[INFO] Parameter: package, Value: org.example.web
[INFO] Parameter: groupId, Value: org.example
[INFO] Parameter: artifactId, Value: mvn-web-app
[INFO] Parameter: version, Value: 1.0-SNAPSHOT
[INFO] Project created from Archetype in dir: /Users/[username]/Development/maven-practice/mvn-web-app
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------

フォルダ構造を確認する

% tree
.
├── pom.xml
└── src
    └── main
        └── webapp
            ├── WEB-INF
            │   └── web.xml
            └── index.jsp

index.jspを修正する

<html>
<body>
<h2>Hello World!</h2>
</body>
</html>

web.xmlを修正する

<!DOCTYPE web-app PUBLIC
 "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
 "http://java.sun.com/dtd/web-app_2_3.dtd" >

<web-app>
  <display-name>Archetype Created Web Application</display-name>
</web-app>

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>mvn-web-app</artifactId>
  <version>1.0-SNAPSHOT</version>
  <packaging>war</packaging>

  <name>mvn-web-app Maven Webapp</name>
  <!-- FIXME change it to the project's website -->
  <url>http://www.example.com</url>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.source>1.7</maven.compiler.source>
    <maven.compiler.target>1.7</maven.compiler.target>
  </properties>

  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.11</version>
      <scope>test</scope>
    </dependency>
  </dependencies>

  <build>
    <finalName>mvn-web-app</finalName>
    <pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) -->
      <plugins>
        <plugin>
          <artifactId>maven-clean-plugin</artifactId>
          <version>3.1.0</version>
        </plugin>
        <!-- see http://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_war_packaging -->
        <plugin>
          <artifactId>maven-resources-plugin</artifactId>
          <version>3.0.2</version>
        </plugin>
        <plugin>
          <artifactId>maven-compiler-plugin</artifactId>
          <version>3.8.0</version>
        </plugin>
        <plugin>
          <artifactId>maven-surefire-plugin</artifactId>
          <version>2.22.1</version>
        </plugin>
        <plugin>
          <artifactId>maven-war-plugin</artifactId>
          <version>3.2.2</version>
        </plugin>
        <plugin>
          <artifactId>maven-install-plugin</artifactId>
          <version>2.5.2</version>
        </plugin>
        <plugin>
          <artifactId>maven-deploy-plugin</artifactId>
          <version>2.8.2</version>
        </plugin>
      </plugins>
    </pluginManagement>
  </build>
</project>

mvn:packageでパッケージを作成します.

mvn package

生成されたファイルを確認します.

% tree
.
├── pom.xml
├── src
│   └── main
│       └── webapp
│           ├── WEB-INF
│           │   └── web.xml
│           └── index.jsp
└── target
    ├── maven-archiver
    │   └── pom.properties
    ├── mvn-web-app
    │   ├── META-INF
    │   ├── WEB-INF
    │   │   ├── classes
    │   │   └── web.xml
    │   └── index.jsp
    └── mvn-web-app.war

mvn-web-app.warが生成されています.mvn-web-app.warの中身を確認してみましょう.ただのzipなのでファイル名を変更してコピーし,展開してみます.

% cp ./target/mvn-web-app.war ./mvn-web-app.zip

% unzip mvn-web-app.zip -d ./mvn-web-app-extract
Archive:  mvn-web-app.zip
  inflating: ./mvn-web-app-extract/META-INF/MANIFEST.MF
   creating: ./mvn-web-app-extract/WEB-INF/
   creating: ./mvn-web-app-extract/WEB-INF/classes/
  inflating: ./mvn-web-app-extract/index.jsp
  inflating: ./mvn-web-app-extract/WEB-INF/web.xml
  inflating: ./mvn-web-app-extract/META-INF/maven/org.example/mvn-web-app/pom.xml
  inflating: ./mvn-web-app-extract/META-INF/maven/org.example/mvn-web-app/pom.properties

maven jetty pluginを追加する(試行錯誤)

pom.xmlにmaven-jetty-pluginを追加します.

          <plugin>
            <groupId>org.mortbay.jetty</groupId>
            <artifactId>maven-jetty-plugin<artifactId>
            <version>6.1.0</version>
            <configuration>
              <scanIntervalSeconds>10</ScanIntervalSeconds>
              <connectors>
                <connector implementation="org.mortbay.jetty.nio.SelectChannelConnector">
                  <port>8080</port>
                  <maxIdleTime>60000</maxIdleTime>
                </connector>
              </connectors>
            </configuration>
          </plugin>

mvn jetty:runで実行します.以下のエラーが出ました.

% mvn jetty:run
[WARNING] failed SelectChannelConnector @ 0.0.0.0:8080
java.net.BindException: Address already in use
    at sun.nio.ch.Net.bind0 (Native Method)
    at sun.nio.ch.Net.bind (Net.java:555)
    at sun.nio.ch.ServerSocketChannelImpl.netBind (ServerSocketChannelImpl.java:337)
    at sun.nio.ch.ServerSocketChannelImpl.bind (ServerSocketChannelImpl.java:294)
    at sun.nio.ch.ServerSocketAdaptor.bind (ServerSocketAdaptor.java:89)
    at org.mortbay.jetty.nio.SelectChannelConnector.open (SelectChannelConnector.java:198)
    at org.mortbay.jetty.AbstractConnector.doStart (AbstractConnector.java:251)

原因はJettyプラグインで指定したPort 8080が他のアプリケーションで既に使われているからでした.lsofコマンドで8080番を使っているアプリケーションを調べてみます.

% lsof -P -i:8080
COMMAND     PID   USER   FD   TYPE             DEVICE SIZE/OFF NODE NAME
XXXXXXXX  84962 xxxxxx    9u  IPv6 0x29cd8d412bd18e51      0t0  TCP *:8080 (LISTEN)

対象のアプリケーションを終了して,改めてlsofコマンドを実行すると,今度は8080番を使用しているアプリケーションは何も表示されません.

% lsof -P -i:8080

もう一度実行してみます.

mvn jetty:run

[INFO] Configuring Jetty for project: mvn-web-app Maven Webapp
[INFO] Webapp source directory = /Users/[username]/Development/maven-practice/mvn-web-app/src/main/webapp
[INFO] web.xml file = /Users/[username]/Development/maven-practice/mvn-web-app/src/main/webapp/WEB-INF/web.xml
[INFO] Classes directory /Users/[username]/Development/maven-practice/mvn-web-app/target/classes does not exist
[INFO] Logging to org.slf4j.impl.MavenSimpleLogger(org.mortbay.log) via org.mortbay.log.Slf4jLog
[INFO] Context path = /mvn-web-app
[INFO] Tmp directory = /Users/[username]/Development/maven-practice/mvn-web-app/target/work
[INFO] Web defaults =  jetty default
[INFO] Web overrides =  none
[INFO] Webapp directory = /Users/[username]/Development/maven-practice/mvn-web-app/src/main/webapp
[INFO] Starting jetty 6.1.0 ...
[INFO] jetty-6.1.0
[INFO] Classpath = [file:/Users/[username]/Development/maven-practice/mvn-web-app/target/classes]
[INFO] Started SelectChannelConnector @ 0.0.0.0:8080
[INFO] Started Jetty Server
[INFO] Starting scanner at interval of 10 seconds.

エラーは出ませんでした.ブラウザからアクセスしてみます.

http://localhost:8080/mvn-web-app/

エラーメッセージが表示されました.

HTTP ERROR: 500
class [Ljava.lang.Object; cannot be cast to class [Lorg.apache.jasper.compiler.JavacErrorDetail; ([Ljava.lang.Object; is in module java.base of loader 'bootstrap'; [Lorg.apache.jasper.compiler.JavacErrorDetail; is in unnamed module of loader org.codehaus.plexus.classworlds.realm.ClassRealm @58496dc)
RequestURI=/mvn-web-app/

Caused by:
java.lang.ClassCastException: class [Ljava.lang.Object; cannot be cast to class [Lorg.apache.jasper.compiler.JavacErrorDetail; ([Ljava.lang.Object; is in module java.base of loader 'bootstrap'; [Lorg.apache.jasper.compiler.JavacErrorDetail; is in unnamed module of loader org.codehaus.plexus.classworlds.realm.ClassRealm @58496dc)
	at org.apache.jasper.compiler.JDTJavaCompiler.compile(JDTJavaCompiler.java:466)
	at org.apache.jasper.compiler.Compiler.generateClass(Compiler.java:317)
	at org.apache.jasper.compiler.Compiler.compile(Compiler.java:364)
	at org.apache.jasper.JspCompilationContext.compile(JspCompilationContext.java:581)
	at org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:344)
	at org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:464)
	at org.apache.jasper.servlet.JspServlet.service(JspServlet.java:358)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:820)
	at org.mortbay.jetty.servlet.ServletHolder.handle(ServletHolder.java:491)
	at org.mortbay.jetty.servlet.ServletHandler.handle(ServletHandler.java:367)
	at org.mortbay.jetty.security.SecurityHandler.handle(SecurityHandler.java:185)
	at org.mortbay.jetty.servlet.SessionHandler.handle(SessionHandler.java:181)
	at org.mortbay.jetty.handler.ContextHandler.handle(ContextHandler.java:689)
	at org.mortbay.jetty.webapp.WebAppContext.handle(WebAppContext.java:391)
	at org.mortbay.jetty.servlet.Dispatcher.forward(Dispatcher.java:268)
	at org.mortbay.jetty.servlet.Dispatcher.forward(Dispatcher.java:126)
	at org.mortbay.jetty.servlet.DefaultServlet.doGet(DefaultServlet.java:414)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:707)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:820)
	at org.mortbay.jetty.servlet.ServletHolder.handle(ServletHolder.java:491)
	at org.mortbay.jetty.servlet.ServletHandler.handle(ServletHandler.java:367)
	at org.mortbay.jetty.security.SecurityHandler.handle(SecurityHandler.java:185)
	at org.mortbay.jetty.servlet.SessionHandler.handle(SessionHandler.java:181)
	at org.mortbay.jetty.handler.ContextHandler.handle(ContextHandler.java:689)
	at org.mortbay.jetty.webapp.WebAppContext.handle(WebAppContext.java:391)
	at org.mortbay.jetty.handler.ContextHandlerCollection.handle(ContextHandlerCollection.java:146)
	at org.mortbay.jetty.handler.HandlerCollection.handle(HandlerCollection.java:114)
	at org.mortbay.jetty.handler.HandlerWrapper.handle(HandlerWrapper.java:139)
	at org.mortbay.jetty.Server.handle(Server.java:285)
	at org.mortbay.jetty.HttpConnection.handleRequest(HttpConnection.java:457)
	at org.mortbay.jetty.HttpConnection$RequestHandler.headerComplete(HttpConnection.java:751)
	at org.mortbay.jetty.HttpParser.parseNext(HttpParser.java:500)
	at org.mortbay.jetty.HttpParser.parseAvailable(HttpParser.java:209)
	at org.mortbay.jetty.HttpConnection.handle(HttpConnection.java:357)
	at org.mortbay.io.nio.SelectChannelEndPoint.run(SelectChannelEndPoint.java:329)
	at org.mortbay.thread.BoundedThreadPool$PoolThread.run(BoundedThreadPool.java:475)

指定したバージョン番号にミスがあったので修正します.

           <groupId>org.mortbay.jetty</groupId>
            <artifactId>maven-jetty-plugin<artifactId>
            <version>6.1.0</version>
  
 -> 
            <groupId>org.mortbay.jetty</groupId>
            <artifactId>maven-jetty-plugin<artifactId>
            <version>6.1.10</version>

もう一度実行してブラウザからアクセスしてみます.

mvn jetty:run

別なエラーが発生しました.

HTTP ERROR: 500
PWC6033: Unable to compile class for JSP

PWC6199: Generated servlet error:
The type java.lang.String cannot be resolved. It is indirectly referenced from required .class files

PWC6199: Generated servlet error:
java.util.Vector cannot be resolved to a type

PWC6199: Generated servlet error:
_jspx_dependants cannot be resolved

RequestURI=/mvn-web-app/

Caused by:
org.apache.jasper.JasperException: PWC6033: Unable to compile class for JSP

PWC6199: Generated servlet error:
The type java.lang.String cannot be resolved. It is indirectly referenced from required .class files

PWC6199: Generated servlet error:
java.util.Vector cannot be resolved to a type

PWC6199: Generated servlet error:
_jspx_dependants cannot be resolved


	at org.apache.jasper.compiler.DefaultErrorHandler.javacError(DefaultErrorHandler.java:107)
	at org.apache.jasper.compiler.ErrorDispatcher.javacError(ErrorDispatcher.java:280)
	at org.apache.jasper.compiler.Compiler.generateClass(Compiler.java:350)
	at org.apache.jasper.compiler.Compiler.compile(Compiler.java:411)
	at org.apache.jasper.JspCompilationContext.compile(JspCompilationContext.java:592)
	at org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:344)
	at org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:470)
	at org.apache.jasper.servlet.JspServlet.service(JspServlet.java:364)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:820)
	at org.mortbay.jetty.servlet.ServletHolder.handle(ServletHolder.java:487)
	at org.mortbay.jetty.servlet.ServletHandler.handle(ServletHandler.java:362)
	at org.mortbay.jetty.security.SecurityHandler.handle(SecurityHandler.java:216)

pom.xmlのjetty-pluginのバージョンを修正してみます.

           <groupId>org.mortbay.jetty</groupId>
           <artifactId>maven-jetty-plugin<artifactId>
           <version>7.0.0.pre5</version>

エラーは変わりません.

HTTP ERROR: 500
PWC6033: Unable to compile class for JSP

PWC6199: Generated servlet error:
The type java.lang.String cannot be resolved. It is indirectly referenced from required .class files

PWC6199: Generated servlet error:
java.util.Vector cannot be resolved to a type

PWC6199: Generated servlet error:
_jspx_dependants cannot be resolved

RequestURI=/mvn-web-app/

Caused by:
org.apache.jasper.JasperException: PWC6033: Unable to compile class for JSP

PWC6199: Generated servlet error:
The type java.lang.String cannot be resolved. It is indirectly referenced from required .class files

色々調べてみるとjettyの開発元がorg.mortbay.jettyからorg.eclipse.jettyに移ったようです.それに合わせて正しいgroupIdを指定する必要があります.

pom.xmlを修正します.

<plugin>
  <groupId>org.mortbay.jetty</groupId>
  <artifactId>maven-jetty-plugin</artifactId>
  <version>7.0.0.pre5</version>
  <configuration>
    <scanIntervalSeconds>10</scanIntervalSeconds>
    <connectors>
      <connector implementation="org.mortbay.jetty.nio.SelectChannelConnector">
        <port>8080</port>
        <maxIdleTime>60000</maxIdleTime>
      </connector>
    </connectors>
  </configuration>
</plugin>

↓

<plugin>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-maven-plugin</artifactId>
<version>11.0.13</version>
  <configuration>
  <scanIntervalSeconds>10</scanIntervalSeconds>
  <connectors>
    <connector implementation="org.mortbay.jetty.nio.SelectChannelConnector">
      <port>8080</port>
      <maxIdleTime>60000</maxIdleTime>
    </connector>
  </connectors>
</configuration>
</plugin>

今度は以下にアクセスしてみます.

http://localhost:8080/mvn-web-app/

またエラーが出ました.

HTTP ERROR 404 Not Found
URI:	/mvn-web-app/
STATUS:	404
MESSAGE:	Not Found
SERVLET:	default

以下にアクセスしてみます.

http://localhost:8080/

表示されました.

なお,以下のパートは削除しても動きます.デフォルト値を上書きする場合のみ必要なようです.

  <!--
    <configuration>
    <scanIntervalSeconds>10</scanIntervalSeconds>
    <connectors>
      <connector implementation="org.mortbay.jetty.nio.SelectChannelConnector">
        <port>8080</port>
        <maxIdleTime>60000</maxIdleTime>
      </connector>
    </connectors>
  </configuration>
  -->

プラグインの記述をpluginからdependencyに動かすと動かない

当たり前ですが,以下のようにpluginに書くべきものをdependencyに記述しても動きません.

<plugins>
  <plugin>
  <groupId>org.eclipse.jetty</groupId>
  <artifactId>jetty-maven-plugin</artifactId>
  <version>11.0.13</version>
  <!--
    <configuration>
    <scanIntervalSeconds>10</scanIntervalSeconds>
    <connectors>
      <connector implementation="org.mortbay.jetty.nio.SelectChannelConnector">
        <port>8080</port>
        <maxIdleTime>60000</maxIdleTime>
      </connector>
    </connectors>
  </configuration>
  -->
  </plugin>
</plugins>
  ↓
<dependencies>
  <dependency>
  <groupId>org.eclipse.jetty</groupId>
  <artifactId>jetty-maven-plugin</artifactId>
  <version>11.0.13</version>
  <type>maven-plugin</type>
  </dependency>
</dependencies>

以下のエラーが出ます.

[ERROR] No plugin found for prefix 'jetty' in the current project and in the plugin groups [org.apache.maven.plugins, org.codehaus.mojo] available from the repositories [local (/Users/[username]/.m2/repository), central (https://repo.maven.apache.org/maven2)] -> [Help 1]

参考

よかったらシェアしてね!
目次