Spring Bootでパスワード強度チェッカーを作る|変数・条件分岐・REST APIの基本

Spring Bootでパスワード強度チェッカーを作る|変数・条件分岐・REST APIの基本

この記事はJava学習シリーズ「課題1」です。まだ環境が整っていない方は Java環境構築ガイド を先に読んでください。


この記事で作るもの

ブラウザで動くパスワード強度チェッカーWebアプリです。HTMLフォームにパスワードを入力すると、Spring Boot APIが強度を判定して結果を表示します。

APIとして使う場合(curl):

curl -X POST http://localhost:8080/api/check-password \
  -H "Content-Type: application/json" \
  -d '{"password": "hello"}'
{
  "score": 1,
  "strength": "弱い",
  "stars": "★☆☆☆☆",
  "advice": [
    "8文字以上にしてください(現在: 5文字)",
    "大文字(A-Z)を含めてください",
    "数字(0-9)を含めてください",
    "記号(!@#$%^&*)を含めてください"
  ]
}

ブラウザで使う場合: http://localhost:8080/ を開くとHTMLフォームが表示されます。

この記事で学べること

  • Spring Bootの基本構造(最初のWebアプリ)
  • アノテーション@RestController, @PostMapping, @RequestBody
  • 変数と型int, String, boolean
  • 条件分岐if / else if / else
  • 正規表現(文字パターンの検索)
  • record(シンプルなDTOクラス)

1. 要件定義:何を作るかを整理する

コードを書く前に「このAPIが何をしなければならないか」を整理します。

#要件(やること)理由
1POST /api/check-password でパスワードを受け取るHTTPリクエストで入力を受け取るWebサービスにするため
28文字以上かどうかをチェックする短すぎると総当たり攻撃に弱い
3大文字・小文字・数字・記号が含まれるかチェックする文字の多様性がパスワード強度を上げる
4達成条件数をスコアにして★で表示する「どれくらい強いか」を視覚的に伝える
5未達成の条件をアドバイスとして返すユーザーが何を改善すればいいかわかる
6ブラウザから使えるHTMLフォームを提供するAPIだけでなくブラウザで動く画面も用意してポートフォリオとして映えるようにする

2. Spring Initializrでプロジェクト作成

Spring Bootのプロジェクトは start.spring.io で雛形を生成します。

Project:      Maven
Language:     Java
Spring Boot:  3.3.x

Group:        com.example
Artifact:     password-checker
Name:         password-checker

Java: 21

Dependencies(「ADD DEPENDENCIES」をクリックして追加):
  ✓ Spring Web   ← HTTPリクエストを受け取るために必要
  ✓ Validation   ← リクエストの入力チェックに使う

「GENERATE」でZIPをダウンロード → 解凍 → IntelliJで「File → Open」。

生成されるプロジェクト構造:

password-checker/
├── pom.xml
└── src/main/
    ├── java/com/example/passwordchecker/
    │   └── PasswordCheckerApplication.java   ← Spring Bootの起動クラス
    └── resources/
        ├── application.properties
        └── static/                           ← ここにindex.htmlを置く

3. Spring Bootの基本構造を理解する

Spring Bootとは? Javaで「WebからHTTPで呼び出せるサービス(REST API)」を作るための最も普及したフレームワークです。HTTPサーバー(Tomcat)が内蔵されており、コードを書いたらすぐにブラウザやcurlから呼び出せます。クラウドワークスのJava案件のほぼすべてでSpring Bootが使われています。

Spring Bootで必要な主要アノテーションを先に把握しておきます。

アノテーション意味
@RestControllerこのクラスはHTTPリクエストを受け取り、JSONを返すControllerだという宣言
@RequestMapping("/api")このControllerは /api 配下のURLを担当する
@PostMapping("/check-password")POST /api/check-password をこのメソッドが処理する
@RequestBodyHTTPリクエストのJSON本体をJavaオブジェクトに変換して受け取る

アノテーション(Annotation)とは? @ で始まる「ラベル(マーカー)」です。クラスやメソッドに付けると、Springフレームワークがそれを読み取って自動的に処理を追加してくれます。たとえば @RestController を付けるだけで「HTTPを受け取ってJSONを返す」設定が完了します。


4. まずHello Worldエンドポイントを作る

