The concept of Java Server Pages is simple: submerge Java code and some special directives into an HTML page to add dynamic capabilities to it. Obviously, this process can go out of hand when complex logic scatters into an untestable JSP, with operations like database querying deeply coupled to HTML generation.
In this article, I'll present some gotchas and practices that will simplify your JSP coding. The goal of these informations is raising the proficiency and understanding of a JSP programmer from basic to at least intermediate. Feel free to add your own suggestions in the comments.
JSP are servlets
Actually, they generate servlets when they go through a quasi-compilation process. The generated code is usually cached, so it can get out of date and be a source of bugs. Your Servlet container should usually take care of the update process, regenerating servlets and the corresponding class files when a JSP source is changed in a matter of seconds.
One advantage of the intermediate process is the leveraging of existing servlet infrastructure: you can look and analyze at the generated code if something is not working right or when looking for performance problems.
Directives vs. actions
Directives are tags interpreted at compile time: they start with <%@ and translate to actual Java code.
For example, the include directive writes the code of a different JSP into the current one. The page import directive defines the list of import statements for the generated servlet, and so on.
Actions are interpreted at runtime: they start with <%jsp and are translated into glue code. For instance, the include action calls a different JSP and then return in the execution of the current one. That's why there are two different inclusion mechanism in the JSP specification.
Include vs. forwards vs. redirect (directives)Three directives are quite similar in effects, but have peculiarities that make them adapt to different use cases.
- The include directive executes an external JSP and prints the response segment in the current one, continuing the execution.
- The forward directive passes the control to the external JSP, so the subsequent content from the original JSP won't be shown nor executed.
- The redirect tells the client to initiate a new HTTP request; the address shown in the location bar will change and any refresh will point to the new page where the user was directed.
Passing parameters to included JSP or to pages you have forwarded to is the natural next step of breaking down your presentation layer in manageable chunks.
Strings can be passed easily as request parameters since they are the only data type natively supported by HTTP data structures. Other basic types like floats and integers are supported:
<jsp: forward page="another.jsp">
<jsp: param name="username" value="piccoloprincipe" />
Beans are a bit more complex to define, but they are custom data structures (class defined by the user) which you will find useful. The finest advantage of introducing beans is that you can access their properties via valid XML tags, though on the client side they won't be seen since they will already be interpreted. Still, you can generate a JSP via XML mechanism thanks to this accessor tags. The code used for accessing a bean passed to a JSP looks like this:
<jsp:useBean id=“user” class=“com.example.model.User” scope=“request” />
Username: <jsp:getProperty name=“user” property=“username” />
4 scopes: page, request, session, application
The variables referenced in a JSP can belong to different scopes. These scopes are related to servlets in general and not only to JSP files:
- in the page scope, we find the equivalent of local variables.
- in the request scope, you can add parameters via the mechanism shown above, which will be maintained also during the inclusion of other JSP. Parameters are Strings, while attributes can be objects.
- in the session scope, all the variables are visible for the current user until it close the browser or logs out; the scope is accessed through the session predefined object. An example of session variables are login informations.
- In the application scope, variables will be always visible throughout all the various pages; it is accessed through the predefined application object. An example of application-scoped object is a database connection pool.
The latter two scopes are usually only accessed in a JSP, while the former two are the bread and butter of page composition.
What you shouldn't do in a JSP
Some relatively complex operations do not fit in a small script like a JAP, but are better off in a servlet which executed before it, or in model and infrastructure code. For example, these are things I would never want to see in a JSP:
- business logic which can be centralized in a service layer or delegated to a Domain Model.
- Opening or using database connections directly.
- Accessing caches, web services...
JSP are meant to contain presentation logic, and to remain editable from designers and non-programmers. Every bit of Java code that gets into them is dangerous as it can be easily altered during a redesign of the markup.
A JSP still generates HTML
JSP are still composed of code, albeit the majority of it consists of HTML. Give JSP code the same dignity that a servlet's one, like you would do with unit tests or XML build files.
And also keep the generated HTML clean. You may end up viewing it in the browser or during acceptance test runs to debug some error.
Finally, factor out logic in a declarative Api like a custom tag handler or even a simple view helper (a function or object you call from scriptlet code): the resulting JSP will be cleaner and you will be able to reuse your helper classes in other pages.