JSTL 1.0: What JSP Applications Need, Part 2
Pages: 1, 2, 3, 4
Using a Controller to Select the Locale
If you've developed Web applications using Java technology for some time, you have no doubt heard about the MVC pattern and, most likely, about the Apache Struts MVC framework. The basic idea behind the MVC pattern is that an application is easier to maintain and evolve if the different parts of the application (Model, View, and Controller) are implemented as separate components. For Java, this typically means using beans as the Model (business logic), JSP pages as the View (the user interface), and a servlet as the Controller (the piece that controls the communication between the View and the Model). The Struts framework provides a generic Controller servlet that delegates the processing of specific types of requests to classes called Action classes, and then uses a JSP page specified by the Action to generate the response.
JSTL is designed to play well in an MVC-based application by exposing
a class that can be used by any Java component, such as a Struts
Action class, to access the configuration variables used by the
JSTL actions in the JSP pages representing the View. The class is
called javax.servlet.jsp.jstl.core.Config and contains
constants (static final String variables) for all
configuration variables, and methods for setting, getting, and removing
the variables in different JSP scopes. You can use code like this in
a Struts Action class to set the default locale for the session, based on
profile data, when a user logs in to the application:
import javax.servlet.jsp.jstl.core.Config;
...
public class LoginAction extends Action {
public ActionForward perform(ActionMapping mapping,
ActionForm form, HttpServletRequest request,
HttpServletResponse response)
throws IOException, ServletException {
String userName = request.getParameter("userName");
String password = request.getParameter("password");
...
User user = authenticate(userName, password);
if (user != null) {
/*
* Valid user. Set the default locale in the session
* to the user's preferred locale
*/
HttpSession session = request.getSession();
Config.set(session, Config.FMT_LOCALE, user.getLocale());
...
}
}
|
Related Reading
Programming Jakarta Struts |
The Config class provides four versions of the
set() method, one for each JSP scope (specified by the
first method parameter). Here I use the one that sets the variable
in the session scope. The second parameter is the name of the
configuration, typically set by the corresponding constant. The
third parameter is the variable value. For reading and removing
variables, the class provides similar get() and
remove() methods, plus a find() method
for locating a variable in any scope. In addition to using these
methods in a Controller, you may want to use them in your own
custom tag handlers to take advantage of the JSTL configuration setting
mechanism.
Generating Localized Text
While date and number formatting is important when localizing an
application, the text content is, of course, even more so. JSTL is
based on Java, so it leverages the generic i18n support in the Java
platform. When it comes to text, this support is based on what's
called a resource bundle. In its simplest form, a resource
bundle is represented by a text file containing keys and a text
value for each key. This example shows a file with two keys
(hello and goodbye) and their values:
hello=Hello
goodbye=Goodbye
Multiple locales are supported by creating separate files for each
locale, with a filename that includes the locale name. For instance, if
the resource bundle file above represents the English locale, it may
be stored in a file named labels_en.properties. The resource
bundle for the Swedish locale would then be stored in a file named
labels_sv.properties, where sv is the language
code for Swedish. The fixed part of the file name, labels
in this example, is called the resource bundle base name, and
it's combined with a locale specification (such as a language code)
to find the resource bundle for a specific locale. All resource bundle
files include the same keys; only the text differs depending on the
locale. The files must be located in a directory that's part of the Web
container's classpath, typically the application's WEB-INF/classes
directory.
The JSTL action that adds text from a resource bundle to a
page is the <fmt:message> action. The bundle
to use can be specified in a number of ways. One way is to nest
the <fmt:message> actions within the body of
a <fmt:bundle> action:
<fmt:bundle basename="labels">
Hello: <fmt:message key="hello" />
Goodbye: <fmt:message key="goodbye" />
</fmt:bundle>
In this case, the <fmt:bundle> action locates
the bundle for the locale that is the closest match between the
locale configuration setting (or the locales in the
Accept-Language header, if no default locale is set) and the
available resource bundles for the specified base name. The nested
actions then get the text from this bundle for the specified key.
As with the formatting actions, you can also establish a default
bundle, either for the whole application with a context parameter
or with the <fmt:setBundle> action or the
Config class for a specific JSP scope:
<fmt:setBundle basename="labels"/>
...
Hello: <fmt:message key="hello" />
Goodbye: <fmt:message key="goodbye" />
After a default bundle has been defined, you can use the
<fmt:message> actions standalone within the
scope where the default is established.
There are more options for the i18n and formatting actions than
I can fit into this article. For instance, you can use messages
that contain dynamic values assigned using nested
<fmt:param> actions, and override which bundle
to use within a certain context. Another important area when it
comes to i18n is how to handle languages with non-Western characters.
I describe all of this and more in JavaServer Pages, 2nd Edition.
Accessing a Database
A somewhat controversial subject is JSTL's inclusion of actions for accessing a database. Some people see this as encouraging bad practices, and argue that all database access should be performed by pure Java components in an MVC-based application instead of by JSP pages. I agree with this point of view for anything but the simplest applications, but there are a lot of applications that qualify as very simple, and where lack of programming skills or time makes a full-blown MVC architecture impractical. Without JSTL support, these applications often end up with Java database access code in scriptlets instead, and that is far worse from both a development and maintenance standpoint. I'll therefore show you how to use JSTL to access a database in JSP pages, but ask you to keep in mind that this approach is not suitable for all types of applications. If your development team includes Java programmers, you should carefully consider encapsulating the database access code in Java classes instead, and use JSP only to display the result.
The JSTL database actions are based on the general Java database API
(JDBC) and use the javax.sql.DataSource abstraction
introduced in JDBC 2.0 to represent the database.
A DataSource provides connections to the
database and can implement a feature called connection pooling.
Opening a physical connection to a database is a very time-consuming
operation. With connection pooling, it only needs to be done once,
and the same connection can then be reused over and over, without
risking problems associated with other connection-sharing approaches.