はじめに
今回はStruts2を利用した、より実践的なアプリケーションの作成をおこなってみたいと思います。今回も前回と同様、ZeroConfigurationで開発をおこなっています。
アプリケーションの概要
このアプリケーションは、シンプルな掲示板アプリケーションです。
複数の端末から共通の掲示板に情報を書き込み、その内容を共有するという単純なものです。情報には、投稿者の名前とメッセージ、そして投稿日時と投稿した端末のIPアドレスを自動で取得した内容が含まれます。
アプリケーションの仕様について簡単にまとめます
掲示板のURLにアクセスすると現在の掲示板の情報が一覧表示されます。
“更新”ボタンを押すと、掲示板の情報が最新表示されます。
掲示板の情報は、投稿日が新しいものから順に表示されます。
“名前”と”メッセージ”を任意に入力し、”投稿”ボタンを押すと、掲示板に情報が
登録され、掲示板の内容が最新表示されます。
“名前”、”メッセージ”のいずれかが未入力の場合はエラーメッセージが表示され
掲示板に情報は登録されません。
アプリケーション画面
ソースコード解説
シンプルな機能の掲示板ではありますが、アプリケーションとしてはMVCモデルを意識し、今後の拡張性も含めながら作成してみました。
モデル
BoardData .java
掲示板へ登録する情報を格納するデータを保持するクラスです。
データの保持以外の機能は特にありません。
package com.pg2se.sample.model.board;
public class BoardData {
private String postDate;
private String name;
private String message;
private String remoteAddress;
public String getPostDate() {
return postDate;
}
public void setPostDate(String postDate) {
this.postDate = postDate;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public String getRemoteAddress() {
return remoteAddress;
}
public void setRemoteAddress(String remoteAddress) {
this.remoteAddress = remoteAddress;
}
}
Board.java
複数の端末で共有する掲示板のオブジェクトと掲示板に情報を登録する機能を持ったクラスです。
package com.pg2se.sample.model.board;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.Vector;
public class Board {
private static List<BoardData> board = new Vector<BoardData>();
private static SimpleDateFormat sdformat = new SimpleDateFormat(“yyyy/MM/dd HH:mm:ss”);
public static List<BoardData> addChatData(String name, String message, String remoteAddress){
BoardData data = new BoardData();
data.setName(name);
data.setMessage(message);
data.setRemoteAddress(remoteAddress);
data.setPostDate(sdformat.format(new Date()));
board.add(0, data);
return board;
}
public static List<BoardData> getChatData(){
return board;
}
}
ビュー
board/board.jsp
掲示板への情報の投稿と掲示板の情報の表示をおこないます。
入力エラーの内容は<s:actionerror/>タグによって出力されます。
“ValueStack”をコードで記述している部分ですが、board.jspをアドレスに指定されて呼び出された場合にアクションが呼び出されず掲示板の最新情報が取得できていないため無理やり取得しています。Struts1の場合は、フォームに関連付けられたformbeanが初期化されるため初期表示も可能だったんですが…。もっと良い方法あればいいんですが。
また、”remoteAddress”をここで取得していますが詳細は後述します。
ボタンは情報投稿用のボタンと、最新情報取得用の更新ボタンがありますが、method属性を指定して、呼び出すアクションクラスのメソッドを指定できます。
<!DOCTYPE html PUBLIC “-//W3C//DTD HTML 4.01 Transitional//EN” “http://www.w3.org/TR/html4/loose.dtd”>
<%@page language=”java” contentType=”text/html; charset=UTF-8″ pageEncoding=”UTF-8″%>
<%@page import=”com.pg2se.sample.model.board.Board”%>
<%@page import=”com.opensymphony.xwork2.util.ValueStack”%>
<%@page import=”org.apache.struts2.ServletActionContext”%><html>
<%@taglib prefix=”s” uri=”/struts-tags” %>
<head>
<meta http-equiv=”Content-Type” content=”text/html; charset=UTF-8″>
<title>シンプル掲示板</title>
</head>
<body>
<h1>シンプル掲示板</h1>
<h2>struts2で作成するサンプルアプリケーション</h2><hr/>
<s:form action=”board.action” theme=”simple”>
<input type=”hidden” name=”remoteAddress” value=”<%= request.getRemoteAddr() %>”/>
<s:text name=”名前”/> <s:textfield name=”name” size=”10″/>
<s:text name=”メッセージ”/> <s:textfield name=”message” size=”60″ value=””/>
<s:submit value=”投稿”/><s:submit value=”更新” method=”update”/>
</s:form><hr/>
<s:actionerror/>
<table border=”1″>
<%
ValueStack stack = (ValueStack)request.getAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY);
if(stack!=null && stack.findValue(“data”)==null){
stack.set(“data”, Board.getChatData());
}
%>
<s:iterator value=”data” status=”stat”>
<s:if test=”#stat.first”>
<th>日時</th>
<th>名前</th>
<th>テキスト</th>
<th>IPアドレス</th>
</s:if>
<tr>
<td><s:property value=”postDate”/></td>
<td><s:property value=”name”/></td>
<td><s:property value=”message”/></td>
<td><s:property value=”remoteAddress”/></td>
</tr>
</s:iterator>
</table>
</body>
</html>
コントローラ
BoardAction.java
掲示板の情報の登録と最新表示をおこなうためのアクションです。
メッセージの投稿用にはデフォルトのアクションexecuteメソッドを、最新情報取得用のアクションにはupdateを使用します。
ActionSupportクラスを継承することで、validation(バリデーション:検証)やメッセージ・エラーメッセージを簡単に設定することができます。validateメソッドを実装するだけでよいのですが今回は使用しませんでした。理由は、validateメソッドはすべてのアクションに対して実行されてしまうため、今回バリデーションの必要がないupdateメソッドに適用されたくなかったためです。今回は自前のisValidメソッドで検証をおこなっています。※xmlファイルでバリデーションの定義をする場合は検証を除外するメソッドを設定できたりするようです。他にも方法はあるようなのですがわかりませんでした、
“remoteAddress”についてはjspファイルから渡されるようにしています。本来はアクションクラスで、requestオブジェクトから取得したいのですがActionSupportクラスからは取得できないようです。取得するためには、ServletRequestAwareインターフェイスを実装する必要があります。そうすると実行時にHttpServletRequestオブジェクトが注入されるようです。
今後の拡張として、掲示板の情報の編集・削除等のメンテナンスや掲示板の情報をデータベースへ保存し永続化するという点が考えられます。
package com.pg2se.sample.action.board;
import java.util.List;
import com.opensymphony.xwork2.ActionSupport;
import com.pg2se.sample.model.board.Board;
import com.pg2se.sample.model.board.BoardData;
public class BoardAction extends ActionSupport {
private String name;
private String message;
private String remoteAddress;
private List<BoardData> data;
private static final long serialVersionUID = 1L;
public String getName() {return name;}
public void setName(String name) { this.name = name;}
public String getMessage() {return message;}
public void setMessage(String message) {this.message = message;}
public String getRemoteAddress() {return remoteAddress;}
public void setRemoteAddress(String remoteAddress) {this.remoteAddress = remoteAddress;}
public List<BoardData> getData() {return data; }
public void setData(List<BoardData> data) {this.data = data;}
//execute
public String execute() {
if(isValid()){
data = Board.addChatData(name, message, remoteAddress);
} else {
data = Board.getChatData();
}
return “success”;
}
//update
public String update() {
data = Board.getChatData();
return “success”;
}
//validate
public boolean isValid() {
if(name == null || name.equals(“”)){
addActionError(“名前を入力してください”);
}
if(message == null || message.equals(“”)){
addActionError(“メッセージを入力してください”);
}
return !hasActionErrors();
}
}