分享
 
 
 

tiles-struts

王朝java/jsp·作者佚名  2006-01-09
窄屏简体版  字體: |||超大  

引用:http://www.javaworld.com/javaworld/jw-01-2002/jw-0104-tilestrut.html

Advertisement

ypically during Web application development, the user interface (UI) group creates the site's look and feel. Based on that look and feel, the group creates HTML pages that represent the application's functionality and navigation. With a servlets and JavaServer Pages (JSPs)-based implementation, where HTML pages are converted into servlets and JSPs, UI developers identify common HTML and JSP view components, such as header, footer, body, menu, and search. This article presents various solutions to effectively and efficiently organize HTML and JSP view components. I evaluate each solution using specific criteria, such as page number, code repetition, and layout control.

To explore templating and layout solutions, we will use the Tiles framework. The Tiles framework's view components are known as tiles. The framework uses an XML configuration file to organize those tiles. This framework not only enables you to reuse tiles, but also the layouts that organize them.

To explore the more powerful and flexible solutions, we will investigate the synergy between the Tiles and Struts frameworks. Struts is an open source framework for developing Web applications using the popular Model-View-Controller (MVC) or Model 2 architectural pattern. Struts comes with a large set of reusable tags for which the Tiles tag library makes an excellent enhancement.

Evaluation criteria

I will evaluate each solution based on the criteria below. The criteria are not mutually exclusive. For a specific situation and particular application, you must always balance between the strengths and weaknesses of each solution with respect to these factors.

Page number

A solution should strive to minimize the number of HTML and JSP pages. As the page number increases, the complexity of developing, managing, and maintaining an application increases drastically.

Code repetition

Under most circumstances, repetition is bad. The more repeated HTML and JSP code, the more difficult it is to develop and maintain an application. A simple change can result in a cascade of changes in many different pages with unpredictable consequences. A concrete and practical way of attaining reuse is to avoid code repetition.

Layout control

While code repetition is bad, repetition of layout logic and code can be worse. Spreading the logic and behavior of view component organization over several JSPs can be a recipe for disaster. Attaining reuse of templating and layout logic is a better form of reuse than only reusing view components. Thus, you can achieve a higher level of reuse with effective layout control.

Coupling

Coupling is the degree of interactivity between entities. Software engineers are taught again and again to minimize coupling between unrelated classes, packages, and so on. We can apply the same principle to view components. Even though there are distinct view components from a user perspective, in the JSP implementation, the components might be intricately coupled. A solution should reduce coupling between unrelated view components.

Complexity

Complexity brings increased development and maintenance costs, making a more complex solution less suitable. Complexity grows fast as well, and what might originally look simple and innocuous can quickly turn into a big mess as you add more pieces.

Solutions

I'll evaluate several solutions using a basic example of JSPs with common view components, like header and footer. I'll present these solutions in order of increasing complexity, and then I'll measure in detail each one against the evaluation criteria.

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>

Now, we define a Struts action, which returns a definition specified in the configuration file upon success. The Struts action DoFirst is a nonoperational action, as shown below:

package com.malani.struts.action;

import org.apache.struts.action.*;

import javax.servlet.http.*;

public class DoFirst extends Action {

public ActionForward perform(

ActionMapping aMapping,

ActionForm aForm,

HttpServletRequest aRequest,

HttpServletResponse aResponse

) {

return aMapping.findForward("success");

}

}

You cannot invoke a definition directly from the browser, but you can invoke one from Struts as if it is an actual resource. Define the Struts actions in the struts-config.xml file as shown below:

<action path="/a"

type="com.malani.struts.action.DoFirst"

>

<forward name="success" path="aDef"/>

</action>

<action path="/b"

type="com.malani.struts.action.DoFirst"

>

<forward name="success" path="bDef"/>

</action>

<action path="/c"

type="com.malani.struts.action.DoFirst"

>

<forward name="success" path="cDef"/>

</action>

Now, invoke the Struts action by requesting a.do and b.do actions respectively to return the desired resource.

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

Solution

Page number

Code repetition

Layout control

Coupling

Complexity

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.

Divine design

In this article, I evaluated various solutions for organizing view components in HTML and JSPs. I also explored the synergy between the Struts and Tiles frameworks. These strategies and solutions will help you make informed design and architectural decisions regarding your Web applications.

I would sincerely like to thank Max Cooper, Stephen Ditlinger, Dru Jensen, Phillip Lindsay, Roshni Malani, Danny Trieu, and Clare Zhang for reviewing this article.

Printer-friendly version |
Mail this to a friend

About the author

Prakash Malani has extensive experience in designing and developing object-oriented software using Java and C++. He has been developing software in many application domains, such as e-commerce, retail, medicine, communications, and interactive television. He practices leading technologies, such as object-oriented analysis & design (OOAD), the Unified Modeling Language (UML), XML, Enterprise JavaBeans (EJBs), JavaServer Pages (JSPs), and more. He teaches Java and related technologies at various institutions, including University of California, Irvine and California State Polytechnic University, Pomona.

Resources

Download the complete source code for Solution 1. Basic JSP:

http://www.javaworld.com/javaworld/jw-01-2002/tilestrut/1_basic.zip

Download the complete source code for Solution 2. JSP include:

http://www.javaworld.com/javaworld/jw-01-2002/tilestrut/2_JSPinclude.zip

Download the complete source code for Solution 3. Tiles insert:

http://www.javaworld.com/javaworld/jw-01-2002/tilestrut/3_tilesInsert.zip

Download the complete source code for Solution 4. Splitting bodies:

http://www.javaworld.com/javaworld/jw-01-2002/tilestrut/4_bodies.zip

Download the complete source code for Solution 5. Templating tiles:

http://www.javaworld.com/javaworld/jw-01-2002/tilestrut/5_templatingTiles.zip

Download the complete source code for Solution 6. Struts and Tiles:

http://www.javaworld.com/javaworld/jw-01-2002/tilestrut/6_struts.zip

Download the complete source code for Solution 7. Tiles inheritance:

http://www.javaworld.com/javaworld/jw-01-2002/tilestrut/7_inheritance.zip

The Tiles framework:

http://www.lifl.fr/~dumoulin/tiles/

See also "Strut Your Stuff with JSP Tags," Thor Kristmundsson (JavaWorld, December 2000):

http://www.javaworld.com/javaworld/jw-12-2000/jw-1201-struts.html

Java Servlet and JavaServer Pages specification:

http://www.jcp.org/aboutJava/communityprocess/final/jsr053/

Browse JavaWorld's Servlets Index:

http://www.javaworld.com/channel_content/jw-servlets-index.shtml

Browse JavaWorld's JavaServer Pages Index:

http://www.javaworld.com/channel_content/jw-jsp-index.shtml

Browse JavaWorld's User Interface Design Index:

http://www.javaworld.com/channel_content/jw-ui-index.shtml

Subscribe to JavaWorld's free weekly email newsletters:

http://www.javaworld.com/subscribe

Speak out in JavaWorld's Java Forum:

http://forums.devworld.com/webx?13@@.ee6b802

You'll find a wealth of IT-related articles from our sister publications at IDG.net

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有