• Aucun résultat trouvé

Actions: forward, include, and param

Dans le document Beginning JSP, JSF and Tomcat (Page 92-95)

„ „ „

JSP in Action

In Chapter 2, you learned that there are three types of JSP elements: scripting, directives, and actions. I described the first two types directly in Chapter 2, and the time has come to look at JSP actions. Actions, like scriptlets, are processed when a page is requested. In this chapter, you will learn how to use JSP standard actions, how to create actions of your own design, and how to use some of the actions

contained in the JSP Standard Tag Library. Besides small specific examples, you will also learn the role of actions in the eshop application that I introduced in the previous chapter. Actions can do everything that scripting elements can do, as you will see at the end of the next chapter, when I will tell you how to write JSP code without any scripting element at all.

JSP Standard Actions

While Tomcat executes directive elements when translating a page, it executes action elements when processing a client’s HTTP request.

JSP actions specify activities to be performed when a page is requested and can therefore operate on objects and affect the response. They normally take the following form:

<jsp:action-name attr1="value1" [attr2="value2"...]> ... </jsp:action-name>

However, actions can also have a body, like in the following example:

<jsp:action-name attribute-list>

<jsp:subaction-name subaction-attribute-list/>

</jsp:action-name>

There are eight JSP standard actions (forward, include, useBean, setProperty, getProperty, text, element, and plugin) and five additional actions that can only appear in the body of other actions (param, params, attribute, body, and fallback).

Actually, to be precise, there are two additional action elements—invoke and doBody—that you cannot invoke from within JSP pages. More about them later in this chapter. There is also a further standard action—root—that I will explain at the end of the next chapter.

Actions: forward, include, and param

The forward action lets you abort execution of the current page and transfer the request to another page:

<jsp:forward page="myOtherPage.jsp">

<jsp:param name="newParName" value="newParValue"/>

</jsp:forward>

The include action is similar to forward, the main difference being that it returns control to the including page after the included page has completed execution. The output of the included page is appended to the output generated by the including page up to the point where the action is executed.

As shown in the example, jsp:param lets you define a new parameter for the invoked page, which also has access to the parameters already available to the invoking page.

Here is another example of a forward action:

<% String dest = "/myJspPages/" + someVar; %>

<jsp:forward page="<%=dest%>">

<jsp:param name="newParName" value="newParValue"/>

</jsp:forward>

This is 100 percent equivalent to the following scriptlet:

<%

String dest = "/myJspPages/" + someVar;

RequestDispatcher rd = application.getRequestDispatcher(dest + "?newParName=newParValue");

rd.forward(request, response);

%>

Tomcat clears the output buffer upon executing the forward action. Therefore, the HTML code generated up to that point by the current page is lost. But if the current page has already filled the response buffer by the time it is aborted with forward, that part of the response will have already left the server. This will probably result in a bad page sent to the client. Therefore, you have to be very careful when invoking forward from within a page that generates a large output.

You don’t have to worry about such a problem with include, because Tomcat doesn’t clear the output buffer when it executes that action.

With both forward and include, the destination page must be a well-formed and complete JSP page.

The forward action must satisfy the additional requirement of generating a complete and valid HTML page, because the output of the destination page is what goes back to the client’s browser in the HTML response. The destination page of an include action might even generate only a single character, although in most cases it provides HTML code. For example, the top bar of the eshop application is generated in the page TopMenu.jsp (see Listing 4-1) and included in seven JSP pages with this code:

<jsp:include page="TopMenu.jsp" flush="true"/>

The flush attribute (default false) ensures that the HTML generated so far by the including page is sent to the client before executing the included page. Note that the included page is not allowed to change the response headers or the status code.

Listing 4-1. TopMenu.jsp

<%@page language="java" contentType="text/html"%>

<%

String base = (String)application.getAttribute("base");

String imageUrl = (String)application.getAttribute("imageUrl");

%>

<div class="header">

