How to implement Master/Detail forms using Spring Roo

I jumped in the Spring Roo wagon since version 1.1.0M1. The first thing I wanted to do after got used to it. It was to try typical requirements that come very often in the work of a Web Developer.
I needed a wep app to work on, so I came up with World Alamac by jD. Basically, WorldAlmanac web site is an experimentation test bed for using Roo. You can visit World Almanac and other Roo-based showcases at https://pragmatikroo.org/showcases.

I created a list of things that I wanted to try: master/detail forms, reports creation, pdf generation, images rendering and SEO to mention a few. Let’s start with the first item of the referred list. The article assumes the Reader is a Developer with familiarity with Spring Roo. For information about Spring Roo please visit the project web site: http://www.springsource.org/roo.

World Almanac Master/Detail Form

The web application uses a database with data of the Countries, Cities and Languages spoken in the Earth. I selected the Country/City entitiesto build a master/detail web form. You can try the web form at http://pragmatikroo.org/worldAlmanac/ on the Cities menu.

As I formalized the master/detail implementation, I realized that it could be get it, as the composition of two list.jspx from the tagx library included with Roo. A top list.jspx for the upper grid (Countries) and another one for the lower (Cities). Some basic grid events are required as well: independent upper and lower navigation, Cities rendering -after country selection- and grids state management.

spring-roo-countries-web-form

Countries Web Form

Master Grid View

The master/detail form is rendered using a customized form created by a finder Roo command. The upper grid code is shown below:
Master Grid Client Code

<page:list id="pl:org.josean.rooworld.domain.Country" items="${countrys}" z="fmh1dw5QkHal9+wnb0JDqVvC1f8=">
      <tblchooser:tblchooser data="${countrys}" maxPages="${upperTblMaxPages}" page="${upage}" size="${usize}" pageid="upage" sizeid="usize" anchorURL="${upperTblAnchorURL}" id="l:org.josean.rooworld.domain.Country" path="/citys" typeIdFieldName="${upperTypeIdFieldName}" z="1FSBfbX2cD9Hf48J/CgEpgGqM5I=">
            <table:column id="c:org.josean.rooworld.domain.Country.name" property="name" maxLength="20" />
            <table:column id="c:org.josean.rooworld.domain.Country.region" property="region" maxLength="20" />
            <table:column id="c:org.josean.rooworld.domain.Country.surfaceArea" property="surfaceArea" z="EnBh6dRSPblki866Bz0xsC4Yvs4=" />
            <table:column id="c:org.josean.rooworld.domain.Country.indepYear" property="indepYear" z="O8Ya+uYQroS0GvycsapKO1RZ3QU=" />
            <table:column id="c:org.josean.rooworld.domain.Country.population" property="population" z="jpsNyj3k7FE84bLm63Wke+N0/lo=" />
            <table:column id="c:org.josean.rooworld.domain.Country.code" property="code" z="?" />
      </tblchooser:tblchooser>
</page:list>

There is a custom tag named tblchooser. This is a custom control that enables attributes to support grid functionaly. Each grid uses local attributes. The tblchooser component is included in the code download associated to this article. Remember this is only the master grid of the master/detail.

Detail Grid Client View

Countries/Cities Web Form after a country selection (Australia)

Detail Grid Client Code

<page:list id="pl:org.josean.rooworld.domain.City" items="${citys}" z="?">
      <table:table data="${citys}" id="l:org.josean.rooworld.domain.City" maxPages="${lowerTblMaxPages}" page="${lpage}" size="${lsize}" pageid="lpage" sizeid="lsize" typeIdFieldName="${lowerTypeIdFieldName}" anchorURL="${lowerTblAnchorURL}" path="/citys" select="false" z="fsLaGs5Dtou//oijKgETnKUig+Q=">
            <table:column id="c:org.josean.rooworld.domain.City.name" property="name" maxLength="20" />
            <table:column id="c:org.josean.rooworld.domain.City.district" property="district" maxLength="20" />
            <table:column id="c:org.josean.rooworld.domain.City.population" property="population" z="IXrFcR0CsSh9GUTIAcPddSpBCrM=" />
      </table:table>
