はじめに
Spring BootはJavaエコシステムでのWeb開発を効率化するフレームワークで、Controller・Service・Repositoryという明確なレイヤー分割やDI、Thymeleafによるサーバーサイドレンダリング(SSR)など、オーソドックスなバックエンド構築手法が確立されています。
一方、フロントエンド界隈では、Reactとその上で動くNext.jsが主流になりつつあります。Next.jsは「Reactベースのフロントエンドフレームワーク」でありながら、SSRやSSG(静的サイト生成)、API Routesといった仕組みを内包し、フロントとバックをシームレスにつなげる機能を提供します。
本記事では、Spring Bootでの開発経験がある方を対象に、Next.js(特にNext.js 13以降推奨のApp Router構成)を理解するためのヒントをまとめます。加えて、実運用を意識したSplunkへのログ送信やエラーコード設計の比較も紹介します。
Spring MVC & ThymeleafとNext.js & Reactの対比
基本的な対応関係
-
Spring MVC & Thymeleaf
- Controller (
@Controller
): HTTPリクエストを受け、Serviceからデータ取得し、ModelをViewへ渡す - View(Thymeleaf/JSP): モデルデータをもとにHTML生成(SSR)
- RestController (
@RestController
): JSONレスポンスのAPIを提供
- Controller (
-
Next.js & React
- サーバーコンポーネント (
app/page.tsx
など): リクエスト時にサーバー側で実行、fetch()
でデータ取得しSSR - Reactコンポーネント: HTML生成ロジックをJSXで記述(テンプレートエンジン相当)
- API Routes (
app/api/.../route.ts
): 簡易なAPIエンドポイントを提供(JSONレスポンス)
- サーバーコンポーネント (
SpringでController+ThymeleafでSSRしていた部分は、Next.jsでは「サーバーコンポーネント+Reactコンポーネント」に置き換わります。また、Springで@RestController
でJSONを返していたような処理は、Next.jsではapp/api
配下にファイルを設置し、GET()
関数を記述するだけで実現可能です。
具体例
Spring側
@Controller
public class UserController {
@Autowired
private UserService userService;
@GetMapping("/users")
public String getUsers(Model model) {
List<User> users = userService.getAllUsers();
model.addAttribute("users", users);
return "users"; // Thymeleafテンプレート(users.html)へ
}
}
<!-- users.html (Thymeleaf) -->
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head><title>User List</title></head>
<body>
<h1>User List</h1>
<ul>
<li th:each="user : ${users}" th:text="${user.name}"></li>
</ul>
</body>
</html>
Next.js側(App Router)
// app/users/page.tsx
type User = { id: number; name: string };
export default async function UsersPage() {
const res = await fetch('http://localhost:3000/api/users', { cache: 'no-store' });
const users: User[] = await res.json();
return (
<div>
<h1>User List (SSR)</h1>
<ul>{users.map(u => <li key={u.id}>{u.name}</li>)}</ul>
</div>
);
}
APIルートとService層の関係
SpringではController・Service・Repositoryのレイヤリングが定番です。一方、Next.jsではAPI Routes内に直接DBアクセスやロジックを記述することもできます。
大規模になればlib/ディレクトリにService相当の関数を分離し、API Routeから呼ぶなど、Spring的なアーキテクチャパターンを任意で適用可能です。
SSRとSSG
Spring + Thymeleafは基本SSRですが、Next.jsではSSRに加えてSSG (Static Site Generation) も可能です。ビルド時に静的HTMLを生成し、CDNから高速配信するなど、パフォーマンス向上やスケーラビリティ確保が容易です。
- SSR: リクエストごとにサーバーでHTML生成 (cache: 'no-store'など)
- SSG: ビルド時または初回アクセス時にHTML生成、その後は静的ファイル配信 (cache: 'force-cache'、generateStaticParams()など)
Splunk等へのログ出し
Spring Bootでのロギング
- Logback + SLF4Jが定番
- logback-spring.xmlでJSON出力設定
- サーバー側でSplunk Universal Forwarderがログファイルを監視してSplunkへ送信
Next.jsでのロギング
Node.js用のロガー(winston, pino)を使用
JSON形式で標準出力へログを出力
コンテナ環境などでFluentdやSplunk Forwarder経由でSplunkへ送信可能
// Next.js API Route例 (winston使用)
import { NextResponse } from 'next/server';
import { createLogger, format, transports } from 'winston';
const logger = createLogger({
level: 'info',
format: format.json(),
transports: [new transports.Console()]
});
export async function GET() {
logger.info({ event: 'fetch_users', message: 'Fetching user data' });
const users = [{ id: 1, name: 'Alice' }, { id: 2, name: 'Bob' }];
return NextResponse.json(users);
}
エラーコード設計
Spring Bootのエラー処理
- @ControllerAdvice + @ExceptionHandlerで一元的なエラーハンドリング
- ErrorResponse DTOを定義し、codeやmessageで統一したフォーマット返却
@ControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(UserNotFoundException.class)
public ResponseEntity<ErrorResponse> handleUserNotFound(UserNotFoundException ex) {
ErrorResponse error = new ErrorResponse("USER_NOT_FOUND", "User does not exist");
return ResponseEntity.status(HttpStatus.NOT_FOUND).body(error);
}
}
Next.jsのエラー処理
- API Route内でtry-catchを使用し、NextResponse.json()で柔軟にエラーJSONを返却
- 共通的なエラー処理はユーティリティ関数やmiddleware.tsでカスタム
- error.tsxを用いてルート単位のエラーページ表示も可能
export async function GET() {
try {
throw new Error('User not found');
} catch (err: any) {
return NextResponse.json(
{ code: 'USER_NOT_FOUND', message: err.message },
{ status: 404 }
);
}
}
まとめ
-
Spring MVC & Thymeleaf → Next.js & React:
SSRを実現する思想は似ており、Controller+Viewをサーバーコンポーネント+Reactで代替。 -
API・Service設計:
SpringではControllerとServiceが明確だが、Next.jsは自由度が高く、必要に応じて分割可能。 -
SSR/SSG/ISR:
Next.jsはビルド時静的生成(SSG)や増分的再生成(ISR)でパフォーマンス向上が容易。 -
ログとSplunk:
SpringはLogback、Next.jsはNodeロガーを利用、最終的にJSON出力してSplunk送信というパターンは共通。 -
エラーコード設計:
Springの@ExceptionHandlerほど標準化はないが、NextResponseで自由にJSONエラーを返せるため、Springで慣れたエラーポリシーを容易に再現可能。
Spring Boot経験者にとって、Next.jsはフロントとバックの境界をシームレスに扱えるフルスタックフレームワークです。
Spring的なアーキテクチャパターンを下敷きに、Next.js特有のSSR/SSGやAPI Routesを活用することで、柔軟でスケーラブルなWebアプリ開発を進めることができます。