[Eclipse/Tomcat] MavenのwebappプロジェクトでServlet+JSP

以前、 [Eclipseを使ってTomcat+JSP+Servlet+MySQLでメモアプリ作成](https://qiita.com/zaki-lknr/items/32690b071abf202281d6)で「Tomcatプロジェクト」でwebアプリのプロジェクトを作成したが、Mavenプロジェクトでアーキタイプに`maven-archetype-webapp`を選択してプロジェクトを作ったほうが良い、ということで作ってみた。

参考: [EclipseでサーバサイドJavaを作るときのプロジェクトとwarファイルのエクスポート](https://qiita.com/zaki-lknr/items/a2e76986b6e473964800)

# プロジェクト設定

## maven-archtype-webappプロジェクト作成

「Mavenプロジェクト」を選択

![image.png](https://qiita-image-store.s3.amazonaws.com/0/256859/221e108b-1bce-2bf6-39c6-9268d9b42ad7.png)

「シンプルなプロジェクトの作成(S)」のチェックを__外して__「次へ」

![image.png](https://qiita-image-store.s3.amazonaws.com/0/256859/c4febdff-568f-146d-73fa-66017a073b0c.png)

アーキタイプは「maven-archtype-webapp」を選択

![image.png](https://qiita-image-store.s3.amazonaws.com/0/256859/4f5aa361-afa5-b033-5b8b-aa8658df9fe6.png)


![image.png](https://qiita-image-store.s3.amazonaws.com/0/256859/ca0bb8cd-1ab6-5613-2e28-9b79d55cc3fc.png)

## ディレクトリ構成

初期状態

![image.png](https://qiita-image-store.s3.amazonaws.com/0/256859/7a57c644-9b76-fde2-67ee-7601a3c79228.png)

作成直後のプロジェクト構成は、ソースファイル用のディレクトリの`src/main/java`と`src/test/java`が欠落しているため、これは新規作成メニューのフォルダや、エクスプローラなどから手動で作成する。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/256859/78e2ab13-355f-668f-4b15-85a44159d6ec.png)

(これはなぜかエラーとして出力されない)

## Javaバージョン設定

EclipseでMavenプロジェクトを作るとJava1.5設定になるのは仕様なんかな。。

### システムライブラリ

「JREシステムライブラリー」のところが「J2SE-1.5」になっているので、右クリックのプロパティーから、「JavaSE-1.8 (java8)」を選択

![image.png](https://qiita-image-store.s3.amazonaws.com/0/256859/b46f04a7-c793-cef0-fce0-e824c7037744.png)

### プロジェクト・ファセット

すると今度は「Javaプロジェクト・ファセットのバージョンと一致しません」というエラーが出るので

![image.png](https://qiita-image-store.s3.amazonaws.com/0/256859/8f4c1bf1-da09-7e39-e26c-47b3b1a903c4.png)

プロジェクトのプロパティを開き「プロジェクト・ファセット」からバージョンを1.8に設定する

![image.png](https://qiita-image-store.s3.amazonaws.com/0/256859/90331af2-17d8-2a51-0424-f6037b602941.png)

### Mavenのコンパイラバージョン

EclipseでのJDKバージョンと別に、mavenビルドを行う際のコンパイラバージョンを指定する。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/256859/edcc246e-3d9c-a379-8762-8e70307fbbd6.png)

ルート要素の`<project>`直下に以下が記述される。(手書きで入れてもよい)

```xml:pom.xml
 <properties>
  <java.version>1.8</java.version>
  <maven.compiler.source>1.8</maven.compiler.source>
  <maven.compiler.target>1.8</maven.compiler.target>
 </properties>
```

これがないと例えばコレクションを使用したソースコードは1.5バージョンのコンパイラが対応していないためエラーとなる。

```
[INFO] ------------------------------------------------------------------------
[INFO] BUILD FAILURE
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 1.395 s
[INFO] Finished at: 2018-12-23T16:03:11+09:00
[INFO] Final Memory: 9M/245M
[INFO] ------------------------------------------------------------------------
[ERROR] Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.1:compile (default-compile) on project memoapp2: Compilation failure
[ERROR] /C:/Users/zaki/src/java-study/memoapp2/src/main/java/jp/example/www/MainServlet.java:[30,51] ダイヤモンド演算子は-source 1.5でサポートされていません
[ERROR] (ダイヤモンド演算子を使用可能にするには、-source 7以降を使用してください)
[ERROR] -> [Help 1]
[ERROR] 
[ERROR] To see the full stack trace of the errors, re-run Maven with the -e switch.
[ERROR] Re-run Maven using the -X switch to enable full debug logging.
[ERROR] 
[ERROR] For more information about the errors and possible solutions, please read the following articles:
[ERROR] [Help 1] http://cwiki.apache.org/confluence/display/MAVEN/MojoFailureException
```

## MavenでServletのjarを組み込む

「スーパークラス "javax.servlet.http.HttpServlet" が Java ビルド・パスで見つかりませんでした」というエラーが(最初から)出ているが、これはServlet関連のライブラリがプロジェクトで参照できていないため。

Mavenを使って設定する。

設定するのは [Java Servlet API](https://mvnrepository.com/artifact/javax.servlet/javax.servlet-api) のjarファイル。
リンク先から2018.12時点で最新の[Java Servlet API 4.0.1](https://mvnrepository.com/artifact/javax.servlet/javax.servlet-api/4.0.1)をプロジェクトに取り込むには、Mavenタブに表示されているXMLの内容を`pom.xml`の`<dependencies> ～ </dependencies>`の部分へコピーする

![image.png](https://qiita-image-store.s3.amazonaws.com/0/256859/0ec321f7-3efd-e777-de5e-2175f1d98d76.png)


```xml
<!-- https://mvnrepository.com/artifact/javax.servlet/javax.servlet-api -->
<dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>javax.servlet-api</artifactId>
    <version>4.0.1</version>
    <scope>provided</scope>
</dependency>
```

この内容を、プロジェクトの`pom.xml`にコピペ

![image.png](https://qiita-image-store.s3.amazonaws.com/0/256859/46e5fca4-c932-87ac-a92a-ed1a600cdca3.png)

これでファイルを保存すると、ファイルの内容に従ってservlet-apiのダウンロードとプロジェクトへの組み込みが自動で行われる。

処理が正常に完了すれば、`HttpServlet`がビルドパスに見つからないエラーが解消される。

# JSPの表示

この時点でプロジェクトの右クリックメニューの「実行(R)」->「サーバーで実行」からTomcatを選択、サーバー上で構成するリソースに対象プロジェクトが含まれていることを確認して実行すれば、プロジェクト作成時に含まれていた`index.jsp`の内容がブラウザで表示できる

![image.png](https://qiita-image-store.s3.amazonaws.com/0/256859/9a3d63f4-ed13-83e7-c68e-14132a7e92bd.png)

![image.png](https://qiita-image-store.s3.amazonaws.com/0/256859/8eb502c7-17f5-1cf2-a2cd-7dc4aa70f1eb.png)

![image.png](https://qiita-image-store.s3.amazonaws.com/0/256859/6dc1d3e0-713e-2c32-93a1-a713d6058290.png)

ただし、jspファイルをブラウザから直接アクセスする場所に構成するのは好ましくないため、`src/main/webapp/WEB-INF`以下の任意のパス(`WEB-INF/jsp`など)へ移動し、直接のアクセスをできなくし、サーブレット経由で表示するようにする。

# Servletの作成と表示

新規作成メニューの「サーブレット」から。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/256859/e67b64b9-210f-297a-ea4c-fbfa9dd13c9a.png)

![image.png](https://qiita-image-store.s3.amazonaws.com/0/256859/9df37ab8-5428-fd70-dc21-a58751942ef2.png)

パッケージ名とクラス名を入力したあと、メタ情報も入力できる。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/256859/c1cc8018-498c-9316-9bc9-e7cbbb6c732e.png)

どのメソッドをオーバーライドするかの選択

![image.png](https://qiita-image-store.s3.amazonaws.com/0/256859/034e764b-b786-2d28-69e0-51d0e47e2280.png)


ここで入力したメタ情報の値は`src/main/webapp/WEB-INF/web.xml`にも反映される

```xml: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>
```

```xml: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>
  <servlet>
  	<servlet-name>MainServlet</servlet-name>
  	<display-name>MainServlet</display-name>
  	<description>メイン画面</description>
  	<servlet-class>jp.example.www.MainServlet</servlet-class>
  </servlet>
  <servlet-mapping>
  	<servlet-name>MainServlet</servlet-name>
  	<url-pattern>/MainServlet</url-pattern>
  </servlet-mapping>
</web-app>
```

Servletのソースは指定したメソッドがオーバーライドされた状態で作成される。

```java
package jp.example.www;

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

/**
 * Servlet implementation class MainServlet
 */
public class MainServlet extends HttpServlet {
    private static final long serialVersionUID = 1L;

    /**
     * @see HttpServlet#HttpServlet()
     */
    public MainServlet() {
        super();
        // TODO Auto-generated constructor stub
    }

    /**
     * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse
     *      response)
     */
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        // TODO Auto-generated method stub
        response.getWriter().append("webapp-maven! Served at: ").append(request.getContextPath());
    }

    /**
     * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse
     *      response)
     */
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        // TODO Auto-generated method stub
        doGet(request, response);
    }

}
```

作成直後の状態でも「実行(R)」->「サーバーで実行」でTomcatを起動(あるいは再起動)すれば、自動生成されたコードの内容で実行される

![image.png](https://qiita-image-store.s3.amazonaws.com/0/256859/dd0de64e-1d6b-aa42-9d86-eb110c177a9f.png)

# ServletからJSPの呼び出し

[Tomcatプロジェクトの場合](https://qiita.com/zaki-lknr/items/32690b071abf202281d6#%E3%83%A1%E3%82%A4%E3%83%B3%E7%94%BB%E9%9D%A2%E3%81%AEui%E3%81%A8%E5%87%A6%E7%90%86%E9%83%A8%E5%88%86%E3%82%92%E4%BD%9C%E6%88%90%E3%81%99%E3%82%8B)と同じ。

`/WEB-INF/jsp/main.jsp`のjspファイルに対し、サーブレットの`doGet()`で以下のように書けば表示される

```java
        String path = "/WEB-INF/jsp/main.jsp";
        RequestDispatcher dispatcher = request.getRequestDispatcher(path);
        dispatcher.forward(request, response);
```

# maven installとwarファイル

「実行(R)」->「Maven install」を実行することで、`target`ディレクトリ直下にwarファイルが生成される

![image.png](https://qiita-image-store.s3.amazonaws.com/0/256859/a426b853-bad1-4379-0328-0689f2a010ea.png)


「Maven clean」を実行すればビルド結果はすべて消去される

# エクスポートによるwarファイル作成

プロジェクトメニューの「エクスポート」でもwarファイル作成ができる

![image.png](https://qiita-image-store.s3.amazonaws.com/0/256859/a47f1ade-da32-4aef-3534-67a9906bd61a.png)

この場合はMavenに関係なく作成でき、任意のパスに出力できる。