</page:list>

Pretty much same as the upper grid. Only difference it uses just a regular table control.

Server Side code

@RequestMapping(params = { "find=ByIncountry", "form" }, method = RequestMethod.GET)
public String CityController.findCitysByIncountryForm(
	@RequestParam(value = "upage", required = false) Integer upage,
	@RequestParam(value = "usize", required = false) Integer usize,
	@RequestParam(value = "lpage", required = false) Integer lpage,
	@RequestParam(value = "lsize", required = false) Integer lsize,
	@RequestParam(value = "ctryselected", required = false) String ctryselected,
	ModelMap modelMap) {
				modelMap.addAttribute("update", false);
				modelMap.addAttribute("delete", false);
				modelMap.addAttribute("create", false);

	if (upage != null || usize != null) {
		int sizeNo = usize == null ? 10 : usize.intValue();
		modelMap.addAttribute(
		"countrys",
		Country.findCountryEntriesAllObj(
		upage == null ? 0 : (upage.intValue() - 1) * sizeNo,
		sizeNo));

		float nrOfPages = (float) Country.countCountrys() / sizeNo;
		modelMap.addAttribute(
			"upperTblMaxPages",
			(int) ((nrOfPages > (int) nrOfPages || nrOfPages == 0.0) ? nrOfPages + 1
							: nrOfPages));
		modelMap.addAttribute("upperTblAnchorURL", "/citys?find=ByIncountry&form");
		modelMap.addAttribute("upperTypeIdFieldName", "code");
		modelMap.addAttribute("upage", upage);
		modelMap.addAttribute("usize", usize);
	} else {
		modelMap.addAttribute("countrys", Country.findAllCountrysAllObj());
	}

	if (ctryselected != null) {
		int sizeNo = 10;
		lpage = lpage == null ? 0 : lpage.intValue();

		int numOfCities = City.countCitiesByCountry(ctryselected);
		int nrOfPages = (int)Math.ceil(((double)numOfCities) / sizeNo);
		int from =  ( lpage ==0? 0 : (lpage.intValue()-1) * sizeNo );
			
		if (nrOfPages >= 1){
						modelMap.addAttribute("citys",City.findCitysByIncountry(ctryselected,from, 10));
			}
	else {
				modelMap.addAttribute("citys",City.findCitysByIncountry(ctryselected,0,numOfCities));
	}
			
	modelMap.addAttribute("lowerTblMaxPages", nrOfPages);
	modelMap.addAttribute("lowerTblAnchorURL","/citys?find=ByIncountry&form&ctryselected=" + ctryselected+ "&upage=" + upage + "&usize=" + usize);
			
	modelMap.addAttribute("lowerTypeIdFieldName", "id");
	modelMap.addAttribute("lpage", lpage);
	modelMap.addAttribute("lsize", lsize);
	} else {
		if (ctryselected == null)
			modelMap.addAttribute("citys", null);
	}
		return "citys/findCitysByIncountry";
	}

This method code handles the master/detail, countries/cities form of WorldAlmanac web app. As you can see it follows closely the client side. The upper section handles the countries grid population and its navigation. The ctryselected is a pivot the actives the lower section on country selection on the web form. There is not much else to explain here. Basically, it is a light customization of the source code generate by Roo.

That is it!

Download Source

Click here to download source code (ZIP, 3kb)

Conclusion

This is WorldAlmanac master/detail implementation -using Spring Roo- in a nutshell. I sincerely look forward to helping some colleagues Developers that have requested details and source code of it. It is more a detailed description than a ready-to go code. However, I truly believe that the approach can be applied to any particular project. It is a simple implementation that uses nothing more than Spring Roo as it was wrapped in version 1.1.0M1. The components might need some tweak since Roo has evolve since code inception. Further questions would be handled using the blog.



