なんとな~くしあわせ?の日記

「そしてそれゆえ、知識そのものが力である」 (Nam et ipsa scientia potestas est.) 〜 フランシス・ベーコン

JSTLを酷使して掲示板を作る

ちょっとJavaで掲示板みたいの作ってみた。

外観

































構成

eclipseWTPを使った。

ファイル名称   
Java_BBS                        
  ├──.classpath
  ├──build                        
  │    └──classes                        
  │         └──http                        
  │              └──bbs                        
  │                   └──main                        
  │                        ├──MainBBSServlet.class    
  │                        ├──PostedSentence.class
  │                        └──SetCharacterEncodingFilter.class
  ├──src                        
  │    └──http                        
  │         └──bbs                        
  │              └──main                           
  │                   ├──MainBBSServlet.java
  │                   ├──PostedSentence.java
  │                   └──SetCharacterEncodingFilter.java … たぶんeclipse使ってWEBアプリ作ろうとすると必ずぶち当たる文字化け問題。それを解決してくれるソース。
  └──WebContent                        
       ├──css                        
       │    └──bbs.css
       ├──img                        
       │    └──kabegami14.jpg
       ├──index.jsp
       ├──META-INF                        
       │    └──MANIFEST.MF
       └──WEB-INF                        
            ├──data                        
            ├──lib                        
            │    ├──commons-lang3-3.0.1.jar
            │    ├──commons-lang3-3.0.1-tests.jar
            │    ├──jstl.jar
            │    └──standard.jar
            └──web.xml

SetCharacterEncodingについては以下のサイトが詳しい。というかJavaの道さんとJSTLリファレンスのサイトにはかなりお世話になっています。
Javaの道:Struts(8.アクション・フォームBeanの日本語処理)
サーブレットのソースは以下

package http.bbs.main;

import java.beans.XMLDecoder;
import java.beans.XMLEncoder;
import java.io.*;
import java.util.*;
import javax.servlet.*;
import javax.servlet.http.*;
import org.apache.commons.lang3.RandomStringUtils;

/**
 * MainBBSServlet 掲示板の制御を行うクラス
 * 
 * @author Nantonaku-Shiawase 2011/10/22 Javaの練習用に作成 ver 1.0
 */
@SuppressWarnings("serial")
public class MainBBSServlet extends HttpServlet {
	
	final static String FILE_PATH = "WEB-INF/data/bbs.dat";
	
	private List<PostedSentence> chatList;
	
	// サーブレット初期化の際に今まで書きこまれた投稿のデータを読み込む
	public void init() throws ServletException {
		chatList = new Vector<PostedSentence>();
		
		File file = getDataFile();
		
		if ( file.exists()) {
			try {
				InputStream in = new FileInputStream(file);
				XMLDecoder decoder = new XMLDecoder(in);
				chatList = (List<PostedSentence>) decoder.readObject();
				decoder.close();
			} catch ( FileNotFoundException e) {
				throw new ServletException(e);
			}
		}
	}

	// doGetは必ずいるんです
	public void doGet(HttpServletRequest req, HttpServletResponse res)
			throws ServletException, IOException {
		doPost(req, res);
	}

	// メインのPostメソッド
	public void doPost(HttpServletRequest req, HttpServletResponse res)
			throws ServletException, IOException {

		res.setContentType("text/html; charset=windows-31j");
		
		if (req.getParameter("sentence").isEmpty()) {
			// 本文に何も入っていいなければ門前払い
			RequestDispatcher dispatcher = req.getRequestDispatcher("index.jsp");
			dispatcher.forward(req, res);
			
		} else {
		// 投稿された内容を納めるクラス
		PostedSentence ps = new PostedSentence();
		
		// 一つ目の要素は名前
		if ( req.getParameter("name").isEmpty() ) {
			ps.add("名無しさん@涙目です");
		} else {
			ps.add(req.getParameter("name"));
		}
		// 2つめの要素はメール欄
		if ( req.getParameter("mail").isEmpty() ) {
			ps.add("[]");
		} else {
			ps.add("[" + req.getParameter("mail") + "]");
		}
		// 3つめは時間
		ps.add(getTime());
		// 4つめはID
		ps.add("ID:" + getID());
		// 5つめは本文
		ps.add(req.getParameter("sentence"));
		// 6・7は記録用…ユーザーエージェントとIPアドレス
		ps.add(req.getHeader("user-agent"));
		ps.add(req.getRemoteAddr());
		
		chatList.add(ps);
		
		// アプリケーションスコープでデータを拾えるように設定
		ServletContext application = getServletContext();
		application.setAttribute("chatList", chatList);
		// 掲示板のインデックスページに転送
		RequestDispatcher dispatcher = req.getRequestDispatcher("index.jsp");
		dispatcher.forward(req, res);
		
		}// 長いelse文になってしまった
	}
	