<div class="logo">

<p>e-Shopping Center</p>

</div>

<div class="cart">

<a class="link2" href="<%=base%>?action=showCart">Show Cart <img src="<%=imageUrl%>/cart.gif" border="0"/></a>

</div>

</div>

TopMenu.jsp generates the HTML code in Listing 4-2 (shown after I removed the empty lines).

Listing 4-2. HTML Generated by TopMenu.jsp

<div class="header">

<div class="logo">

<p>e-Shopping Center</p>

</div>

<div class="cart">

<a class="link2" href="/eshop/shop?action=showCart">Show Cart <img src="/eshop/images//cart.gif" border="0"/></a>

</div>

</div>

Notice that TopMenu.jsp uses styles (such as class="header") that aren’t loaded or defined within the same file. If you’re wondering how that’s possible, you probably don’t clearly understand the distinction between source JSP and output HTML. The JSP code in TopMenu.jsp is executed on the server, and it produces HTML code, which is then appended to the output buffer. JSP doesn’t need style sheets. It is the generated HTML that needs them when it’s interpreted by the client’s browser.

You might think that <jsp:include page="..."/> is the same as <%@include file="..."%>, but this is definitely not the case. The most important difference is that while the include directive includes the content of a file without any processing, the include action includes the output of the included resource.

If the resource is a JSP page, this makes a big difference. In practical terms, this also explains why JSP pages to be included with jsp:include must be well-formed and complete pages rather than simply JSP fragments.

To illustrate a subtle consequence of the different mechanisms of inclusion, I have prepared a small test page (see Listing 4-3). To try it out, copy to the usual test folder (webapps\ROOT\tests\) the folder named jsp_includes that you will find in the software package for this chapter, and then type localhost:8080/tests/jsp_includes/includes.jsp in a web browser.

Listing 4-3. includes.jsp

<%@page language="java" contentType="text/html"%>

<html><head><title>A</title></head><body>

<table border="1">

<tr><th>incl B</th><th>incl C</th><th>C contains</th></tr>

<tr><td>jsp:include</td><td>jsp:include</td><td><jsp:include page="d/b_act.jsp"/></td></tr>

As you can see, I first included the d/b_act.jsp and d/b_dir.jsp files with an include action and then with an include directive. The two files contain these lines, respectively:

<%@page language="java" contentType="text/html"%><jsp:include page="c.txt"/>

<%@page language="java" contentType="text/html"%><%@include file="c.txt"%>

I placed a c.txt file (only containing the letter A) in the directory of includes.jsp and a second c.txt file (only containing the letter B) in the d directory. Figure 4-1 shows the result of running includes.jsp.

Figure 4-1. The output of includes.jsp

As you can see, includes.jsp displays the letter B in all cases except when you implement the outer inclusion with the directive and the inner inclusion with the action. This means that only with that particular combination of file inclusions, includes.jsp accesses the c.txt file that is in the same directory. In the other three cases, includes.jsp accesses the c.txt file that is in the d directory, together with b_act.jsp and b_dir.jsp. To understand these results, you have to know that when Tomcat translates a JSP page into a Java class, it replaces <jsp:include page="fname"/> with an execution of the method org.apache.jasper.runtime.JspRuntimeLibrary.include(request, response, "fname", out, false), while <%@include file="fname"%> results in the copying of the content of the fname file.

Therefore, in the third case of the example, the <jsp:include page="c.txt"/> inside b_act.jsp is replaced with an include(request, response, "c.txt", out, false), and then the whole b_act.jsp is copied into includes.jsp. That’s why the servlet picks up the file in the directory of includes.jsp. The fact that b_act.jsp was in a different directory was lost when its include directive was replaced by the file content.

I decided to spend a bit of time on this issue because the inclusion mechanism is often misunderstood and causes many people to knock their heads against the wall when files seem to disappear.

Dans le document Beginning JSP, JSF and Tomcat (Page 92-95)