12 Comments

  • Rohit 29 September, 2011, 22:48

    Hi,

    Do you have any idea about how to make these columns sortable

    Thanks & Regards,
    Rohit

    • jD 3 October, 2011, 15:20

      @Rohit,

      Yes, I do…

      Thanks

      • Mohit 9 April, 2013, 13:26

        Hi,

        In one of your replies you said that you can make these columns sortable,
        Request to please share an example on how to do it.

        Thanks & Regards,

  • Brijesh 20 October, 2011, 15:00

    Hi Viral,

    This is nice, I want to create a grid in spring roo and set action ADD/UPDATE/DELETE in this grid so please help me

    • jD 20 October, 2011, 18:26

      @Brijesh,

      Thank you – thank you for your comment…
      I offer consulting services for this kind of help. Please visit my blog page for details at http://pragmatikroo.blogspot.com.

      BTW, I am the author of this tutorial. Viral is just the publisher.

      B. Roogards
      jD

  • leandro ambrosio 12 April, 2012, 19:19

    Hi Mr. JD

    I just wonder how far did you get on the springroo book you have mentioned sometime ago that you would be working latetlly. Shall we expect something to be released soon?

    • jD 13 April, 2012, 2:34

      Hola leandro,

      Thank you very much for asking it…
      Bad news first:
      No luck so far… I thought the best way to get the attention of a book house was by getting the endorsement of VIP on the Spring Roo. I contacted them and initially it seemed that they might support me with it. But never happened. On the other hand it seems the book houses go first with theirs “traditional” authors first or I haven’t introduce myself like a viable author for them.

      Good news:
      I am accumulating more solutions for recurrent questions shown in the Spring Roo forum and others. So now I have material for several books. Like SR and mobile web apps, SR and jQuery and others.

      Finally, I believe that eventually one of these book houses would realize that my approach of publishing books dedicated only on answering questions posted in the forums is a very-very good seller. Why because they are unique in some cases or very hard to find.

      I am open to suggestion too!
      B. Roogards
      jD

      • jD 13 April, 2012, 2:38

        The referred letter was sent to VIP in the SR “Team.” I missed the word team previously.

        I have to ask my friend Viral Patel how to edit a posted blog for the next time.

        Thank you
        jD

  • appu 28 May, 2012, 19:01

    this is non sense. i don get wat is required.

  • Tariq Ahsan 6 June, 2012, 23:21

    Thanks for posting these useful articles on Spring Roo. As I do not have access to Maven Central Repository I am unable to fully utilize the downloadable zip file you have provided us. Wondering if you might be able to have a full web project available for download?

    Please keep on sharing your valuable knowledge and experience. Thanking you again.

  • Yassin 10 January, 2013, 14:14

    First of all, Thanks for this Article., it’s gives us how far can we go with Spring Roo Technology.

    Now i am Beginner in Spring Roo and i want to implement your suggest solution in three level of relationships.

    therefor, I try many times to implement your solution only between to tables , but didn’t work. The reasons are :

    To customize the generated Controller.
    To customize the JSPX Views, i had some difficultes , because of the Tags Elements and the complexity of generated code for the Web Interface.

    one another thing is about the “tablechooser ” Tag. it’s not working form me, it’s give me some errors in the level of “findCitysByIncountry.jspx”, because some of “jsp:directive.attribute” aren’t found.

    I spend a lot of time, without any result, I ask you now for your Help, if you might.

    Best Regards,
    Yassin

  • Ron 10 May, 2013, 20:20

    Hello jD, Your articles are excellent. I have many years Java back ground, I’m interested in learning by doing some roo and rad stuff. Can you email me and I want to discuss a possible arrangement with you. I’m also on gtalk. – icancertify@gmail.com .

    Thanks and keep doing the great work,
    Ron

Leave a Reply

Your email address will not be published. Required fields are marked *

Note

To post source code in comment, use [code language] [/code] tag, for example:

  • [code java] Java source code here [/code]
  • [code html] HTML here [/code]