Java Server Pages (JSP) is one of the famous tools for Java-based Web application development. A JSP page contains regular markup code plus special JSP elements. When the page is requested, the static markup code and the dynamic content produced by the JSP elements are combined to form the complete response to the request.
It's impossible to tell everything about using JSP effectively in a short article so this article focuses on the frequently asked questions that most new users look for.
1. Choosing the Right Include Mechanism
A JSP page can include page fragments from other files to form the complete response. You can use this, for instance, to keep header, footer, and navigation bar content in separate files and include them in all other pages. There are two include mechanisms: the include directive and the include action. It's not always obvious which one to use, though.
The include directive, <%@ include file="filename.inc" %>, includes the content of the specified file during the translation phase--when the page is converted to a servlet. The main page and the included file are simply merged. This means that scripting variables declared in one file (using scripting elements or an action element like
The include action,
My rule of thumb for when to use the different mechanisms is this:
o Use the include directive if the file changes rarely. It's the fastest mechanism. If your container doesn't automatically detect changes, you can force the changes to take effect by deleting the main page class file.
o Use the include action only for content that changes often, and if which page to include cannot be decided until the main page is requested.
2. Dealing with Buffer
An HTTP response message contains both headers and a body. The headers tell the browser things like what type of data the body contains (HTML text, an image), the size of the body, if the body can be cached, and so on. Headers are also used to set cookies and to tell the browser to automatically get another page (a redirect). All response headers must be sent to the browser before the body is sent.
To allow parts of the body to be produced (from static template text as well as content generated dynamically by JSP elements) before headers are set, the body is buffered. Instead of sending the response to the browser as soon as something is written to the response body, the JSP container writes all static markup code and all dynamic content generated by JSP elements to the buffer. At some point, such as when the buffer is full or the end of the page is reached, the container sends all headers that have been set followed by the buffered body content. In servlet speak, this is called committing the response. After the response has been committed, you can't set headers, such as for cookies or a redirection instruction. Another thing you can't do is forward the request to another page.
In most cases, this is not a problem. The default buffer size is 8KB, more than enough for a typical page, and you can increase it with the buffer attribute of the page directive. But if you use the include action in a page, you may be in for a surprise. Due to limitations in the way the servlet features used by
An unfortunate side-effect of this automatic flushing is that runtime errors triggered by JSP elements after a
3. Passing Data Between Pages Processing the Same Request
Quite often, more than one JSP page is used to process a single request. One example is when you use the include action to include a common navigation bar in all pages. Another example is when you use one page for request processing (e.g., input validation and database access) and then use the forward action,
First of all, the page invoked using a
value="The name or password is not valid" />
The target page has access to the all request parameters the same way, no matter if they are original or additional parameters.
Request parameters can only hold string values. If you need to pass an object, say a UserInfoBean with various user information properties, you need to pass it as a request attribute instead (or as a session or application scope bean, but let's ignore that for now). A request attribute is the same thing as a request scope object, so the first page can create the object and set all its properties with the
class="com.mycompany.UserInfoBean">
...
In order to use the bean in a page invoked through
class="com.mycompany.UserInfoBean" />
4. Choosing Between Forward and Redirect
If you want to pass the control from one page to another, you can either forward to the other page, as described above, or redirect to the new page (using the sendRedirect() method of the implicit response object).
There's an important difference between a forward and a redirect. When you forward, the target page is invoked by the JSP container through an internal method call; the new page continues to process the same request and the browser is not aware of the fact that more than one page is involved. A redirect, on the other hand, means that the first page tells the browser to make a new request to the target page. The URL shown in the browser therefore changes to the URL of the new page when you redirect, but stays unchanged when you use forward. A redirect is slower than a forward because the browser has to make a new request. Another difference is that request scope objects are no longer available after a redirect because it results in a new request. If you need to pass data to the page you redirect to, you have to use a query string and pass them as request parameters (or save the data as session or application scope objects).
So how do you decide if you should use forward or redirect? I look at it like this: Forwarding is always faster, so that's the first choice. But since the URL in the browser refers to the start page even after the forward, I ask myself what happens if the user reloads the page (or just resizes the window; this often reloads the page automatically). If the start page is a page that updates some information, such as adding an item to the shopping cart or inserting information in a database, I don't want it to be invoked again on a reload. To show the result of the processing, I therefore redirect to a page with a confirmation message, instead of using forward.
5. Choosing Between Beans and Custom Actions
In JSP 1.0, JavaBeans were the only type of components that you could use to encapsulate the Java code and invoke using standard JSP action elements, such as
As is often the case in software development, it's hard to say exactly when a bean or a custom action is the preferred component type. My rule of thumb is that a bean is a great carrier of information and a custom action is great for processing information. Custom actions can use beans as input and output. For instance, you can use a bean to capture form input, with the
6. Using Packages for Bean Classes
When you develop a bean to be used in a JSP page, I recommend that you make it part of a named package. A Java class that does not use a package statement ends up in the so-called unnamed package. The servlet class generated from the JSP page is, however, typically assigned to a named package. If you try to refer to a class in the unnamed package from a class in a named package, Java cannot find the class unless you use an import statement to import it. In a JSP page that means you must use both a page directive to import the class, and the
<%@ page import="UserInfoBean" %>
If the bean is part of a named packed, the
class="com.mycompany.UserInfoBean" />
7. Mixing Scripting Variables and Scope Variables
My general advice is that you avoid embedding Java code in your JSP pages. Code in scripting elements can easily lead to hard to find syntax errors and too much code in the pages makes the Web application hard to maintain. One specific area of confusion when you use both Java code scriptlets and JSP action elements is how scripting variables and objects created by an action element in a JSP scope interact. Or rather, don't interact. Consider this example:
class="com.mycompany.UserInfoBean" >
<%
userInfo = new com.mycompany.UserInfoBean();
%>
Here a UserInfoBean instance is created by the
...
<%
userInfo = new com.mycompany.UserInfoBean();
pageContext.setAttribute("userInfo", userInfo);
%>
property="firstName" />
In this modified example, the setAttribute() method is used to replace the page scope object created by
8. Setting Properties to Non-String Data Type Values
Bean properties, as you probably know, are represented by accessor methods: a setter method for a writeable property and a getter method for a readable property. The data type of the property is the data type of the setter method's single argument and the getter methods return type.
The
Property TypeConversion Method boolean or BooleanBoolean.valueOf(String) byte or ByteByte.valueOf(String) char or CharacterString.charAt(int) double or DoubleDouble.valueOf(String) int or IntegerInteger.valueOf(String) float or FloatFloat.valueOf(String) long or LongLong.valueOf(String)
If your property is of a type not listed in the table, you need to take care of the conversion yourself. The most author-friendly way is to use a String property, even for properties that logically should be of a different type, such as a date or a RGB color value, and let the bean convert it internally. But if you really want to use a data type other than String or the ones listed above, the page author can use a request-time attribute value that evaluates to the correct data type to set the property value:
value='<%= new
java.util.Date(request.getParameter("empDate")) %>' />
Note that this example uses a deprecated Date constructor and is very error-prone (it fails if the empDate parameter is missing or doesn't hold a valid date string). I use it only to illustrate how you can set an attribute of a data type that has no JSP-supported conversion rule, such as the Date class used here.
The rules described here for bean properties set by
9. Accessing a Database
One of the most frequently asked questions on Sun Microsystem's JSP-INTEREST mailing list is how to access a database from a JSP page. I'm sorry, but a complete description is out of scope for this article. I can give you some guidelines, though.
JSP is Java, so as in all Java programs, you'd use JDBC to access a database. You can read more about the JDBC API here.
I recommend that you do not put the database access code directly in the JSP page. Instead, create a bean or a custom action that does all the hard work. My book contains a set of custom actions for database access that you can use, and there are many other examples available on the Net (see Tip 10 of this article). For a complex application, you may actually want to use a servlet for all database access and let it forward the request to a JSP page that only deals with rendering the result. This model is often referred to as the Model-View-Controller (MVC) model, or Model 2 (a term used in a prerelease of the JSP specification). I show examples of this alternative in my book as well. You can also learn more about the MVC model from the Apache Struts project.
Database access is typically very expensive in terms of server resources. You should use a connection pool (covered in the book and frequently discussed on the JSP-INTEREST list) to share database connections efficiently between all requests. Another resource saver is to cache the results of database queries as much as possible. In many cases, the database information rarely changes. For instance, product catalog information may change only when products are added or deleted, or when the prices change. For this type of information you can get the data once and save it as an application scope object that all users can access. In the rare event that the information changes, just replace the application scope object with a new version. Another caching strategy for data that changes infrequently is to cache it as a session scope object. The user will then see the data as it looks when the session starts, but changes made during the session are not visible. If you use the session cache strategy, you must also consider if the amount of memory used for the cache (one copy per session) is worth the gain in reduced number of database accesses. Typically it is worth it, but make sure your server has enough memory to handle the peaks.
If you decide to use a cache, don't use the JDBC ResultSet object itself as the cache object. A ResultSet is tightly linked to a specific connection and therefore conflicts with the connection pooling. Instead, copy the data from the ResultSet into an application specific bean, a Vector of Vector's, or something similar.
10. Finding out More
I hope you have found something in this article that helps you develop your JSP based application. But there's a lot more you should know to use this powerful technology as efficiently as possible. I recommend, you read Han’s book on, JavaServer Pages (O'Reilly).
There's also plenty of information on the Internet. The best place to start Sun's JSP page. There you find the JSP specification, articles and tutorials written by Sun employees, and lots of references to other JSP-related sites and products.
No comments:
Post a Comment