|
JSP - Part 2
This document introduces the use of JSP version 2.0 custom tags and their associated tag handlers. It is at this point that JSP really takes off and the ability to separate business logic (java code) and presentation (html) becomes much greater.
Introduction Java Server Pages (JSP) technology makes it easy to embed bits of Java code (or scriptlets) within HTML documents. This solution, however, may not be suitable for all HTML content developers, perhaps because they do not know Java and they do not care to learn its syntax. While JavaBeans can be used to encapsulate much of the Java code, using them in JSP pages still requires content developers to have some knowledge of Java syntax. JSP technology allows you to introduce new custom tags. As a Java developer, you can enhance JSP pages by introducing custom tags that can be deployed and used in an HTML-like syntax. Custom tags also allow you to provide better packaging - by improving the separation between business logic and presentation. Furthermore, some tags (i.e. tag handlers) may be reusable.
Overview of Tags
A bodyless tag is a tag that has a start tag but does not have a matching end tag. It has the syntax:
Bodyless tags are used to represent certain functions, such as presenting an input field, or displaying an image. Here is an example of a bodyless tag in HTML:
Notice that bodyless tags in HTML - because they are 'old technology' - do not follow ideal syntax : they do not end with '/>'.
A tag with a body has a start tag and a matching end tag, with a 'body' inbetween. It has the syntax: <tagName attributeName="value" anotherAttributeName="anotherValue">tag body</tagName> Tags with a body are used to perform operations on the body content, such as formatting. Here is an example of a tag with a body in HTML ('p' is shorthand for paragraph): <p align="center">body text</p>
JSP Custom Tags JSP custom tags are merely Java classes that implement special interfaces. Once they are developed and deployed, their actions can be called from your HTML using an XML-style syntax. They have a start tag and an end tag. They may or may not have a body. The body-less tag has '/>' at the end - and this is because it follows the more consistent XML format. A bodyless tag can be expressed as:
A tag with a body can be expressed as: <tagLibrary:tagName>body</tagLibrary:tagName>
The Benefits of Custom Tags A very important thing to note about JSP custom tags is that they do not offer more functionality than scriptlets - they simply provide better packaging, by helping you improve the separation of business logic and presentation. Some of the benefits of custom tags are:
In short, you can use custom tags to accomplish complex tasks the same way you use HTML tags to create a complex presentation.
The SimpleTag Interface Prior to JSP version 2.0, there existed functionality for custom tags that in certain respects works differently from that specified in JSP version 2. Although both now co-exist, TJI will, for now at least, only support the later, improved custom tag API. The easy way to spot the difference in tag handlers is that the older handlers implemented the Tag interface with two key methods - doStartTag() and doEndTag(). The latter handlers implement the SimpleTag interface and involve only one key method - doTag(). The complete interface definition of SimpleTag is shown below:
The doTag() method is called only once for any given tag invocation. This means that all code (including tag logic, iteration, or body evaluations) related to this tag is contained in just one method. Class SimpleTagSupport provides a default implementation for all the methods in interface SimpleTag, and it is normally much easier for a custom tag handler class to extend class SimpleTagSupport than itself implement all the methods in interface SimpleTag. The useful methods getParent() and getJspContext() are provided by class SimpleTagSupport. The method getParent() can be called to get the parent tag handler instance in the case of nested tag handlers. Method setParent() will have been called by the server container if the handler is nested. If the handler is not nested, getParent() will return null. The setJspContext() method is called by the server container and provides access to the same variables as the predefined variables available to scriptlets - but via method calls. For example, to get the output stream : getJspContext().getWriter() returns the current JspWriter instance. The following items are valid in a SimpleTag body :
The setJspBody() method is provided to support body content and is called by the server container. The container invokes the setJspBody() method with a JspFragment object encapsulating the body of the tag. The tag handler implementation can call invoke() on that fragment to process the body - that is, to output the static HTML, call child tag handlers, etc. The SimpleTagSupport convenience class provides the method getJspBody().
The SimpleTagSupport Class The javax.servlet.jsp.tagext.SimpleTagSupport class provides a default implementation of all the methods in interface SimpleTag. When developing tag handlers, the best approach in most cases is to extend this class (or your own extension of this class). In most cases the only thing to do next is overide the doTag() method; the default implementation does nothing. The following lifecycle events take place for the simple tag handler (in the same order):
Some Simple Examples
The JSP tag : <mytags:SayHello/> The Java Tag Handler : package mytags;
The JSP tag : <mytags:LoopTwice>Hello (again) !</mytags:LoopTwice> The Java Tag Handler : package mytags;
The JSP tag : <mytags:Loop numLoops="5">Hello again !</mytags:Loop> The Java Tag Handler : package mytags;
Note that the 'setter' methods in tag handlers used to receive tag attributes can have parameter types other than String - the primitive types int, boolean and float are also allowed. This is true for dynamic parameters too.
One can use a JSP expression as a dynamic parameter that is calculated at run-time. For example:
The JSP tag : <mytags:RequestParam id="num"><mytags:Loop>Hello again !</mytags:Loop></mytags:RequestParam>
Loop is almost the same as before - but it will call its parent (tag handler RequestParam) to find out how many times to loop. RequestParam gets a specified parameter from the HttpServletRequest and makes it available to child tag handlers through the method getParam(). The URL calling the JSP page might be something like package mytags; and package mytags;
Of course, the above functionality could much more easily be achieved by using the standard tag library (see JSP Part 3) - but it has demonstrated how custom tags can communicate.
The possibilities here are many! See the custom tag based version of Duke's Book Store example project available from our web site to see some of the many ways this can be done. NOTE : The full way to write a tag handler class, including the required imports and the exceptions it throws, is : import javax.servlet.jsp.*;import javax.servlet.jsp.tagext.*;import java.io.*; You may also need to import javax.servlet.http.*;
Notes on developing JSP in TJI TJI simplifies greatly the development and setup of custom tags. Although some of the more advanced features are lost in this approach, it is ideal for less expert JSP developers or those who just want to learn about the core features of JSP. <tagsetname:tagname> is, in TJI, directly 'translated' to both a full class name of tagsetname.tagname such that tagsetname is the package name - and to a specific directory:
In deployment to a server outside of TJI, there are sets of files to be created that specify these mappings. One of these - the Tag Library Descriptor (TLD) - also provides for some extra functionality that TJI does not currently support (for example, whether a particular parameter is 'required'). However, as can be seen from the Duke's Book Store example projects, it is still possible to do a lot with JSP in TJI. And if you run a separate server, such as TomCat, you can still do the bulk of your development in TJI. The Duke's Book Store example using custom tags comes as two projects:
So, although both the servlets generated from the JSP files and the tag handlers share the same base directory - <homePath>/web/servlets - they are in different directories; the tag handlers will be in directory <homepath>/web/servlets/tags because tags is their package name. Hence, when a tag handler requires access to a class such as BookDB, the database java class (which will be in the servlets directory, the base directory for java code), it needs to be imported by the tag handler - not because it has a different base directory but because it is in a different package. (There is no reason to add to the project classpath - the tag handler classes will be found automatically because they share the same base directory as the auto-generated servlets.) The project type to use for tag handler projects is 'Tag Handler'. A project type of 'JSP' is used for the JSP files, other resources such as HTML and gif image files - and for non-tag handler java files, such as Java Beans. This is the preferred way to develop JSP applications in TJI - the tag handlers are in a separate project, which can be open at the same time. When a tag handler is recompiled you can simply reload the JSP page associated with it - because tag handlers (the newer JSP version 2.0 ones) are instantiated when they are called. When a JSP page is changed, you can also simply reload the page because TJI will know that the page needs to be recompiled. When any JSP file is reloaded by TJI's web browser, all the application's servlets will be reloaded to ensure consistency. The session will also be reset. So if cookies are enabled, you should select 'Clear Cookies' from the 'Options' menu, if these are used to maintain session state, if you wish to start the application run with a new session. The Duke's Book Store example project that uses custom tags could be written in many different ways - the one available for download is one person's 'first cut' notion of how it can be done. But other possibilities may be better. Perhaps by incorporating the use of Java Beans. Although not all features of JSP are yet supported by TJI, this does not preclude the development of any task - the features so far implemented allow you to do anything! It's just that JSP files you might wish to use from your past development, or from elsewhere, might need to be adapted - or run using a separate JSP 'container' (server). Example Project 1 (JSP) - available from our website - illustrates very simply all the main features of JSP - scriptlets, expressions, beans and custom tags (including nested and with dynamic parameters) - and is a good place to start for those new to JSP. When there is a compile-time error or run-time exception involving the java in a JSP page, TJI will show the error by loading the auto-generated java servlet (in read-only mode). Once the problem is identified, you can alter the JSP file or associated tag handler as appropriate and then re-run the project. The auto-generated servlets are named as the associated JSP file plus an underscore. So, for example, Login.jsp will be translated to Login_.java. This is to avoid a name conflict with any hand-coded servlets in the servlets directory. You can set a .jsp file as the project's main 'HTML' file so that simply pressing the 'Run' button will launch the JSP project in the in-built Web Browser ('Web' tab), starting with that page. Finally, note that a difference exists in how TJI translates and runs JSP from most other JSP enabled servers - it is far less pre-emptive in indicating parse errors (structural problems) - but when such problems exist, you will not get the result you would expect - and from what does happen you can easily locate and then solve the problem. This approach is not a design goal - rather, it allows TJI to incorporate a JSP engine that is far smaller than it would otherwise need to be.
|