- 追加された行はこの色です。
- 削除された行はこの色です。
// 下階層用テンプレート
#topicpath
----
//ここにコンテンツを記述します。
#contents
WEB開発で必ずついて回るのが、Submitボタン二度押しや戻るボタンを押されるなど、勝手な画面遷移をされないような配慮です。Strutsでは同期トークンという機能でこれらの考慮をサポートしてくれます。
実際にサンプルで、ある画面でSubmitを二度押ししたとき、それを検知して二つ目のリクエストをエラーではじくという事を考えてみます。
**同期トークンとは [#n88a5573]
同期トークンの機能とは以下の通りです。
+あるアクションで、サーバ上でユニークなID(以下、トークン)を生成し、返却するhtmlにhidden等で仕込んでおく
+そのアクションで、トークンはSessionにも格納しておく
+次のリクエストにはhidden内のトークンが飛んでくる
+次のアクションで、hiddenパラメタ内のトークンとSessionのトークンが等しいことを確認する
+等しければ、正しいリクエストということで処理する。Session内のトークンを新しいモノに書き換え、hiddenで返すトークンもその新しいモノにする。等しくなければ、正規のリクエストではないということで、エラー処理する。
+以下繰り返し。
この中で、トークンの生成、トークンチェック、hiddenにトークンを書き出す、などはStrutsが自動でやってくれますので、使う側はトークンをチェックするメソッドをアクションクラスに記述したり、エラー処理だけをやっておけばよいと言うことですね。ラクチンです。
**やってみる [#ee906f33]
***流れ [#c64313a1]
index.do -> IndexAction -> index.jsp -> double.do -> DoubleAction -> success.jsp
という流れのサンプルです。
***ソース [#c08839fb]
-IndexAction
public ActionForward execute(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response)
throws Exception {
saveToken(request);
return mapping.findForward("success");
}
-index.jsp
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<%@ page language="java" contentType="text/html; charset=UTF-8" %>
<%@ taglib uri="http://struts.apache.org/tags-bean" prefix="bean" %>
<%@ taglib uri="http://struts.apache.org/tags-html" prefix="html" %>
<%@ taglib uri="http://struts.apache.org/tags-logic" prefix="logic" %>
<%@page import="org.apache.struts.Globals"%>
<html:html xhtml="true" lang="true">
<head>
<title>同期トークンの稼動確認JSP</title>
<meta http-equiv="Content-Type" content="application/xhtml+xml; charset=UTF-8" />
<html:base />
</head>
<body>
<html:form method="post" action="/double" >
<html:submit />
</html:form>
<%=session.getAttribute(Globals.TRANSACTION_TOKEN_KEY) %>
</body>
</html:html>
-DoubleAction
public ActionForward execute(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response)
throws Exception {
ActionMessages errors = new ActionMessages();
HttpSession session = request.getSession();
boolean tokenValid = false;
synchronized (session) {
tokenValid = isTokenValid(request);
saveToken(request);
}
if (!tokenValid) {
StringBuffer buffer = new StringBuffer();
buffer.append("tokenチェックエラー");
errors.add(ActionMessages.GLOBAL_MESSAGE, new ActionMessage(
new String(buffer), false));
saveErrors(request, errors);
}
}
***セッションにトークンをセット [#n9e5325d]
IndexActionでSessionにトークンをセットしています。トークンを生成してSessionにセットするメソッドは
org.apache.struts.action.Action#saveToken
です((中ではsessionIdをMD5でハッシュして、更に現在時刻でハッシュしているみたいです))((Sessionにセットされるときのキー値は"org.apache.struts.action.TOKEN"です。この定数値はorg.apache.struts.Globals.TRANSACTION_TOKEN_KEYで取得可能です。))。
***JSPのhiddenにトークンをセット [#m937a884]
index.jspではformを使ってSubmitしていますが、出力されるhtmlには自動的にhiddenタグが挿入されます。具体的にはSubmitのformは
<html:form method="post" action="/double" >
<html:submit />
</html:form>
としているだけなのですが出力されるhtmlは
<form id="hogeForm" method="post" action="/strutsExamples/double.do">
<div><input type="hidden" name="org.apache.struts.taglib.html.TOKEN"
value="612326e14b3ce599284543e2246f170b" /></div>
<input type="submit" value="Submit" />
</form>
となります。あるキー値でhiddenにトークンがセットされています((hiddenの定数値"org.apache.struts.taglib.html.TOKEN" はorg.apache.struts.Globals.TOKEN_KEYで取得可能です。))。
***次のリクエストで、サーバでトークンのチェック [#k368ed90]
さてこれでsessionにトークンがセットされ、さらにhtmlのhiddenにトークンがセットされました。次のリクエストを受けるアクション(DoubleAction)では
synchronized (session) {
tokenValid = isTokenValid(request);
saveToken(request);
}
if (!tokenValid) {
StringBuffer buffer = new StringBuffer();
buffer.append("tokenチェックエラー");
errors.add(ActionMessages.GLOBAL_MESSAGE, new ActionMessage(
new String(buffer), false));
saveErrors(request, errors);
}
となっています。
isTokenValid(request);
がSessionのトークンとhiddenのトークンをチェックするメソッドです。で、次の
saveToken(request);
で再度トークンを書き換えています。
isTokenValid(request)はスレッドセーフですが、トークンを変更するまでスレッドセーフでなくてはいけないので、sessionインスタンスのモニタを取得して処理しています((スレッドセーフなメソッドを用意しておいてくれてもいいような、、、))。
**Formでなく<html:link />の場合 [#e1cadcc0]
上の例のように<html:form />タグの場合は自動でhiddenタグが挿入されトークンがPostされましたが、<html:link />タグなどの場合は
<html:link action="/double" transaction="true">リンク</html:link>
としてtransaction属性をtrueに指定します。transaction属性を指定すると
http://localhost:8080/strutsExamples/double.do
?org.apache.struts.taglib.html.TOKEN=f8e8901ab4cc126a148fe3d46d5596e7
とパラメタにトークンが設定されます。ちなみにこのtransaction属性はデフォルトはfalseなので、トークンを送信したい場合は明示的に指定してあげる必要があります。
**サンプル。 [#kf462253]
-[[サンプルプログラム(ViewVC)>http://www.masatom.in/cgi-bin/viewvc.cgi/tags/V1.0.0_20080120_01/strutsExamples/?root=Others]]
-[[サンプルプログラム(Subversion)>https://www.masatom.in/svnsamples/repo/tags/V1.0.0_20080120_01/strutsExamples]]
この記事は
#vote(おもしろかった[199],そうでもない[27])
#vote(おもしろかった[200],そうでもない[27])
- その他のリンク系のタグは、rewriteタグがありますね。これもtransaction="true"をつけて制御します。 -- [[きの]] &new{2008-01-27 (日) 00:39:44};
- メイン画面と別にサブウィンドウでも更新する画面の場合ってトークンがずれてしまいますよね? -- [[yama]] &new{2011-03-02 (水) 13:07:06};
- auztxyMoZWaQ -- [[dzpntfpgxt]] &new{2012-07-16 (月) 10:44:19};
- test1 -- [[test]] &new{2015-07-15 (水) 09:11:21};
#comment
#topicpath
SIZE(10){現在のアクセス:&counter;}