	public void destroy () {
		File file = getDataFile();
		try {
			OutputStream out = new FileOutputStream(file);
			XMLEncoder encoder = new XMLEncoder(out);
			encoder.writeObject(chatList);
			encoder.close();
		} catch ( IOException e) {
			e.printStackTrace();
		}
	}
	
	// ファイルのパスを確認してオブジェクトで返すメソッド
	private File getDataFile() {
		String path = getServletContext().getRealPath(FILE_PATH);
		return new File(path);
	}
	
	// 投稿日を取得するメソッド
	private String getTime() {
		Calendar cal = Calendar.getInstance();
		
	    int year = cal.get(Calendar.YEAR);
	    int month = cal.get(Calendar.MONTH) + 1;
	    int day = cal.get(Calendar.DATE);
	    int hour = cal.get(Calendar.HOUR_OF_DAY);
	    int minute = cal.get(Calendar.MINUTE);
	    int second = cal.get(Calendar.SECOND);
	    
	    StringBuffer dow = new StringBuffer();
	    switch (cal.get(Calendar.DAY_OF_WEEK)) {
	      case Calendar.SUNDAY: dow.append("日"); break;
	      case Calendar.MONDAY: dow.append("月"); break;
	      case Calendar.TUESDAY: dow.append("火"); break;
	      case Calendar.WEDNESDAY: dow.append("水"); break;
	      case Calendar.THURSDAY: dow.append("木"); break;
	      case Calendar.FRIDAY: dow.append("金"); break;
	      case Calendar.SATURDAY: dow.append("土"); break;
	    }
	    return ("投稿日:" + year + "/" + month + "/" + day + " (" + dow + ") " + hour + ":" + minute + ":" + second);
	}
	
	// ランダムなIDを取得して返すメソッド
	private String getID () {
		RandomStringUtils rs = new RandomStringUtils();
		return rs.random(9,"0123456789qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM+/");
	}
	
}

そして問題のJSPファイルは以下

<%@ page language="java" contentType="text/html; charset=windows-31j"
    pageEncoding="windows-31j"%>
<%@ page import="java.util.*" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<jsp:useBean id="bean" class="http.bbs.main.MainBBSServlet" scope="application"/>
<c:set var="chatList" value="${ chatList }" scope="application" property="List" />

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=windows-31j">
<link rel="stylesheet" href="css/bbs.css" type="text/css">
<title>掲示板トップ</title>
</head>
<body background="img/kabegami14.jpg">
<!-- 全体を中央寄せにします -->
<div id="wrapper">
<h2>掲示板トップ</h2>


<div class="formbox"><form action="<%= request.getContextPath() %>/MainBBSServlet" method="post" id="BBSform">
	名前: <input type="text" name="name"> メール: <input type="text" name="mail"><br><br>
	本文: <input type="text" name="sentence" style="height: 90px; width: 450px">
	<input type="submit" value="書き込み" ></input><br><br>
</form></div>

<div id="thread" class="bbs_box">
	<h3>スレッド一覧</h3>
	<span><a href="http://www.google.com">http://www.google.com</a></span><br>
	<span>ダミーですが何か?</span><br>
</div>

<div id="postedcontent" class="formbox">
	<table>
		<c:forEach var="objParent" items="${chatList}"  varStatus="sttParent">
			<table>
			<tr id="<c:out value="${sttParent.index}"/>"> 
				<c:forEach begin="0" end="4" step="1" var="objChild" items="${objParent}" varStatus="sttChild">
				      <c:if test="${sttChild.index  == 4}"><tr></c:if>
					  <td><c:if test="${sttChild.index  == 0}"><c:out value="${sttParent.index +1 }"/></c:if><c:out value="${objChild}"/>
					  <c:if test="${sttChild.index  == 4}"></tr></c:if>
				</c:forEach>
			</tr>
			</table>
		</c:forEach>
	</table>
</div>

</div>
</body>
</html>
  • ポイント

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>

この部分でクラスとスコープを宣言して書き込みのリストを拾えるようにしておく
そして読み手無視のJSTL

		<c:forEach var="objParent" items="${chatList}"  varStatus="sttParent"> ← 入れ子になったリストを取り出す
			<table>
			<tr id="<c:out value="${sttParent.index}"/>"> 
				<c:forEach begin="0" end="4" step="1" var="objChild" items="${objParent}" varStatus="sttChild"> ← オブジェクトの5,6番目はユーザーに見せない
				      <c:if test="${sttChild.index  == 4}"><tr></c:if>
	                              <td><c:if test="${sttChild.index  == 0}"><c:out value="${sttParent.index +1 }"/></c:if><c:out value="${objChild}"/>
			              <c:if test="${sttChild.index  == 4}"></tr></c:if>
				</c:forEach>
			</tr>
			</table>
		</c:forEach>

この本はよかった。ありがてえ。

基礎からのサーブレット/JSP 改訂版 (プログラマの種シリーズ)

基礎からのサーブレット/JSP 改訂版 (プログラマの種シリーズ)

次はPerlで同じ物をつくりたいですなあ。