【Java】primefacesを用いてjsfでフィードバック申し込みのページ作ってみました


アカペラの演奏の審査をしてきたが・・・
僕は究極の平等主義者です。
ハンムラビハンムラビ。

しかしそんなハンムラビにも悩み事があります。

オーディションの審査員を行うと
その日の夜から三日三晩Facebook, Twitter, LINEが
縦横無尽に鳴り続けフィードバッククレクレ族の
猛攻が始まるのです。

そこで今日はこんなシステムを作ってみました!


システム概要
スクリーンショット 2016-06-08 0.55.04

  1. webページからバンドがフィードバックを申請出来る
  2. 申請時にタイムスタンプがつくので綺麗に先着順で管理できる
  3. [文字列]_[バンド名].pdfでフィードバックシートを作ってアップロードするだけでバンドに自動でメールが飛ぶ
  4. メールが飛ぶと今度は返却日時にタイムスタンプがつくので綺麗に返却状況を管理出来る

まあ内部ロジックは至極単純なものでファイル名を読んでバンド名で照合をかけて
バンド名に対応するアドレスに定型文でメールを送っているだけです。

今日はこのシステムの①と②の機能の部分の作り方を
紹介したいなと思います!


使ったもの
Javaサーブレットのフレームワークは

  • javax.faces-2.2.9
  • primefaces4.0

DBは

  • mysql Ver 14.14 Distrib 5.6.27

です!
Javaのバージョンは1.8を利用しております!


xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
	xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
	id="PrimeFaces" version="3.0">
	<display-name>fantasia</display-name>

	<context-param>
		<param-name>primefaces.THEME</param-name>
		<param-value>bootstrap</param-value>
	</context-param>

	<servlet>
		<servlet-name>Faces Servlet</servlet-name>
		<servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
		<load-on-startup>1</load-on-startup>
	</servlet>

	<servlet-mapping>
		<servlet-name>Faces Servlet</servlet-name>
		<url-pattern>*.jsf</url-pattern>
	</servlet-mapping>

	<welcome-file-list>
		<welcome-file>./index.jsf</welcome-file>
	</welcome-file-list>
</web-app>

まずは定義ファイルですよね!
上から順にサーブレット名、フレームワークのテーマ、urlのパターン、何も指定しなかった際の遷移先ファイルを指定しています。
realm認証とかしたい場合はここにログインページやエラーページも書いて上げる事になりますが今日は割愛。


view(.xhtml)
今回バンド側に表示するページは
バンド名とメールアドレスを提出するだけのシンプルなものだったので
viewの制御は.xhtmlファイルに全てまとめて書いてしまいました。

<!DOCTYPE html>
<html xmlns="http://www.w3c.org/1999/xhtml"
	xmlns:h="http://java.sun.com/jsf/html"
	xmlns:f="http://java.sun.com/jsf/core"
	xmlns:p="http://primefaces.org/ui">
<h:head>
	<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
	<meta name="viewport"
		content="width=device-width,initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no" />
</h:head>
<h:body>
	<h:form>
		<p:growl id="growl" autoUpdate="true" />
		<h:panelGrid columns="3">
			<h:outputText value="バンド名" />
			<p:inputText id="bandname" required="true" requiredMessage="バンド名を入力してください"
				value="#{bandDao.bandname}" />
			<p:watermark for="bandname" value="バンド名" id="bandnamePH" />
			<h:outputText value="バンマス連絡先" />
			<p:inputText id="email" required="true" requiredMessage="メールアドレスを入れてください"
				validatorMessage="メールアドレスを入力してください" value="#{bandDao.email}">
				<f:validateRegex
					pattern="^[_A-Za-z0-9-\+]+(\.[_A-Za-z0-9-]+)*@[A-Za-z0-9-]+(\.[A-Za-z0-9]+)*(\.[A-Za-z]{2,})$" />
			</p:inputText>
			<p:watermark for="email" value="メールアドレス" id="emailPH" />
			<p:commandButton value="FB申込" update="growl, appInfo"
				actionListener="#{bandDao.register}"></p:commandButton>
			<p:commandButton value="順番確認" update="appInfo"
				actionListener="#{bandDao.getAppList}" immediate="true"></p:commandButton>
		</h:panelGrid>

		<p:fieldset legend="申請状況">
			<h:panelGrid columns="1" cellpadding="5">
				<h:outputText value="#{bandDao.appInfo}" id="appInfo" />
			</h:panelGrid>
		</p:fieldset>
	</h:form>
</h:body>
</html>

“:p”から始まっているのがprimefacesコンポーネントです。
個人的によろしくなかったと反省しているのが「順番確認」ボタン。
わざわざformを分けるのがダルかったのでimmediate=”true”で無理矢理動かしてます。

