Hello world, I'm currently working on a framework that should include Struts2 but I got some problems. First the context is a [webFramework]+Spring2+Hibernate project. I read some tutorial mainly about simple CRUD samples, but when trying to do a more serious application, the patterns used in the samples I found doesn't seam to match to our needs. I got 2 main problems due to the use of the valueStack, I think. Here is the code where I experienced problems.
========================== struts.xml ========================= <struts> <constant name="struts.enable.DynamicMethodInvocation" value= "true" /> <constant name="struts.devMode" value="true" /> <constant name="struts.objectFactory" value= "org.apache.struts2.spring.StrutsSpringObjectFactory" /> <action name="*List" class="com.XXX.SAMPLEPROJECT.web.action.{1}Action" method="list"> <result name="success">/pages/{1}List.jsp</result> </action> <action name="*Edit" class="com.XXX.SAMPLEPROJECT.web.action.{1}Action" method="input"> <result name="success" type="redirect-action">{1}List</result> <result name="input">/pages/forms/{1}Form.jsp</result> <result name="error">/pages/error.jsp</result> </action> <action name="*Delete" class="com.XXX.SAMPLEPROJECT.web.action.{1}Action" method="delete"> <result name="success" type="redirect-action">{1}List</result> <result name="error">/pages/error.jsp</result> </action> </struts> ========================== FichierList.jsp ========================= <%@ include file="/pages/commons/tld.jsp"%> <table id="listtable"> <thead> <tr> <td>Id</td> <td>Nom</td> <td>Extension</td> <td>Oeuvre</td> <td>Edit</td> <td>Suppr</td> </tr> </thead> <s:iterator value="theFichiers"> <tr> <td><s:property value="id" /></td> <td><s:property value="nom" /></td> <td><s:property value="extension" /></td> <td><s:property value="oeuvre.nom" /></td> <s:url id="editUrl" action="FichierEdit"> <s:param name="currentFichierId" value="id" /> </s:url> <td><s:a href="%{editUrl}">Edit</s:a></td> <s:url id="deleteUrl" action="FichierDelete"> <s:param name="currentFichierId" value="id" /> </s:url> <td><s:a href="%{deleteUrl}">Delete</s:a></td> </tr> </s:iterator> </table> <s:url id="addFichier" action="FichierEdit" /> <s:a href="%{addFichier}">Create a Fichier</s:a> ========================== FichierForm.jsp ========================= <%@ include file="/pages/commons/tld.jsp"%> <s:action name="OeuvreList" id="oeuvrelist" /> Debug: (currentFichier.id: <s:property value="%{currentFichier.id}" /> , currentFichierId: <s:property value="%{currentFichierId}" /> ) <s:form action="FichierEdit!save" method="post" validate="false"> <s:textfield name="currentFichier.nom" value="%{currentFichier.nom}" label="Nom" size="20" /> <s:textfield name="currentFichier.extension" value="%{currentFichier.extension}" label="Extension" size="4" /> <s:select name="currentFichier.oeuvre.id" value="%{currentFichier.oeuvre.id}" list="%{#oeuvrelist.theOeuvres}" listKey="id" listValue="nom" label="Oeuvre" /> <s:hidden name="currentFichierId" value="%{currentFichier.id}" /> <s:submit id="submit" value="Create" /> <s:submit id="cancel" value="Cancel" name="redirect-action:FichierList" /> </s:form> ========================== FichierAction.class ========================= public class FichierAction extends GenericAction { private IFichierService theFichierService; private Long currentFichierId = new Long(0); private Fichier currentFichier; private List<Fichier> theFichiers; public String input() { currentFichier = theFichierService.findById( currentFichierId); if (currentFichier == null) { currentFichier = new Fichier(); } return INPUT; } public String save() { theFichierService.saveOrUpdate(currentFichier); return SUCCESS; } public String delete() { currentFichier = theFichierService.findById(currentFichierId); if (currentFichier != null) { theFichierService.delete(currentFichier); return SUCCESS; } else { return ERROR; } } public String list() { theFichiers = theFichierService.findAll(); return SUCCESS; } ... } ========================== applicationContext.xml ========================= <bean id="com.XXX.SAMPLEPROJECT.web.action.FichierAction" class= "com.XXX.SAMPLEPROJECT.web.action.FichierAction" autowire="byType" /> ================================================================= I havn't any problem when listing data from my DB, but it changes when I try to use forms. The same form (and action method) is used for creation and edition. When I click on the edit link to edit a Fichier (with id=1 here) in the list, the URL is: ".../FichierEdit.action?currentFichierId=1" so the attribute currentFichierId is set to 1. Here we go with the issues: == 1st Issue == - if I click on a link to another page in my menu, the URL will be: ".../otherUrlEdit.action?currentFichierId=1" ... and I can't find how to avoid it. == 2nd Issue == - if I submit, my values are well stored in database, I'm back to the list, the URL is clean, but if I'm trying to create a new entry with my "Create a Fichier" link, the form is populated according to the id that was set in my Action because of my previous navigation. It seem logic but the way to reset this value keeping the ability to edit is still a mystery. == 3rd Issue == The code provided is a modified version of the original because I encoutered another problem with the prepare method (+interceptor) and the bean retrieval from db. My action class was : ... public void prepare() { super.prepare(); if( currentFichierId==0 ) { currentFichier = new Fichier(); } else { currentFichier = theFichierService.findById(currentFichierId); } } public String input() { return INPUT; } ... - I was expecting the prepare method to load the populated model from database, with values set in the form fields ... but the first time the action is called, surprise, the prepare is called but my form is empty. My debug string made me descovering that currentFichierId is set to 1, but the id of my currentFichier is 0. I don't understand that comportment, If somebody has any idea or advice about the way I'm using Struts2, to solve problems or just to comment, you're welcome. I'm waiting for any feedback because this framework and architecture will have to be robust enough to be used in production. Thanks for your support. Michaƫl Coindeau