新人エンジニアがハマりやすい!当社のSpring Boot研修でよくある10のミスとその回避法
こんにちは。ゆうせいです。
今回は、新人エンジニアが当社のSpring Boot(スプリングブート)を使った研修やプロジェクトでつまずきやすいポイントを10個紹介していきます。
「なんで動かないの?」「エラーの原因がわからない…」そんな不安や混乱を減らすために、初心者でも理解できるように、丁寧に、噛み砕いて解説していきます!
なぜSpring Bootでミスが起こるのか?
Spring Bootは非常に便利なフレームワークです。設定が簡単で、少ないコードで多くのことができます。
しかしその反面、「なぜ動くのか」が見えにくいため、仕組みを理解せずに使うとミスに気づきにくいのです。
では早速、よくあるミス10選を見ていきましょう。
よくあるミス①:データベースに該当データがなく、空のリストが返る
どんな場面で起こる?
たとえば、あるユーザー名で検索する処理があるとしましょう。
jList<User> users = userDao.findByName("Tanaka");
User user = users.get(0); // ← ここでエラー!
このとき、データベースに "Tanaka"
という名前のユーザーが1人も存在しなければ、findByName()
は空のリスト(要素数0のList)を返します。
その結果、.get(0)
のように最初の要素を無条件で取り出そうとすると、IndexOutOfBoundsException(インデックス範囲外例外)
が発生します。
解決策
まず何より「データベースでSELECT文を実行して、ちゃんと該当データがあるか確認」することが大切です。
SELECT * FROM users WHERE name = 'Tanaka';
このSQLで結果が0行になるなら、Java側でも空のリストが返ることを前提に処理を書かなくてはなりません。
安全なコードの書き方
List<User> users = userDao.findByName("Tanaka");
if (users.isEmpty()) {
// ユーザーが存在しないときの処理
System.out.println("該当ユーザーは見つかりませんでした");
} else {
User user = users.get(0); // 安全に取り出せる
}
よくあるミス②:小さな実験コードを書かずに、いきなり本番規模のシステムに手を加える
なぜダメなの?
いきなり本番コードを修正してしまうと、何が原因でバグが出たのか分からなくなることがよくあります。
また、初学者ほど「全体像が見えていない状態」で手を入れてしまい、予期せぬ副作用を引き起こします。
解決策
まずは、小さなテストプロジェクトや単体クラスでの検証コードを書きましょう。
よくあるミス③:フォームのname
属性のスペルミス
よくあるパターン
<input type="text" name="usernmae">
Java側のDTOでは username
を期待しているのに、HTMLで usernmae
と書いてしまうと、値が渡りません。
解決策
コピペ厳守!
スペルはコピーペーストを使って入力し、目でしっかり確認しましょう。英単語を選択したいときはその英単語をダブルクリックするのが最も効率的です。
残念ながらコード補完は効かないので特に間違えやすいです。
よくあるミス④:ファイルの配置場所を間違える(画像など)
Spring Bootのルール
静的ファイル(画像、CSS、JavaScriptなど)は、src/main/resources/static
に置く必要があります。
間違えた配置例
src/main/resources/image.png
これは一つ上のフォルダにファイルを置いてしまっている例です。ブラウザからアクセスできません。
よくあるミス⑤:リダイレクト時のURL記述ミス
よくあるコード例
return "redirect:user/list";
これは /user/list
ではなく 現在のパス/user/list
にリダイレクトされてしまいます。
解決策
ルートパスから始めたいときはスラッシュをつけましょう!
return "redirect:/user/list";
よくあるミス⑥:JDBCで LIKE '%?%' のような形でプレースホルダを使ってあいまい検索(部分一致検索)しようとする
どんなコードを書いてしまいがちか?
String keyword = "matsuda";
String sql = "SELECT * FROM users WHERE name LIKE '%?%'";
PreparedStatement stmt = conn.prepareStatement(sql);
stmt.setString(1, keyword);
このコード、一見それっぽく見えますが 絶対にうまくいきません。
なぜなら、JDBCの ?
はあくまで「値の位置指定」であり、文字列の一部として解釈されません。
正しい書き方
あいまい検索をしたい場合、%をJava側で付けた状態で渡すのが正解です。
String keyword = "matsuda";
String sql = "SELECT * FROM users WHERE name LIKE ?";
PreparedStatement stmt = conn.prepareStatement(sql);
stmt.setString(1, "%" + keyword + "%");
このようにすると、SQLとしては以下のように展開されます:
SELECT * FROM users WHERE name LIKE '%tanaka%'
つまり、%
をSQLに書くのではなく、Javaの値側で付け加えるという考え方なんです。
よくあるミス⑦:DTOに必要なフィールドがない
例
DTO(Data Transfer Object)とは、フォームから受け取ったデータを一時的に保持するクラスです。
public class UserForm {
private String name;
}
しかし、HTMLに email
も入力されている場合、それがDTOにないとバインドされずに無視されます。
解決策
画面の入力項目とDTOのフィールドは必ず一致させましょう。
よくあるミス⑧:DAOで全件取得を使いまわす
問題点
以下のようなことをしていませんか?
List<User> users = userDao.findAll();
User target = users.stream().filter(u -> u.getId() == 3).findFirst().get();
データ量にもよりますが、この方法は非効率になることがあります。
全件取得は、件数が増えるとパフォーマンスが大きく低下します。
解決策
1件取得用のメソッドを用意しましょう!
User user = userDao.findById(3);
よくあるミス⑨:session
とmodel
の使い分けミス
違いは何?
model
: 一時的なデータ、1ページ限りsession
: 複数ページをまたいでデータを保持したいときに使う
よくある間違い
ログイン情報を毎回model
で渡しなおすと、ページが変わるたびにデータが消えてしまいます。
解決策
ログインユーザー情報などは、HttpSession
に保存しましょう。
session.setAttribute("loginUser", user);
よくあるミス⑩:ControllerでURLのパスが重複していてSpring Bootが起動できない
さて、最後のミスは「Spring Bootアプリケーションが起動しない」という、かなり焦ってしまうタイプの問題です。
その原因のひとつが、「異なるControllerで同じURLパスを定義してしまう」こと。これは意外と見落としがちなんです!
以下のようなコードを見てみましょう。
ユーザー向けの画面を表示するController
@Controller
public class UserPageController {
@GetMapping("/status")
public String showUserStatus() {
return "user/status";
}
}
管理者向けの画面を表示するController(別のファイル)
@Controller
public class AdminPageController {
@GetMapping("/status")
public String showAdminStatus() {
return "admin/status";
}
}
ここで問題になるのは、どちらのControllerも同じ「/status」というURLを持っていることです。
Spring Bootは、1つのURLに対してどのメソッドを呼べばいいのかを明確にする必要があります。
ところがこのように重複してしまうと、
Mapping ambiguity detected: '/status' is defined in multiple classes.
というようなエラーが発生し、アプリケーション自体が起動しなくなります。
なぜ起こる? なぜ気づかない?
このエラーは特にプロジェクトが大きくなってきたときに起こりやすくなります。
- Controllerが複数のファイルに分かれていて、
- チームで並行開発していて、
- 似たようなURLを使っているとき、
別の人が定義した同じURLパスに気づかず重複してしまうというケースがよくあるのです。
解決策:エンドポイント一覧を作って管理する
実際の開発では、エンドポイント(URL)の一覧をドキュメントとしてまとめておくのも非常に効果的です。
エクセルやホワイトボードでも構いません。どのURLがどのControllerに割り当てられているかを可視化することで、重複を防げます。
おさらい:よくあるミス一覧表
番号 | ミス内容 | 対策ポイント |
---|---|---|
① | 存在しないデータを取得 | データベースでSELECT文を実行して、ちゃんと該当データがあるか確認 |
② | 小さな実験をせずに本番コード修正 | テスト用コードでまず検証 |
③ | name属性のスペルミス | コピペを使う |
④ | ファイル配置ミス | staticディレクトリに配置 |
⑤ | リダイレクト時のURLミス | / で始めるパスにする |
⑥ | LIKE '%?%' のような形でプレースホルダを使ってあいまい検索 | プレースホルダは?だけ、%をJava側で付けた状態で渡す |
⑦ | DTOのフィールド不足 | 入力項目とDTOの一致を確認 |
⑧ | 全件取得からの1件抽出 | 専用の取得メソッドを用意 |
⑨ | sessionとmodelの混同 | 複数ページはsession、一時的ならmodel |
⑩ | ControllerでURLのパスが重複 | エンドポイント一覧を作って管理する |
今後の学習の指針
Spring Bootを使いこなすには、「便利な裏側にある仕組み」を理解することがとても大切です。
まずは以下のステップを意識して学習していきましょう。
- 小さなアプリケーションを作る
- Springのアノテーションの意味を調べる
- MVCの流れをしっかり追えるようにする
- デバッグ力を鍛える(ブレークポイントやログ)
次は「Spring Securityの初歩」や「エラー処理のベストプラクティス」についても学んでいきましょう!
何か不安な点や、もう少し深掘りしたい項目があればいつでも教えてくださいね。
セイ・コンサルティング・グループの新人エンジニア研修のメニューへのリンク
投稿者プロフィール
