Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

Almost every web application has more than one page. And more often that not, you want to apply a consistent theme or layout across all those pages (or perhaps distinct layouts for each subset of pages). In the very beginning a common approach was to write JSPs like this:

Code Block
xml
languagexml
titleRudimentary layout reuse by include
 
<jsp:include page="/nav/header.jsp"/> 
... 
<jsp:include page="/nav/context.jsp"/> 
My page content here 
<jsp:include page="/nav/footer.jsp" /> 

...

Stripes uses JSPs to both define and render the layouts. The following is an example of a really simple layout, with a consistent header and footer, using the Stripes layout tags:

Code Block
xml
languagexml
title/layout/default.jsp
 
<%@ page contentType="text/html;charset=UTF-8" language="java" %> 
<%@ taglib prefix="stripes" uri="http://stripes.sourceforge.net/stripes.tld" %> 

<stripes:layout-definition> 
<html> 
	<head> 
		<title>Layout Example</title> 
		<link rel="stylesheet" 
			type="text/css" 
			xhref="${pageContext.request.contextPath}/style/default.css"/>
		<stripes:layout-component name="html_head"/> 
	</head> 

	<body> 
		<stripes:layout-component name="header"> 
			<jsp:include page="/layout/_header.jsp"/> 
		</stripes:layout-component> 

		<div class="pageContent"> 
			<stripes:layout-component name="contents"/> 
		</div> 

		<stripes:layout-component name="footer"> 
			<jsp:include page="/layout/_footer.jsp"/> 
		</stripes:layout-component> 
	</body> 
</html> 
</stripes:layout-definition> 

...

Let's take a look at a Hello World page that uses this layout.

Code Block
xml
languagexml
title/HelloWorld.jsp
 
<%@ taglib prefix="stripes" uri="http://stripes.sourceforge.net/stripes.tld" %> 
<stripes:layout-render name="/layout/default.jsp"> 
	<stripes:layout-component name="contents"> 
		Hello World! 
	</stripes:layout-component> 
</stripes:layout-render> 

...

For just this reason the <stripes:layout-render> tag accepts dynamic attributes. This means you can supply any value you like as an attribute to the <stripes:layout-render> tag. All such attributes are made available to the layout definition as page context attributes. And since you can refer to page context attributes using EL, and all sorts of tags, that's pretty handy. Imagine we modified our JSP example above to:

Code Block
xml
languagexml
title/HelloWorld.jsp
 
<%@ taglib prefix="stripes" uri="http://stripes.sourceforge.net/stripes.tld" %> 
<stripes:layout-render name="/layout/default.jsp" pageTitle="Using A Layout"> 
	<stripes:layout-component name="contents"> 
		Hello World! 
	</stripes:layout-component> 
</stripes:layout-render> 

...

Code Block
xml
xml
title/layout/default.jsp
 
... 
<stripes:layout-definition> 
<html> 
	<head> 
		<title>Examples: ${pageTitle}</title> 
		<link rel="stylesheet" 
			type="text/css" 
			xhref="${pageContext.request.contextPath}/style/default.css"/>
		<stripes:layout-component name="html_head"/> 
	</head> 

	<body> 
		<stripes:layout-component name="header"> 
			<jsp:include page="/layout/_header.jsp"/> 
		</stripes:layout-component> 

		<div class="title>${pageTitle}</div> 

		<div class="pageContent"> 
			<stripes:layout-component name="contents"/> 
		</div> 

		<stripes:layout-component name="footer"> 
			<jsp:include page="/layout/_footer.jsp"/> 
		</stripes:layout-component> 
	</body> 
</html> 
</stripes:layout-definition> 

But suppose in some cases the page title isn't quite so simple? Perhaps we want to include the user's name and do some formatting or internationalization? Well, it just so happens that layout-components are also made available in the page context under their name. So we could happily define another JSP that passes the pageTitle this way:

Code Block
xml
languagexml
title/HelloWorld2.jsp
 
<%@ taglib prefix="stripes" uri="http://stripes.sourceforge.net/stripes.tld" %> 
<stripes:layout-render name="/layout/default.jsp"> 
	<stripes:layout-component name="contents"> 
		Hello World! 
	</stripes:layout-component> 
	<stripes:layout-component name="pageTitle"> 
		<jsp:useBean scope="session" name="user" class="com.myco.myapp.User"/> 
		<c:choose> 
			<c:when test="${user.male}>Mr.</c:when> 
			<c:otherwise>Ms.</c:otherwise> 
		<c:choose> 
		${user.lastName} is using a Layout 
	</stripes:layout-component> 
</stripes:layout-render> 

...

This might be obvious, but you can also use a layout to control how a small piece of a page renders. Using the layout tags in this way is very similar to using the new JSP tag files which allow you to write custom tags using JSP fragments. With on important difference. While you can pass the result of JSP fragments to a tag file, those fragments cannot contain any scriptlets. Often this isn't a problem, but sometimes it can get in the way. Anyway, you can imagine that perhaps you want to always display images in a standard way, with a caption. You might define a layout like:

Code Block
xml
languagexml
title/layout/image.jsp
 
<stripes:layout-definition> 
	<table style="minimal"> 
		<tr> 
			<td align="center"><img xsrc="${pageContext.request.contextPath}/${src}" alt="${caption}" /></td> 
		</tr> 
		<tr> 
			<td style="caption">${caption}</td> 
		</tr> 
	</table> 
</stripes:layout-definition> 

And then use that in your JSP to give your images a consistent look and feel:

Code Block
xml
languagexml
title/HelloWorld.jsp
 
<%@ taglib prefix="stripes" uri="http://stripes.sourceforge.net/stripes.tld" %> 
<stripes:layout-render name="/layout/default.jsp" pageTitle="Using A Layout"> 
	<stripes:layout-component name="contents"> 
		<p>Lookee! An image!</p> 

		<stripes:layout-render name="/layout/image.jsp" 
			xsrc="/HelloWorld.jpg" 
			caption="Hello World!"/> 
	</stripes:layout-component> 
</stripes:layout-render> 

...

Now suppose you've come this far and your site looks great, all the navigation is consistent, but you have a bunch of pages that all do searches for various kinds of things, but they all look slightly differently. Some have the search criteria above the results, some below. Some have the buttons left aligned, some right aligned. Etc. You could define a layout for searches, and re-use the global layout! Perhaps it would start out like:

Code Block
xml
languagexml
title/layout/search.jsp
 
<stripes:layout-definition> 
	<stripes:layout-render name="/layout/default.jsp" pageTitle="${type} Search"> 
		<stripes:layout-component name="contents"> 
			<div class="searchFields">${inputs}</div> 
			<div class="searchButtons">${buttons}</div> 
			<div class="searchResults">${results}</div> 
		</stripes:layout-component> 
	</stripe:layout-render> 
</stripes:layout-definition> 

...

Note

Because we have a <stripes:layout-render> tag nested inside a <stripes:layout-definition> tag, any <stripes:layout-component> tags inside the render tag will be bound to the render tag - not the definition tag. That's why, in this example, we use EL expressions (inputs, buttons and results) to import the components from page context instead of <stripes:layout-component> tags.