UI design with Tiles and Struts


Solution 1: Basic JSP
Consider the following JSP for a.jsp:
   
   
< html >  
< body >
Header
< p >
a's body...
< p >
Footer 
< p >
</ body >
</ html >


Consider the following JSP for b.jsp:

   
   
< html >
< body >
Header
< p >  
b's body... 
< p >
Footer 
< p >
</ body >
</ html >


In many cases, the developers obtain the code from the UI group and literally convert it into a JSP as necessary. As shown above, each JSP has a duplicate header and footer. Solution 1 is undesirable because changes in common view components, like header and footer, require changes in all relevant pages, as each page is responsible for laying out the view components. This simple solution lacks foresight. With so much HTML and JSP code duplication, we minimize the number of pages but at a heavy maintenance cost. There is strong coupling between the different view components, which, as I explained earlier, is undesirable.

Solution 2: JSP include
Consider the following JSP for a.jsp:
   
   
< html >
< body >
<% -- include header -- %>
< jsp:include  page ="/header.jsp"   />
a's body...
< p >
<% -- include footer -- %>
< jsp:include  page ="/footer.jsp"   />
</ body >
</ html >


Consider the following JSP for b.jsp:

   
   
< html >  
< body >
<% -- include header -- %>
< jsp:include  page ="/header.jsp"   />
b's body...
< p >
<% -- include footer -- %>
< jsp:include  page ="/footer.jsp"   />
</ body >
</ html >


Note that common view components, like header and footer, are split up using the JSP include mechanism.

Consider this header.jsp:

Header
<p>

Consider this footer.jsp:

Footer 
<p>



Solution 2 nicely addresses some of Solution 1's major shortcomings. You only need to change common view components once. Hence, this solution greatly eliminates HTML and JSP code repetition, significantly improving application maintainability. It increases the page number a bit, but drastically reduces the tight coupling between common view components and other pages. On the complexity scale, this solution is simple and readily implemented on many real-world applications. However, it has one major drawback: if you change how and where you organize the view components (i.e., by changing the component layout), then you would need to update every page -- resulting in an expensive and prohibitive change. Solution 2 achieves view component reuse, but does not achieve the reuse of layout and templating logic.

Solution 3: Tiles insert

Consider this JSP for a.jsp:

   
   
<% @ taglib uri="/WEB-INF/tiles.tld" prefix="tiles"  %>
< html >
< body >
<% -- include header -- %>
< tiles:insert  page ="/header.jsp"  flush ="true" />
a's body...
< p >
<% -- include footer -- %>
< tiles:insert  page ="/footer.jsp"  flush ="true" />
</ body >
</ html >


Consider this JSP for b.jsp:

   
   
<% @ taglib uri="/WEB-INF/tiles.tld" prefix="tiles"  %>
< html >
< body >
<% -- include header -- %>
< tiles:insert  page ="/header.jsp"  flush ="true" />
b's body...
< p >
<% -- include footer -- %>
< tiles:insert  page ="/footer.jsp"  flush ="true" />
</ body >
</ html >


Instead of using the JSP include mechanism, Solution 3 uses the Tiles insert mechanism. Using the Tiles insert tag, you include the view components in the appropriate positions. In all other aspects, the solution mirrors the JSP include solution (Solution 2) exactly, with the same advantages and disadvantages.

Solution 4: Splitting bodies

Consider this a.jsp:

 
<% @ taglib uri="/WEB-INF/tiles.tld" prefix="tiles"  %>
< html >
< body >
<% -- include header -- %>
< tiles:insert  page ="/header.jsp"  flush ="true" />
<% -- include body -- %>
< tiles:insert  page ="aBody.jsp"  flush ="true" />
<% -- include footer -- %>
< tiles:insert  page ="/footer.jsp"  flush ="true" />
</ body >
</ html >


Consider this b.jsp:

   
   
