INTEGRATING SERVLET AND JSP
As you have seen, servlets can manipulate HTTP status codes and headers, use
cookies, track sessions, save information between requests, compress pages, access
cookies, track sessions, save information between requests, compress pages, access
databases, generate GIF images on-the-fly, and perform many other tasks flexibly and
efficiently. Therefore servlets are great when your application requires a lot of real
programming to accomplish its task.
efficiently. Therefore servlets are great when your application requires a lot of real
programming to accomplish its task.
But, generating HTML with servlets can be tedious and can yield a result that is hard
to modify. That’s where JSP comes in; it let’s you separate much of the presentation
from the dynamic content. That way, you can write the HTML in the normal manner,
even using HTML-specific tools and putting your web content developers to work on
your JSP documents.
to modify. That’s where JSP comes in; it let’s you separate much of the presentation
from the dynamic content. That way, you can write the HTML in the normal manner,
even using HTML-specific tools and putting your web content developers to work on
your JSP documents.
Now, let us discuss the limitation of JSP. As you know, the assumption behind a JSP
document is that it provides a single overall presentation. But what if you want to give
totally different results depending on the data that you receive? Beans and custom
tags, although extremely powerful and flexible, but they don’t overcome the limitation
that the JSP page defines a relatively fixed top-level page appearance. The solution is
to use both servlets and Java Server Pages. If you have a complicated application that
may require several substantially different presentations, a servlet can handle the
initial request, partially process the data, set up beans, then forward the results to one
of a number of different JSP pages, depending on the circumstances
document is that it provides a single overall presentation. But what if you want to give
totally different results depending on the data that you receive? Beans and custom
tags, although extremely powerful and flexible, but they don’t overcome the limitation
that the JSP page defines a relatively fixed top-level page appearance. The solution is
to use both servlets and Java Server Pages. If you have a complicated application that
may require several substantially different presentations, a servlet can handle the
initial request, partially process the data, set up beans, then forward the results to one
of a number of different JSP pages, depending on the circumstances
In early JSP specifications, this approach was known as the model 2 approach to JSP.
Rather than completely forwarding the request, the servlet can generate part of the
output itself, then include the output of one or more JSP pages to obtain the final
result.
Rather than completely forwarding the request, the servlet can generate part of the
output itself, then include the output of one or more JSP pages to obtain the final
result.
.4.1 Forwarding Requests
The key to letting servlets forward requests or include external content is to use a
requestDispatcher. You obtain a RequestDispatcher by calling the
getRequestDispatcher method of ServletContext, supplying a URL relative to the
server root
requestDispatcher. You obtain a RequestDispatcher by calling the
getRequestDispatcher method of ServletContext, supplying a URL relative to the
server root
For example, to obtain a RequestDispatcher associated with
http://yourhost/presentations/presentation1.jsp, you would do the following
String url = “/presentations/presentation1.jsp”;
RequestDispatcher dispatcher =
getServletContext().getRequestDispatcher(url);
RequestDispatcher dispatcher =
getServletContext().getRequestDispatcher(url);
Once, you have a RequestDispatcher, you use forward to completely transfer control
to the associated URL and use include to output the associated URL’s content. In both
cases, you supply the HttpServletRequest and HttpServletResponse as arguments.
Both methods throw Servlet-Exception and IOException. For example, the example
4.1 shows a portion of a servlet that forwards the request to one of three different JSP
pages, depending on the value of the operation parameter. To avoid repeating the
getRequestDispatcher call, I use a utility method called gotoPage that takes the URL,
the HttpServletRequest and the HttpServletResponse; gets a RequestDispatcher; and
then calls forward on it.
to the associated URL and use include to output the associated URL’s content. In both
cases, you supply the HttpServletRequest and HttpServletResponse as arguments.
Both methods throw Servlet-Exception and IOException. For example, the example
4.1 shows a portion of a servlet that forwards the request to one of three different JSP
pages, depending on the value of the operation parameter. To avoid repeating the
getRequestDispatcher call, I use a utility method called gotoPage that takes the URL,
the HttpServletRequest and the HttpServletResponse; gets a RequestDispatcher; and
then calls forward on it.
Example 4.1: Request Forwarding Example
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String operation = request.getParameter(“operation”);
if (operation == null) {
operation = “unknown”;
}
if (operation.equals(“operation1”)) {
gotoPage(“/operations/presentation1.jsp”,request, response);
}
else if (operation.equals(“operation2”)) {
gotoPage("/operations/presentation2.jsp", request, response);
}
else {
gotoPage("/operations/unknownRequestHandler.jsp",request,
response);
}
if (operation == null) {
operation = “unknown”;
}
if (operation.equals(“operation1”)) {
gotoPage(“/operations/presentation1.jsp”,request, response);
}
else if (operation.equals(“operation2”)) {
gotoPage("/operations/presentation2.jsp", request, response);
}
else {
gotoPage("/operations/unknownRequestHandler.jsp",request,
response);
}
}
private void gotoPage(String address, HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
RequestDispatcher dispatcher
=getServletContext().getRequestDispatcher(address);
dispatcher.forward(request, response);
}
private void gotoPage(String address, HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
RequestDispatcher dispatcher
=getServletContext().getRequestDispatcher(address);
dispatcher.forward(request, response);
}
Using Static Resources
In most cases, you forward requests to a JSP page or another servlet. In some cases,
however, you might want to send the request to a static HTML page. In an
e-commerce site, for example, requests that indicate that the user does not have a valid
account name might be forwarded to an account application page that uses HTML
forms togather the requisite information. With GET requests, forwarding requests to a
static HTML page is perfectly legal and requires no special syntax; just supply the
address of the HTML page as the argument to getRequestDispatcher. However, since,
forwarded requests use the same request method as the original request, POST
requests cannot be forwarded to normal HTML pages. The solution to this problem is
to simply rename the HTML page to have a .jsp extension. Renaming somefile.html to
somefile.jsp does not change its output for GET requests, but somefile.html cannot
handle POST requests, whereas somefile.jsp gives an identical response for both GET
and POST.
however, you might want to send the request to a static HTML page. In an
e-commerce site, for example, requests that indicate that the user does not have a valid
account name might be forwarded to an account application page that uses HTML
forms togather the requisite information. With GET requests, forwarding requests to a
static HTML page is perfectly legal and requires no special syntax; just supply the
address of the HTML page as the argument to getRequestDispatcher. However, since,
forwarded requests use the same request method as the original request, POST
requests cannot be forwarded to normal HTML pages. The solution to this problem is
to simply rename the HTML page to have a .jsp extension. Renaming somefile.html to
somefile.jsp does not change its output for GET requests, but somefile.html cannot
handle POST requests, whereas somefile.jsp gives an identical response for both GET
and POST.
Supplying Information to the Destination Pages
To forward the request to a JSP page, a servlet merely needs to obtain a
RequestDispatcher by calling the getRequestDispatcher method of ServletContext,
then call forward on the result, supplying the Http- ServletRequest and
HttpServletResponse as arguments. That’s fine as far as it goes, but this approach
requires the destination page to read the information it needs out of the
HttpServletRequest. There are two reasons why it might not be a good idea to have
the destination page look up and process all the data itself. First, complicated
programming is easier in a servlet than in a JSP page. Second, multiple JSP pages may
require the same data, so it would be wasteful for each JSP page to have to set up the
same data. A better approach is for, the original servlet to set up the information that
the destination pages need, then store it somewhere that the destination pages can
easily access. There are two main places for the servlet to store the data that the JSP
pages will use: in the HttpServletRequest and as a bean in the location specific to the
scope attribute of jsp:useBean
RequestDispatcher by calling the getRequestDispatcher method of ServletContext,
then call forward on the result, supplying the Http- ServletRequest and
HttpServletResponse as arguments. That’s fine as far as it goes, but this approach
requires the destination page to read the information it needs out of the
HttpServletRequest. There are two reasons why it might not be a good idea to have
the destination page look up and process all the data itself. First, complicated
programming is easier in a servlet than in a JSP page. Second, multiple JSP pages may
require the same data, so it would be wasteful for each JSP page to have to set up the
same data. A better approach is for, the original servlet to set up the information that
the destination pages need, then store it somewhere that the destination pages can
easily access. There are two main places for the servlet to store the data that the JSP
pages will use: in the HttpServletRequest and as a bean in the location specific to the
scope attribute of jsp:useBean
The originating servlet would store arbitrary objects in the HttpServlet-Request by
using
using
request.setAttribute(“key1”, value1);
The destination page would access the value by using a JSP scripting element to call
Type1 value1 = (Type1)request.getAttribute(“key1”);
Type1 value1 = (Type1)request.getAttribute(“key1”);
For complex values, an even better approach is to represent the value as a bean and
store it in the location used by jsp:useBean for shared beans. For example, a scope of
application means that the value is stored in the ServletContext, and ServletContext
uses setAttribute to store values. Thus, to make a bean accessible to all servlets or JSP
pages in the server or Web application, the originating servlet would do the following
store it in the location used by jsp:useBean for shared beans. For example, a scope of
application means that the value is stored in the ServletContext, and ServletContext
uses setAttribute to store values. Thus, to make a bean accessible to all servlets or JSP
pages in the server or Web application, the originating servlet would do the following
Type1 value1 = computeValueFromRequest(request);
getServletContext().setAttribute(“key1”, value1);
getServletContext().setAttribute(“key1”, value1);
The destination JSP page would normally access the previously stored value by using
jsp:useBean as follows:
jsp:useBean as follows:
<jsp:useBean id= “key1” class= “Type1” scope=“application” />
Alternatively, the destination page could use a scripting element to explicitly call
application.getAttribute(“key1”) and cast the result to Type1. For a servlet to make
application.getAttribute(“key1”) and cast the result to Type1. For a servlet to make
data specific to a user session rather than globally accessible, the servlet would store
the value in the HttpSession in the normal manner, as below:
Type1 value1 = computeValueFromRequest(request);
HttpSession session = request.getSession(true);
session.putValue(“key1”, value1);
HttpSession session = request.getSession(true);
session.putValue(“key1”, value1);
The destination page would then access the value by means of
<jsp:useBean id= “key1” class= “Type1” scope= “session” />
<jsp:useBean id= “key1” class= “Type1” scope= “session” />
The Servlet 2.2 specification adds a third way to send data to the destination page
when using GET requests: simply append the query data to the URL. For example
when using GET requests: simply append the query data to the URL. For example
String address = “/path/resource.jsp?newParam=value”;
RequestDispatcher dispatcher =getServletContext().getRequestDispatcher(address);
dispatcher.forward(request, response);
RequestDispatcher dispatcher =getServletContext().getRequestDispatcher(address);
dispatcher.forward(request, response);
This technique results in an additional request parameter of newParam (with a value
of value) being added to whatever request parameters already existed. The new
parameter is added to the beginning of the query data so that it will replace existing
values if the destination page uses getParameter (use the first occurrence of the named
parameter) rather than get- ParameterValues (use all occurrences of the named
parameter
of value) being added to whatever request parameters already existed. The new
parameter is added to the beginning of the query data so that it will replace existing
values if the destination page uses getParameter (use the first occurrence of the named
parameter) rather than get- ParameterValues (use all occurrences of the named
parameter
Interpreting Relative URLs in the Destination Page
Although a servlet can forward the request to arbitrary locations on the same server,
the process is quite different from that of using the sendRedirect method of
HttpServletResponse.
the process is quite different from that of using the sendRedirect method of
HttpServletResponse.
First, sendRedirect requires the client to reconnect to the new resource, whereas the
forward method of RequestDispatcher is handled completely on the server.
forward method of RequestDispatcher is handled completely on the server.
Second, sendRedirect does not automatically preserve all of the request data; forward
does.
does.
Third, sendRedirect results in a different final URL, whereas with forward, the URL
of the original servlet is maintained.
This final point means that, if the destination page uses relative URLs for images or
style sheets, it needs to make them relative to the server root, not to the destination
page’s actual location. For example, consider the following style sheet entry:
of the original servlet is maintained.
This final point means that, if the destination page uses relative URLs for images or
style sheets, it needs to make them relative to the server root, not to the destination
page’s actual location. For example, consider the following style sheet entry:
<LINK REL=STYLESHEET HREF= “my-styles.css” TYPE= “text/css”>
If the JSP page containing this entry is accessed by means of a forwarded request, mystyles.
css will be interpreted relative to the URL of the originating servlet, not relative
to the JSP page itself, almost certainly resulting in an error. The solution is to give the
full server path to the style sheet file, as follows:
<LINK REL=STYLESHEET HREF= “/path/my-styles.css” TYPE= “text/css”>
The same approach is required for addresses used in <IMG SRC=...> and
<A HREF=...>.
css will be interpreted relative to the URL of the originating servlet, not relative
to the JSP page itself, almost certainly resulting in an error. The solution is to give the
full server path to the style sheet file, as follows:
<LINK REL=STYLESHEET HREF= “/path/my-styles.css” TYPE= “text/css”>
The same approach is required for addresses used in <IMG SRC=...> and
<A HREF=...>.
4.4.2 Including Static or Dynamic Content
If a servlet uses the forward method of RequestDispatcher, it cannot actually send any
output to the client—it must leave that entirely to the destination page. If the servlet
wants to generate some of the content itself but use a JSP page or static HTML
output to the client—it must leave that entirely to the destination page. If the servlet
wants to generate some of the content itself but use a JSP page or static HTML
document for other parts of the result, the servlet can use the include method of
RequestDispatcher instead. The process is very similar to that for forwarding requests:
Call the getRequestDispatcher method of ServletContext with an address relative to
the server root, then call include with the HttpServletRequest and
HttpServletResponse.
RequestDispatcher instead. The process is very similar to that for forwarding requests:
Call the getRequestDispatcher method of ServletContext with an address relative to
the server root, then call include with the HttpServletRequest and
HttpServletResponse.
The two differences when include is used are that you can send content to the browser
before making the call and that control is returned to the servlet after the include call
finishes. Although the included pages (servlets, JSP pages, or even static HTML) can
send output to the client, they should not try to set HTTP response headers. Here is an
example
before making the call and that control is returned to the servlet after the include call
finishes. Although the included pages (servlets, JSP pages, or even static HTML) can
send output to the client, they should not try to set HTTP response headers. Here is an
example
response.setContentType(“text/html”);
PrintWriter out = response.getWriter();
out.println(“...”);
RequestDispatcher dispatcher =
getServletContext().getRequestDispatcher(“/path/resource”);
dispatcher.include(request, response);
out.println(“...”);
PrintWriter out = response.getWriter();
out.println(“...”);
RequestDispatcher dispatcher =
getServletContext().getRequestDispatcher(“/path/resource”);
dispatcher.include(request, response);
out.println(“...”);
The include method has many of the same features as the forward method. If the
original method uses POST, so does the forwarded request. Whatever request data
was associated with the original request is also associated with the auxiliary request,
and you can add new parameters (in version 2.2 only) by appending them to the URL
supplied to getRequestDispatcher. Version 2.2 also supports the ability to get a
RequestDispatcher by name (getNamedDispatcher) or by using a relative URL (use
the getRequestDispatcher method of the HttpServletRequest). However, include does
one thing that forward does not: it automatically sets up attributes in the Http-
ServletRequest object that describe the original request path in case, the included
servlet or JSP page needs that information. These attributes, available to the included
resource by calling getAttribute on the Http-ServletRequest, are listed below:
original method uses POST, so does the forwarded request. Whatever request data
was associated with the original request is also associated with the auxiliary request,
and you can add new parameters (in version 2.2 only) by appending them to the URL
supplied to getRequestDispatcher. Version 2.2 also supports the ability to get a
RequestDispatcher by name (getNamedDispatcher) or by using a relative URL (use
the getRequestDispatcher method of the HttpServletRequest). However, include does
one thing that forward does not: it automatically sets up attributes in the Http-
ServletRequest object that describe the original request path in case, the included
servlet or JSP page needs that information. These attributes, available to the included
resource by calling getAttribute on the Http-ServletRequest, are listed below:
• javax.servlet.include.request_uri
• javax.servlet.include.context_path
• javax.servlet.include.servlet_path
• javax.servlet.include.path_info
• javax
Note that this type of file inclusion is not the same as the nonstandard servlet chaining
supported as an extension by several early servlet engines. With servlet chaining, each
servlet in a series of requests can see (and modify) the output of the servlet before it.
With the include method of RequestDispatcher, the included resource cannot see the
output generated by the original servlet. In fact, there is no standard construct in the
servlet specification that reproduces the behaviour of servlet chaining.
supported as an extension by several early servlet engines. With servlet chaining, each
servlet in a series of requests can see (and modify) the output of the servlet before it.
With the include method of RequestDispatcher, the included resource cannot see the
output generated by the original servlet. In fact, there is no standard construct in the
servlet specification that reproduces the behaviour of servlet chaining.
Also note that this type of file inclusion differs from that supported by the JSP include
directive. There, the actual source code of JSP files was included in the page by use of
the include directive, whereas the include method of RequestDispatcher just includes
the result of the specified resource. On the other hand, the jsp:include action has
behavior similar to that of the include method, except that jsp:include is available only
from JSP pages, not from servlets
directive. There, the actual source code of JSP files was included in the page by use of
the include directive, whereas the include method of RequestDispatcher just includes
the result of the specified resource. On the other hand, the jsp:include action has
behavior similar to that of the include method, except that jsp:include is available only
from JSP pages, not from servlets
4.4.3 Forwarding Requests from JSP Pages
The most common request forwarding scenario is that the request first comes to a
servlet and the servlet forwards the request to a JSP page. The reason is a servlet
usually handles the original request is that checking request parameters and setting up
beans requires a lot of programming, and it is more convenient to do this
programming in a servlet than in a JSP document. The reason that the destination page
is usually a JSP document is that JSP simplifies the process of creating the HTML
content.
servlet and the servlet forwards the request to a JSP page. The reason is a servlet
usually handles the original request is that checking request parameters and setting up
beans requires a lot of programming, and it is more convenient to do this
programming in a servlet than in a JSP document. The reason that the destination page
is usually a JSP document is that JSP simplifies the process of creating the HTML
content.
However, just because this is the usual approach doesn’t mean that it is the only way
of doing things. It is certainly possible for the destination page to be a servlet.
Similarly, it is quite possible for a JSP page to forward requests elsewhere. For
example, a request might go to a JSP page that normally presents results of a certain
type and that forwards the request elsewhere only when it receives unexpected values.
Sending requests to servlets instead of JSP pages requires no changes whatsoever in
the use of the RequestDispatcher. However, there is special syntactic support for
forwarding requests from JSP pages. In JSP, the jsp:forward action is simpler and
easier to use than wrapping up Request-Dispatcher code in a scriptlet. This action
takes the following form
of doing things. It is certainly possible for the destination page to be a servlet.
Similarly, it is quite possible for a JSP page to forward requests elsewhere. For
example, a request might go to a JSP page that normally presents results of a certain
type and that forwards the request elsewhere only when it receives unexpected values.
Sending requests to servlets instead of JSP pages requires no changes whatsoever in
the use of the RequestDispatcher. However, there is special syntactic support for
forwarding requests from JSP pages. In JSP, the jsp:forward action is simpler and
easier to use than wrapping up Request-Dispatcher code in a scriptlet. This action
takes the following form
<jsp:forward page= “Relative URL” />
The page attribute is allowed to contain JSP expressions so that the destination can be
computed at request time.
For example, the following sends about half the visitors tocomputed at request time.
http://host/examples/page1.jsp and the others to http://host/examples/page2.jsp.
<%
String destination;
if (Math.random() > 0.5) {
destination = “/examples/page1.jsp”;
}
else {
destination = “/examples/page2.jsp”;
}
%>
<jsp:forward page= “<%= destination %>” />
No comments:
Post a Comment