これは怒られちゃうやつですね・・・。
ちなみにファイルの一番上で各タグはどのコンポーネントなのか
明示してあげないと動かないので気をつけてください!


お豆ちゃん(bean)
サーバー側の処理を書くjavaファイルですね!

@Named
@RequestScoped
@ManagedBean(name = "bandDao")
public class BandDao implements Serializable {
	/**
	 * 
	 */
	private static final long serialVersionUID = 1804569931056271989L;
	private final static String INSERT = "INSERT INTO fantasia (bandname, email, appdate) values (?, ?, CURTIME())";
	private final static String SELECT_ALL = "select bandname, date_format(appdate,'%m/%e %H:%i'), submitdate from fantasia order by appdate";
	
	private String bandname;
	private String email;
	private ArrayList<String> appList = new ArrayList<String>();
	private String appInfo = "";
	
	public String getBandname() {
		return bandname;
	}
	public void setBandname(String bandname) {
		this.bandname = bandname;
	}
	public String getEmail() {
		return email;
	}
	public void setEmail(String email) {
		this.email = email;
	}	
	public String getAppInfo() {
		return appInfo;
	}
	public void setAppInfo(String appInfo) {
		this.appInfo = appInfo;
	}
	
	private Connection connect() throws SQLException {
		Connection con = null;
		String url = "jdbc:mysql://localhost/my_db";
		String user = "";
		String password = "";

		try {
			Class.forName("com.mysql.jdbc.Driver").newInstance();
			con = DriverManager.getConnection(url, user, password);
			con.setAutoCommit(false);
		} catch (ClassNotFoundException e) {
			System.out.println("ClassNotFoundException:" + e.getMessage());
		} catch (SQLException e) {
			System.out.println("SQLException:" + e.getMessage());
		} catch (Exception e) {
			System.out.println("Exception:" + e.getMessage());
		}
		
		return con;
	}
	
	FacesContext context = FacesContext.getCurrentInstance();

	public void register() throws SQLException {
		Connection con = null;
		PreparedStatement ps = null;
		ResultSet rs = null;
		try {
			con = connect();
			ps = con.prepareStatement(INSERT);
			ps.setString(1, bandname);
			ps.setString(2, email);
			ps.addBatch();
			if(ps != null){
				ps.executeBatch();
				con.commit();
				context.addMessage(null, new FacesMessage("【成功】" + bandname + "さんのFBを受け付けました。", "【成功】" + bandname + "さんのFBを受け付けました。"));
			}
		} finally {
			DbUtils.closeQuietly(con, ps, rs);
		}
		getAppList();
	}
	
	public void getAppList() throws SQLException {
		Connection con = null;
		PreparedStatement ps = null;
		ResultSet rs = null;
		try {
			con = connect();
			ps = con.prepareStatement(SELECT_ALL);
			rs = ps.executeQuery();
			while(rs.next()){
				String info = rs.getString(1)+"("+rs.getString(2)+")";
				if(rs.getString(3) != null){
					info = "<font color=\"#40AAEF\">" + info + "</font>";
				}
				appList.add(info);
			}
		} finally {
			DbUtils.closeQuietly(con, ps, rs);
		}
		StringBuffer sb = new StringBuffer();
		sb.append("<ol>");
		for(String tempInfo : appList){
			sb.append("<li>");
			sb.append(tempInfo);
			sb.append("</li>");
		}
		sb.append("</ol>");
		appInfo = sb.toString();
	}
}

DAOと言いつつDAOのやるべき事を越えている気もしますが・・・。
この程度の処理を書くのにjavaファイルを分ける気にもなれなかったので
1つのファイルにまとめてしまいました。

理想を言うとconnectionを生成するコードはファイルを分けたかったかなと。
そしてhtmlを生成して返す箇所はメソッドぐらいは切り分けても良かったかなと思います。

後はXSSのバリデーションを
facesコンポートネントに丸投げした良いのかと言う問題もありますが・・・。


まとめ
とりあえずさくっと作ってみました!
裏側で自動メール送信とかのロジックも書いているのですが
それはprimefacesとはあんまり関係ないのかなと思ったり。

jsfでサーブレットを書こうとすると
こまごまとした知識が無くてもかけてしまうので僕は非常に好きです。

そしてjspとちがって
.jspファイルにif文とかが直接書かれないので
なんでもかんでもviewに処理を書く糞コーダーが現れても
保守性が保ちやすいのではないでしょうか?


最後まで読んでいただきありがとうございます。もしこの記事を気に入って頂けたようであればシェアをお願い致します。非常に励みになります。


コメントを残す