Java + Apache Tomcat 10 + Jakarta Servlet 5.0 + JSP で Hello World

## 概要

- Jakarta Servlet (Java Servlet) と JSP を含む WAR ファイルを Gradle で作成する
- Apache Tomcat 10 をインストールする
- WAR ファイルを Apache Tomcat 10 にデプロイする

## 今回の環境

- Apache Tomcat 10.0.2 (Jakarta Servlet 5.0, JSP 3.0)
- Java 15 (AdoptOpenJDK 15.0.2+7)
- Gradle 6.8.1
- macOS 10.15.7 Catalina

## Apache Tomcat 10 について

- Apache Tomcat 10.0.2 は Apache Tomcat 10 系列の最初の安定版バージョン
- Apache Tomcat 10 にて Java EE から Jakarta EE へ移行した
- API のパッケージ名が javax.* から jakarta.* へ変更になった

[Apache Tomcat® \- Welcome\!](http://tomcat.apache.org/)

> Tomcat 10.0.2 Released
> 2021-02-02
> 
> The Apache Tomcat Project is proud to announce the release of version 10.0.2 of Apache Tomcat. This release is the first stable release in the 10.0.x series and is targeted at Jakarta EE 9.
> 
> Users of Tomcat 10 onwards should be aware that, as a result of the move from Java EE to Jakarta EE as part of the transfer of Java EE to the Eclipse Foundation, the primary package for all implemented APIs has changed from javax.* to jakarta.*. This will almost certainly require code changes to enable applications to migrate from Tomcat 9 and earlier to Tomcat 10 and later. A migration tool is under development to aid this process.

## ビルド用・起動用の Java VM を用意する

環境変数 JAVA_HOME と PATH を設定する。

```
$ export JAVA_HOME=/Library/Java/JavaVirtualMachines/adoptopenjdk-15.jdk/Contents/Home

$ PATH=${JAVA_HOME}/bin:${PATH}

$ java -version
openjdk version "15.0.2" 2021-01-19
OpenJDK Runtime Environment AdoptOpenJDK (build 15.0.2+7)
OpenJDK 64-Bit Server VM AdoptOpenJDK (build 15.0.2+7, mixed mode, sharing)
```


## Servlet と JSP を含む WAR ファイルを Gradle で作成する

### ソースコードを置くディレクトリを用意する

今回は任意のディレクトリに mywebapp というディレクトリを作成してその中にシンプルなサンプルコードを用意する。

```
$ mkdir mywebapp

$ cd mywebapp
```

### ファイル一覧

```
mywebapp
├── build.gradle
└── src
    └── main
        ├── java
        │   └── com
        │       └── example
        │           └── MyServlet.java
        └── webapp
            ├── WEB-INF
            │   └── web.xml
            └── myjsp.jsp
```

### build.gradle

```groovy
plugins {
  id 'war'
}

repositories {
  mavenCentral()
}

dependencies {
  // Jakarta Servlet 5.0 API
  // https://mvnrepository.com/artifact/jakarta.servlet/jakarta.servlet-api
  providedCompile 'jakarta.servlet:jakarta.servlet-api:5.0.0'
}

// Java 15
sourceCompatibility = 15
targetCompatibility = 15

// Application
version = '1.0'
```

### src/main/java/com/example/MyServlet.java

```java
package com.example;

// Jakarta Servlet 5.0 API では
// パッケージ名が javax.servlet から jakarta.servlet へ変更された
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;

import java.io.IOException;
import java.io.PrintWriter;

@WebServlet("/myservlet")
public class MyServlet extends HttpServlet {

  @Override
  protected void doGet(HttpServletRequest req, HttpServletResponse res) throws IOException {
    res.setContentType("text/html; charset=utf-8");
    try (PrintWriter out = res.getWriter()) {
      out.println("<html><body>");
      out.println("サーブレット: Hello Servlet World!<br>");
      out.println(getServletContext().getServerInfo());
      out.println("</body></html>");
    }
  }
}
```

### src/main/webapp/myjsp.jsp

```jsp
<%@ page contentType="text/html; charset=utf-8" %><html><body>
ジェイエスピー: Hello JSP World!<br>
<%= pageContext.getServletContext().getServerInfo() %><br>
java.vm.name: <%= System.getProperty("java.vm.name") %><br>
java.vm.vendor: <%= System.getProperty("java.vm.vendor") %><br>
java.vm.version: <%= System.getProperty("java.vm.version") %><br>
</body></html>
```

### src/main/webapp/WEB-INF/web.xml

```xml
<?xml version="1.0" encoding="UTF-8"?>

<!-- Web Application Deployment Descriptor (Jakarta Servlet 5.0) -->
<web-app
  xmlns="https://jakarta.ee/xml/ns/jakartaee"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee
  https://jakarta.ee/xml/ns/jakartaee/web-app_5_0.xsd"
  version="5.0">

  <servlet>
    <servlet-name>myjsp</servlet-name>
    <jsp-file>/myjsp.jsp</jsp-file>
  </servlet>

  <servlet-mapping>
    <servlet-name>myjsp</servlet-name>
    <url-pattern>/myjsp</url-pattern>
  </servlet-mapping>

</web-app>
```

### WAR ファイルを作成する

Gradle の build タスクで WAR ファイルを作成する。

```
$ gradle build
```

WAR ファイルが生成されていることを確認する。

```
$ file build/libs/mywebapp-1.0.war
build/libs/mywebapp-1.0.war: Zip archive data, at least v1.0 to extract
```

## Apache Tomcat 10 をインストールする

### インストールするディレクトリを用意する

今回は任意のディレクトリに tomcat10 というディレクトリを作成してその中にインストールする。

```
$ mkdir tomcat10

$ cd tomcat10
```

### Apache Tomcat 10 をダウンロードして展開する

[Apache Tomcat® \- Apache Tomcat 10 Software Downloads](https://tomcat.apache.org/download-10.cgi)

```
$ wget https://downloads.apache.org/tomcat/tomcat-10/v10.0.2/bin/apache-tomcat-10.0.2.tar.gz

$ tar xf apache-tomcat-10.0.2.tar.gz
```

### Apache Tomcat 10 が起動することを確認する

startup.sh で Apache Tomcat 10 を起動する。

```
$ ./apache-tomcat-10.0.2/bin/startup.sh 
Using CATALINA_BASE:   /Users/foo/tomcat10/apache-tomcat-10.0.2
Using CATALINA_HOME:   /Users/foo/tomcat10/apache-tomcat-10.0.2
Using CATALINA_TMPDIR: /Users/foo/tomcat10/apache-tomcat-10.0.2/temp
Using JRE_HOME:        /Library/Java/JavaVirtualMachines/adoptopenjdk-15.jdk/Contents/Home
Using CLASSPATH:       /Users/foo/tomcat10/apache-tomcat-10.0.2/bin/bootstrap.jar:/Users/foo/tomcat10/apache-tomcat-10.0.2/bin/tomcat-juli.jar
Using CATALINA_OPTS:   
Tomcat started.
```

curl でアクセスして起動していることを確認する。

```
$ curl --include -s http://localhost:8080/ | head -15
HTTP/1.1 200 
Content-Type: text/html;charset=UTF-8
Transfer-Encoding: chunked
Date: Wed, 03 Feb 2021 23:34:17 GMT




<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8" />
        <title>Apache Tomcat/10.0.2</title>
        <link href="favicon.ico" rel="icon" type="image/x-icon" />
        <link href="tomcat.css" rel="stylesheet" type="text/css" />
```

shutdown.sh で Apache Tomcat 10 を停止する。

```
$ ./apache-tomcat-10.0.2/bin/shutdown.sh
```

## WAR ファイルを Apache Tomcat 10 にデプロイする

### WAR ファイルを Apache Tomcat 10 の webapps ディレクトリに設置する

```
$ cp mywebapp/build/libs/mywebapp-1.0.war tomcat10/apache-tomcat-10.0.2/webapps/mywebapp.war
```

### Apache Tomcat 10 を起動する

```
$ ./tomcat10/apache-tomcat-10.0.2/bin/startup.sh
```

### Servlet と JSP にアクセスする

curl で Servlet にアクセスして動作を確認する。

```
$ curl --include http://localhost:8080/mywebapp/myservlet
HTTP/1.1 200 
Content-Type: text/html;charset=utf-8
Content-Length: 94
Date: Wed, 03 Feb 2021 23:40:23 GMT

<html><body>
サーブレット: Hello Servlet World!<br>
Apache Tomcat/10.0.2
</body></html>
```

curl で JSP にアクセスして動作を確認する。

```
$ curl --include http://localhost:8080/mywebapp/myjsp
HTTP/1.1 200 
Set-Cookie: JSESSIONID=A2983AEBEC5A144E1D24059263B734A9; Path=/mywebapp; HttpOnly
Content-Type: text/html;charset=utf-8
Content-Length: 203
Date: Wed, 03 Feb 2021 23:40:45 GMT

<html><body>
ジェイエスピー: Hello JSP World!<br>
Apache Tomcat/10.0.2<br>
java.vm.name: OpenJDK 64-Bit Server VM<br>
java.vm.vendor: AdoptOpenJDK<br>
java.vm.version: 15.0.2+7<br>
</body></html>
```

## 参考資料

- [Jakarta EE Platform 9 \| The Eclipse Foundation](https://jakarta.ee/specifications/platform/9/)
- [Jakarta Servlet 5\.0 \| The Eclipse Foundation](https://jakarta.ee/specifications/servlet/5.0/)
- [Jakarta Server Pages 3\.0 \| The Eclipse Foundation](https://jakarta.ee/specifications/pages/3.0/)
- [Jakarta Servlet Specification - 14. Deployment Descriptor](https://jakarta.ee/specifications/servlet/5.0/jakarta-servlet-spec-5.0.html#deployment-descriptor)
- [Jakarta EE XML Schemas \| The Eclipse Foundation](https://jakarta.ee/xml/ns/jakartaee/)
- [Apache Tomcat 10 \(10\.0\.2\) \- Documentation Index](https://tomcat.apache.org/tomcat-10.0-doc/)
- [Apache Tomcat® \- Which Version Do I Want?](https://tomcat.apache.org/whichversion.html)