At line 1 changed 1 line. |
__Part V:__ [Adding Validation and List Screen|ValidationAndListSpring] - Adding validation logic to the person object 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|ValidationAndListSpring] - Adding validation logic to the Person object so that firstName and lastName are required fields and adding a list screen to display all person records in the database. |
At line 3 changed 1 line. |
;:''This tutorial depends on __Part IV:__ [Configuring Tiles and FormController|ConfiguringTilesSpring].'' |
;:''This tutorial depends on __Part III:__ [Creating Controllers and JSPs|SpringControllers].'' |
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 Person object using Commons 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 11 changed 1 line. |
* [1] Add XDoclet Validator to Person.java |
* [1] Add XDoclet Validator tags to Person.java |
At line 14 added 1 line. |
* [4] Add ''getPeople'' methods to PersonDao and Manager |
At line 20 changed 1 line. |
To use Commons Validator with Spring MVC, normally you have to write a validation.xml file by hand. However, using XDoclet, it's much easier - we just need to add a couple of ''@spring.validator'' tags to our POJO (Person.java). Let's open it up (src/dao/**/persistence/Person.java) and modify your setFirstName and setLastName methods to resemble the following: |
To use Commons Validator with Spring MVC, normally you have to write a validation.xml file by hand. However, thanks to XDoclet, it's much easier - you just need to add a couple of ''@spring.validator'' tags to our POJO (Person.java). Let's open it up (src/dao/**/dao/Person.java) and modify your setFirstName and setLastName methods to resemble the following: |
At line 43 changed 1 line. |
@struts.validator type="required" msgkey="errors.required" |
@spring.validator type="required" msgkey="errors.required" |
At line 66 changed 1 line. |
To enable validation in our personForm.jsp, you'll need to make sure your personForm.jsp has the following at the bottom: |
To enable validation in personForm.jsp, you'll need to make sure your personForm.jsp has the following at the bottom: |
At line 68 changed 1 line. |
{{{<html:javascript formName="person" cdata="false" |
{{{<v:javascript formName="person" cdata="false" |
At line 99 changed 1 line. |
%%(border: 1px solid black; margin: 0 auto; height: 202px; width: 423px) |
%%(border: 1px solid black; margin: 0 auto; height: 215px; width: 521px) |
At line 102 changed 1 line. |
|
|
|
At line 107 changed 1 line. |
<html:javascript formName="personForm" cdata="false" |
<v:javascript formName="personForm" cdata="false" |
At line 116 changed 1 line. |
Open test/dao/**/persistence/PersonDaoTest.java and add a ''testGetPeople'' method: |
Open test/dao/**/dao/PersonDaoTest.java and add a ''testGetPeople'' method: |
At line 121 changed 1 line. |
person = new Person(); |
person = new Person(); |
At line 127 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. |
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 133 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 139 changed 1 line. |
;:%%(color: red)''Where did we add getPeople() to the DAO and Manager, did I miss that? -Lance'' |
In order for these tests to compile, you need to add the ''getPeople()'' method to the PersonDao and PersonManager interfaces, and their implementations. |
At line 141 changed 1 line. |
Save all your files and make sure everything compiles with __ant clean compile__. Now you should be able to run both tests by running the following: |
!!Add getPeople() method to DAO and Manager [#4] |
Open src/dao/**/dao/PersonDao.java and add the getPeople() method signature: |
At line 155 added 47 lines. |
[{Java2HtmlPlugin |
|
public List getPeople(Person person); |
}] |
|
Now add the same method signature to src/service/**/service/__PersonManager.java__. Save all your files and adjust the imports in your tests. Next you need to implement the getPeople() method in your implementation classes. Open src/dao/**/dao/hibernate/PersonDaoHibernate.java and add the following method: |
|
[{Java2HtmlPlugin |
|
public List getPeople(Person person) { |
return getHibernateTemplate().find("from Person"); |
} |
}] |
|
<div class="note" style="margin-left: 30px"> |
You'll notice here that nothing is being done with the ''person'' parameter. This is just a placeholder for now - in the future you may want to filter on it's properties using [Hibernate's Query Language|http://www.hibernate.org/hib_docs/reference/en/html/queryhql.html] (HQL) or using [Criteria Queries|http://www.hibernate.org/hib_docs/reference/en/html/querycriteria.html]. |
|
''An example using a Criteria Query:'' |
|
[{Java2HtmlPlugin |
|
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(); |
|
}] |
</div> |
|
Now implement the ''getPeople()'' method in src/service/**/impl/PersonManagerImpl.java: |
|
[{Java2HtmlPlugin |
|
public List getPeople(Person person) { |
return dao.getPeople(person); |
} |
}] |
|
After saving all your changes, you should be able to run both tests by executing the following: |
|
At line 146 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 149 changed 2 lines. |
In the last couple of tutorials, we've been working with the PersonFormController to interact with our HTML form. Now we need to create a new Controller that'll simply handle getting and displaying a list of people in the database. You could also use a |
[MultiActionController|http://www.springframework.org/docs/api/org/springframework/web/servlet/mvc/multiaction/MultiActionController.html\ to handle all your List screens. |
In the last couple of tutorials, we've been working with the PersonFormController to interact with our HTML form. Now we need to create a new Controller that'll simply handle getting and displaying a list of people in the database. |
At line 210 added 2 lines. |
;:''You could also use a [MultiActionController|http://www.springframework.org/docs/api/org/springframework/web/servlet/mvc/multiaction/MultiActionController.html] to handle all your List screens.'' |
|
At line 154 removed 2 lines. |
;:%%(color: blue)''I copied the testHandleRequest method from UserControllerTest.java and changed the "User" stuff to "Person".'' |
|
At line 216 added 12 lines. |
package org.appfuse.webapp.action; |
|
import java.util.Map; |
|
import javax.servlet.http.HttpServletRequest; |
import javax.servlet.http.HttpServletResponse; |
|
import org.appfuse.Constants; |
import org.springframework.web.servlet.ModelAndView; |
|
public class PersonControllerTest extends BaseControllerTestCase { |
|
At line 160 changed 3 lines. |
ModelAndView mav = |
c.handleRequest((HttpServletRequest) null, |
(HttpServletResponse) null); |
ModelAndView mav = c.handleRequest((HttpServletRequest) null, |
(HttpServletResponse) null); |
At line 164 changed 1 line. |
assertNotNull(m.get(Constants.USER_LIST)); |
assertNotNull(m.get(Constants.PERSON_LIST)); |
At line 236 added 1 line. |
} |
At line 169 changed 1 line. |
This class will not compile until you (1) create the PersonController class and (2) add the PERSON_LIST variable to the src/dao/**/Constants.java file. |
This class will not compile until you (1) create the PersonController class and (2) add the PERSON_LIST variable to the src/dao/**/Constants.java file. Some folks have suggested that this class be named ''PersonControllerList'' - the name choice is up to you. I prefer Controller and FormController because it tells me one implements [Controller|http://www.springframework.org/docs/api/org/springframework/web/servlet/mvc/Controller.html] while the latter extends [SimpleFormController|http://www.springframework.org/docs/api/org/springframework/web/servlet/mvc/SimpleFormController.html]. |
At line 184 changed 1 line. |
Create src/web/**/action/PersonController.java. It should implement {{org.springframework.web.servlet.mvc.Controller}} and resemble the following: |
Create src/web/**/action/PersonController.java. It should implement {{org.springframework.web.servlet.mvc.Controller}} and read as follows: |
At line 203 removed 1 line. |
|
At line 205 changed 1 line. |
private static Log log = LogFactory.getLog(PersonController.class); |
private final Log log = LogFactory.getLog(PersonController.class); |
At line 208 changed 2 lines. |
public void setPersonManager(PersonManager userManager) { |
this.mgr = userManager; |
public void setPersonManager(PersonManager personManager) { |
this.mgr = personManager; |
At line 292 added 1 line. |
|
At line 234 changed 1 line. |
Now if you run __ant test-web -Dtestcase=PersonController__, the test should pass. Now we need to create a URL mapping for this controller. To do this, search for the "urlMapping" bean in web/WEB-INF/action-servlet.xml and add the following line to the "mappings" property: |
Now if you run __ant test-web -Dtestcase=PersonController__, the test should pass. Next, create a URL mapping for this controller. To do this, search for the "urlMapping" bean in web/WEB-INF/action-servlet.xml and add the following line to the "mappings" property: |
At line 241 removed 2 lines. |
Now we need to create a Tile's definition for the personList.jsp page. |
|
At line 244 changed 1 line. |
Let's create the JSP to hold our list and a Tile's definition for it. There should already be a personList.jsp in the ''web/pages'' folder of your project. If it's not there, you can use the ViewGen Tool to create it. To do this from the command-line, navigate to extras/viewgen and run __ant -Dform.name=Person__. This will generate a personList.jsp in extras/viewgen/build. |
Open the personList.jsp file in the ''web/pages'' folder of your project. One 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 246 removed 14 lines. |
Once personList.jsp exists in ''web/pages'', open it for editing. |
|
The template we used to create this JSP has the column for the id property hard-coded, so XDoclet adds it twice. We need to remove this from personList.jsp - so delete the following from this file: |
|
[{Java2HtmlPlugin |
|
<display:column property="id" sort="true" headerClass="sortable" |
titleKey="person.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 266 changed 1 line. |
Now we need to add a new definition to tiles-config.xml for this list screen. Open web/WEB-INF/tiles-config.xml and add the following XML: |
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 268 removed 14 lines. |
;:%%(color: blue)''I usually copy an existing list definition - i.e. userList.'' |
|
[{Java2HtmlPlugin |
|
<!-- Person List definition --> |
<definition name="personList" extends="mainMenu"> |
<put name="titleKey" value="personList.title" /> |
<put name="headingKey" value="personList.heading" /> |
<put name="content" value="/WEB-INF/pages/personList.jsp"/> |
</definition> |
}] |
|
Finally, we need to add these keys (personList.title and personList.heading) to web/WEB-INF/classes/ApplicationResources_en.properties. Open this file and add the following: |
|
At line 288 changed 1 line. |
As a reminder, the {{personList.title}} is what ends up in the brower's title bar (the <title> tag) and |
As a reminder, the {{personList.title}} is what ends up in the browser's title bar (the <title> tag) and |
At line 315 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 317 changed 1 line. |
To test that displaying this page works, we can create a new JSP test in test/web/web-tests.xml: |
To test that displaying this page works, you can create a new JSP test in test/web/web-tests.xml: |
At line 381 added 1 line. |
|
At line 361 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 400 changed 1 line. |
You've completed the full lifecycle of developing a set of master-detail pages with AppFuse and Spring's MVC framework - __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 Spring's MVC framework - __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 405 changed 1 line. |
Total time: 2 minutes 31 seconds |
Total time: 4 minutes 21 seconds |
At line 407 removed 2 lines. |
|
If you'd like, you [can download the files created in this tutorial|appfuse-tutorial-springmvc.zip]. |