WEB開発で必ずついて回るのが、Submitボタン二度押しや戻るボタンを押されるなど、勝手な画面遷移をされないような配慮です。Strutsでは同期トークンという機能でこれらの考慮をサポートしてくれます。
実際にサンプルで、ある画面でSubmitを二度押ししたとき、それを検知して二つ目のリクエストをエラーではじくという事を考えてみます。
同期トークンの機能とは以下の通りです。
この中で、トークンの生成、トークンチェック、hiddenにトークンを書き出す、などはStrutsが自動でやってくれますので、使う側はトークンをチェックするメソッドをアクションクラスに記述したり、エラー処理だけをやっておけばよいと言うことですね。ラクチンです。
index.do -> IndexAction -> index.jsp -> double.do -> DoubleAction -> success.jsp
という流れのサンプルです。
public ActionForward execute(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { saveToken(request); return mapping.findForward("success"); }
<?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>
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); } }
IndexAction?でSessionにトークンをセットしています。トークンを生成してSessionにセットするメソッドは
org.apache.struts.action.Action#saveToken
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にトークンがセットされています*3。
さてこれで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インスタンスのモニタを取得して処理しています*4。
上の例のように<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なので、トークンを送信したい場合は明示的に指定してあげる必要があります。
この記事は
現在のアクセス:123610