以下のコードでは、ユーザーがメッセージを入力して"Send"ボタンを押すと、そのメッセージがサーバーにPOSTリクエストとして送信されます。そして、2秒ごとにGETリクエストを送信してチャットボックスを更新します。

ただし、このサンプルコードはかなり簡易的で、本番環境での使用を前提としたものではありません。本番環境では、より高度な技術(WebSocketなど)やフレームワーク(Spring、Node.jsなど)を使用することを強く推奨します。

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Chat App</title>
<script
				src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script>
	// jQueryライブラリを使用します。このスクリプトタグはHTMLページに埋め込むためのものです。
	$(document).ready(function() {
		// ドキュメント(ページ)が読み込まれ、準備ができたら以下のコードを実行します。

		$("#sendMessage").click(function() {
			// IDが"sendMessage"のHTML要素(ボタンなど)がクリックされたときに、以下のコードを実行します。

			let message = $("#message").val();
			// IDが"message"のHTML要素(テキストフィールドなど)から値を取得し、それを変数"message"に代入します。

			$.post("Chat", {
				message : message
			});
			// "Chat"というエンドポイントに対してPOSTリクエストを送信します。このリクエストのボディには、先ほど取得した"message"の値が含まれます。

			$("#message").val("");
			// メッセージを送信した後、IDが"message"のHTML要素の値を空にします(テキストフィールドをクリアします)。
		});

		setInterval(function() {
			// 指定した時間間隔(この場合は2000ミリ秒、つまり2秒)ごとに、以下のコードを実行します。

			$.get("Chat", function(data, status) {
				// "Chat"というエンドポイントからGETリクエストを送信し、レスポンスが返ってきたら以下のコードを実行します。
				// "data"はサーバーから返されたデータ、"status"はリクエストのステータス("success"、"notmodified"など)です。

				$("#chatBox").html(data);
				// IDが"chatBox"のHTML要素(テキストエリアなど)の内容を、サーバーから返されたデータ("data")で更新します。
			});
		}, 2000);
		// setIntervalの第2引数は、指定したコードを実行する時間間隔(ミリ秒)です。この場合は2000ミリ秒、つまり2秒です。
	});
</script>

</head>
<body>
				<textarea id="chatBox" readonly rows="10" cols="30"></textarea>
				<br />
				<input type="text" id="message">
				<button id="sendMessage">Send</button>
</body>
</html>

package controller;

import java.io.IOException;
import java.io.PrintWriter;
import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@WebServlet("/Chat")
public class ChatServlet extends HttpServlet {
	private static final Queue<String> messages = new ConcurrentLinkedQueue<>();
	// スレッドセーフなQueueインスタンスを作成します。このQueueは文字列のメッセージを保持します。静的(static)であり、すべてのChatServletインスタンス間で共有されます。

	@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		// HTTP
		// GETリクエストを処理するためのメソッドをオーバーライド(再定義)します。HttpServletRequestオブジェクトはリクエスト情報を、HttpServletResponseオブジェクトはレスポンス情報を保持します。

		resp.setContentType("text/html");
		// HTTPレスポンスのContent-Typeヘッダを"text/html"に設定します。これにより、レスポンスボディがHTMLであることをブラウザに伝えます。

		PrintWriter out = resp.getWriter();
		// HttpServletResponseオブジェクトからPrintWriterを取得します。これにより、レスポンスボディにテキストを書き込むことができます。

		messages.forEach(out::println);
		// "messages"
		// Queueの各メッセージを、PrintWriterのprintlnメソッドを使ってレスポンスボディに書き込みます。つまり、保存されているすべてのメッセージをクライアントに送り返します。
	}

	@Override
	protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		// HTTP POSTリクエストを処理するためのメソッドをオーバーライド(再定義)します。

		String message = req.getParameter("message");
		// HttpServletRequestオブジェクトから"message"という名前のパラメータを取得します。このパラメータは、クライアントから送信されたメッセージを含んでいます。

		messages.add(message);
		// 取得したメッセージを"messages" Queueに追加します。
	}
}

なお、このサンプルコードではエラーハンドリングやセキュリティ対策などは考慮していません。実際のアプリケーションで使用する場合は、それらの重要な要素も適切に考慮する必要があります。

最後までお読みいただきありがとうございます。