本システムは、現代的なフルスタック技術スタックを採用し、ユーザーがスマートフォン上で手軽に蔵書を管理・閲覧できるミニアプリケーションです。バックエンドにはSpringBoot、フロントエンドにはVue.jsとuni-appを組み合わせ、データ永続化にはMyBatis-Plusを使用しています。
アーキテクチャ概要
SpringBootは内蔵サーバーと自動設定機能により、最小限の設定で高効率なAPIサーバーを構築可能。依存関係に基づいて必要なBeanやコンポーネントを自動生成し、開発スピードを大幅に向上させます。また、Spring SecurityやSpring Data JPAとの統合も容易です。
Vue.jsはリアクティブなデータバインディングと仮想DOMにより、UIの更新を自動化。開発者はビジネスロジックに集中でき、コードの保守性と再利用性が向上します。uni-appとの連携により、1つのコードベースで複数プラットフォーム(微信小程序、H5、Appなど)への対応が可能です。
MyBatis-Plusは、CRUD操作の簡略化、動的SQL生成、ページネーション、楽観ロックなどの機能を提供。エンティティクラスとMapperインターフェースを自動生成するツールもあり、ボイラープレートコードを削減できます。
認証・セッション管理の実装
ログイン処理では、ユーザー名とパスワードを検証後、一時トークンを発行。トークンは1時間有効とし、リクエストヘッダー経由で送信されます。認証インターセプターが各リクエストを監視し、無効なトークンの場合は401エラーを返却します。
@RestController
public class AuthController {
@Autowired
private UserService userService;
@Autowired
private TokenManager tokenManager;
@PostMapping("/auth/login")
public ResponseEntity<ApiResponse> authenticate(@RequestBody LoginRequest req) {
User user = userService.findByUsername(req.getUsername());
if (user == null || !user.getPassword().equals(req.getPassword())) {
return ResponseEntity.status(401).body(ApiResponse.error("認証失敗"));
}
String sessionToken = tokenManager.createSession(user.getId(), user.getUsername(), user.getRole());
return ResponseEntity.ok(ApiResponse.success().add("token", sessionToken));
}
}
@Component
public class AuthInterceptor implements HandlerInterceptor {
private static final String TOKEN_HEADER = "X-Auth-Token";
@Autowired
private TokenManager tokenManager;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
if (isPreflight(request)) {
handlePreflight(response);
return false;
}
if (handler instanceof HandlerMethod && ((HandlerMethod) handler).hasMethodAnnotation(IgnoreAuth.class)) {
return true;
}
String token = request.getHeader(TOKEN_HEADER);
if (token == null || !tokenManager.isValid(token)) {
writeUnauthorized(response);
return false;
}
SessionInfo session = tokenManager.getSession(token);
request.setAttribute("userId", session.getUserId());
request.setAttribute("userRole", session.getRole());
return true;
}
private void writeUnauthorized(HttpServletResponse response) throws IOException {
response.setStatus(401);
response.setContentType("application/json;charset=UTF-8");
try (PrintWriter out = response.getWriter()) {
out.print("{\"code\":401,\"msg\":\"未認証\"}");
}
}
}
データベース設計
セッション管理用のauth_sessionテーブルは、ユーザーID、トークン文字列、有効期限などを保持。トークンはUUID形式で生成され、セキュリティを確保します。
CREATE TABLE `auth_session` (
`session_id` BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT 'セッションID',
`user_id` BIGINT NOT NULL COMMENT 'ユーザーID',
`username` VARCHAR(64) NOT NULL,
`user_role` VARCHAR(32) NOT NULL COMMENT 'ロール',
`access_token` VARCHAR(128) UNIQUE NOT NULL COMMENT 'アクセストークン',
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
`expires_at` TIMESTAMP NOT NULL COMMENT '有効期限'
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- サンプルデータ
INSERT INTO `auth_session` VALUES
(101, 201, 'alice_reader', 'reader', 'tok_7x9a2mzq8nvp3kls0r4c6yb1e5wd9f', '2025-04-01 10:00:00', '2025-04-01 11:00:00'),
(102, 301, 'bob_admin', 'admin', 'tok_k9p2nvm7x4zc1rq8s5t3y6w0e2fa7b', '2025-04-01 10:05:00', '2025-04-01 11:05:00');
テスト戦略
主にブラックボックステストを実施。代表的なテストケースとして:
- ログイン機能:正しい資格情報でログイン成功、誤ったパスワードでエラーメッセージ表示、空のユーザー名でバリデーションエラー
- ユーザー管理:重複ユーザー登録時のエラー、必須項目未入力時の警告、削除確認ダイアログの表示
すべてのテストケースは、実際のユーザー体験を模倣し、UX観点からも検証を行っています。