At line 1 changed 1 line. |
__Part IV:__ [Adding Validation and List Screen|ValidationAndList] - Adding validation logic to the personForm so that firstName and lastName are required fields and adding a list screen to display all person records in the database. |
__Part IV:__ [Adding Validation and List Screen|ValidationAndList] - Adding validation logic to the PersonForm so that firstName and lastName are required fields and adding a list screen to display all person records in the database. |
At line 6 changed 1 line. |
This tutorial will show you how to add Validation logic (client and server-side) to the personForm object using Struts' Validator. We'll also create a list screen using the [Display Tag Library|http://displaytag.sf.net] to display all the people in the database. |
This tutorial will show you how to add Validation logic (client and server-side) to the PersonForm object using Struts' Validator. We'll also create a list screen using the [Display Tag Library|http://displaytag.sf.net] to display all the people in the database. |
At line 21 changed 1 line. |
To use the Struts Validator, normally you have to write a validation.xml file by hand. If you're not using AppFuse, you also have to configure the Validator Plugin and error keys in your ApplicationResources_en.properties. For more information on this, see the [Validation Made Easy Tutorial|http://www.reumann.net/do/struts/lesson3/step8]. |
To use the Struts Validator, normally you have to write a validation.xml file by hand. If you're not using AppFuse, you also have to configure the Validator Plugin and error keys in your ApplicationResources.properties. For more information on this, see the [Validation Made Easy Tutorial|http://www.learntechnology.net/struts-lesson-3.do] (there's also a [rich set of tutorials|http://www.learntechnology.net/struts-lesson-1.do] for Struts itself). |
At line 53 changed 1 line. |
Now if you save Person.java and run __ant clean webdoclet__, a validation.xml file will be generated in build/appfuse/WEB-INF/. It's contents should have now have an entry for "personForm". |
Now if you save Person.java and run __ant clean webdoclet__, a validation.xml file will be generated in build/appfuse/WEB-INF/. Its contents should have now have an entry for "personForm". |
At line 71 changed 1 line. |
To enable client-side validation in our personForm.jsp, a javascript JSP tag and script is required at the bottom of personForm.jsp. The following should already exist (thanks to viewgen) - you just need to uncomment it. The reason it's commented out is that the Validator will throw an exception if a formName is specified and no validation rules exist for it. |
Client-side validation is enabled by default in personForm.jsp. There is an <html:javascript> JSP tag and script at the bottom of this page that enables it. The following should already exist (thanks to AppGen) - but you might need to uncomment it if you commented it out in the last tutorial. |
At line 73 removed 2 lines. |
;:''Personally, I think this is [a bug|http://nagoya.apache.org/bugzilla/show_bug.cgi?id=27316], but the Struts Committers disagreed.'' |
|
At line 78 added 2 lines. |
%%note __NOTE:__ If you have nested objects with validation rules, those will be picked up and put into validation.xml. This is because an @struts.validator tag gets added to the setter of the nested object when the form is generated (using metadata/templates/struts_form.xdt). If you have many-to-many bi-directional relationships between objects, this can cause a problem. There are two solutions to fix this. The first is to remove the @struts.validator tag from struts_form.xdt and manually place it on the setter in your POJO. The second is [described here|https://appfuse.dev.java.net/issues/show_bug.cgi?id=88].%% |
|
At line 98 changed 1 line. |
To make sure things are ''really'' working as expected, you can turn off JavaScript and ensure the server-side validation is working. This is easy in [Mozilla Firebird|http://www.mozilla.org/products/firebird/] (my favorite browser), just go to Tools → Options → Web Features and uncheck "Enable JavaScript". Now if you clear the fields and save the form, you should see the following: |
To make sure things are ''really'' working as expected, you can turn off JavaScript and ensure the server-side validation is working. This is easy in [Firefox|http://www.mozilla.org/products/firefox/] (my favorite browser), just go to Tools → Options → Web Features and uncheck "Enable JavaScript". Now if you clear the fields and save the form, you should see the following: |
At line 135 changed 1 line. |
The reason I'm passing in a person object to the ''getPeople'' method is to allow for filtering (based on values in person) in the future. Add this parameter in your getPeople() method signature is optional, but the rest of this tutorial assumes you have done this. |
The reason I'm passing in a person object to the ''getPeople'' method is to allow for filtering (based on values in person) in the future. Adding this parameter in your getPeople() method signature is optional, but the rest of this tutorial assumes you have done this. |
At line 141 changed 3 lines. |
public void testGetPeople() { |
List results = mgr.getPeople(new Person()); |
assertTrue(results.size() > 0); |
public void testGetPeople() throws Exception { |
List results = new ArrayList(); |
person = new Person(); |
results.add(person); |
|
// set expected behavior on dao |
personDao.expects(once()).method("getPeople") |
.will(returnValue(results)); |
|
List people = personManager.getPeople(null); |
assertTrue(people.size() == 1); |
personDao.verify(); |
At line 173 changed 12 lines. |
Example example = Example.create(person) |
.excludeZeroes() // exclude zero valued properties |
.ignoreCase(); // perform case insensitive string comparisons |
try { |
return getSession().createCriteria(Person.class) |
.add(example) |
.list(); |
} catch (Exception e) { |
throw new DataAccessException(e.getMessage()); |
} |
return new ArrayList(); |
|
// filter on properties set in the person object |
HibernateCallback callback = new HibernateCallback() { |
public Object doInHibernate(Session session) throws HibernateException { |
Example ex = Example.create(person).ignoreCase().ignoreZeroes() |
.enableLike(MatchMode.ANYWHERE); |
return session.createCriteria(Person.class).add(ex).list(); |
} |
}; |
return (List) getHibernateTemplate().execute(callback); |
At line 197 changed 1 line. |
After saving all your changes, you should be able to run both tests by running the following: |
After saving all your changes, you should be able to run both tests by executing the following: |
At line 202 changed 1 line. |
If everything works - ''nice job!'' Now we need to add this ''retrieve all'' functionality to the web tier. |
If everything works - ''nice job!'' Now you need to add this ''retrieve all'' functionality to the web tier. |
At line 233 changed 1 line. |
Now save all your changes. You won't be able to run __ant test-cactus -Dtestcase=PersonAction__ yet since ''PersonAction.search()'' does not exist (yet). |
Now save all your changes. You won't be able to run __ant test-web -Dtestcase=PersonAction__ yet since ''PersonAction.search()'' does not exist (yet). |
At line 266 changed 1 line. |
Make sure Tomcat is stopped and run __ant test-cactus -Dtestcase=PersonAction__. |
Run __ant test-web -Dtestcase=PersonAction__. |
At line 273 changed 1 line. |
There should already be a personList.jsp file in ''web/pages''. If not, you can create it using viewgen. From the command-line, navigate to extras/viewgen and run __ant -Dform.name=PersonForm__. This will generate a PersonFormList.jsp in extras/viewgen/build. |
Open the personList.jsp file in ''web/pages''. You'll probably want to change the code to show the plural form of the items you're listing. The generated name in this example is "persons" and it should probably be people. At or near line 31, you should have the following line: |
At line 275 removed 30 lines. |
Once personList.jsp exists in ''web/pages'', open it for editing. |
|
At the top of the file is a <bean:struts> tags that exposes the edit screen's forward as a page-scoped variable. This should already have a value of "editPerson". |
|
[{Java2HtmlPlugin |
|
<%-- For linking to edit screen --%> |
<bean:struts id="editURL" forward="editPerson"/> |
}] |
|
Add this to the metadata/web/global-forwards.xml, as well as one for viewing the list. This way, they will get included in our struts-config.xml file. |
|
[{Java2HtmlPlugin |
|
<forward name="editPerson" path="/editPerson.html"/> |
<forward name="viewPeople" path="/editPerson.html?action=Search"/> |
}] |
|
The template you used to create this JSP has the column for the id property hard-coded, so XDoclet adds it twice. To remove this from personList.jsp, delete the following from this file: |
|
[{Java2HtmlPlugin |
|
<display:column property="id" sort="true" headerClass="sortable" |
titleKey="personForm.id"/> |
}] |
|
;:''If anyone knows of a way to modify the extras/viewgen/src/List_jsp.xdt to not include this column tag, please let me know.'' |
|
Another thing you'll probably want to change is the plural form of the items you're listing. The generated name in this example is "persons" and it should probably be people. At or near line 31, you should have the following line: |
|
At line 311 changed 1 line. |
Finally, add the title and heading keys (personList.title and personList.heading) to web/WEB-INF/classes/ApplicationResources_en.properties. Open this file and add the following: |
Finally, add the title and heading keys (personList.title and personList.heading) to web/WEB-INF/classes/ApplicationResources.properties. Open this file and add the following: |
At line 349 changed 1 line. |
{{{<verifytitle description="display Person List" text=".*$(personList.title}.*" regex="true"/>}}} |
{{{<verifytitle description="display Person List" text=".*${personList.title}.*" regex="true"/>}}} |
At line 351 changed 1 line. |
We use "viewPeople" instead of "list" so that the search method will be executed, rather than simply forwarding to the personForm.jsp (which the "list" forward points to). |
Finally, declare the viewPeople forward in metadata/web/global-forwards.xml after viewUsers as below: |
At line 329 added 4 lines. |
{{{<forward name="viewPeople" path="/editPerson.html?method=Search"/>}}} |
|
The name "viewPeople" is used instead of "list" so that the search method will be executed, rather than simply forwarding to the personForm.jsp (which the "list" forward points to). |
|
At line 344 added 1 line. |
|
At line 371 added 1 line. |
|
At line 374 added 1 line. |
|
At line 401 changed 1 line. |
Where ''menu.viewPeople'' is an entry in web/WEB-INF/classes/ApplicationResources_en.properties. |
Where ''menu.viewPeople'' is an entry in web/WEB-INF/classes/ApplicationResources.properties. |
At line 431 changed 1 line. |
Now if you run __ant clean deploy__ and start Tomcat, you should see something like the screenshot below. |
Now if you run __ant clean deploy__ start Tomcat and go to [http://localhost:8080/appfuse/mainMenu.html], you should see something like the screenshot below. |
At line 440 changed 1 line. |
You've completed the full lifecycle of developing a set of master-detail pages with AppFuse - __congratulations__. Now the real test is if you can run all the tests in your app without failure. To test, stop tomcat and run __ant clean test-all__. This will run all the unit tests within your project. As a reminder, it should be easy to setup and test AppFuse from scratch using __ant setup-db setup-tomcat test-all__. Also, if you're looking for more robust examples - checkout [StrutsResume]. |
You've completed the full lifecycle of developing a set of master-detail pages with AppFuse and Struts - __Congratulations__! Now the real test is if you can run all the tests in your app without failure. To test, stop tomcat and run __ant clean test-all__. This will run all the unit tests within your project. As a reminder, it should be easy to setup and test AppFuse from scratch using __ant setup-db setup-tomcat test-all__. Also, if you're looking for more robust examples - checkout [Struts Resume|StrutsResume]. |
At line 447 removed 2 lines. |
|
If you'd like, you [can download the files created in this tutorial|appfuse-tutorial-struts.zip]. |