JavaでWebの作成

# Pleiadesのインストール手順
今回は `Version: 2025-03 (4.35.0)` のEclipseを使用しています
[Pleiadesのダウンロードリンク](https://willbrains.jp/)

## Eclipseで「dynamic web project」の作成と「Servlet」を使った開発
#### ポイント
- **Pleiades** をインストールすると **[Tomcat]** もセットで付いてくるので別途インストールする必要がない。
- **Java** も **Pleiades** に入っているので **Windows本体** に入れる必要はない。
- 起動直後は **「WTP」** のインストールする必要があった
- **Eclipse** に `Tomcat`をインストールした方がいいのかと思って **Eclipse Marketplace** からインストールすると逆に表示が出来なくなったのでインストールしない方がよさそうです。
- script.jsのコードを書き換えてもキャッシュが残っていると再起動しても反映されないようです。

## Pleiadesのダウンロード後
以下のような見た目のファイルがインストール出来るが **Zip** ファイルではないのでダブルクリックで実行します。
![pleiades_win04-1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3957418/68055e7b-80cb-44f2-bad1-a72d6bb87453.png)

インストールで **C:\pleiades** に配置したら、`"C:\pleiades\2025-03\eclipse\eclipse.exe"` を実行します。

次に `「Help」→「Istall New Software」` を開きます
![手順1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3957418/a8fd1246-c85a-473b-a7d6-4cbf849dd2a5.png)
![手順２.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3957418/6cc18b53-533f-42e2-a3b2-30b266074348.png)

その後は `「https://download.eclipse.org/releases/2025-03」` を **Work with** に入力すると、インストール候補がリストで現れるので必要なものをインストール
今回は **Web, XML, Java EE and OSGi Enterprise Development を探してチェック** が必要になります。

![手順3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3957418/cb08e031-6d91-448a-b859-eb6be1a6c498.png)


再起動したら、まずは **「Window」→「Preferences」** に移動

![サーバ設定1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3957418/161da2f9-db76-41a1-8ec2-79bad63b79e4.png)

次に **「Server」→ 「Runtime Environments」** に移動
![サーバ設定2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3957418/b21760a0-3fa4-43d2-a525-7a15df116e2e.png)

「Server runtime environments」が複数あると思うので使用するもの１つだけ選んで、残りは削除します。※後でエラーが起きにくくさせるため

# 「dynamic web project」を新規追加
- 「File」→ 「New」 → 「Other」を選択 ※「Dynamic Web Project」がある場合は直接選択

- 「Other」を選択したら、 「Web」を開いて「Dynamic Web Project」を選択
![スクリーンショット 2025-06-07 135728.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3957418/3d3b7b7a-0041-47fc-8199-39bb7366abc3.png)

- プロジェクト名を設定したら「Next」に進む
- 次の画面も「Next」で進んだら、下の画面になると思うので☑をします
![スクリーンショット 2025-06-07 135744.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3957418/33906f29-c371-4b29-86c5-efe938bb764d.png)

# 「Servlet」を新規追加
- プロジェクト名で右クリックをして、「File」→ 「New」 → 「Other」を選択
- 「Web」を開いて「Servlet」を選択 
- Java package の名前は 「sample_main」、クラス名は「sample」にしました。

![スクリーンショット 2025-06-07 140249.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3957418/6b64a153-1339-486e-8bd3-24783514c85b.png)

以下がサーブレッドのコードになります。
```mojiokoshi\src\main\java\sample_main\sample.java
package sample_main;

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

/**
 * Servlet implementation class sample
 */
@WebServlet("/sample")
public class sample extends HttpServlet {
	private static final long serialVersionUID = 1L;
       
    /**
     * @see HttpServlet#HttpServlet()
     */
    public sample() {
        super();
        // TODO Auto-generated constructor stub
    }

	/**
	 * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
	 */
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        response.setContentType("text/html;charset=UTF-8");
        response.getWriter().println("<html>");
        response.getWriter().println("<head><title>画像表示</title></head>");
        response.getWriter().println("<body>");
        response.getWriter().println("<h1>画像を表示します</h1>");
        response.getWriter().println("<img src='images/kirby.png' alt='サンプル画像' />");
        response.getWriter().println("<h1>録音テスト</h1>");
        response.getWriter().println("<button id='start'>Start</button>");
        response.getWriter().println("<button id='stop'>Stop</button>");
        response.getWriter().println("<button id='play'>Play</button>");
        response.getWriter().println("<p></p>");
        response.getWriter().println("<audio id='audio' controls></audio>");
        // ★ ここを module に変更
        response.getWriter().println("<script type='module' src='script.js'></script>");
        response.getWriter().println("</body>");
        response.getWriter().println("</html>");
    }

	/**
	 * @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);
	}

}
```
# 最後にServerの起動を行います。
![スクリーンショット 2025-06-07 141449.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3957418/96e324e1-2871-421c-a51f-dabebd2d767d.png)

まずServersタブを表示する為に画像の赤丸の場所か
「Window」→「Show View」→「Saver」→「Savers」を選択
![スクリーンショット 2025-06-07 141729.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3957418/7d21ee41-bd81-4f11-b5dc-6c78b9daf490.png)

表示出来たら以下のようになります。
![スクリーンショット 2025-06-07 141604.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3957418/259eab07-419e-42a4-8f64-9f9876d53374.png)

# 「Savers」タブにTomcatを追加 
- 使用する Tomcat を選択します。
- Tomcatを選択したら右クリック「Add and Remove」を選択
※もし下の画像の設定が済んでたら必要ないです。
![スクリーンショット 2025-06-07 142319.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3957418/b178af63-915b-4cd4-94c0-241cb517117b.png)

- 最後に右クリックでStartかRestartで起動します。

# Dynamic Web Project Web構成
Dynamic Web Projectの「Servlet」がフロントエンドだと最初は思い込んでいたんですが、実は「Servlet」はバックエンドの役割らしいのです。
### 以下に内容をまとめています

# Java Webアプリ開発メモ
## 1. Servletの役割

Servlet（サーブレット）はJavaにおけるバックエンドの役割を担います。フォーム処理、ファイルアップロード、データベース接続、APIレスポンスなどのサーバサイド処理を担当します。

## 2. フロントエンドの構成（Dynamic Web Project）

- **HTML/JSP:** `src/main/webapp/` に配置  
- **CSS/JS:** `src/main/webapp/css/` や `src/main/webapp/js/` など  
- **画像:** `src/main/webapp/images/` など  

### 例:
![スクリーンショット 2025-06-07 141355.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3957418/3d4669d4-33f5-4c6d-b79d-3c4e8a4e6c5b.png)



# WARファイルの生成手順と音声ファイルの保存先

## 1. WARファイルの生成方法（Eclipse）

1. Eclipseで対象の Dynamic Web Project を選択。
2. メニューから **File → Export** を選択。
3. **Web → WAR file** を選択し、**[Next]** をクリック。
4. 保存先を指定（例：`C:\Users\you\Desktop\yourapp.war`）。
5. **[Finish]** をクリックしてエクスポート完了。

## 2. 音声ファイルの保存場所について

> アップロードされた音声ファイル（例：`.webm`）は、  
> サーバ上の次のディレクトリに保存されます：
>
> ```
> {Tomcatのインストールパス}/webapps/{プロジェクト名}/uploads/
> ```

### 保存処理の概要（Javaサーブレット）

- サーブレットが `getServletContext().getRealPath("/uploads")` で物理パスを取得。
- そのディレクトリにファイルが保存される。
- 例：`C:\apache-tomcat\webapps\yourapp\uploads\recording_1720000000000.webm`

### 注意事項

- **Webアプリ再デプロイ時にアップロードファイルが消える**可能性あり。
- 永続保存が必要な場合は、`C:/data/uploads` などの外部ディレクトリを使う設計が推奨。

# サーブレッド
```mojiokoshi\src\main\java\update\UploadServlet.java
package update;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;

import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.MultipartConfig;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.Part;

@WebServlet("/upload")
@MultipartConfig
public class UploadServlet extends HttpServlet {
    private static final long serialVersionUID = 1L;

    protected void doPost(HttpServletRequest request, HttpServletResponse response)
        throws ServletException, IOException {

        Part filePart = request.getPart("audio");
        String filename = "recording_" + System.currentTimeMillis() + ".webm";
        String uploadDir = "C:\\dev\\tomcat\\webapps\\global_uploads";

        File dir = new File(uploadDir);
        if (!dir.exists()) dir.mkdirs();

        File outputFile = new File(dir, filename);
        try (InputStream input = filePart.getInputStream()) {
            Files.copy(input, outputFile.toPath());
        }

        response.setContentType("text/plain; charset=UTF-8");
        response.getWriter().write("アップロード成功: " + filename);
    }
}
```

# スクリプト
```mojiokoshi\src\main\webapp\script.js
/**
 * 
 */
let mediaRecorder;
let recordedChunks = [];

document.getElementById("start").onclick = async () => {
    const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
    mediaRecorder = new MediaRecorder(stream);
    recordedChunks = [];

    mediaRecorder.ondataavailable = e => recordedChunks.push(e.data);
    mediaRecorder.start();
};

document.getElementById("stop").onclick = () => {
    mediaRecorder.stop();
};

document.getElementById("play").onclick = () => {
    const blob = new Blob(recordedChunks, { type: 'audio/webm' });
    const audio = document.getElementById("audio");
    audio.src = URL.createObjectURL(blob);
    audio.play();
};

document.getElementById("save").onclick = () => {
    if (recordedChunks.length === 0) {
        alert("録音データがありません");
        return;
    }

    const blob = new Blob(recordedChunks, { type: 'audio/webm' });
    const formData = new FormData();
    formData.append("audio", blob, "audio.webm");

    fetch("/mojiokoshi/upload", {
        method: "POST",
        body: formData
    })
    .then(res => res.text())
    .then(msg => alert("保存完了：" + msg))
    .catch(err => {
        console.error("アップロード失敗", err);
        alert("アップロードに失敗しました");
    });
};

```