<% @ taglib uri="/WEB-INF/tiles.tld" prefix="tiles"  %>
< html >
< body >
<% -- include header -- %>
< tiles:insert  page ="/header.jsp"  flush ="true" />
<% -- include body -- %>
< tiles:insert  page ="bBody.jsp"  flush ="true" />
<% -- include footer -- %>
< tiles:insert  page ="/footer.jsp"  flush ="true" />
</ body >
</ html >


Solution 4 differs slightly from the Tiles insert solution. Solution 4 separates the core bodies into their individual pages, like aBody.jsp and bBody.jsp.

Consider the following JSP for aBody.jsp:

a's body...
<p>



Consider the following JSP for bBody.jsp:

b's body...
<p>



Solution 4's advantage: it limits body changes to the respective pages. Also, it lets you reuse the bodies in other places, eliminating the need for repetition and duplication. Thus, the solution further diminishes the coupling between common view components and other application components. Creating and managing each body component introduces an additional complexity level. As with other solutions, each page still does its own layout. Hence, there is no overarching layout policy or scheme.

Solution 5: Templating tiles

Using Tiles's templating feature, you can define the following layout (from the layout.jsp file shown below) as a template. Since this is a layout, you insert placeholders instead of the actual view components using the Tiles insert tag. Thus, for all components, this page defines one reusable layout:

   
   
<% @ taglib uri="/WEB-INF/tiles.tld" prefix="tiles"  %>
< html >
< body >
    
<% -- include header -- %>
    
< tiles:insert  attribute ="header" />
    
    
<% -- include body -- %>
    
< tiles:insert  attribute ="body" />
    
    
<% -- include footer -- %>
    
< tiles:insert  attribute ="footer" />
</ body >
</ html >


Other content pages, like a.jsp and b.jsp, use the above layout for arranging components. In the actual page, you insert the layout using the Tiles insert tag. Using the Tiles put tag, you can specify the actual view components for all placeholders specified in the layout.

Consider this a.jsp:

   
   
<% @ taglib uri="/WEB-INF/tiles.tld" prefix="tiles"  %>
< tiles:insert  page ="/layout.jsp"  flush ="true" >
    
< tiles:put  name ="header"  value ="/header.jsp" />
    
< tiles:put  name ="body"  value ="/aBody.jsp" />
    
< tiles:put  name ="footer"  value ="/footer.jsp" />     
</ tiles:insert >


Consider this b.jsp:

   
   
<% @ taglib uri="/WEB-INF/tiles.tld" prefix="tiles"  %>
< tiles:insert  page ="/layout.jsp"  flush ="true" >
    
< tiles:put  name ="header"  value ="/header.jsp" />
    
< tiles:put  name ="body"  value ="/bBody.jsp" />
    
< tiles:put  name ="footer"  value ="/footer.jsp" />     
</ tiles:insert >


Solution 5's most significant advantage is that it encapsulates the layout scheme or mechanism, drastically reducing the coupling between common view components and other content bodies. However, it increases complexity by introducing another layout page. Understanding and implementing templating can also be difficult at first.

Solution 6: Struts and Tiles

The above layout page, layout.jsp, contains the HTML and JSP code for organizing the components. The content pages, a.jsp and b.jsp, do not contain any HTML code; they just contain the Tiles tags to insert the necessary components. Wouldn't it be nice to specify all the content pages in one XML configuration file?

Let's name that file tileDefinitions.xml and specify its pages as:

   
   
<? xml version="1.0" encoding="ISO-8859-1" ?>
< component-definitions >
    
< definition  name ="aDef"  path ="/layout.jsp" >
        
< put  name ="header"  value ="/header.jsp" />
        
< put  name ="footer"  value ="/footer.jsp" />
        
< put  name ="body"  value ="/aBody.jsp" />
    
</ definition >
    
< definition  name ="bDef"  path ="/layout.jsp" >
        
< put  name ="header"  value ="/header.jsp" />
        
< put  name ="footer"  value ="/footer.jsp" />
        
< put  name ="body"  value ="/bBody.jsp" />
    
</ definition >
    
< definition  name ="cDef"  path ="/layout.jsp" >
        
