At line 16 removed 1 line. |
|
At line 17 added 1 line. |
In this step, we'll generate a ''skeleton'' or our JSP for displaying information from the PersonForm. I say ''skeleton'' because it'll just be the <form> itself. It will contain table rows and Struts' <html:text> tags for each property in PersonForm.java. The tool that we use to do this was written by [Erik Hatcher|http://www.blogscene.org/erik/]. It's basically just a single class (FormTagsHandler.java) and a couple of XDoclet templates (FormKeys.xdt and StrutsForm_jsp.xdt). All these files are located in tools/strutsgen. |
At line 19 added 34 lines. |
Here are the simple steps to generating the JSP and a properties file containing the labels for the form elements: |
|
* Execute __ant ejbdoclet__ - this generates the PersonForm.java from the Person.java POJO. |
* From the command-line, navigate to "tools/strutsgen" |
* Execute __ant -Dform.name=PersonForm__ to generate two files in tools/strutsgen/build: |
** PersonForm.properties (labels for your form elements) |
** personForm.jsp (skeleton JSP file) |
* Copy the contents of PersonForm.properties into web/WEB-INF/classes/ApplicationResources.properties. ''You can remove the keys for personForm.saved and personForm.unsaved - these are properties from the BaseObject that we don't used in our Forms. If you do this, make sure and remove the rows (<tr>'s) containing these properties in personForm.jsp. Here is an example of what you might add to ApplicationResources.properties:'' |
<div style="margin-left: 40px"> |
{{{ |
# -- person form -- |
personForm.firstName=First Name |
personForm.id=Id |
personForm.lastName=Last Name |
}}} |
</div> |
* Copy personForm.jsp to web/personForm.jsp |
|
We copy the JSP to the ''web'' folder instead of ''web/pages'' because the ''pages'' directory ends up in ''WEB-INF/pages'' when the application is packaged into a [WAR|http://java.sun.com/j2ee/tutorial/1_3-fcs/doc/WCC3.html#69310] file. This is a [recommended practice|http://husted.com/struts/catalog.html] when building secure web applications. |
|
;: ''The container provides security for all files below WEB-INF. This applies to client requests, but not to forwards from the ActionServlet. Placing all JSPs below WEB-INF ensures they are only accessed through Actions, and not directly by the client or each other. This allows security to be moved up into the Controller, where it can be handled more efficiently, and out of the base presentation layer.'' |
|
The web application security for AppFuse specifies that all *.do url-patterns should be protected. This guarantees 1) all Actions are protected, and 2) you must go through an Action to get to a JSP (or at least the ones in ''pages''). |
|
All this is to say that __putting the personForm.jsp in the ''web'' folder will allow us to view it without making a Tile for it__. ''We'll get to that in the next tutorial.'' |
|
At this point, you won't be able to view this JSP in your browser because the <html:form> tag in personForm.jsp has ''action=""'' which is not allowed. You can try it yourself by setting up AppFuse on Tomcat using __ant setup-db setup-tomcat deploy__. |
|
Then, start Tomcat and then go to [http://localhost:8080/appfuse/personForm.jsp]. This will result in the following error: |
{{{ |
javax.servlet.jsp.JspException: Cannot retrieve mapping for action / |
}}} |
Therefore, we need to create an Action for this JSP, and we should probably create a Test before we write our Action. |
|
At line 54 added 1 line. |
To create a StrutsTestCase Test for our Action, start by creating a PersonActionTest.java file in the test/web/**/action directory. |
At line 56 added 35 lines. |
;:%%(color: blue)''As usual, copy → save as an existing ActionTest (i.e. UserActionTest). Replace [[Uu]ser with [[P]erson. You might want to make sure [Cactus|http://jakarta.apache.org/cactus] (StrutsTestCase is an extension of Cactus] tests are running before you copy an existing one. Run __ant test-cactus -Dtestcase=UserAction__ to verify the UserAction works. Stop Tomcat before you do this.''%% |
|
If you did copy UserActionTest, make sure and change ''UserFormEx'' to ''PersonForm''. The reason for ''UserFormEx'' is to extend the UserForm and put custom web-only properties or methods into our form. Since the UserForm is generated, it's not very feasibly to do it in the User.java object. |
|
When we do create an Action (in [step 3|3]}, we're only going to create an __execute__ method, rather than all the different CRUD methods. So let's just test that method to start. |
|
[{Java2HtmlPlugin |
|
package org.appfuse.webapp.action; |
|
public class PersonActionTest extends BaseStrutsTestCase { |
//~ Constructors =========================================================== |
|
public PersonActionTest(String name) { |
super(name); |
} |
|
//~ Methods ================================================================ |
|
public void testExecute() throws Exception { |
setRequestPathInfo("/editPerson"); |
addRequestParameter("id", "1"); |
actionPerform(); |
|
verifyNoActionErrors(); |
} |
|
public static void main(String[] args) { |
junit.textui.TestRunner.run(PersonActionTest.class); |
} |
} |
}] |
|
Everything should compile at this point (ant compile-web) since we're not referring to the PersonAction directly in our test. However, if you try to run __ant test-cactus -Dtestcase=PersonAction__, it won't work (make sure Tomcat is ''not'' running if you decide to try this). |
|
At line 92 added 1 line. |
Now we have to create an Action (a.k.a. the Controller) to talk to our Manager and retrieve/save our data. In src/web/**/action, create a PersonAction.java file with the following contents: |
At line 94 added 64 lines. |
[{Java2HtmlPlugin |
|
package org.appfuse.webapp.action; |
|
import javax.servlet.http.HttpServletRequest; |
import javax.servlet.http.HttpServletResponse; |
|
import org.apache.commons.logging.Log; |
import org.apache.commons.logging.LogFactory; |
import org.apache.struts.action.ActionForm; |
import org.apache.struts.action.ActionForward; |
import org.apache.struts.action.ActionMapping; |
|
|
/** |
* Implementation of <strong>Action</strong> that interacts with the {@link |
* PersonForm} and retrieves values. It interacts with the {@link |
* PersonManager} to retrieve/persist values to the database. |
* |
* @struts.action name="personForm" path="/editPerson" scope="request" |
* validate="false" parameter="action" input="mainMenu" |
*/ |
public final class PersonAction extends BaseAction { |
//~ Instance fields ======================================================== |
|
private Log log = LogFactory.getLog(PersonAction.class); |
|
//~ Methods ================================================================ |
|
public ActionForward execute(ActionMapping mapping, ActionForm form, |
HttpServletRequest request, |
HttpServletResponse response) |
throws Exception { |
if (log.isDebugEnabled()) { |
log.debug("Entering 'execute' method"); |
} |
|
// return nothing (yet) |
return null; |
} |
} |
}] |
|
We're not putting much in PersonAction at this point because we just want to 1) render the JSP and 2) verify our Test runs. The XDoclet tags (beginning with ''@struts.action'') will generate the following XML in the build/appfuse/WEB-INF/struts-config.xml file (when you run __ant webdoclet__): |
[{Java2HtmlPlugin |
|
<action path="/editPerson" type="org.appfuse.webapp.action.PersonAction" |
name="personForm" scope="request" input="mainMenu" |
parameter="action" unknown="false" validate="false"> |
</action> |
}] |
|
;:''I formatted the XML above the the purposes of the tutorial. No content has changed.'' |
|
Now we need to change the "action" attribute in the <personForm.jsp> to be ''action="editPerson"''. |
|
[{Java2HtmlPlugin |
|
<html:form action="editPerson" method="post" styleId="personForm" |
focus="" onsubmit="return validatePersonForm(this)"> |
}] |
|
Everything is almost done for this tutorial, let's get to running our tests! |
|
At line 25 changed 20 lines. |
Here's a quick-n-dirty how to. We're creating a new Action/JSP for the "Position" entity in this example:</p> |
<ul class="glassList"> |
<li>Generate your Struts' ActionForms by executing "ant ejbdoclet" from the command-line</li> |
<li>Generate a skeleton JSP using the strutsgen tool in the tools folder: |
<ul> |
<li>From the command-line, navigate to "tools/strutsgen"</li> |
<li>Execute "ant gen -Dform.name=PositionForm" to generate two files in tools/strutsgen/build: PositionForm.properties (labels for your form elements) and PositionForm.jsp (skeleton JSP file)</li> |
<li>Copy the contents of PositionForm.properties into web/WEB-INF/classes/ApplicationResources.properties.</li> |
<li>Copy PositionForm.jsp to web/positionForm.jsp</li> |
</ul> |
<li>Create a new Struts Action in src/web. We called it PositionAction.java. Look in ResumeAction.java for the XDoclet javadocs at the beginning of the class. Use these as an example to create a /savePosition action-mapping.</li> |
<li>Delete all methods in PositionAction.java (if you used ResumeAction.java as a template). Find and replace [[Rr]esume with [[Pp]osition.</li> |
<li>Override the <em>execute</em> method and put a debugging statement into the method body to verify we're hitting it. Something like: System.out.println("entering execute method");</li> |
<li>Edit web/positionForm.jsp so the form's action="savePosition"</li> |
<li>Run "ant deploy" to deploy the updated application to Tomcat.</li> |
<li>Start Tomcat and go to <a href="http://localhost:8080/apptracker/positionForm.jsp">http://localhost:8080/apptracker/positionForm.jsp</a>. |
</li> |
<li>This should bring up the JSP, with a simple form in it. Click the <button>Save</button> button and you should see "entering execute method" in your Tomcat console. If so - nice work!</li> |
</ul> |
<p>Next up - integrating positionForm.jsp with Tiles, putting some meat into the Action's execute method, creating an ActionTest, replacing execute with different CRUD methods (add, edit, search), customizing the JSP so it looks good and finally - write a WebTest to test the JSPs functionality (or doing it via the browser). |
To test the JSP visually in your browser, save everything, run __ant deploy__, start Tomcat, and navigate to [http://localhost:8080/appfuse/personForm.jsp]. You should see something similar to the following image in your browser: |
%%(border: 1px solid black; height: 125px; width: 270px; margin: 0 auto;) |
[personForm-plain.png] |
%% |
;:''There is also a __deploy-web__ target in build.xml that will allow you to just deploy the files in the web directory. Nothing gets compiled or generated when you use this target.'' |
|
Now, if you stop Tomcat and run __ant test-cactus -Dtestcase=PersonAction__, that should work too! |
|
%%(color:green)BUILD SUCCESSFUL\\ |
Total time: 51 seconds%% |
|
;:''Look in your console's log for <span style="color: purple">PersonAction.execute(33) | Entering 'execute' method</span>. This is the log.debug statement we put in our execute method. You should also be able to [view personForm.jsp|http://localhost:8080/appfuse/personForm.jsp] (make sure Tomcat is running and you've logged into AppFuse) and click the "Save" button to see the same debug message.'' |
|
---- |
|
''Next Up:'' __Part IV:__ [Configuring Tiles and Action CRUD methods|ConfiguringTiles] - Integrating personForm.jsp with Tiles, replacing execute with different CRUD methods (add, edit, delete), customizing the JSP so it looks good and finally - writing a WebTest to test the JSPs functionality. |