Spring Boot 3とJava 17で作るECサイト完全ガイド【実装から学ぶWeb開発】
この記事で分かること
- Spring Boot 3.1.5を使った実践的なECサイトの作り方
- JWT認証の実装方法
- Spring SecurityとSpring Data JPAの使い方
- 1万行規模のプロジェクト構成とアーキテクチャ設計
- 学生・初学者が実務レベルのコードを書くためのポイント
対象読者: Javaの基礎を学んだ学生・初学者、Spring Bootでポートフォリオを作りたい方
開発期間: 約2ヶ月
コード規模: 10,000行以上
GitHubリポジトリ: https://github.com/shanks665/ECplatform
目次
- プロジェクト概要
- 技術スタック
- アーキテクチャ設計
-
実装で学んだ重要ポイント
- JWT認証の実装
- DTOパターンとMapStruct
- 例外ハンドリング
- ページネーションと検索
- セキュリティ対策
-
苦労した点と解決策
- 循環参照エラー
- LazyInitializationException
- テストデータ管理
- フロントエンド連携
- 学生エンジニアへのアドバイス
- 今後の展望
- まとめ
プロジェクト概要
こんにちは!現在、Javaを学習中の学生エンジニアです。
今回、Spring Boot 3.1.5とJava 17を使って、本格的なEコマースプラットフォームを開発しました。コード行数は10,000行以上、エンティティやサービス、コントローラーなど合わせて85ファイル以上の規模になりました。
この記事では、プロジェクトを通じて学んだ技術や苦労した点、そして学生の皆さんへ伝えたいポイントをまとめます。
この記事を読むことで得られる知識:
- 実務レベルのSpring Bootプロジェクトの構成方法
- JWT + Spring Securityによる認証実装
- JPA/Hibernateのベストプラクティス
- よくあるエラーと解決方法
- 初学者が大規模プロジェクトを完成させるコツ
🎯 なぜこのプロジェクトを作ったのか
動機
- 実践的なJavaスキルの習得: 教科書やチュートリアルを超えた、実務レベルのコードを書きたかった
- モダンな技術スタックの理解: Spring Boot 3系、JWT認証、RESTful APIなど、現場で使われる技術を体験したかった
- ポートフォリオとしての価値: 就活や将来のキャリアに向けて、実力を示せるものを作りたかった
学習目標
- Spring Bootのエコシステムを深く理解する
- レイヤードアーキテクチャを実践する
- 認証・認可の実装を学ぶ
- データベース設計とJPAの使いこなし
- RESTful APIの設計原則を体得する
🛠️ 技術スタック:モダンなJava開発環境
バックエンド技術
- Java 17(LTS版): 最新の長期サポートバージョン。Records、Switch式、Text Blocksなどの新機能を活用
-
Spring Boot 3.1.5:
- Spring Framework 6系ベース
- 依存性注入(DI)、AOP、トランザクション管理
- Auto-configuration機能で設定を最小化
-
Spring Security 6 + JWT:
- トークンベースのステートレス認証
- JJWT 0.11.5を使用
- BCryptによるパスワードハッシュ化
-
Spring Data JPA(Hibernate):
- データアクセス層の抽象化
- クエリメソッドの自動生成
- Specificationパターンで動的クエリ
-
H2 Database / PostgreSQL:
- 開発時はH2(インメモリDB)
- 本番環境はPostgreSQL
開発支援ツール
-
Lombok 1.18.30:
-
@Data,@Builderでボイラープレート削減 - コンパイル時にGetter/Setter自動生成
-
-
MapStruct 1.5.5:
- DTOとエンティティ間のマッピング自動化
- リフレクション不要で高パフォーマンス
-
Swagger/OpenAPI 2.2.0:
- API仕様書の自動生成
- ブラウザでAPIテスト可能
-
Maven 3.9+:
- 依存性管理とビルド自動化
- pom.xmlで一元管理
フロントエンド技術
-
Vanilla JavaScript (ES6+):
- フレームワークに依存しない基礎力を養成
- Async/Awaitで非同期処理
-
Fetch API:
- RESTful APIとの通信
- Promise/Async/Await対応
-
LocalStorage API:
- JWTトークンの保存
- カート情報の永続化
📐 アーキテクチャ設計
レイヤードアーキテクチャの採用
┌─────────────────────────────────┐
│ Presentation Layer │ ← Controller
│ (REST API Endpoints) │
├─────────────────────────────────┤
│ Service Layer │ ← Business Logic
│ (ビジネスロジック) │
├─────────────────────────────────┤
│ Repository Layer │ ← Data Access
│ (データアクセス) │
├─────────────────────────────────┤
│ Database │ ← H2/PostgreSQL
└─────────────────────────────────┘
なぜこの構造にしたか:
- 各層の責務が明確で、コードの見通しが良い
- テストが書きやすい(モックを使った単体テストが容易)
- 将来的な変更に強い(例: DBをMySQLに変更しても上位層は影響を受けない)
主要なエンティティ設計
User (ユーザー)
├─ 1:N → ShoppingCart (カート)
├─ 1:N → Order (注文)
└─ 1:N → Address (住所)
Product (商品)
├─ N:1 → Category (カテゴリー)
├─ 1:N → ProductImage (画像)
└─ 1:N → ProductReview (レビュー)
Order (注文)
├─ N:1 → User (ユーザー)
└─ 1:N → OrderItem (注文明細)
ポイント:
- 双方向の関連は極力避け、単方向に統一(無限ループ防止)
-
@JsonIgnoreや@JsonBackReferenceを使ってシリアライズ問題を回避 - カスケード設定(
CascadeType)を慎重に選択
💡 実装で学んだ重要ポイント
1. Spring SecurityでJWT認証を実装する方法
従来のセッションベース認証ではなく、トークンベースのJWT認証を採用しました。Spring Security 6系で動作確認済みです。
メリット:
- スケーラブル(複数サーバーでのセッション共有不要)
- RESTfulの原則に沿う(ステートレス)
- モバイルアプリとの連携が容易
実装のポイント:
// JWTトークンの生成
public String generateToken(Authentication authentication) {
UserDetailsImpl userPrincipal = (UserDetailsImpl) authentication.getPrincipal();
Date now = new Date();
Date expiryDate = new Date(now.getTime() + jwtExpirationMs);
return Jwts.builder()
.setSubject(userPrincipal.getUsername())
.setIssuedAt(now)
.setExpiration(expiryDate)
.signWith(key(), SignatureAlgorithm.HS512)
.compact();
}
学び:
- トークンの有効期限管理の重要性
- リフレッシュトークンの設計(今後の課題)
- セキュリティヘッダーの設定(CORS、XSS対策)
2. DTOパターンとMapStructの使い方【ボイラープレート削減】
エンティティをそのままAPIレスポンスとして返すのではなく、DTO(Data Transfer Object)を経由させました。MapStruct 1.5.5を使って自動マッピングを実現しています。
なぜDTOを使うのか:
- エンティティの内部構造を隠蔽(セキュリティ)
- 循環参照の回避
- APIバージョン管理がしやすい
- 不要なデータの送信を防ぐ(パフォーマンス向上)
MapStructの威力:
@Mapper(componentModel = "spring")
public interface ProductMapper {
ProductResponseDTO toResponseDTO(Product product);
Product toEntity(ProductRequestDTO dto);
}
手動でマッピングコードを書く必要がなく、コンパイル時に自動生成されます。
3. @ControllerAdviceで例外ハンドリングを統一する
カスタム例外クラスと@ControllerAdviceでグローバルな例外処理を実装。すべてのコントローラーで一貫したエラーレスポンスを返せます。
@ControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(ResourceNotFoundException.class)
public ResponseEntity<ErrorResponse> handleResourceNotFound(
ResourceNotFoundException ex) {
ErrorResponse error = new ErrorResponse(
HttpStatus.NOT_FOUND.value(),
ex.getMessage(),
LocalDateTime.now()
);
return new ResponseEntity<>(error, HttpStatus.NOT_FOUND);
}
}
メリット:
- 一貫したエラーレスポンス形式
- コントローラーがスッキリする
- デバッグが容易
4. Spring Data JPAでページネーションと検索機能を実装
大量の商品データを効率的に扱うため、Spring Data JPAのPageableインターフェースを活用。動的検索にはSpecificationパターンを使用しています。
@GetMapping
public ResponseEntity<ApiResponse<Page<ProductResponseDTO>>> getAllProducts(
@RequestParam(defaultValue = "0") int page,
@RequestParam(defaultValue = "12") int size,
@RequestParam(required = false) String search,
@RequestParam(required = false) Long categoryId) {
Pageable pageable = PageRequest.of(page, size);
Page<Product> products = productService.searchProducts(
search, categoryId, pageable);
// ...
}
学び:
-
Pageableインターフェースの活用 - 動的なクエリ生成(
Specificationパターン) - N+1問題の対策(
@EntityGraphの利用)
5. セキュリティのベストプラクティス
- パスワードはBCryptでハッシュ化(10ラウンド)
- JWTシークレットキーは環境変数で管理
- SQLインジェクション対策(JPQLのパラメータバインディング)
- XSS対策(入力値のバリデーション、出力のエスケープ)
- CORS設定の適切な制限
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder(10);
}
🚧 苦労した点と解決策
1. 循環参照エラーの解決方法【JPA + Jackson】
問題: エンティティ間の双方向関連で、JSONシリアライズ時に無限ループが発生。JacksonのJsonMappingExceptionが頻発しました。
User → Order → OrderItem → Product → Category → ...
解決策:
-
@JsonIgnoreで不要な方向の関連を除外 - DTOに変換してからレスポンスを返す
- 単方向の関連を優先する設計に変更
2. LazyInitializationExceptionの原因と対策
問題: トランザクション外でLazy Fetchしたエンティティにアクセスしてエラー。Hibernateで頻出する問題です。
could not initialize proxy - no Session
解決策:
- サービス層に
@Transactionalを付与 - 必要なデータは
@EntityGraphで事前にFetch - DTOへの変換をトランザクション内で完結させる
3. テストデータの管理
問題: 開発・テスト時に毎回データを手動で投入するのが面倒。
解決策:
@Component
@RequiredArgsConstructor
public class DataInitializer implements CommandLineRunner {
@Override
public void run(String... args) {
// 初期データの投入
initializeUsers();
initializeCategories();
initializeProducts();
}
}
アプリケーション起動時に自動でサンプルデータを投入。
4. フロントエンドとの連携
問題: APIのエラーハンドリング、認証トークンの管理。
解決策:
// 共通のFetch関数
async function fetchWithAuth(url, options = {}) {
const token = localStorage.getItem('token');
const headers = {
'Content-Type': 'application/json',
...(token && { 'Authorization': `Bearer ${token}` }),
...options.headers
};
const response = await fetch(url, { ...options, headers });
if (response.status === 401) {
// トークン切れの処理
localStorage.removeItem('token');
window.location.href = '/login.html';
}
return response.json();
}
📊 プロジェクト規模
最終的なコードの規模:
| 項目 | 数量 |
|---|---|
| 総コード行数 | 10,000+ 行 |
| Javaファイル | 85+ ファイル |
| エンティティクラス | 12 個 |
| リポジトリ | 12 個 |
| サービスクラス | 6 個 |
| コントローラー | 6 個 |
| DTO | 20+ 個 |
| 列挙型 | 6 個 |
🎓 学生エンジニアへのアドバイス
1. 小さく始めて、着実に拡張する
最初から完璧を目指さず、MVPから始めましょう。
第1週: ユーザー登録・ログイン
第2週: 商品一覧・詳細
第3週: カート機能
第4週: 注文機能
...
2. 公式ドキュメントを読む習慣
Stack OverflowやQiitaも有用ですが、公式ドキュメントが最強です。
3. コードレビューを積極的に受ける
- GitHubでプルリクエストを出す
- 先輩や仲間にコードを見てもらう
- オープンソースプロジェクトのコードを読む
4. テストコードを書く
実装よりもテストを先に書く「TDD(テスト駆動開発)」にも挑戦してみましょう。
@Test
void testCreateProduct_Success() {
// Given
ProductRequestDTO request = new ProductRequestDTO(...);
// When
ProductResponseDTO response = productService.createProduct(request);
// Then
assertNotNull(response.getId());
assertEquals("Test Product", response.getName());
}
5. ポートフォリオとして磨く
- READMEを充実させる(スクリーンショット、デモ動画)
- デプロイする(Heroku、Railway、AWS EC2など)
- 技術ブログを書く(Qiita、Zenn、個人ブログ)
🚀 今後の展望
このプロジェクトをさらに進化させたい分野:
技術的な改善
- キャッシュ層の追加: Redis導入でパフォーマンス向上
- 全文検索: Elasticsearchで高度な検索機能
- リアルタイム通知: WebSocketで在庫変更通知
- マイクロサービス化: 認証、商品、注文を独立したサービスに分離
機能追加
- 商品レコメンデーション(機械学習)
- 決済システムの統合(Stripe、PayPal)
- 管理画面(React/Vue.js)
- モバイルアプリ(React Native)
📚 参考にした資料
書籍
- 「Spring徹底入門」(翔泳社)
- 「リーダブルコード」(オライリー)
- 「実践ドメイン駆動設計」(翔泳社)
オンラインリソース
🔗 リポジトリ
プロジェクトの全コードはGitHubで公開しています:
GitHub: https://github.com/shanks665/ECplatform
# クローンして試してみる
git clone https://github.com/shanks665/ECplatform.git
cd ECplatform
mvn spring-boot:run
# ブラウザで開く
open http://localhost:8080
主な機能:
- ✅ ユーザー登録・ログイン(JWT認証)
- ✅ 商品一覧・検索・フィルタリング
- ✅ ショッピングカート
- ✅ 注文処理
- ✅ 管理者機能
- ✅ Swagger API ドキュメント
まとめ:Spring Boot学習で得られた5つのこと
この10,000行超えのプロジェクトを通じて、Spring Bootの奥深さと設計の重要性を実感しました。
本プロジェクトで習得した技術
-
Spring Boot 3系の実践的な使い方
- Spring Security 6でのJWT認証実装
- Spring Data JPAによるデータベースアクセス
- RESTful APIの設計とSwagger統合
-
レイヤードアーキテクチャの実践
- Controller/Service/Repository層の適切な分離
- DTOパターンによる責務の明確化
- MapStructを使った効率的なマッピング
-
実務で使えるエラーハンドリング
- @ControllerAdviceでの統一的な例外処理
- カスタム例外クラスの設計
- 循環参照やLazyInitializationExceptionの対策
-
セキュリティのベストプラクティス
- BCryptによるパスワードハッシュ化
- JWT + Refresh Tokenの設計
- CORS、XSS、SQLインジェクション対策
-
大規模プロジェクトの完遂力
- 段階的な機能追加による進め方
- テストデータの効率的な管理
- Gitを使ったバージョン管理
初学者・学生エンジニアの方へのメッセージ
まずは小さく始めよう:
- いきなり完璧を目指さず、まずは基本的なCRUD操作から
- 1週間ごとに1機能ずつ追加していく
- 動くものを早く作って、フィードバックを得る
失敗を恐れないこと:
- エラーは学びのチャンス(このプロジェクトも数百回エラーが出ました)
- Stack OverflowとGitHub Issuesは最高の教材
- 公式ドキュメントを読む習慣をつける
作ったものを公開しよう:
- GitHubでソースコードを公開
- README.mdを丁寧に書く
- Qiitaやブログで技術記事を書く
- 就活のポートフォリオとして活用
技術を学ぶ過程で、このプロジェクトが少しでも参考になれば嬉しいです。
フィードバック歓迎
質問やフィードバックがあれば、ぜひGitHubのIssueやコメント欄でお気軽にどうぞ!
- 🐛 GitHubでIssueを作成
- 💬 コメント欄で質問
- ⭐ 参考になったらGitHubスターをお願いします!
関連キーワード
Spring Boot 3 Java 17 Spring Security JWT認証 Spring Data JPA ECサイト Webアプリ開発 RESTful API Maven H2 Database PostgreSQL ポートフォリオ 学生エンジニア 初心者向け 実践的 アーキテクチャ設計 Lombok MapStruct Swagger
この記事が役立つ人
- ✅ Spring Bootの実践的な使い方を知りたい
- ✅ ポートフォリオとして見せられるWebアプリを作りたい
- ✅ JWT認証の実装方法を学びたい
- ✅ レイヤードアーキテクチャを理解したい
- ✅ JPA/Hibernateの使い方をマスターしたい
- ✅ 就活に向けて技術力をアピールしたい
タグ
Java SpringBoot 初心者 ポートフォリオ Web開発 RESTfulAPI JWT SpringSecurity SpringDataJPA ECサイト Maven 実装 学習 チュートリアル 入門