JBoss at Work: A Practical Guide
2.4. Building the View Cars Page
Let's begin by implementing the View Cars page. As you can imagine, the first thing most people do when they visit a car dealership is walk around the lot to see which cars the dealer has in stock. In a similar vein, we'll create a view that allows visitors to "walk the lot" via the web. This view also gives us an excuse to explore the structure of a WAR file. We'll deploy the WAR to JBoss and see it run in container. Once we have that much under our belt, we'll swing back around and do a quick refactoring to implement the model and controller. 2.4.1. Iteration 1: HTML
JSPs are plain HTML files with some templating capabilities that enable us to plug in data dynamically at runtime. Here is an example of our page using static HTML. (We'll add the dynamic content in just a moment.) Example 2-1 should give you a basic feel for what the webpage will look like, and Figure 2-1 shows the result in a web browser. Example 2-1. carList.html
<html> <body> <table border="1"> <tr> <th bgcolor="cccccc" align="left">Make</th> <th bgcolor="cccccc" align="left">Model</th> <th bgcolor="cccccc" align="right">Model Year</th> </tr> <tr> <td align="left">Toyota</td> <td align="left">Camry</td> <td align="right">2005</td> </tr> <tr> <td align="left">Toyota</td> <td align="left">Corolla</td> <td align="right">1999</td> </tr> <tr> <td align="left">Ford</td> <td align="left">Explorer</td> <td align="right">2005</td> </tr> </table> </body> </html> Figure 2-1. carList.html rendered in a web browser 2.4.2. Iteration 2: JSP and JSTL
Now that we see what we are working toward, let's make this page dynamic. To start, we'll fill the data table using pluggable values rather than using static HTML. While you can include straight Java code in JSPs, this practice is generally frowned upon. First, this "scriptlet" code is not compiled until runtime. This means that your users bear the brunt of missed semicolons and fat-fingered method calls. It also encourages "copy and paste" reuse. Without compiled code, you cannot test it thoroughly, JAR it up, and reuse it across applications. Most importantly, scriptlets aren't tag-based. By relying on them, you mix programming and tag-based technologies. The solution to all these problems is Tag Libraries (taglibs ). Taglibs are compiled Java classes that emit well-formed fragments of HTML. Once you've identified a taglib at the top of your JSP, you can mix the new tags in right along with the native JSP tags. Since taglibs are stored in a JAR file, they can be distributed easily and reused across applications. The JSP Standard Tag Library (JSTL) allows you to use custom tags to do the dynamic things you'd normally do using code or scriptletsinsert data into the page dynamically, perform do/while loops, and use if/then branches, for example. Two JARs make up the the JSTLstandard.jar and jstl.jar. As you'll see in a moment, you should include these JARs in your WAR's WEB-INF/lib directory. Here is the same page using the JSTL to populate the table. Don't worry about the scriptlet at the topwe have a bit of a "chicken and egg" situation on our hands. We use the scriptlet only because we don't have a model or controller in place yet. It will be the first thing to go once we implement the remaining parts of the MVC framework. Focus instead on the JSTL code used to populate the HTML table, as in Example 2-2. Example 2-2. carList-jstl.jsp
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <% // DON'T FREAK OUT!!! This scriptlet code will go away once // we have a model and controller in place... String[ ][ ] carList = { {"Toyota", "Camry", "2005"}, {"Toyota", "Corolla", "1999"}, {"Ford", "Explorer", "2005"} }; pageContext.setAttribute("carList", carList); %> <html> <body> <table border="1"> <tr> <th bgcolor="cccccc" align="left">Make</th> <th bgcolor="cccccc" align="left">Model</th> <th bgcolor="cccccc" align="right">Model Year</th> </tr> <c:forEach items='${carList}' var='car'> <tr> <td align="left">${car[0]}</td> <td align="left">${car[1]}</td> <td align="right">${car[2]}</td> </tr> </c:forEach> </table> </body> </html>
Notice that our source code became considerably shorter. We're using a JSTL forEach loop to walk through each value in the string array instead of building out the entire table by hand. By doing so, we have to describe the row only once instead of for each car, as in the previous HTML example. The syntax used to fill in the <td> elements${car[0]}is the JSP Expression Language (EL). It's not truly tag-based, but is used often in conjunctions with the JSTL. You can use a <c:out> JSTL tag if you'd prefer to use only tag-based solutions. 2.4.3. Iteration 3: CSS
Our source code has gotten considerably more concise, but we're not done optimizing yet. There still is a lot of repetitive formatting syntax in place. The Don't Repeat Yourself (DRY) principle is in serious violation at this point. You can solve this problem by incorporating a bit of Cascading Style Sheet (CSS) magic. CSS is not a J2EE technologyit is part of the HTML standard. Even though Java discussions don't mention it much, it should be an indispensable part of any J2EE developer's toolkit. It allows you to separate presentation details from your data by centralizing styling instructions in a single file. This brings several benefits along for the ride. It keeps your HTML code clean and concise by eliminating all formatting markup. It allows you to create semantic, descriptive styles instead of relying on physical styling. Most importantly, it allows you to change your look and feel globally by modifying a single file. (This is called "skinning" your web site.) Example 2-3 is a simple example of a CSS-styled JSP page. Example 2-3. carList.jsp
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <% // DON'T FREAK OUT!!! This scriptlet code will go away once // we have a model and controller in place... String[ ][ ] carList = { {"Toyota", "Camry", "2005"}, {"Toyota", "Corolla", "1999"}, {"Ford", "Explorer", "2005"} }; pageContext.setAttribute("carList", carList); %> <html> <head> <link rel="stylesheet" type="text/css" href="default.css"> </head> <body> <table> <tr> <th>Make</th> <th>Model</th> <th >Model Year</th> </tr> <c:forEach items='${carList}' var='car'> <tr> <td>${car[0]}</td> <td>${car[1]}</td> <td >${car[2]}</td> </tr> </c:forEach> </table> </body> </html> Example 2-4 is a default CSS-styled JSP page. Example 2-4. default.css
table { border-style: solid; border-color: #aaa; border-width: 1px; } th { color: #000; background-color: #ccc; border-style: solid; border-color: #aaa; border-width: 1px; font-weight: bold; text-align: left; } td { color: #000; background-color: #fff; border-style: solid; border-color: #aaa; border-width: 1px; text-align: left; } .model-year { text-align: right; }
Notice the link to the stylesheet in the JSP's <head> section. This tells the web browser to download the stylesheet and use it to render the page. If the stylesheet cannot be found at the address provided, the web page still will be rendered without an error message or any indication that there was a problem. This means that you can supply a bogus address up front and drop in a valid CSS file reference later on. (Of course if your page isn't formatted the way you'd expect, the link to the CSS file is a good place to start troubleshooting.) In the CSS file, you can set up rendering styles for both built-in tags (table, th) and custom names (model-year). If you plan to apply the style to multiple tags, begin the named style with a period. This creates a CSS class. If you want to limit it to a single use per page (like "footer", "copyright", etc.), begin the named style with a hash ("#"), which creates a CSS ID. We've only scratched the surface of CSS capabilities. In addition to using it for styling, you can use it to precisely position your HTML elements on the screen. This sets the stage for advanced web UI tricks like tabbed interfaces and drag-and-drop. For a more comprehensive discussion of CSS, see Cascading Style Sheets: The Definitive Guide by Eric A. Meyer (O'Reilly). 2.4.4. Deploying the Application as a WAR File
Now that our webpage is looking good, let's bundle everything up into a WAR file and deploy it. The WAR file, as you might guess from its name (Web ARchive), is a collection of presentation tier files. Bundling them up into a single file makes it easy to deploy a complete web application. Recall from the last chapter that all you need to do to deploy a web application in JBoss is copy the WAR file into the $JBOSS_HOME/server/default/deploy directory. In the spirit of high cohesiveness, the WAR file should not contain files that pertain to the other tiers (like EJBs or persistence code). The next chapter discusses the anatomy of an Enterprise Archive (EAR) file. The EAR file is a meta-wrapper, bundling your presentation tier WAR with additional JARs that support the persistence and business tiers. If you haven't done so already, visit http://www.jbossatwork.com and download the sample code bundle. Unzip it to the directory of your choice and change to the ch02 directory. You should see a number of subdirectoriesone for each example in this chapter. Change to /02-view/webapp. Type ant to compile the application and create the WAR file, as in Example 2-5. Example 2-5. Building the WAR using Ant
Buildfile: build.xml clean: [delete] Deleting directory /Users/sdavis/Desktop/jbossatwork/ch02/02-view/webapp/build compile: [mkdir] Created dir: /Users/sdavis/Desktop/jbossatwork/ch02/02-view/webapp/build [mkdir] Created dir: /Users/sdavis/Desktop/jbossatwork/ch02/02-view/webapp/build/classes war: [mkdir] Created dir: /Users/sdavis/Desktop/jbossatwork/ch02/02-view/webapp/build/distribution [war] Building war: /Users/sdavis/Desktop/jbossatwork/ch02/02-view/webapp/build/ distribution/jaw.war all: BUILD SUCCESSFUL Total time: 2 seconds Copy the resulting WAR file to $JBOSS_HOME/server/default/deploy to deploy it. Visit http://localhost:8080/jaw to see it in action. Follow the View Inventory link to see the list of cars. 2.4.5. A Deeper Examination of the WAR
Notice that the URL of your web application is the same as the WAR filename. This URL is called the Context Root . The next chapter shows you how to set your Context Root to be anything, independent of your WAR name. To do this, you'll need to package things up in an EAR. Before getting into the complexity of EARs, though, you need a solid understanding of the WAR file structure. Most graphical zip utilities can display WAR file contents, as in Example 2-6. For fans of the command line, type jar tvf jaw.war. Example 2-6. Contents of jaw.war
0 Mon Mar 28 21:41:50 MST 2005 META-INF/ 103 Mon Mar 28 21:41:48 MST 2005 META-INF/MANIFEST.MF 837 Mon Mar 28 21:33:16 MST 2005 carList-jstl.jsp 637 Mon Mar 28 21:31:56 MST 2005 carList.html 823 Mon Mar 28 21:28:20 MST 2005 carList.jsp 448 Mon Mar 28 21:41:40 MST 2005 default.css 226 Mon Mar 28 21:14:52 MST 2005 index.jsp 0 Mon Mar 28 21:26:42 MST 2005 WEB-INF/ 399 Mon Mar 28 21:01:44 MST 2005 WEB-INF/web.xml 0 Mon Mar 28 21:41:50 MST 2005 WEB-INF/classes/ 0 Mon Mar 28 21:41:50 MST 2005 WEB-INF/lib/ 20682 Fri Feb 11 20:05:08 MST 2005 WEB-INF/lib/jstl.jar 393259 Fri Feb 11 20:05:08 MST 2005 WEB-INF/lib/standard.jar
The root of your WAR file is your web application root. Notice index.jspthis file is the starting page of your application. You'll see momentarily that this is specified in web.xml. Along for the ride are your other JSP and CSS files. Your compiled java classes and library JARs are stored in the WEB INF directory. Files in WEB-INF are hidden from public viewweb users cannot see the directory contents or any of its subdirectories from their browser. They can, however, call a resource stored in WEB-INF (like a servlet), as long as it was configured in web.xml. As you might have guessed by now, WEB-INF/web.xml (Example 2-7) is an important file to be familiar with. It is the main web deployment descriptor file. Example 2-7. web.xml
<?xml version="1.0" encoding="ISO-8859-1"?> <web-app version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee web-app_2_4.xsd"> <!-- The Welcome File List --> <welcome-file-list> <welcome-file>index.jsp</welcome-file> </welcome-file-list> </web-app>
For now, web.xml only identifies the welcome file list. It is common practice to name your main file index.jsp, but you can use any arbitrary name you'd like as long as it is listed here. This file will continue to grow throughout the book. Web.xml is where you identify servlets, JNDI lookups, and security options, among many other things.
2.4.6. Ant
You could painstakingly assemble the WAR by hand, or simply use the WAR task included in Ant. While you're deciding which path to take, look at the Ant task in Example 2-8. Example 2-8. WAR Ant Task
<target name="war" depends="compile" description="Packages the Web files into a WAR file"> <mkdir dir="${distribution.dir}" /> <war destFile="${distribution.dir}/${war.name}" webxml="${web.inf.dir}/web.xml"> <!-- files to be included in / --> <fileset dir="${web.dir}" exclude="WEB-INF/web.xml" /> <!-- files to be included in /WEB-INF/classes --> <classes dir="${classes.dir}" /> <!-- files to be included in /WEB-INF/lib --> <lib dir="${lib.dir}" /> <!-- files to be included in /WEB-INF --> <webinf dir="${web.inf.dir}" excludes="web.xml" /> </war> </target> In case you're not fluent in XML-ese, this task gathers up all files from their various locations and puts them in the appropriate WAR file spot:
Once the WAR file is pieced together, the Ant task places it in ${distribution.dir} (which in our case is build/distribution). Notice the EL-like syntax? It allows us to define variables at the top of the file and reuse them throughout. |