< put  name ="header"  value ="/header.jsp" />
        
< put  name ="footer"  value ="/footer.jsp" />
        
< put  name ="body"  value ="/cBody.jsp" />
    
</ definition >
</ component-definitions >


Solution 6 eliminates all the content pages, like a.jsp and b.jsp, by putting their definitions in the XML file. Since a resource like a.jsp no longer exists, how can we request it? More importantly, how can we request the definitions in the tileDefinitions.xml file?

The powerful and synergistic integration of Struts and Tiles comes to the rescue. Besides the regular Struts configuration parameters, we specify the configuration file's location as another parameter in the web.xml file, as shown below. Specifying the definitions-config parameter enables Struts to find and know about the Tiles definitions:

  
    
    
<!--  Standard Action Servlet Configuration (with debugging)  -->
  
< servlet >
    
< servlet-name > action </ servlet-name >
<!--
    <servlet-class>org.apache.struts.action.ActionServlet</servlet-class>
-->
    
< servlet-class > org.apache.struts.tiles.ActionComponentServlet </ servlet-class >
    
< init-param >
        
< param-name > definitions-config </ param-name >
        
< param-value > /WEB-INF/tileDefinitions.xml </ param-value >
    
</ init-param >
    ...
  
</ servlet >
 

Solution 6's main advantage is that it consolidates all definitions in an XML configuration file. Eliminating the content pages drastically reduces the total page number. By introducing Struts, we turn up the complexity another notch.

Solution 7: Tiles inheritance

In the definitions configuration file, observe that each page's definition looks similar. Each definition has three components, two of which are fixed as header and footer. A powerful Tiles feature enables inheritance between definitions. Hence, you can define a base definition and let the original definitions inherit from that definition. The original definitions must only supply their unique part. The following shows the XML configuration file with inheritance between definitions:

   
   
<? xml version="1.0" encoding="ISO-8859-1" ?>
< component-definitions >
    
< definition  name ="baseDef"  path ="/layout.jsp" >
        
< put  name ="header"  value ="/header.jsp" />
        
< put  name ="footer"  value ="/footer.jsp" />
        
< put  name ="body"  value ="" />
    
</ definition >
    
< definition  name ="aDef"  extends ="baseDef" >
        
< put  name ="body"  value ="/aBody.jsp" />
    
</ definition >
    
< definition  name ="bDef"  extends ="baseDef" >
        
< put  name ="body"  value ="/bBody.jsp" />
    
</ definition >
    
< definition  name ="cDef"  extends ="baseDef" >
        
< put  name ="body"  value ="/cBody.jsp" />
    
</ definition >
</ component-definitions >


Elimination of duplicate and redundant information in the configuration file is an advantage of this solution. Overall, the advantages and disadvantages of this solution are identical to the Struts and Tiles solution.

Solution summary

The following table summarizes the different solutions with respect to the evaluation criteria. I encourage you to add other creative solutions as well as other important evaluation criteria, such as extensibility, maintainability, and performance.

Evaluate various solutions per specified criteria

SolutionPage numberCode repetitionLayout controlCouplingComplexity
1: Basic*********
2: JSP include********
3: Tiles insert********
4: Splitting bodies***********
5: Templating tiles**********
6: Struts and Tiles**********
7: Tiles inheritance**********
Scale: High: ***   Medium: **   Low: *


The table shows that each solution's complexity level gradually increases. It also shows that as you increase complexity, you reduce code repetition, increase layout-control flexibility, and diminish coupling between unrelated view components. The page number initially increases as various view components split, but as you define more pages in a definitions configuration file, consolidation will occur.  

What solution is best?

The best solution depends on your project's needs and requirements and your skills and knowledge in developing and maintaining a Web application. The Basic solution is too simple; I don't recommend it because it goes against the grain of good software engineering practices. If your Web application is complex, then templating offers great layout control. Hence, you may want to research and utilize a templating framework like Tiles. If you already use Struts, then you should leverage the synergy between Tiles and Struts for a powerful solution.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值