システム概要
本システムは、自習室の座席予約、利用時間管理、ユーザ認証を統合的に管理するWebアプリケーションです。バックエンドにはSpringBootフレームワークを採用し、フロントエンドにはVue.jsを使用したモダンなアーキテクチャを実現しています。RESTful API設計により、拡張性とメンテナンス性を高めています。
バックエンドアーキテクチャ
Java17とSpringBoot 3.xをコア技術として採用しています。依存性注入(DI)とアスペクト指向プログラミング(AOP)を活用したレイヤードアーキテクチャにより、ビジネスロジックとデータアクセス層を明確に分離しています。セキュリティにはJWTトークンベースの認証方式を実装し、パスワードはBCryptアルゴリズムでハッシュ化して保存します。
認証API実装例
以下に、会員認証機能のコントローラ実装を示します。トークン生成、パスワード検証、ロールベースアクセス制御を含む完全な認証フローです。
/**
* 会員管理エンドポイント
*/
@RestController
@RequestMapping("/api/members")
public class AccountManagerController {
@Autowired
private AccountService accountService;
@Autowired
private SessionService sessionService;
/**
* 認証処理
*/
@PostMapping("/auth")
public ResponseEntity<AuthResult> authenticate(@RequestBody CredentialDto loginInfo) {
MemberAccount account = accountService.findByLoginId(loginInfo.getLoginId());
if (account == null) {
return ResponseEntity.status(HttpStatus.UNAUTHORIZED)
.body(new AuthResult("アカウントが存在しません"));
}
if (!account.getUserRole().equals(loginInfo.getRole())) {
return ResponseEntity.status(HttpStatus.FORBIDDEN)
.body(new AuthResult("ロール権限が一致しません"));
}
if (!PasswordEncoder.matches(loginInfo.getPassword(), account.getCredential())) {
return ResponseEntity.status(HttpStatus.UNAUTHORIZED)
.body(new AuthResult("認証情報が不正です"));
}
String jwtToken = sessionService.createToken(account.getAccountId(),
account.getLoginId(),
account.getUserRole());
return ResponseEntity.ok(new AuthResult(jwtToken, "認証成功"));
}
/**
* アカウント新規登録
*/
@PostMapping("/register")
public ResponseEntity<String> createAccount(@RequestBody MemberAccount newAccount) {
if (accountService.existsByLoginId(newAccount.getLoginId())) {
return ResponseEntity.badRequest().body("ログインIDは既に使用されています");
}
newAccount.setCredential(PasswordEncoder.encode(newAccount.getCredential()));
accountService.save(newAccount);
return ResponseEntity.ok("アカウント作成完了");
}
/**
* セッション終了
*/
@PostMapping("/logout")
public ResponseEntity<String> terminateSession(HttpServletRequest request) {
String token = request.getHeader("Authorization");
sessionService.invalidateToken(token);
return ResponseEntity.ok("ログアウト処理完了");
}
/**
* パスワード再発行
*/
@PutMapping("/credentials/reset")
public ResponseEntity<String> restoreCredentials(@RequestParam String loginId) {
MemberAccount target = accountService.findByLoginId(loginId);
if (target == null) {
return ResponseEntity.notFound().build();
}
String temporaryPassword = PasswordGenerator.createTemporaryPass();
target.setCredential(PasswordEncoder.encode(temporaryPassword));
accountService.update(target);
return ResponseEntity.ok("一時パスワード: " + temporaryPassword);
}
/**
* ページネーション付き一覧取得
*/
@GetMapping("/list")
public ResponseEntity<PageResult<MemberAccount>> fetchList(
@RequestParam Map<String, Object> conditions,
@RequestParam(defaultValue = "1") int page,
@RequestParam(defaultValue = "10") int size) {
PageRequest pageable = PageRequest.of(page - 1, size);
Page<MemberAccount> result = accountService.searchWithConditions(conditions, pageable);
return ResponseEntity.ok(PageResult.from(result));
}
/**
* アカウント詳細取得
*/
@GetMapping("/details/{accountId}")
public ResponseEntity<MemberAccount> fetchDetails(@PathVariable Long accountId) {
return ResponseEntity.ok(accountService.findById(accountId));
}
/**
* 現在のセッション情報
*/
@GetMapping("/current-session")
public ResponseEntity<MemberAccount> fetchCurrentSession(HttpServletRequest request) {
Long currentUserId = (Long) request.getAttribute("authenticatedUserId");
return ResponseEntity.ok(accountService.findById(currentUserId));
}
/**
* アカウント情報更新
*/
@PutMapping("/modify")
public ResponseEntity<String> modifyAccount(@RequestBody MemberAccount updates) {
accountService.updateSelective(updates);
return ResponseEntity.ok("更新処理完了");
}
/**
* 一括削除
*/
@DeleteMapping("/batch-remove")
public ResponseEntity<String> removeAccounts(@RequestBody List<Long> targetIds) {
accountService.deleteByIdList(targetIds);
return ResponseEntity.ok("削除処理完了");
}
}
データベース設計
データ永続化層にはMySQL 8.0を採用し、InnoDBストレージエンジンを使用しています。読み取り/書き込み分離とインデックス最適化を実施し、同時接続500件を想定したパフォーマンスチューニングを行っています。
会員アカウントテーブル定義
-- 会員管理テーブル
DROP TABLE IF EXISTS `member_accounts`;
CREATE TABLE `member_accounts` (
`account_id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 'アカウント識別子',
`login_id` VARCHAR(50) NOT NULL UNIQUE COMMENT 'ログイン用ID',
`credential` VARCHAR(255) NOT NULL COMMENT 'ハッシュ化パスワード',
`user_role` ENUM('STUDENT', 'ADMIN', 'GUEST') NOT NULL DEFAULT 'STUDENT' COMMENT 'ユーザロール',
`email` VARCHAR(100) COMMENT '連絡先メール',
`account_status` TINYINT NOT NULL DEFAULT 1 COMMENT 'ステータス(1:有効 0:無効)',
`created_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '作成日時',
`updated_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新日時',
PRIMARY KEY (`account_id`),
KEY `idx_login_id` (`login_id`),
KEY `idx_role_status` (`user_role`, `account_status`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='会員アカウント管理テーブル';
-- 初期管理ユーザ
INSERT INTO `member_accounts`
(`login_id`, `credential`, `user_role`, `email`, `account_status`)
VALUES
('admin', '$2a$10$N.zmdr9k7uOCQb376NoUnuTJ8iAt6Z5EHsM8lE9lBaWVaN1oT7uWm', 'ADMIN', 'admin@studyroom.local', 1);
フロントエンド実装
Vue.js 3とTypeScript、Viteビルドツールを採用しています。Piniaによる状態管理とVue Routerによるルーティング管理を実装し、Element Plus UIフレームワークで一貫したユーザーインターフェースを提供します。Axiosを使用したAPIクライアントにはリクエスト/レスポンスインターセプターを設定し、トークンの自動付与とエラーハンドリングを集中管理しています。
主要機能モジュール
- 座席管理: リアルタイム座席状況表示、予約・解放処理、利用時間監視
- 予約スケジューラ: 時間帯別予約制限、重複予約防止、キャンセル待ち機能
- 利用料金計算: 時間単位料金算出、割引ルール適用、請求書生成
- アクセス制御: QRコード入退室管理、顔認証連携、不正利用検知
- 統計分析: 利用頻度分析、収益レポート、混雑予測グラフ
本システムはマイクロサービスアーキテクチャへの拡張も見据え、Dockerコンテナ化とKubernetesオーケストレーション対応を前提に設計されています。APIゲートウェイ経由でのサービス連携と、Redisによるキャッシュ戦略の導入により、今後の大規模展開に柔軟に対応可能です。