src/main/java/com/example/passwordchecker/PasswordController.java を新規作成します。

最初は「APIが動く」ことだけを確認するために、最小限のエンドポイントを作ります。

package com.example.passwordchecker;

import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/api")
public class PasswordController {

    @GetMapping("/hello")
    public String hello() {
        return "Hello from Password Checker!";
    }
}

PasswordCheckerApplication.java の緑の三角▶をクリックして起動します。コンソールに Tomcat started on port 8080 が表示されたらブラウザで http://localhost:8080/api/hello を開きます。

Hello from Password Checker! が表示されれば成功です。


5. Javaの「変数と型」を理解する

パスワードチェックのロジックを実装する前に、使う変数の型を確認します。

プログラムでデータを記憶する場所を変数と呼びます。Javaでは変数を作るとき**「何を入れるか(型)」を先に宣言する**必要があります。

String password = "hello";   // 文字列を入れる箱
int score = 0;               // 整数を入れる箱
boolean isValid = true;      // 真偽値を入れる箱

なぜ型を宣言するの? JavaScriptでは let x = 10; と書けば自動的に「数値だな」と判断されます。しかしJavaは静的型付け言語で「この変数には必ず整数しか入らない」とコンパイル時に決定します。型の間違いをプログラムを実行する前に検出できます。

今回のチェッカーで使う主な型:

型名意味使い場面
String文字列パスワードの文字列
int整数達成条件のスコア
List<String>文字列のリストアドバイスの一覧

6. パスワード判定のロジックを実装する(要件2〜5)

正規表現で文字パターンをチェックする理由

「大文字が含まれるか」「数字が含まれるか」を調べるには、文字列の「パターン」を検索する必要があります。そのために正規表現を使います。

正規表現(Regular Expression)とは? 「大文字が1つ以上ある」「数字が含まれる」などの文字パターンを短い記号で表現するミニ言語です。String クラスの matches() メソッドで使えます。

".*[A-Z].*" の意味:

部分意味
.*任意の文字が0文字以上(何でもOK)
[A-Z]AからZの大文字が1文字
.*[A-Z].*前後に何があってもよく、どこかに大文字が1文字以上ある
"Hello".matches(".*[A-Z].*")  // → true(Hが大文字)
"hello".matches(".*[A-Z].*")  // → false(大文字なし)
"abc123".matches(".*[0-9].*") // → true(数字あり)

スコア計算とアドバイスのメソッドを実装する

各条件をチェックして1つずつスコアに加算します。未達成の条件はアドバイスとしてリストに追加します。

// 要件2〜4:各条件を満たすごとに+1してスコアを返す
private int calculateScore(String password) {
    int score = 0;
    if (password.length() >= 8)  score++;
    if (password.length() >= 12) score++;
    if (password.matches(".*[A-Z].*")) score++;
    if (password.matches(".*[a-z].*")) score++;
    if (password.matches(".*[0-9].*")) score++;
    if (password.matches(".*[!@#$%^&*()_+\\-=].*")) score++;
    return score;
}

// 要件5:未達成の条件をアドバイスのリストで返す
private List<String> getAdvice(String password) {
    List<String> advice = new ArrayList<>();
    if (password.length() < 8)
        advice.add("8文字以上にしてください(現在: " + password.length() + "文字)");
    if (!password.matches(".*[A-Z].*")) advice.add("大文字(A-Z)を含めてください");
    if (!password.matches(".*[a-z].*")) advice.add("小文字(a-z)を含めてください");
    if (!password.matches(".*[0-9].*")) advice.add("数字(0-9)を含めてください");
    if (!password.matches(".*[!@#$%^&*()_+\\-=].*")) advice.add("記号(!@#$%^&*)を含めてください");
    return advice;
}

// 要件4:スコアを強度ラベルと★に変換する
private String getStrength(int score) {
    if (score <= 2) return "弱い";
    if (score <= 3) return "普通";
    if (score <= 4) return "強い";
    return "非常に強い";
}

private String getStars(int score) {
    String[] stars = {"★☆☆☆☆","★☆☆☆☆","★★☆☆☆","★★★☆☆","★★★★☆","★★★★★","★★★★★"};
    return stars[Math.min(score, stars.length - 1)];
}

7. DTOクラスを作る(要件1)

