1. サーバー統合の実装
1.1 プロジェクト準備
既存の学生情報管理システムをブラウザからアクセス可能なWebアプリケーションに改造します。
- 既存コードを現在のプロジェクトにコピー
- パッケージパスの不整合を修正
- HTTPリクエスト解析と動的リソース処理機能を実装
1.2 HTTPリクエスト処理クラス
URLパラメータを解析し、Map形式で管理するHttpRequestクラスを実装します。
public class HttpRequest {
private Map<String,String> queryParams = new HashMap<>();
public void parse() {
try {
SocketChannel channel = (SocketChannel) selectionKey.channel();
StringBuilder buffer = new StringBuilder();
ByteBuffer data = ByteBuffer.allocate(1024);
int length;
while((length = channel.read(data)) > 0) {
data.flip();
buffer.append(new String(data.array(), 0, length));
data.clear();
}
parseHttpRequest(buffer);
extractQueryParams();
} catch (IOException e) {
e.printStackTrace();
}
}
private void extractQueryParams() {
String uri = this.requestURI;
String[] parts = uri.split("\\?");
if(parts.length == 2) {
String[] params = parts[1].split("&");
for (String param : params) {
String[] keyValue = param.split("=");
if(keyValue.length == 2) {
queryParams.put(keyValue[0], keyValue[1]);
}
}
}
}
public String getParameter(String key) {
return queryParams.get(key);
}
}
1.3 動的リソースプロセッサ
リクエストURIからクエリパラメータを除去し、適切なServletを呼び出す処理を実装します。
public class DynamicResourceProcessor {
public void handle(HttpRequest request, HttpResponse response) {
String uri = request.getRequestURI();
String basePath = uri.split("\\?")[0];
HttpServlet servlet = ServletConcurrentHashMap.map.get(basePath);
if(servlet != null) {
servlet.service(request, response);
}
}
}
1.4 学生管理Servlet
学生情報のCRUD操作を行うServletを実装します。
@WebServlet(urlPatterns = "/api/student")
public class StudentServlet implements HttpServlet {
private StudentService service = new StudentService();
@Override
public void service(HttpRequest request, HttpResponse response) {
String action = request.getParameter("action");
switch(action) {
case "create":
createStudent(request, response);
break;
case "delete":
deleteStudent(request, response);
break;
case "update":
updateStudent(request, response);
break;
case "list":
listStudents(request, response);
break;
}
}
private void listStudents(HttpRequest request, HttpResponse response) {
Student[] students = service.getAllStudents();
StringBuilder output = new StringBuilder();
for (Student student : students) {
output.append(student.getId())
.append(", ")
.append(student.getName())
.append(", ")
.append(student.getAge())
.append(", ")
.append(student.getBirthday())
.append("<br>");
}
response.setContentType("text/html;charset=UTF-8");
response.write(output.length() > 0 ? output.toString() : "学生データがありません");
}
private void createStudent(HttpRequest request, HttpResponse response) {
String id = request.getParameter("id");
if(service.studentExists(id)) {
response.setContentType("text/html;charset=UTF-8");
response.write("IDが重複しています");
return;
}
try {
Student student = new Student();
student.setId(id);
student.setName(request.getParameter("name"));
student.setAge(Integer.parseInt(request.getParameter("age")));
student.setBirthday(request.getParameter("birthday"));
service.registerStudent(student);
response.setContentType("text/html;charset=UTF-8");
response.write("学生登録が完了しました");
} catch (Exception e) {
response.write("入力データに誤りがあります");
}
}
private void updateStudent(HttpRequest request, HttpResponse response) {}
private void deleteStudent(HttpRequest request, HttpResponse response) {}
}
2. 単体テスト
2.1 JUnitの基本利用
JUnitはJavaの主要な単体テストフレームワークです。
- オープンソースで利用可能
- アノテーションベースのテスト記述
- 開発効率と品質向上に貢献
2.2 テスト実装手順
- junit-4.9.jarをプロジェクトに追加
- publicで引数なしのvoidメソッドを作成
- @Testアノテーションでテストメソッドを識別
- JUnitランナーでテスト実行
public class CalculatorTest {
@Test
public void testAddition() {
int result = 10 + 20;
System.out.println(result);
}
}
2.3 ライフサイクルアノテーション
| アノテーション | 役割 |
|---|---|
| @Test | テストメソッドの識別 |
| @Before | 各テスト前に実行 |
| @After | 各テスト後に実行 |
public class LifecycleTest {
@Before
public void setup() {
System.out.println("初期化処理");
}
@Test
public void testCase() {
System.out.println("テスト実行");
}
@After
public void cleanup() {
System.out.println("後処理");
}
}
3. ログ管理
3.1 ログの重要性
アプリケーションの動作履歴を永続的に記録する仕組みです。
| 比較項目 | 標準出力 | ログ技術 |
|---|---|---|
| 無効化 | コード変更が必要 | 設定変更のみで可能 |
| 出力先 | コンソールのみ | ファイル・DBへの保存 |
| パフォーマンス | メインスレッドに影響 | 別スレッドでの記録 |
3.2 Log4jの基本構成
ApacheのOSSであるLog4jは柔軟なログ設定が可能です。
- 出力先の自由な指定(コンソール、ファイルなど)
- ログレベルによる出力制御
- 設定ファイルによる運用管理
3.3 基本実装
- Log4j関連ライブラリを導入
- log4j.properties設定ファイルを作成
- Loggerインスタンスを取得
- 必要なレベルでログ出力
# log4j.properties
log4j.rootLogger=debug,console,file
log4j.appender.console=org.apache.log4j.ConsoleAppender
log4j.appender.console.Target=System.out
log4j.appender.console.layout=org.apache.log4j.PatternLayout
log4j.appender.console.layout.ConversionPattern=%d %t %5p %c{1}:%L - %m%n
log4j.appender.file=org.apache.log4j.FileAppender
log4j.appender.file.File=/var/logs/app.log
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=%d %5p %c{1}:%L - %m%n
public class LoggingExample {
private static final Logger logger = LoggerFactory.getLogger(LoggingExample.class);
public static void main(String[] args) {
logger.debug("デバッグ情報");
logger.info("通常情報");
logger.warn("警告情報");
logger.error("エラー情報");
}
}
3.4 主要設定要素
3つのコアコンポーネント
- Loggers: ログレベル(DEBUG < INFO < WARN < ERROR < FATAL)
- Appenders: 出力先(org.apache.log4j.ConsoleAppender, FileAppender)
- Layouts: 出力形式(PatternLayoutが最も汎用的)
基本設定書式
log4j.rootLogger=ログレベル,出力先1,出力先2,...
3.5 アプリケーションへの適用
@WebServlet(urlPatterns = "/auth/login")
public class AuthenticationServlet implements HttpServlet {
private static final Logger logger = LoggerFactory.getLogger(AuthenticationServlet.class);
@Override
public void service(HttpRequest request, HttpResponse response) {
logger.info("認証リクエストを受信");
response.setContentType("text/html;charset=UTF-8");
response.write("認証成功");
logger.debug("認証レスポンスを送信完了");
}
}