Dockerを用いて掲示板を作った1

# これは何

DockerとWebアプリ作成の勉強のため，[この本](https://www.amazon.co.jp/Web%E3%82%B5%E3%83%BC%E3%83%90%E3%82%92%E4%BD%9C%E3%82%8A%E3%81%AA%E3%81%8C%E3%82%89%E5%AD%A6%E3%81%B6-%E5%9F%BA%E7%A4%8E%E3%81%8B%E3%82%89%E3%81%AEWeb%E3%82%A2%E3%83%97%E3%83%AA%E3%82%B1%E3%83%BC%E3%82%B7%E3%83%A7%E3%83%B3%E9%96%8B%E7%99%BA%E5%85%A5%E9%96%80-%E5%89%8D%E6%A9%8B%E5%92%8C%E5%BC%A5-ebook/dp/B01GNXNIWE)の第3章をDockerコンテナの上で実装してみた際のメモ．


## ファイル構成

```sh
$ tree .
.
├── Dockerfile
└── testbbs
    └── WEB-INF
        ├── classes
        ├── src
        │   ├── Message.java
        │   ├── PostBBS.java
        │   └── ShowBBS.java
        └── web.xml

4 directories, 5 files
```

## Dockerfile

```docker:Dockerfile
FROM tomcat:8.5.54-jdk11-adoptopenjdk-hotspot
WORKDIR /usr/local/tomcat/webapps/
RUN mkdir -p ./testbbs
COPY ./testbbs ./testbbs/
RUN javac -classpath $CATALINA_HOME/lib/servlet-api.jar -d ./testbbs/WEB-INF/classes ./testbbs/WEB-INF/src/*.java
```

## Javaファイル
参考にしてる本と同じ．

```java:Message.java
import java.util.*;

public class Message {
	public static ArrayList<Message> messageList = new ArrayList<Message>();
	String title;
	String handle;
	String message;
	Date date;

	Message (String title, String handle, String message) {
		this.title = title;
		this.handle = handle;
		this.message = message;
		this.date = new Date();
	}
}
```

```java:PostBBS.java
import java.io.*;
import javax.servlet.http.*;

public class PostBBS extends HttpServlet {
	@Override
	public void doPost(HttpServletRequest request, HttpServletResponse response)
			throws UnsupportedEncodingException, IOException {
		request.setCharacterEncoding("UTF-8");
		Message newMessage = new Message(request.getParameter("title"),
				request.getParameter("handle"),
				request.getParameter("message"));

		Message.messageList.add(0, newMessage);
		response.sendRedirect("/testbbs/ShowBBS");
	}
}
```

```java:ShowBBS.java
import java.io.*;
import javax.servlet.http.*;

public class ShowBBS extends HttpServlet {
	private String espaceHTML (String src) {
		return src.replace ("&", "&amp;").replace("<", "&lt;")
			.replace (">", "&gt;").replace ("\"", "&quot;")
			.replace ("'", "&#39;");
	}

	@Override
	public void doGet (HttpServletRequest request, HttpServletResponse response) 
			throws IOException {
		response.setContentType("text/html; charset=UTF-8");
		PrintWriter out = response.getWriter();
		out.println("<html>");
		out.println("<head>");
		out.println("<title>テスト掲示板</title>");
		out.println("</head>");
		out.println("<body>");
		out.println("<h1>テスト掲示板</h1>");
		out.println("<form action='/testbbs/PostBBS' method='post'>");
		out.println("タイトル：<input type='text' name='title' size='60'>");
		out.println("<br />");
		out.println("ハンドル名：<input type='text' name='handle'>");
		out.println("<br />");
		out.println("<textarea name='message' rows='4' cols='60'></textarea>");
		out.println("<br />");
		out.println("<input type='submit' />");
		out.println("</form>");
		out.println("<hr />");

		for (Message message: Message.messageList) {
			out.println("<p> 『" + espaceHTML(message.title) + "』&nbsp; &nbsp;");
			out.println(espaceHTML(message.handle) + " さん&nbsp;&nbsp;");
			out.println(espaceHTML(message.date.toString()) + "</p>");
			out.println("<p>");
			out.println(espaceHTML(message.message).replace("\r\n", "<br />"));
			out.println("</p><hr />");
		}
		
		out.println("</body>");
		out.println("</html>");
	}

}
```


## web.xmlファイル
これも本と同じ．

```xml:web.xml
<web-app xmlns="http://xmlns.jcp.org/xml/nx/javaee"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
						http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
	version="3.1"
	metadata-complete="true">

	<servlet>
		<servlet-name>ShowBBS</servlet-name>
		<servlet-class>ShowBBS</servlet-class>
	</servlet>
	<servlet>
		<servlet-name>PostBBS</servlet-name>
		<servlet-class>PostBBS</servlet-class>
	</servlet>
	<servlet-mapping>
		<servlet-name>ShowBBS</servlet-name>
		<url-pattern>/ShowBBS</url-pattern>
	</servlet-mapping>
	<servlet-mapping>
		<servlet-name>PostBBS</servlet-name>
		<url-pattern>/PostBBS</url-pattern>
	</servlet-mapping>
</web-app>
```


# ビルドして実行

```sh
$ docker build -t henacat .
Sending build context to Docker daemon  11.78kB

Step 1/6 : FROM tomcat:8.5.54-jdk11-adoptopenjdk-hotspot
 ---> 66317f378ae0
Step 2/6 : RUN apt-get update && apt-get install -y wget
 ---> Using cache
 ---> 871dd39a71cc
Step 3/6 : WORKDIR /usr/local/tomcat/webapps/
 ---> Using cache
 ---> 19d29e246ff6
Step 4/6 : RUN mkdir -p ./testbbs
 ---> Using cache
 ---> c2765cdc59e3
Step 5/6 : COPY ./testbbs ./testbbs/
 ---> Using cache
 ---> dbd09272e03b
Step 6/6 : RUN javac -classpath $CATALINA_HOME/lib/servlet-api.jar -d ./testbbs/WEB-INF/classes ./testbbs/WEB-INF/src/*.java
 ---> Using cache
 ---> 41e02fb5b101
Successfully built 41e02fb5b101
Successfully tagged henacat:latest

$ docker run -d -p 8080:8080 -it henacat
$ docker ps -a
CONTAINER ID   IMAGE     COMMAND             CREATED              STATUS              PORTS                    NAMES
249799090cb1   henacat   "catalina.sh run"   About a minute ago   Up About a minute   0.0.0.0:8080->8080/tcp   elegant_ishizaka

```

http://localhost:8080/testbbs/ShowBBS にアクセスすると，ちゃんと掲示板が表示される．

![Screen Shot 2021-01-11 at 2.42.20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276005/ff6a5dfe-571f-183b-fd22-d0946ba5c070.png)


# ハマったこと

最初に使ったDockerイメージはtomcat:10.0.0-jdk11-adoptopenjdk-hotspot だったが，これだとコンパイルが通らなかった．
どうもサーブレットのためのパッケージが見つからないらしい．
クラスパスを間違えたかなと思い色々変えてみたがコンパイルエラーは直らず，tomcatの問題かと思いドキュメントを見にいくと，tomcat-10からどうもパッケージ名が変わったらしい．
[tomcat-8](https://tomcat.apache.org/tomcat-8.0-doc/servletapi/javax/servlet/http/HttpServlet.html) では，javax.servlet.httpだったのが，[tomcat-10](https://tomcat.apache.org/tomcat-10.0-doc/servletapi/jakarta/servlet/http/HttpServlet.html)では，jakarta.servlet.httpとなっており，そりゃパッケージ見つからんってエラー吐かれるよなと．
と言うわけで，本と同じtomcat-8のDockerイメージを用いることで無事解決．


# 参考文献

[前橋和弥「Webサーバを作りながら学ぶ基礎からのWebアプリケーション開発入門」技術評論社 (2016)](https://www.amazon.co.jp/Web%E3%82%B5%E3%83%BC%E3%83%90%E3%82%92%E4%BD%9C%E3%82%8A%E3%81%AA%E3%81%8C%E3%82%89%E5%AD%A6%E3%81%B6-%E5%9F%BA%E7%A4%8E%E3%81%8B%E3%82%89%E3%81%AEWeb%E3%82%A2%E3%83%97%E3%83%AA%E3%82%B1%E3%83%BC%E3%82%B7%E3%83%A7%E3%83%B3%E9%96%8B%E7%99%BA%E5%85%A5%E9%96%80-%E5%89%8D%E6%A9%8B%E5%92%8C%E5%BC%A5-ebook/dp/B01GNXNIWE)