APIのリクエスト(入力)とレスポンス(出力)の形を定義するクラスが必要です。

DTOとは? 「このAPIにはこの形でJSONを送ってください」「このAPIはこの形のJSONを返します」というデータの形を定義するクラスです。record を使うと1行で作れます。

同じパッケージ内に2つのファイルを作成します。

PasswordRequest.java(リクエストの形 {"password": "hello"}):

package com.example.passwordchecker;

import jakarta.validation.constraints.NotBlank;

public record PasswordRequest(
    @NotBlank(message = "パスワードは必須です")
    String password
) {}

PasswordResponse.java(レスポンスの形):

package com.example.passwordchecker;

import java.util.List;

public record PasswordResponse(
    int score,
    String strength,
    String stars,
    List<String> advice
) {}

8. Controllerに組み込む(完成版)

要件1〜5をすべて組み合わせた PasswordController.java の完成版です。

package com.example.passwordchecker;

import jakarta.validation.Valid;
import org.springframework.web.bind.annotation.*;
import java.util.ArrayList;
import java.util.List;

@RestController
@RequestMapping("/api")
public class PasswordController {

    // 要件1:POST /api/check-password でパスワードを受け取り、判定結果を返す
    @PostMapping("/check-password")
    public PasswordResponse checkPassword(@Valid @RequestBody PasswordRequest request) {
        String password = request.password();

        int score          = calculateScore(password);
        List<String> advice = getAdvice(password);

        return new PasswordResponse(score, getStrength(score), getStars(score), advice);
    }

    // 要件2〜4:スコア計算
    private int calculateScore(String password) {
        int score = 0;
        if (password.length() >= 8)  score++;
        if (password.length() >= 12) score++;
        if (password.matches(".*[A-Z].*")) score++;
        if (password.matches(".*[a-z].*")) score++;
        if (password.matches(".*[0-9].*")) score++;
        if (password.matches(".*[!@#$%^&*()_+\\-=].*")) score++;
        return score;
    }

    // 要件5:アドバイス生成
    private List<String> getAdvice(String password) {
        List<String> advice = new ArrayList<>();
        if (password.length() < 8)
            advice.add("8文字以上にしてください(現在: " + password.length() + "文字)");
        if (!password.matches(".*[A-Z].*")) advice.add("大文字(A-Z)を含めてください");
        if (!password.matches(".*[a-z].*")) advice.add("小文字(a-z)を含めてください");
        if (!password.matches(".*[0-9].*")) advice.add("数字(0-9)を含めてください");
        if (!password.matches(".*[!@#$%^&*()_+\\-=].*")) advice.add("記号(!@#$%^&*)を含めてください");
        return advice;
    }

    private String getStrength(int score) {
        if (score <= 2) return "弱い";
        if (score <= 3) return "普通";
        if (score <= 4) return "強い";
        return "非常に強い";
    }

    private String getStars(int score) {
        String[] stars = {"★☆☆☆☆","★☆☆☆☆","★★☆☆☆","★★★☆☆","★★★★☆","★★★★★","★★★★★"};
        return stars[Math.min(score, stars.length - 1)];
    }
}

curlでテストします:

# 弱いパスワード
curl -X POST http://localhost:8080/api/check-password \
  -H "Content-Type: application/json" \
  -d '{"password": "hello"}'

# 強いパスワード
curl -X POST http://localhost:8080/api/check-password \
  -H "Content-Type: application/json" \
  -d '{"password": "Tr0ub4dor&3"}'

9. ブラウザ用HTMLフロントエンドを追加する(要件6)

src/main/resources/static/index.html を作成します。Spring Bootはこのフォルダのファイルを自動的にWebで公開します。

