そろそろかな
validation.xmlを??アノテーション化しようと思っていたら、すごいのを見つけてしまった。
その名も「無設定Struts」きしだのはてなさんが提供してくれてる。
これはすごくいいなー。
URLからAction、ActionForm、JSPを特定して実行できる。
自分の考えより何歩も先いってる。すごい!!
っていうことで、validation.xmlを??アノテーション化するのはやめ。あるものを作る必要はないし。
今はJ2SE1.4だから使えないけど、J2SE1.5(5.0?)にいずれバージョンアップして利用しよ。
ということで、今日はPARTYテーブルを編集する機能を作ってみる。
経験をつんできてるからすぐにできそうな予感。でもすぐにつまずきそうな感じもする。
AuthActionを作ったときと同じ感じで、Actionから作って足りないLogic処理を見つけて、Logicに処理の追加。っていう手順で作っていく。
テストクラスはつくならない予定・・・。
うーん。やっぱりテストクラスを作るべきかなー。悩む・・・。
とりあえず、前に進んでダメなら戻ってこよう。
まずは、PartyActionインターフェイスの作成。
public interface PartyAction { public static final String[] ACTION = { "path=/site/party", "name=partyForm", "scope=request", "unknown=false", "validate=false" }; public static final String[] list_FORWARD = { "path=/pages/party/list.jsp" }; public static final String[] detail_FORWARD = { "path=/pages/party/detail.jsp" }; public static final String[] insert_FORWARD = { "path=/pages/party/insert.jsp" }; public static final String[] insertConfirm_FORWARD = { "path=/pages/party/insertConfirm.jsp" }; public static final String[] insertError_FORWARD = { "path=/pages/party/insert.jsp" }; public static final String[] insertSuccess_FORWARD = { "path=/pages/party/detail.jsp" }; public static final String[] update_FORWARD = { "path=/pages/party/update.jsp" }; public static final String[] updateConfirm_FORWARD = { "path=/pages/party/updateConfirm.jsp" }; public static final String[] updateError_FORWARD = { "path=/pages/party/update.jsp" }; public static final String[] updateSuccess_FORWARD = { "path=/pages/party/detail.jsp" }; public static final String[] deleteConfirm_FORWARD = { "path=/pages/party/deleteConfirm.jsp" }; public static final String[] deleteError_FORWARD = { "path=/pages/party/detail.jsp" }; public static final String[] deleteSuccess_FORWARD = { "path=/pages/party/detail.jsp" }; // ----------------------------------------------------------------------- public String list(); public String detail(); public String insertInit(); public static final String insertConfirm_VALIDATE = "insertError"; public String insertConfirm(); public static final String insert_VALIDATE = "insertError"; public String insert(); public String updateInit(); public static final String updateConfirm_VALIDATE = "updateError"; public String updateConfirm(); public static final String update_VALIDATE = "updateError"; public String update(); public String deleteConfirm(); public String delete(); }
えらいことになってしまった。ダメな匂いが・・・
やっぱり1Action/1メソッドがいいような気がしてきた・・・
とりあえず作って、それからダメな点を修正していこう。
次はPartyActionの実装。
public class PartyActionImpl implements PartyAction { private PartyLogic partyLogic; private PartyDto partyForm; private List parties; public static final String errors_EXPORT = "errors"; private Map errors = new HashMap(); public PartyActionImpl(PartyLogic partyLogic) { this.partyLogic = partyLogic; } public String list() { parties = partyLogic.getAllParties(); return "list"; } public String detail() { partyForm = partyLogic.getParty(partyForm); return "detail"; } public String insertInit() { // 編集するために必要となる情報(SelectBox情報等)はない。 return "insert"; } public String insertConfirm() { errors = partyLogic.validateInsert(partyForm); if (!errors.isEmpty()) { return "insertError"; } return "insertConfirm"; } public String insert() { errors = partyLogic.validateInsert(partyForm); if (!errors.isEmpty()) { return "insertError"; } partyLogic.insert(partyForm); return "insertSuccess"; } public String updateInit() { partyForm = partyLogic.getParty(partyForm); // 編集するために必要となる情報(SelectBox情報等)はない。 return "update"; } public String updateConfirm() { errors = partyLogic.validateUpdate(partyForm); if (!errors.isEmpty()) { return "updateError"; } return "updateConfirm"; } public String update() { errors = partyLogic.validateUpdate(partyForm); if (!errors.isEmpty()) { return "updateError"; } partyLogic.update(partyForm); return "updateSuccess"; } public String deleteConfirm() { errors = partyLogic.validateDelete(partyForm); if (!errors.isEmpty()) { return "deleteError"; } return "deleteConfirm"; } public String delete() { errors = partyLogic.validateDelete(partyForm); if (!errors.isEmpty()) { return "deleteError"; } partyLogic.delete(partyForm); return "deleteSuccess"; } // ----------------------------------------------------------------------- public PartyDto getPartyForm() { return partyForm; } public void setPartyForm(PartyDto partyForm) { this.partyForm = partyForm; } public Map getErrors() { return errors; } public List getParties() { return parties; } }
これもツッコミどころが満載って雰囲気を出してる。後から修正要って感じ。
たりないPartyLogicのメソッドを追加。
PartyLogic#validate???()ってメソッドは、入力パラメータ検証ではできない検証(accountが重複しているかのチェック等)を行うために作成。
public class PartyLogicImpl implements PartyLogic { private PartyDao partyDao; public PartyLogicImpl(PartyDao partyDao) { this.partyDao = partyDao; } public boolean existParty(PartyDto dto) { PartyDto party = partyDao.findByAccount(dto.getAccount()); if (party == null) { return false; } return party.getPassword().equals(dto.getPassword()); } public PartyDto getParty(String account) { return partyDao.findByAccount(account); } public PartyDto getParty(PartyDto dto) { return partyDao.findBean(dto); } public List getAllParties() { return partyDao.findAll(); } public Map validateInsert(PartyDto dto) { Map result = new HashMap(); PartyDto found = partyDao.findByAccount(dto.getAccount()); if (found != null) { result.put("errors.account.duplication", new Object[] {}); } return result; } public void insert(PartyDto dto) { partyDao.insert(dto); } public Map validateUpdate(PartyDto dto) { Map result = new HashMap(); PartyDto found = partyDao.findBean(dto); if (found == null) { result.put("errors.update.notfound", new Object[] {}); } found = partyDao.findByAccount(dto.getAccount()); if (found != null && !found.getId().equals(dto.getId())) { result.put("errors.account.duplication", new Object[] {}); } return result; } public void update(PartyDto dto) { partyDao.update(dto); } public Map validateDelete(PartyDto dto) { Map result = new HashMap(); PartyDto found = partyDao.findBean(dto); if (found == null) { result.put("errors.delete.notfound", new Object[] {}); } return result; } public void delete(PartyDto dto) { partyDao.delete(dto); } }
こっちの問題点はわかりやすい
- valiedate???()の返却値となるMapの内容がAction内の処理形式に依存してる。
- insert()、update()、delete()する前にそれぞれのvalidate???()を呼ぶべきではないか。
- valiedate???()はテストすべき。
1つ目は仕方ないってことにしよう。下手にこっても大変になるだけのような気がするし。
2つ目と3つ目はそうしよう。
そこで、PartyLogicImplとPartyActionImplの修正。これは簡単。
次はPartyLogicImpl#validate???()関連のテスト作成。
public class PartyLogicTest extends S2DaoTestCase { private PartyLogic logic; private PartyDto dto = new PartyDto(new Integer(2)); public PartyLogicTest(String arg0) { super(arg0); } public void setUp() { include("study/xxx/dicon/alldao.dicon"); include("study/xxx/dicon/party.dicon"); } public void testValidateInsertOKTx() { deleteTable(PartyDto.TABLE); PartyDto ins = new PartyDto(); ins.setAccount("INSTEST"); ins.setPassword("INSPWD"); ins.setName("INSテスト"); Map errors = logic.validateInsert(ins); assertTrue(errors.isEmpty()); } public void testValidateInsertNGAccountDuplicationTx() { deleteTable(PartyDto.TABLE); readXlsWriteDb("study/xxx/dao/PartyTestData.xls"); PartyDto ins = logic.getParty(dto); Map errors = logic.validateInsert(ins); assertFalse(errors.isEmpty()); assertTrue(errors.containsKey("errors.account.duplication")); } public void testValidateUpdateOKTx() { deleteTable(PartyDto.TABLE); readXlsWriteDb("study/xxx/dao/PartyTestData.xls"); PartyDto up = logic.getParty(dto); Map errors = logic.validateUpdate(up); assertTrue(errors.isEmpty()); } public void testValidateUpdateNGNotfoundTx() { deleteTable(PartyDto.TABLE); PartyDto up = new PartyDto(new Integer(1)); up.setAccount("UPTEST"); Map errors = logic.validateUpdate(up); assertFalse(errors.isEmpty()); assertTrue(errors.containsKey("errors.update.notfound")); } public void testValidateUpdateNGAccountDuplicationTx() { deleteTable(PartyDto.TABLE); readXlsWriteDb("study/xxx/dao/PartyTestData.xls"); PartyDto up = logic.getParty(dto); up.setAccount("TEST"); Map errors = logic.validateUpdate(up); assertFalse(errors.isEmpty()); assertTrue(errors.containsKey("errors.account.duplication")); } public void testValidateDeleteOKTx() { deleteTable(PartyDto.TABLE); readXlsWriteDb("study/xxx/dao/PartyTestData.xls"); Map errors = logic.validateDelete(dto); assertTrue(errors.isEmpty()); } public void testValidateDeleteNGNotfoundTx() { deleteTable(PartyDto.TABLE); Map errors = logic.validateDelete(dto); assertFalse(errors.isEmpty()); assertTrue(errors.containsKey("errors.delete.notfound")); } }
テスト実行。グリーンバー。
先にPartyLogicImplを作っていたから、わざとassertTrue()のところをassertFalse()に変えて失敗することも確認。
次は、DICONファイルとstruts-config.xml、MessageResources.propertiesへの記述の追加。
struts-config.xmlへform-beanの追加を忘れないようにしないと。
中途半端な改造をしたから。
一番山場となるJSPを作る作業。
これは大変だ。
重複する内容が多くなるけど、\pages\party\フォルダにこれだけのJSPをつくならないといけない。
これは大変だ。
まずは、list.jspの作成。
html:linkタグの使い方を忘れた。変な感じだったってことは覚えてるけど。調べてみる。
思ってたほど変でもなかった。
list.jspはこんな感じかな
<%@page contentType="text/html; charset=SHIFT_JIS" %> <%@taglib uri="/tags/c" prefix="c" %> <%@taglib uri="/tags/struts-bean" prefix="bean" %> <%@taglib uri="/tags/struts-html" prefix="html" %> <c:set var="path" value="/site/party"/> <html:html> <head> <title><bean:message key="title.party.list" /></title> </head> <body> <html:form action="${path}" method="POST"> <!-- メニューボタン --> <table class="btn-menu"><tr> <td nowrap> <html:submit property="${path}:list" styleClass="btn-menu"> <bean:message key="button.list" /> </html:submit><html:submit property="${path}:insertInit" styleClass="btn-menu"> <bean:message key="button.insert.new" /> </html:submit> </td> </tr></table> <table class="outer"> <tr><td> <html:errors /> </td></tr> <tr><td> <table class="list"> <tr class="list-header"> <th><bean:message key="form.party.account" /></th> <th><bean:message key="form.party.name" /></th> <th><br /></th> </tr> <c:forEach var="party" items="${parties}" varStatus="status"> <tr class="<c:out value="list-${status.count % 2}" />"> <td class="text"><c:out value="${party.account}" /></td> <td class="text"><c:out value="${party.name}" /></td> <td class="text"> <html:link page="/do${path}?${path}:detail" paramId="id" paramName="party" paramProperty="id"> <bean:message key="button.detail.s" /> </html:link> <html:link page="/do${path}?${path}:updateInit" paramId="id" paramName="party" paramProperty="id"> <bean:message key="button.update.s" /> </html:link> <html:link page="/do${path}?${path}:deleteConfirm" paramId="id" paramName="party" paramProperty="id"> <bean:message key="button.delete.s" /> </html:link> </td> </tr> </c:forEach> </table> </td></tr> </table> </html:form> </body> </html:html>
それとメニュー欄にパーティ一覧画面へのリンクを追加。
Tomcatを起動して動作確認。
うまく表示できた。JSPエラーなし。今日も調子がいいみたい。
次はdetail.jspこれも追加して動作確認。
javax.servlet.ServletException: キー "form.party.name" に対応するメッセージが見つかりません
ってJSPエラーがでたけど、そこだけだった。やっぱり調子がいい。
detail.jspはこんな感じ。
<%@page contentType="text/html; charset=SHIFT_JIS" %> <%@taglib uri="/tags/c" prefix="c" %> <%@taglib uri="/tags/struts-bean" prefix="bean" %> <%@taglib uri="/tags/struts-html" prefix="html" %> <c:set var="path" value="/site/party"/> <c:set var="form" value="${partyForm}"/> <html:html> <head> <title><bean:message key="title.party.detail" /></title> </head> <body> <html:form action="${path}" method="POST"> <!-- メニューボタン --> <table class="btn-menu"><tr> <td nowrap> <html:submit property="${path}:list" styleClass="btn-menu"> <bean:message key="button.list" /> </html:submit><html:submit property="${path}:insertInit" styleClass="btn-menu"> <bean:message key="button.insert.new" /> </html:submit> </td> </tr></table> <table class="outer"> <tr><td> <html:errors /> </td></tr> <html:hidden property="id" /> <html:hidden property="account" /> <html:hidden property="password" /> <html:hidden property="name" /> <html:hidden property="parentId" /> <tr><td> <table class="detail"> <tr> <th class="detail"><bean:message key="form.party.account" /></th> <td class="text"><c:out value="${form.account}" /></td> </tr> <tr> <th class="detail"><bean:message key="form.party.password" /></th> <td class="text"><c:out value="${form.password}" /></td> </tr> <tr> <th class="detail"><bean:message key="form.party.name" /></th> <td class="text"><c:out value="${form.name}" /></td> </tr> </table> </td></tr> </table> <table class="btn"><tr> <td nowrap> <html:submit property="${path}:updateInit" styleClass="btn-menu"> <bean:message key="button.update" /> </html:submit><html:submit property="${path}:deleteConfirm" styleClass="btn-menu"> <bean:message key="button.delete" /> </html:submit> </td> </tr></table> </html:form> </body> </html:html>
パスワードも表示してしまうという強烈なdetail.jsp。修正要。
なんとなくだけど、insert.jspの前にupdate.jspを先に作る。
うまくできた。調子にのってupdateConfirm.jspの作成。
「戻る」ボタンに対応するメソッドがない。PartyAction#updateBack()を作って対応。
できた。でも、
更新画面(各種情報を変更して「変更」ボタンクリック)→確認画面(内容を確認して「OK」ボタンクリック)→更新後の情報での詳細画面
って感じで画面遷移しているんだけど、最後の詳細画面表示時に「変更しました」っていうメッセージがほしい。
困ったなー。簡単に実装するためには、PartyActionImplで
public String update() { errors = partyLogic.update(partyForm); if (!errors.isEmpty()) { return "updateError"; } errors.put("messages.complete.update", new Object[] {}); return "updateSuccess"; }
ってすればいいと思うけど、正常終了しているのにエラーメッセージを利用するのは気が引ける。
どうしよう。
変数名をerrorsからmessagesに変更すればOKかも。なんか屁理屈っぽいけど。結構いい案かも。
これでいこう。さっそくPartyActionImplを修正。
そしてTomcat起動して動作確認。
うまくできた。
変更機能は完了。
次は、追加機能としてinsert.jspとinsertConfirm.jspを作成。
JSPエラーなくできた。順調。
最後は、deleteConfirm.jspの作成。
これも順調に行くかなーと思ったら、詳細情報が表示されていない。取得してないからだ。
PartyActionImpl#deleteConfirm()を少し修正。
public String deleteConfirm() { messages = partyLogic.validateDelete(partyForm); if (!messages.isEmpty()) { return "deleteError"; } partyForm = partyLogic.getParty(partyForm); return "deleteConfirm"; }
削除後に表示する詳細画面で削除した情報が表示されてる・・・。表示しないように修正しよう。
public String delete() { messages = partyLogic.delete(partyForm); if (!messages.isEmpty()) { return "deleteError"; } messages.put("messages.complete.delete", new Object[] {}); partyForm = null; return "deleteSuccess"; }
PartyActionImpl#delete()後には、partyFormにnullを設定して、detail.jspはpartyFormがemptyなら詳細情報を表示しないように修正。
動作確認。できた。これで一通りは完成かな。
細かいところを修正しよう。
PartyActionでのinsertSuccess_FORWARDのpathをdetailメソッドを呼び出すように変更。
今回は詳細情報表示が単純だけど、複雑になってきたときに困ると思うから。Actionの連鎖ができるか確認。
public static final String[] insertSuccess_FORWARD = { "path=/pages/party/detail.jsp" };
public static final String[] insertSuccess_FORWARD = { "path=/do/site/party?/site/party:detail" };
動作確認。エラー。しかも
java.lang.ClassCastException org.apache.struts.util.RequestUtils.lookupActionForm(RequestUtils.java:210) org.apache.struts.util.RequestUtils.createActionForm(RequestUtils.java:179)
なぜ?
ちょっと調査。
requestからActionFormを取り出したときのキャストで発生してる。
ActionFormの処理はS2Strutsから独自で変更したところだから、自分で組み込んだバグだ。
XxxActionPropertyBinderImplにバグがあるのか?
あった。
POJOActionからexportするときに特別な処理をしていないからPOJOFormのままexportしてた。
XxxActionPropertyBinderImplとXxxActionExecuteProcessorImplのバグだ。S2Strutsが提供してくれているActionExecuteProcessorImplだったら発生しなかった。
修正しないと。でも、その前にテストメソッドを作るのが先。
ActionPropertyBindingTest#testExportActionForm()を追加。
public void testExportActionForm() throws Exception { ExportActionFormActionImpl action = new ExportActionFormActionImpl(); Object form = new BeanValidatorForm( new ExportActionForm("noUpdateForm")); ActionMapping mapping = new MockActionMapping(); mapping.setType(ExportActionFormAction.class.getName()); mapping.setName("exportActionForm"); mapping.setScope("request"); getRequest().setAttribute(Globals.MAPPING_KEY, mapping); getRequest().setAttribute("exportActionForm", form); ActionForward actionForward = actionExecuteProcessor .processActionExecute(getRequest(), getResponse(), action, form, mapping); assertTrue(getRequest().getAttribute("exportActionForm") instanceof BeanValidatorForm); BeanValidatorForm beanValidatorForm = (BeanValidatorForm) getRequest() .getAttribute("exportActionForm"); WrapDynaBean dynaBean = (WrapDynaBean) beanValidatorForm.getDynaBean(); ExportActionForm exportForm = (ExportActionForm) dynaBean.getInstance(); assertEquals("updateForm", exportForm.getTestMessage()); }
ExportActionFormActionImplは
public class ExportActionFormActionImpl implements ExportActionFormAction { private ExportActionForm exportActionForm; public String test() { exportActionForm = new ExportActionForm("updateForm"); return "success"; } public ExportActionForm getExportActionForm() { return exportActionForm; } public void setExportActionForm(ExportActionForm exportActionForm) { this.exportActionForm = exportActionForm; } }
テスト実行。
エラー。
[ESSR0046]コンポーネント(interface study.xxx.extention.struts.processor.ExportActionFormAction)が見つかりません
DICONファイルに記述を忘れてた。
記述を追加して再度テスト実行。
期待した失敗。
次はグリーンバーにするためにXxxActionPropertyBinderImplの修正。
自前でBeanValidatorFormを作る場合は、newするだけでいいのかなー。
BeanValidatorForm#setServletContext()が気になる。
XxxActionPropertyBinderImplの修正内容は
public void exportProperties(Object action, S2Container container, BeanDesc beanDesc) { for (int i = 0; i < beanDesc.getPropertyDescSize(); ++i) { PropertyDesc propertyDesc = beanDesc.getPropertyDesc(i); if (propertyDesc.hasReadMethod()) { Object var = propertyDesc.getValue(action); if (isActionFormProperty(container, propertyDesc)) { exportActionFormProperty(container, propertyDesc, var); } else if (isSessionProperty(beanDesc, propertyDesc)) { exportSessionProperty(container, propertyDesc, var); } else if (isErrorsProperty(beanDesc, propertyDesc)) { exportErrorsProperty(container, propertyDesc, var); } else { exportProperty(container, propertyDesc, var); } } } } private void exportActionFormProperty(S2Container container, PropertyDesc propertyDesc, Object var) { HttpServletRequest request = container.getRequest(); ActionMapping mapping = ActionMappingUtil.get(request); ActionFormUtil.setActionForm(request, mapping, var); }
で、ActionFormUtilに
public static void setActionForm(HttpServletRequest request, ActionMapping mapping, Object var) { ActionForm form; if (var instanceof ActionForm) { form = (ActionForm) var; } else { form = createBeanValidatorForm(request, mapping, var); } if (REQUEST.equals(mapping.getScope())) { request.setAttribute(mapping.getAttribute(), form); } else { HttpSession session = request.getSession(); session.setAttribute(mapping.getAttribute(), form); } } private static BeanValidatorForm createBeanValidatorForm( HttpServletRequest request, ActionMapping mapping, Object var) { BeanValidatorForm result = new BeanValidatorForm(var); ActionForm oldForm = getActionForm(request, mapping); // TODO 自前でBeanValidatorFormを作ったあとの処理についてはもう一度考える MultipartRequestHandler multipartHandler = oldForm .getMultipartRequestHandler(); if (multipartHandler != null) { result.setServlet(multipartHandler.getServlet()); result.setMultipartRequestHandler(multipartHandler); } return result; }
を追加した。
ActionFormUtil#createBeanValidatorForm()は適当。勉強不足を露呈してる・・・。
ソースを追う限りではこれで十分だと思ったけど、どうだか。
テスト実行。グリーンバー。だけど、すっきりしないなー。
このテストの時にActionFormをクリアした場合の動作が気になったからついでにActionPropertyBindingTest#testClearActionForm()を追加しよう。
public void testClearActionForm() throws Exception { ClearActionFormActionImpl action = new ClearActionFormActionImpl(); Object form = new BeanValidatorForm( new ClearActionForm()); ActionMapping mapping = new MockActionMapping(); mapping.setType(ClearActionFormAction.class.getName()); mapping.setName("clearActionForm"); mapping.setScope("request"); getRequest().setAttribute(Globals.MAPPING_KEY, mapping); getRequest().setAttribute("clearActionForm", form); ActionForward actionForward = actionExecuteProcessor .processActionExecute(getRequest(), getResponse(), action, form, mapping); assertTrue(getRequest().getAttribute("clearActionForm") == null); }
public class ClearActionFormActionImpl implements ClearActionFormAction { private ClearActionForm clearActionForm; public String test() { clearActionForm = null; return "success"; } public ClearActionForm getClearActionForm() { return clearActionForm; } public void setClearActionForm(ClearActionForm clearActionForm) { this.clearActionForm = clearActionForm; } }
やっぱり、さっき作ったActionFormUtilがダメみたい。
nullの場合はremoveAttribute()するように修正。ついでにメソッド名も変更。
テスト実行。グリーンバー。
やっとTomcatを起動して動作確認。
insertConfirmでJSPエラー。
${form}はクラス "org.apache.struts.validator.BeanValidatorForm"だから、getAccount()なんてありません。
っていってる。
さっきの修正が影響してるんだ。修正しないと。
ちょっとラッキー
JSP内の処理で
<c:set var="form" value="${partyForm}"/>
ってしてたから、この1行を修正すればOKだ。ラッキー
POJOFormのとり方はついさっきActionFormUtilの修正で見たから覚えてる。
<c:set var="form" value="${partyForm.dynaBean.instance}"/>
みたいに修正して再度確認。
できた。
他のJSPも修正しないと。
やっとPartyActionでのinsertSuccess_FORWARDのpathをdetailメソッドを呼び出すように変更後の動作確認。
public static final String[] insertSuccess_FORWARD = { "path=/do/site/party?/site/party:detail" };
だめだ。空ページが表示される。
なぜだ???
pathの記述の最後に"="がないからかなー。下のように変更してチャレンジ。
public static final String[] insertSuccess_FORWARD = { "path=/do/site/party?/site/party:detail=" };
今度は、IDがうまくわたらず空の詳細画面が表示された。ちょっと進歩したけど、やっぱりダメだ。
うーん。
Actionの連鎖って、この他にもたくさん問題がでそうだし、あんまりしないほうがいいよって聞いた(見た?)ことあるから(本当か?)、これ以上こだわるのはやめよう。
この問題をクリアしても、次は「ActionFormの内容が上書きされた」とかで悩むと思うし。
何個かバグもなくせたことを成果としよう。
やめ。ってことで素直に戻す。一回目の挫折。
public static final String[] insertSuccess_FORWARD = { "path=/pages/party/detail.jsp" };
そして今回作った機能が動くかもう一度確認して、気持ちをよくしてから今日の勉強は終了。