Your Website's appearance says loads about your organization's core values. However, it's almost impossible to find a visual design that pleases everybody -- and rolling out a professional design and keeping it consistent throughout the Website is hard work. You cannot make major changes to the visual design without disrupting other elements, such as the layout or the HTML code.
However, you can provide your users with a way to customize your Website to their individual tastes without obstructing the underlying code. With skins, you can create different professional visual designs for your site and give your users a choice of which look and feel they would like to see. And you can do it all without disrupting your JavaServer Pages (JSP) or HTML code!
This article will show how you can use a skin server to add some personalization to your Website. You can use the JSPs in Resources as a starting point for integrating user preferences in your enrollment procedures or your customer self-management features, for example.
Factor out visual elements
A Website's design can be broken into a set of key visual elements that are independent of the underlying HTML or JSP code. A file represents each visual element. For example, GIF or JPEG files symbolize logos or icons; other styles or preferences can be stored in cascading style sheets (CSS) and represented by CSS files. Make sure that you identify and factor out generic visual elements that are loosely coupled with the inner logic, content, or tone of your Website. A skin consists of a set of these visual elements, or files, and can be easily exchanged without disrupting your HTML or JSP code. Exchanging a skin simply means exchanging the relevant files.
With only a few changes to your Website's code, you can request visual elements for a particular skin from a skin server instead of referring to specific underlying files. For example, if you factored out the logo element for your site, the skin server could provide a version of the logo that would change depending on the user's preferences. Internally, the skin server maps the request to a file. For example, if a user who has chosen the Blue Ocean skin wants to download the site logo, the request is mapped to the file data/blue_ocean_logo.gif
. In this way, you can easily add new skins without changing your JSP or HTML code.
Add user preferences
Every customizable Website needs to process and store individual user preferences. A user's collection of preferences is often called a user profile. A user profile might store the visual design the user prefers -- the Blue Ocean design, for example. The sample code in this article uses a JavaBean to store and process a user profile.
Figure 1 shows a Web form from which the user can choose a skin by selecting any one of four radio buttons.
Listing 1 contains the code for the form shown in Figure 1, where users enter their preferences for a user ID and a skin. I designed this simple form to highlight the use of personalization; in a real-world Website, the user profile could hold more information about the user's preferences.
Listing 1: ChangeUserProfile.jsp
<%@ page contentType="text/html" language="Java" import="UserProfileBean" %> <jsp:useBean id="userProfile" class="UserProfileBean" scope="session" /> <jsp:setProperty name="userProfile" property="*" /> <%! private String isSkinChecked( UserProfileBean userProfile, String skin ) { String checkmark = (userProfile.getPreferredSkin().equals(skin))? "CHECKED":"" ; return checkmark; } %> <head> <title>Enter your profile</title> <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> </head> <H1>Enter your profile:</H1> <BR> <form method="post" action="http://localhost:8080/skins/jsp/ProcessUserProfile.jsp"> <TABLE> <TR valign="middle"> <TD>User ID: </TD> <TD><INPUT TYPE='text' NAME='userId' value='<jsp:getProperty name="userProfile" property="userId" />'></TD> </TR> <TR> <TD colspan="2"> </TD> </TR> <TR valign="top"> <TD>Skin: </TD> <TD> <INPUT TYPE="radio" NAME="preferredSkin" VALUE="green_piece" <%= isSkinChecked(userProfile, "Green Piece") %>> Green Peace <BR> <INPUT TYPE="radio" NAME="preferredSkin" VALUE="blue_ocean" <%= isSkinChecked(userProfile, "Blue Ocean") %>> Blue Ocean<BR> <INPUT TYPE="radio" NAME="preferredSkin" VALUE="red_whip" <%= isSkinChecked(userProfile, "Red Whip") %>> Red Whip<BR> </TD> </TR> </TABLE> <DIV ALIGN="center"> <input type="submit" name="Submit" value="Submit"> <input type="reset" name="Submit2" value="Reset"> </DIV> </form>
ChangeUserProfile.jsp
contains a set of radio buttons with which the user can select a skin. The radio buttons' names map to the property preferredSkin
of the userProfile
bean. When the user submits the form, the bean's property is set to the value of the selected radio button. For example, if the user selected the Blue Ocean radio button, the bean's property preferredSkin
would then hold the value blue_ocean
.
After the user submits the form, its values are stored in the JavaBean userProfile
and can be processed. Listing 2 shows sample Java code for a user profile bean, which holds a string with the identifier for the skin that the user has chosen to see. This skin identifier is used later to tailor skin server requests to the user's preference.
Listing 2: UserProfileBean.java
// UserProfileBean.java public class UserProfileBean { String userId ="Anonymous"; String preferredSkin ="Default" ; public void setUserId( String id ) { userId = id ; } public String getUserId() { return userId ; } public void setPreferredSkin( String skinName ) { preferredSkin = skinName ; } public String getPreferredSkin() { return preferredSkin ; } } ;
Process the user profile
The form containing the user preferences is submitted to ProcessUserProfile.jsp
. Listing 3 shows a sample JSP that you can use to process the user profile information. It does not do anything practical, but you can use it as a starting point for storing the user profile in an LDAP (lightweight directory access protocol) directory or in a database.
Listing 3: ProcessUserProfile.jsp
<%@ page contentType="text/html" %> <%@ page language="Java" %> <%@ page import="java.util.*, UserProfileBean" %> <jsp:useBean id="userProfile" class="UserProfileBean" scope="session" /> <jsp:setProperty name="userProfile" property="*"/> User ID is: <jsp:getProperty name="userProfile" property="userId"/> <BR> Preferred Skin : <jsp:getProperty name="userProfile" property="preferredSkin"/> <jsp:forward page="/jsp/PersonalHomepage.jsp"/>
ProcessUserProfile.jsp
ultimately forwards the request to a different JSP that makes use of the user profile.
Add personalization to your Website
You have seen how a user can choose a skin and how this information is stored in a JavaBean. Next, you will learn how to use these preferences to display a personalized Website.
Figure 2 shows a portal displaying the sample skin Green Piece. When you reach Figure 3 below, you'll see the same portal with another sample skin, this one called Red Whip. Although the underlying JSP code is identical (see Listing 4), the design is very different.
Changes to your Website
After the user profile is saved, your JSPs can exploit it to personalize a portal or homepage. Using the user profile bean in your JSPs, you can easily access the relevant properties to generate a personalized page. Listing 4 demonstrates how to use the user profile to create a customized look and feel for the user's preferred skin.
Listing 4: PersonalHomepage.jsp
<%@ page contentType="text/html" language="Java" import="UserProfileBean" %> <JSP:USEBEAN id="userProfile" class="UserProfileBean" scope="session"/> <JSP:SETPROPERTY name="userProfile" property="*"/> <HEAD> <TITLE>My Personalized Homepage</TITLE> <!-- ATN: The following line has been wrapped for better legibility. It should be a single line with no whitespace after "?skin=". --> <LINK rel="stylesheet" href="http://localhost:8080/skins/jsp/SkinServer.jsp?skin= <jsp:getProperty name="userprofile" property="preferredskin"/>&id=css"> </HEAD> <BODY> <!-- ATN: The following line has been wrapped for better legibility. It should be a single line with no whitespace after "?skin=" --> <IMG src="http://localhost:8080/skins/jsp/SkinServer.jsp?skin= <jsp:getProperty name="userprofile" property="preferredskin"/>& id=logo"> <H1>My personalized Homepage!</H1> <TABLE width="100%" border="0" cellspacing="0" cellpadding="0"> <TR> <TD> <TABLE class="Portlet" width="100%" border="0" cellspacing="0" cellpadding="0"> <TR> <TD class="TitleBar"> Title Bar </TD> </TR> <TR> <TD class="ContentArea"> Ipsem lorem retequiem latus gratis forticicum adventiris seculem.<BR> Lorventic marbot simplif forticicum lorentus practicum sempre isbit </TD> </TR> </TABLE> </TD> <TD> </TD> <TD> <TABLE class="Portlet" width="100%" border="0" cellspacing="0" cellpadding="0"> <TR> <TD class="TitleBar"> Title Bar </TD> </TR> <TR> <TD class="ContentArea"> Ipsem lorem retequiem latus gratis forticicum adventiris seculem.<BR>Lorventic marbot simplif forticicum lorentus practicum sempre isbit </TD> </TR> </TABLE> </TD> </TR> </TABLE> </BODY>
Figure 3 shows a portal in the skin called Red Whip. The skins in figures 2 and 3 were both generated by the same JSP code (Listing 4), but they feature different looks.
PersonalHomepage.jsp
makes use of the preferredSkin
property for a user profile bean; the <LINK>
and <IMG>
tags now refer to a JSP's URL and not to files.
The following code demonstrates how to write an <IMG>
tag for a logo.
<IMG SRC = "http://localhost:8080/skins/jsp/SkinServer.jsp?skin=<jsp:getProperty name="userProfile" property="preferredSkin"/>&id=logo">
The <IMG>
tag represents the logo for the personalized homepage. Instead of referring to a static file in the SRC
attribute, the tag now makes a request to a skin server. The request contains two parameters: the preferredSkin
property's value of the userProfile
bean and the visual element's identifier. With the pattern demonstrated in Listing 4, you can replace references to static files to make the skins exchangeable.
The skin server
Listing 5 contains the core of a basic skin server. The skin server loads a property file that contains mappings of pairs (skin, ID) to files. Each mapping is defined as <skin>.<id>=<file>
. The skin server then maps the request parameters to a file name and forwards the request to that file. That file is finally transmitted to the receiver; in this example, the file forwards to the browser that displays the HTML for PersonalHomepage.jsp
.
Listing 5: SkinServer.jsp
<%@ page language="Java" import="java.util.*, UserProfileBean" %> <%-- Load Property bundle --%> <% Properties props = new Properties(); try { props.load( new FileInputStream( application.getRealPath("data/skin.properties") ) ) ; } catch( Exception e ) { e.printStackTrace( System.err ) ; } String parameter = request.getParameter( "skin" ) + "." + request.getParameter( "id" ) ; %> <jsp:forward page="<%=props.getProperty( parameter )%>"/>
In Listing 6, you can see the structure of the properties stored in a property file. For example, a request for the skin blue_ocean
's logo element would map to the file data/yourco_blue_ocean.gif
.
Listing 6: skin.properties
# -- General Structure --# # <skin name>.<skin element>=<file> #-- Red Whip Skin --# red_whip.css=/data/red.css red_whip.logo=/data/yourco_red_whip.gif #-- Blue Ocean Skin --# blue_ocean.css=/data/blue.css blue_ocean.logo=/data/yourco_blue_ocean.gif #-- Green Piece Skin --# green_piece.css=/data/green.css green_piece.logo=/data/yourco_green_piece.gif
Improve performance
You can improve performance by loading the properties files only once, when the SkinServer
JSP loads. For example, you could wrap the properties in a JavaBean, which loads the properties only once and then resides in memory until the JSP unloads.