なんじゃくにっき

プログラミングの話題中心。

Rhinoを使ってサーバーサイドでJavaからJavaScriptの関数を使う(2)

 一昨日の記事ではHello Worldしかやらなかったので続き。
 
 郵便番号の妥当性チェックを、クライアント側とサーバー側で共通のjsを使って行う。

 あくまでも最終的なデータの保証をするのはサーバー側で、
クライアント側でチェックを行うのは操作性アップのため
(サーバーといちいちやり取りしなくてもデータの検証が出来るとストレスが溜まらない)。
 
 とはいっても、この件に関しては、通常はクライアントサイドでの検証が十分なら
サーバー側で弾かれるということはない(はず)。
但し、直リクエストされたりすると予期していない形のデータが送られてくることがあるので
サーバー側でのチェックは外せない。 ・・という思想で行く。

 御託が長くなったが、以下、ソース。

 


/js/postalcodeutil.js
function isValidPostalCode( postalcode ){
return (postalcode.match(/^\d{3}-?\d{4}$/));
}
 
 ただ正規表現にマッチするかどうかJavaScriptで調べるだけ。
これくらいのものならわざわざRhino使わずにJavaで書いたほうが楽だが、あくまでサンプルってことで。
 

index.jsp(入力画面)
POSTする前にJavaScriptで妥当性チェック。
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8" />
<meta http-equiv="Content-Style-Type" content="text/css" />
<meta http-equiv="Content-Script-Type" content="text/JavaScript" />
<script type="text/javascript" src="js/postalcodeutil.js"></script>
<script type="text/javascript">
<!--
function onSendButtonClick(){
if (isValidPostalCode(document.getElementById("PostalCodeEdit").value))
document.Form1.submit();
else
alert("NG");
}
// -->

</script>
</head>
<body>

<form name="Form1" method="POST" action="postalcode">
<table>
<tr>
<td>Postal Code:<td>
<td><input type="text" id="PostalCodeEdit" name="postalcode"
maxlength="8" size="8"/>
</td>
</tr>
<tr>
<td>Address:<td>
<td><input type="text" id="AddressEdit" name="address"
maxlength="40" size="40"/>
</td>
</tr>
<tr>
<td><td>
<td><input type="button" name="SendButton" value="send" onClick="onSendButtonClick()"></td>
</tr>
</table>
</form>

</body>
</html>

 
 

Pageクラス
package examples.page;

import javax.servlet.ServletContext;

import org.t2framework.commons.util.Logger;
import org.t2framework.t2.annotation.composite.GET;
import org.t2framework.t2.annotation.composite.POST;
import org.t2framework.t2.annotation.core.Default;
import org.t2framework.t2.annotation.core.Form;
import org.t2framework.t2.annotation.core.Page;
import org.t2framework.t2.navigation.Forward;
import org.t2framework.t2.spi.Navigation;

import examples.dto.PostalcodeDTO;
import examples.util.PostalcodeUtil;

@Page("/postalcode")
public class PostalCodePage {
@SuppressWarnings("unused")
private static Logger logger = Logger.getLogger(PostalCodePage.class);

@GET
@Default
public Navigation get(){
return Forward.to("/WEB-INF/pages/index.jsp");
}

@POST
public Navigation post(final @Form PostalcodeDTO dto,
final ServletContext context) throws Exception{
PostalcodeUtil util = PostalcodeUtil.getInstance();
util.setJSPath(context.getRealPath("js/postalcodeutil.js"));

if (util.isValidPostalCode(dto.getPostalcode())){
/*
* 正常時の処理をここに処理を書く
*/

} else {
/*
* エラー時の処理をここに処理を書く
*/

}

return Forward.to("/WEB-INF/pages/result.jsp");
}
}

T2の@Formが便利。 
 

DTOクラス(Formで送信されるData Transfer Object)
package examples.dto;

import java.io.Serializable;

public class PostalcodeDTO implements Serializable {
private static final long serialVersionUID = 1L;
private String postalcode;
private String address;

public void setPostalcode(String postalcode) {
this.postalcode = postalcode;
}
public String getPostalcode() {
return postalcode;
}
public void setAddress(String address) {
this.address = address;
}
public String getAddress() {
return address;
}
}

 


Rhinoを扱うクラス
package examples.util;

import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.InputStreamReader;

import org.mozilla.javascript.Context;
import org.mozilla.javascript.Function;
import org.mozilla.javascript.Scriptable;

public class RhinoUtil {
private Context context;
private Scriptable scope;

public RhinoUtil(String realpath) throws Exception{
context = Context.enter();
FileInputStream is = new FileInputStream(realpath);
BufferedReader reader =
new BufferedReader(new InputStreamReader(is, "UTF8"));

scope = context.initStandardObjects();
context.evaluateReader(scope, reader, "<cmd>", 1, null);
reader.close();
is.close();
}

public Object execJSFunction(String functionname, Object functionArgs[])
throws Exception{

Object function = scope.get(functionname, scope);
if (!(function instanceof Function))
throw new RuntimeException("there is no function named " + functionname);

return ((Function)function).call(context, scope, scope, functionArgs);
}
}

 
  

妥当性チェックのためのクラス
初回インスタンス化時のみjsを読み込むようにする。
package examples.util;

import org.mozilla.javascript.Context;
import org.t2framework.commons.util.Logger;

import examples.page.IndexPage;

public class PostalcodeUtil {
@SuppressWarnings("unused")
private static Logger logger = Logger.getLogger(IndexPage.class);

private static PostalcodeUtil instance = new PostalcodeUtil();

public static PostalcodeUtil getInstance() {
return instance;
}

private RhinoUtil rhinoutil = null;

public void setJSPath(String realpath) throws Exception{
if (rhinoutil != null)
return;
else
rhinoutil = new RhinoUtil(realpath);
}

public boolean isValidPostalCode(String postalcode) throws Exception{
Object functionArgs[] = {postalcode};
Object result = rhinoutil.execJSFunction("isValidPostalCode", functionArgs);
return Context.toBoolean(result);
}
}