<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>パスワード強度チェッカー</title>
  <style>
    body { font-family: sans-serif; max-width: 480px; margin: 60px auto; padding: 0 20px; }
    h1 { font-size: 1.4rem; color: #1e293b; }
    input {
      width: 100%; padding: 10px; font-size: 1rem;
      border: 1px solid #cbd5e1; border-radius: 6px; box-sizing: border-box;
    }
    button {
      margin-top: 10px; padding: 10px 24px;
      background: #4f46e5; color: white; border: none;
      border-radius: 6px; cursor: pointer; font-size: 1rem;
    }
    button:hover { background: #4338ca; }
    #result { margin-top: 20px; padding: 16px; background: #f8fafc; border-radius: 8px; display: none; }
    .stars { font-size: 1.6rem; }
    .strength { font-weight: bold; margin-left: 8px; font-size: 1.1rem; }
    .advice { margin-top: 12px; padding-left: 16px; color: #64748b; }
    .safe { color: #16a34a; font-weight: bold; margin-top: 10px; }
  </style>
</head>
<body>
  <h1>パスワード強度チェッカー</h1>
  <input type="password" id="password" placeholder="パスワードを入力してください">
  <br>
  <button onclick="check()">チェックする</button>

  <div id="result">
    <div>
      <span class="stars" id="stars"></span>
      <span class="strength" id="strength"></span>
    </div>
    <ul class="advice" id="advice"></ul>
    <p class="safe" id="safe" style="display:none">このパスワードは非常に安全です!</p>
  </div>

  <script>
    async function check() {
      const password = document.getElementById('password').value;
      if (!password) return;

      const res = await fetch('/api/check-password', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ password })
      });
      const data = await res.json();

      document.getElementById('stars').textContent = data.stars;
      document.getElementById('strength').textContent = data.strength;

      const adviceEl = document.getElementById('advice');
      const safeEl   = document.getElementById('safe');

      if (data.advice.length === 0) {
        adviceEl.innerHTML = '';
        safeEl.style.display = 'block';
      } else {
        adviceEl.innerHTML = data.advice.map(a => `<li>${a}</li>`).join('');
        safeEl.style.display = 'none';
      }

      document.getElementById('result').style.display = 'block';
    }
  </script>
</body>
</html>

http://localhost:8080/ を開くとHTMLフォームが表示されます。


10. GitHubに公開する

git init
git add .
git commit -m "feat: パスワード強度チェッカーAPI(Spring Boot)"
git remote add origin https://github.com/YOUR_NAME/password-checker.git
git push -u origin main

README.md に以下を記載してポートフォリオとして仕上げます。

# パスワード強度チェッカー API

Spring Boot で作成したパスワード強度判定 REST API。

## 技術スタック

- Java 21 / Spring Boot 3.3
- Spring Web / Bean Validation

## エンドポイント

| メソッド | パス | 説明 |
|--------|------|------|
| POST | /api/check-password | パスワード強度を判定してJSONで返す |
| GET  | /                   | ブラウザ用HTMLフォーム |

## 使い方

\`\`\`bash
./mvnw spring-boot:run

curl -X POST http://localhost:8080/api/check-password \
  -H "Content-Type: application/json" \
  -d '{"password": "Tr0ub4dor&3"}'
\`\`\`

まとめ:学んだこと

概念内容どこで使ったか
要件定義コード前に「何を作るか」を言葉で整理する設計フェーズ
Spring BootWebサービスのJavaフレームワークプロジェクト全体の土台
@RestControllerJSONを返すControllerの宣言PasswordController
@PostMappingPOSTリクエストのエンドポイント定義/api/check-password
@RequestBodyJSON→Javaオブジェクトの変換リクエスト受け取り
recordシンプルなDTOクラスPasswordRequest / PasswordResponse
型と変数int / String でデータを記憶するscore / password
正規表現matches() で文字パターンを検索する大文字・数字・記号チェック
if / else if条件によって処理を変えるスコア→★への変換
List<String>複数のアドバイスをまとめるadvice

Javaの学習シリーズ: 環境構築 | 今ここ(課題1・パスワードチェッカー) | 課題2・データ分析API | 課題3・為替変換API | 課題4・Spring Boot Todo API | 課題5・家計簿API

この記事をシェアする

関連記事


CHECK IT OUT

Members Only

サブスク加入者限定の コンテンツを配信中

  • 毎月のAI・自動化トレンドレポート
  • クリエイター向け業務効率化テンプレート
  • ツール選定・SaaS比較まとめ(限定公開)
Discord サーバー & LINE 公式の両方で通知します
クリエイター・個人事業主向け 受付中

「これ自動化できないかな?」 そのアイデア、ITで実現できます。

業務の自動化・お客様向けツール開発・AI活用まで、クリエイター・個人事業主専門のITコンサルタントが対応します。まずは気軽にご相談ください。

LINEで相談 フォームで相談