Implementing the Forum Example

printer-friendly version of this section  Print  e-mail this section  E-Mail  add a public, group or private note  Add Note  add a bookmark about this section  Add Bookmark    

JSTL: JSP Standard Tag Library Kick Start
By Jeff Heaton

Table of Contents
Chapter 7.  Accessing Data with SQL Tags


You have now seen how the JSTL SQL tags work. You have also seen the basic screen and database structure of the forum application. We'll now show you how the forum application is implemented. This way, you can see all of the JSTL SQL tags in action.

The listings in the following sections make up part of the forum application. We will examine only those listings that demonstrate unique uses of the JSTL SQL tags. You can find the source code to the complete forum application on the Sams Publishing Web site.

Let's start at the very beginning, with logging into the system.

Using a Query to Log In

The first page that a user will encounter on the forum application is index.jsp. This file displays a form that asks users either to enter their user ID and password, or to click the Register button to create a new account. Listing 7.4 shows the source code to this page, and Figure 7.5 shows what the form looks like.

Figure 7.5. The login page.

graphics/07fig05.jpg

NOTE

Listing 7.4 shows an example of an index file designed to work with MySQL. If you are using Microsoft Access, you should use the provided index-msa.jsp file. This file has been designed to work with Microsoft Access. All of the other files that make up the forum application will work with either database.


Listing 7.4 Logging In with MySQL (index.jsp)
<%@ taglib uri="http://java.sun.com/jstl/core" prefix="c" %> <%@ taglib uri="http://java.sun.com/jstl/core-rt" prefix="c-rt" %> <%@ taglib uri="http://java.sun.com/jstl/sql" prefix="sql" %> <c:if test="${dataSource==null}">   <sql:setDataSource var="dataSource" driver="org.gjt.mm.mysql.Driver"   url="jdbc:mysql://localhost/forum?user=forumuser"   scope="session" /> </c:if> <c:if test="${pageContext.request.method=='POST'}">   <c:if test="${param.reg!=null}">     <c:redirect url="register.jsp" />   </c:if>   <sql:query var="users" dataSource="${dataSource}">select c_uid,c_type   from t_users where c_uid = ? and c_pwd = ?   <sql:param value="${param.uid}" />   <sql:param value="${param.pwd}" />   </sql:query>   <c:choose>     <c:when test="${users.rowCount<1}">       <h3 color="red">Sorry, we have no one registered with that       name.</h3>       <sql:update var="result" dataSource="${dataSource}">update       t_users set c_bad = c_bad + 1 where c_uid = ?       <sql:param value="${param.uid}" />       </sql:update>     </c:when>     <c:otherwise>       <%         Cookie mycookie = new Cookie("login",request.getParameter("uid"));         mycookie.setMaxAge(0x7ffffff);         response.addCookie(mycookie);        %>       <c:forEach var="aUser" items="${users.rows}">         <c:set var="userID" value="${aUser.c_uid}" scope="session" />         <c:set var="userType" value="${aUser.c_type}"         scope="session" />       </c:forEach>       <c:redirect url="welcome.jsp" />     </c:otherwise>   </c:choose> </c:if> <c-rt:if test="<%=request.getCookies()!=null%>">   <c-rt:forEach var="aCookie" items="<%=request.getCookies()%>">     <c:if test="${aCookie.name=='login'}">       <c:set var="uid" value="${aCookie.value}" />     </c:if>   </c-rt:forEach> </c-rt:if> <html>   <head>     <title>Welcome</title>   </head>   <body>     Welcome to the forum. Please login.<br>     <form method="POST">       <table border="1" cellpadding="0" cellspacing="0"       style="border-collapse: collapse" bordercolor="#111111"       width="49%" >         <tr>           <td width="100%" colspan="2" bgcolor="#0000FF">             <p align="center">               <b>                 <font color="#FFFFFF" size="4">Login to                 Forum</font>               </b>             </p>           </td>         </tr>         <tr>           <td width="26%">Login Name</td>           <td width="74%">           <input type="text" name="uid" value="<c:out value=   "${uid}"/>" size="20" />           </td>         </tr>         <tr>           <td width="26%">Password</td>           <td width="74%">             <input type="password" name="pwd" size="20" />           </td>         </tr>         <tr>           <td width="100%" colspan="2">             <p align="center">               <input type="submit" value="Login" name="Login" />               <input type="submit" value="Register" name="reg" />             </p>           </td>         </tr>       </table>       <p>&#160;</p>     </form>     <p>Note: use id of       <b>admin       </b> and password of       <b>admin       </b> on first use.     </p>   </body> </html> 

There are two distinct modes that the index.jsp page operates in. First, it must prepare to display the login form. Second, it must respond to the data posted by the login form. Let's first examine how the login form is prepared.

Preparing the Login Form

The first thing that the index page does is establish a connection with the database. To do this, the index page first checks to make sure that a connection is not already established. If there is no connection, then a new connection is opened. The following code does this:

<c:if test="${dataSource==null}">   <sql:setDataSource var="dataSource" driver="org.gjt.mm.mysql.Driver"   url="jdbc:mysql://localhost/forum?user=forumuser"   scope="session" /> </c:if> 

As you can see, the connection to the database is stored in the session variable dataSource. The connection will be maintained as long as the user's session remains active. This data source will be used through the application.

Next, the index.jsp file checks to see whether this request was a POST. If it was a POST, then we must process the results of the login form. In this section, we show you what to do if the request is not a POST.

The index page stores as a cookie the name of the user who last logged in. This allows the forum application to automatically default the user ID to the user ID of the last user who logged in. The following code attempts to locate the cookie that holds the ID of the last logged-in user:

<c-rt:if test="<%=request.getCookies()!=null%>">   <c-rt:forEach var="aCookie" items="<%=request.getCookies()%>">     <c:if test="${aCookie.name=='login'}">       <c:set var="uid" value="${aCookie.value}" />     </c:if>   </c-rt:forEach> </c-rt:if> 

This code uses RT tags to access the cookies collection. The cookies collection is then scanned for a cookie named login. If the login cookie is found, it will be used to set the default value for the login ID on the form.

Now, the index.jsp page is ready to display the login form. Once the form is displayed, the user can select to log in or register. When the user clicks one of these two buttons, the index.jsp page posts the data that the user entered back to itself. Let's now see what happens to the login screen when it receives a POST.

Handling a POST

The forum login page is designed to post back to itself. The following JSTL tag allows us to determine whether data has been posted:

<c:if test="${pageContext.request.method=='POST'}">   <c:if test="${param.reg!=null}">     <c:redirect url="register.jsp" />   </c:if> 

This code also checks to see whether the user clicked the Register button. Users are redirected to the register.jsp page if they click the Register button. If the user doesn't click Register, we must determine whether the user ID and password are correct. To do this, we construct a query that returns the rows that match both the user ID and password. There should be only one such row. The following code performs a query that checks to see whether there is a match:

<sql:query var="users" dataSource="${dataSource}">select c_uid,c_type from t_users where c_uid = ? and c_pwd = ? <sql:param value="${param.uid}" /> <sql:param value="${param.pwd}" /> </sql:query> 

As you can see, this SQL command has two parameters and uses two <sql:param> tags. Now that the query has been executed, we must check the results. If no results are found, the following test becomes true:

<c:choose>   <c:when test="${users.rowCount<1}">     <h3 color="red">Sorry, we have no one registered with that     name.</h3> 

This means that the user login has failed. In this case, we should increment the bad login count for this user. The following UPDATE command does this. This command assumes that the user does exist, which has been verified by the previous <c:when> tag:

  <sql:update var="result" dataSource="${dataSource}">update   t_users set c_bad = c_bad + 1 where c_uid = ?   <sql:param value="${param.uid}" />   </sql:update> </c:when> 

If the user record is found, then the user is valid. The following code executes when a valid login occurs:

<c:otherwise>   <% 

First, we need to set the cookie so that the user's name will default during the next login. The following code sets this cookie:

      Cookie mycookie = new Cookie("login",request. getParameter("uid"));       mycookie.setMaxAge(0x7ffffff);       response.addCookie(mycookie);      %> 

Next, we examine the record that was returned. We copy the user's type and login name to session-scoped variables so that they can be accessed later:

<c:forEach var="aUser" items="${users.rows}">   <c:set var="userID" value="${aUser.c_uid}" scope="session" />   <c:set var="userType" value="${aUser.c_type}"   scope="session" /> </c:forEach> 

Now that the user has been logged in, we redirect the user to the welcome page. The following code does this:

<c:redirect url="welcome.jsp" /> 

In the next section, we examine what happens when the user registers.

Using an Update to Register

We saw how the <sql:query> tag can be used to check the user ID and password of a user. Now, let's see how to use the <sql:update> tag to add a new user to the database. Listing 7.5 shows the source code for the registration page, register.jsp, and Figure 7.6 shows our registration page.

Listing 7.5 Registering with the System (register.jsp)
<%@ taglib uri="http://java.sun.com/jstl/core" prefix="c" %> <%@ taglib uri="http://java.sun.com/jstl/core-rt" prefix="c-rt" %> <%@ taglib uri="http://java.sun.com/jstl/sql" prefix="sql" %> <%@ taglib uri="http://java.sun.com/jstl/sql-rt" prefix="sql-rt" %> <c:if test="${pageContext.request.method=='POST'}">   <c:choose>     <c:when test="${param.uid==''}">       <h3>Must enter a login id!</h3>     </c:when>     <c:when test="${param.pwd==''}">       <h3>Must enter a password!</h3>     </c:when>     <c:when test="${param.pwd!=param.pwd2}">       <h3>Passwords do not match!</h3>     </c:when>     <c:otherwise>       <sql:query var="users" dataSource="${dataSource}">       select c_uid from t_users where c_uid = ?       <sql:param value="${param.uid}" />       </sql:query>       <c:choose>         <c:when test="${users.rowCount>0}">           <h3>Someone already has that user id.</h3>         </c:when>         <c:otherwise>           <sql:update var="users" dataSource="${dataSource}">insert           into t_users(c_uid,c_pwd,c_accesses,c_first,c_last,c_bad,c_   posted,c_type) values (?,?,0,NOW(),NOW(),0,0,'G')           <sql:param value="${param.uid}" />           <sql:param value="${param.pwd}" />           </sql:update>           <c:set var="userID" value="${param.uid}"           scope="session" />           <c:set var="userType" value="G" scope="session" />           <c:redirect url="welcome.jsp" />         </c:otherwise>       </c:choose>     </c:otherwise>   </c:choose> </c:if> <html>   <head>     <title>Register</title>   </head>   <body>     <p>     Thanks for joining the forum. Please choose a login name     and a password. Please enter your password twice to verify.     </p>     <form method="POST">       <table border="1" cellpadding="0" cellspacing="0"       style="border-collapse: collapse" bordercolor="#111111"       width="49%" >         <tr>           <td width="100%" colspan="2" bgcolor="#0000FF">             <p align="center">               <b>                 <font color="#FFFFFF" size="4">Register</font>               </b>             </p>           </td>         </tr>         <tr>           <td width="26%">Login Name</td>           <td width="74%">             <input type="text" name="uid" size="20" />           </td>         </tr>         <tr>           <td width="26%">Password</td>           <td width="74%">             <input type="password" name="pwd" size="20" />           </td>         </tr>         <tr>           <td width="26%">Verify Password</td>           <td width="74%">             <input type="password" name="pwd2" size="20" />           </td>         </tr>         <tr>           <td width="100%" colspan="2">             <p align="center">               <input type="submit" value="OK" name="OK" />             </p>           </td>         </tr>       </table>       <p>&#160;</p>     </form>     <p>&#160;</p>   </body> </html> 
Figure 7.6. The registration page.

graphics/07fig06.jpg

The form displayed by this page is a basic HTML form with no data supplied. We begin by examining the process that the register.jsp page goes through when data is posted to it. As usual, the page begins with a check to determine whether this is a POST or simply the first time that the user is displaying the page:

<c:if test="${pageContext.request.method=='POST'}">   <c:choose> 

On this page, the user can log in as a new user. The structure of this page is similar to that of the login page. The page displays a form, as shown in Figure 7.6, and asks the user to fill in information. When the user clicks the OK button, the data is posted back to the register.jsp page.

Once it has been determined that this is a POST, a <c:choose> tag block is entered that will determine whether the user failed to enter all required information. First, we check to see whether the user has entered a valid user ID:

<c:when test="${param.uid==''}">   <h3>Must enter a login id!</h3> </c:when> 

Next, we check to see whether the user entered a password. The user is asked to enter the password again for verification. We do not need to check to see whether a second password has been entered; if the second password is blank, the comparison between the second and the primary password will fail:

<c:when test="${param.pwd==''}">   <h3>Must enter a password!</h3> </c:when> 

Finally, we check to see whether the two passwords match. If they do, then we are ready to try to create an account for this user:

<c:when test="${param.pwd!=param.pwd2}">   <h3>Passwords do not match!</h3> </c:when> 

Before we can create an account, we must ensure that the name chosen by the user has not already been taken. The following query checks for this:

<c:otherwise>   <sql:query var="users" dataSource="${dataSource}">   select c_uid from t_users where c_uid = ?   <sql:param value="${param.uid}" />   </sql:query> 

If rows are returned, then we know that the user's ID has already been taken. If this is the case, we display an error and fall back through to the form so that the user must re-enter the user ID:

<c:choose>   <c:when test="${users.rowCount>0}">     <h3>Someone already has that user id.</h3>   </c:when> 

If the user's ID did match, we execute an insert statement that will add the user to the database:

      <c:otherwise>         <sql:update var="users" dataSource="${dataSource}">insert         into t_users(c_uid,c_pwd,c_accesses,c_first,c_last,c_bad,c_ posted,c_type) values (?,?,0,NOW(),NOW(),0,0,'G')         <sql:param value="${param.uid}" />         <sql:param value="${param.pwd}" />         </sql:update> 

WARNING

Our query uses the NOW() function. This function works in Microsoft Access and MySQL, but may not work in other databases. If your database gives an error for this SQL command, you must replace the NOW() function with whatever function your database uses to return the current time and date.


The next step is to register two session variables that associate this session with the user who just logged in. To do this, we assign the session-scoped variable uid to the user ID. We also assign the session-scoped variable userType to the type of user who just logged on. The following code does this:

  <c:set var="userID" value="${param.uid}"   scope="session" />   <c:set var="userType" value="G" scope="session" />   <c:redirect url="welcome.jsp" /> </c:otherwise> 

Now we will remember what user is logged in from page to page. We can simply access the variable uid and determine the current user. We can also use the userType scoped variable to determine whether the user has sufficient security to undertake certain operations. As you can see, we set the user's type to G for Guest, since this is a new user. Now that the user has been registered, he or she will be taken to the welcome page the same page that the login.jsp page goes to after a successful login.

Welcome to the Forum

We've seen how to query existing data and how to add new data to the database. In this section, we show you how to update data that already exists in the database.

When users successfully register or log in, they are taken to a welcome page. The source code to welcome.jsp is shown in Listing 7.6.

Listing 7.6 Updating User Statistics (welcome.jsp)
<%@ taglib uri="http://java.sun.com/jstl/core" prefix="c" %> <%@ taglib uri="http://java.sun.com/jstl/core-rt" prefix="c-rt" %> <%@ taglib uri="http://java.sun.com/jstl/sql" prefix="sql" %> <%@ taglib uri="http://java.sun.com/jstl/fmt" prefix="fmt" %> <%@ taglib uri="http://java.sun.com/jstl/fmt-rt" prefix="fmt-rt" %> <c:if test="${ userID==null}">   <c:redirect url="index.jsp" /> </c:if> <html>   <head>     <title>welcome</title>   </head>   <body link="#000000" vlink="#000000" alink="#000000">     <sql:query var="users" dataSource="${dataSource}">     select c_uid,c_pwd,c_accesses,c_first,c_last,c_bad,c_posted,c_   type from t_users where c_uid = ?     <sql:param value="${ userID}" />     </sql:query>     <c:forEach var="row" items="${users.rows}">       <table border="0" style="border-collapse: collapse"       bordercolor="#111111" cellpadding="0" cellspacing="0">         <tbody>           <tr>             <td bgcolor="#0000FF" colspan="2">               <b>                 <font color="#FFFFFF">Welcome                 <c:out value="${ userID}" />                 </font>               </b>               <font color="#FFFFFF">&#160;</font>             </td>           </tr>           <tr>             <td bgcolor="#FFFF66"><b>Login ID</b></td>             <td bgcolor="#FFFF66">               <c:out value="${row.c_uid}" />             </td>           </tr>           <tr>             <td bgcolor="#FFFFFF"><b>Times on</b></td>             <td>               <c:out value="${row.c_accesses}" />             </td>           </tr>           <tr>             <td bgcolor="#FFFF66"><b>First Login</b></td>             <td bgcolor="#FFFF66">               <fmt:formatDate value="${row.c_first}" />             </td>           </tr>           <tr>             <td bgcolor="#FFFFFF"><b>Last Login</b></td>             <td>               <fmt:formatDate value="${row.c_last}" />             </td>           </tr>           <tr>             <td bgcolor="#FFFF66"><b>Failed Logins</b></td>             <td bgcolor="#FFFF66">               <c:out value="${row.c_bad}" />             </td>           </tr>           <tr>             <td><b>Messages Posted&nbsp;&nbsp;</b></td>             <td>               <c:out value="${row.c_posted}" />             </td>           </tr>           <tr>             <td bordercolor="#000000" bgcolor="#FFFF66"><b>User             Type</b></td>             <td bgcolor="#FFFF66">               <c:out value="${row.c_type}" />             </td>           </tr>         </tbody>       </table>     </c:forEach>     <sql:update var="result" dataSource="${dataSource}">update     t_users set c_accesses = c_accesses + 1, c_bad = 0, c_last =     now() where c_uid = ?     <sql:param value="${ userID}" />     </sql:update>     <br />     <a href="main.jsp">[Continue]</a>   </body> </html> 

The welcome page accomplishes two primary functions. First, it updates the user's statistics. The number of logins is increased by one, and the bad logins counter is reset to 0. The current date is inserted into the last successful login field. Second, this page displays the user's current statistics. The output from welcome.jsp is shown in Figure 7.7.

Figure 7.7. The welcome page.

graphics/07fig07.jpg

The JSTL code in welcome.jsp begins with a quick security check. The following code ensures that the user's session is valid:

<c:if test="${ userID==null}">   <c:redirect url="index.jsp" /> </c:if> 

If you examine any of the other source files, you'll notice that they contain this same check. The only source files that don't are index.jsp and register.jsp, since at that point the user has not yet logged on. If the user has reached one of the internal pages protected by the <c:if> tag and the user ID is not valid anymore, this means one of two things. Most likely, the user's session has expired, which happens after 30 minutes of inactivity by default. A second possibility is that a hacker is trying to access the site by skipping the login page. In either case, the user is simply routed back to the login page.

The next thing welcome.jsp does is update the user's statistics with this update statement:

<sql:update var="result" dataSource="${dataSource}">update t_users set c_accesses = c_accesses + 1, c_bad = 0, c_last = now() where c_uid = ? <sql:param value="${ userID}" /> </sql:update> 

This code updates the user who has just logged in.

Using Transactions to Administer the Forum

Let's now see how the forum application uses the <sql:transaction> tags to properly delete records from the table. This is done in the main administration page at admin.jsp, shown in Listing 7.7.

Listing 7.7 Administration (admin.jsp)
<%@ taglib uri="http://java.sun.com/jstl/core" prefix="c" %> <%@ taglib uri="http://java.sun.com/jstl/core-rt" prefix="c-rt" %> <%@ taglib uri="http://java.sun.com/jstl/sql" prefix="sql" %> <c:if test="${ userID==null}">   <c:redirect url="index.jsp" /> </c:if> <c:if test="${ userType!='A'}">   <c:redirect url="main.jsp" /> </c:if> <c:if test="${param.mode=='del'}">   <sql:transaction dataSource="${dataSource}">     <sql:update>       delete from t_forums where c_code = ?     <sql:param value="${param.target}" />     </sql:update>     <sql:update>       delete from t_messages where c_forum_code = ?     <sql:param value="${param.target}" />     </sql:update>   </sql:transaction>   <h3>Forum deleted</h3> </c:if> <html>   <head>     <title>Admin</title>   </head>   <body link="#000000" vlink="#000000" alink="#000000">   <sql:query var="forums" dataSource="${dataSource}">select   c_code,c_name from t_forums order by c_sequence</sql:query>   <p>From this screen you can edit forums, delete forums or create   new forums.   <br />   You may also edit users.</p>   <table border="0" width="393">     <tbody>       <tr>         <td colspan="3" bgcolor="#0000FF" width="381">           <b>             <font size="4" color="#FFFFFF">The following forums are             available:</font>           </b>         </td>       </tr>       <c:forEach var="row" items="${forums.rows}"       varStatus="status">         <jsp:useBean          type="javax.servlet.jsp.jstl.core.LoopTagStatus" />         <c-rt:choose>           <c-rt:when test="<%=status.getCount()%2==0%>">             <c:set var="color" value="#FFFFFF" />           </c-rt:when>           <c-rt:otherwise>             <c:set var="color" value="#FFFF66" />           </c-rt:otherwise>         </c-rt:choose>         <c:url value="${pageContext.request.requestURI}" var="del">           <c:param name="mode" value="del" />           <c:param name="target" value="${row.c_code}" />         </c:url>         <c:url value="editforum.jsp" var="edit">           <c:param name="mode" value="edit" />           <c:param name="target" value="${row.c_code}" />         </c:url>         <tr bgcolor="<c:out value="${color}"/>">         <td width="192">           <a href="<c:out value="${del}"/>">[Delete]</a>           <a href="<c:out value="${edit}"/>">[Edit]</a>         </td>         <td width="22">           <c:out value="${row.c_code}" />         </td>         <td width="165">           <c:out value="${row.c_name}" />         </td>         </tr>       </c:forEach>     </tbody>   </table>   &#160;   <p>     <a href="newforum.jsp">[New Forum]</a>     <a href="users.jsp">[Edit Users]</a>     <a href="main.jsp">[Exit]</a>   </p>   </body> </html> 

The administration page does the usual checks to see whether the user's session has expired. However, the administration page also ensures that the user has sufficient access rights to get to this page. If users reach this page without admin security, they are simply redirected to the main forum page, main.jsp:

<c:if test="${ userID==null}">   <c:redirect url="index.jsp" /> </c:if> <c:if test="${ userType!='A'}">   <c:redirect url="main.jsp" /> </c:if> 

This page is also responsible for handling forum deletes. To delete a forum, the page first checks to see whether the user has clicked one of the delete hyperlinks:

<c:if test="${param.mode=='del'}"> 

If the use has requested a delete, then a transaction is begun on the data source:

<sql:transaction dataSource="${dataSource}"> 

Deleting a forum involves two operations, and we need to ensure that both are carried out. If one or the other fails, we want both to fail. To do this, we use a transaction. The first component of the transaction deletes the forum from the t_forums table:

<sql:update>   delete from t_forums where c_code = ? <sql:param value="${param.target}" /> </sql:update> 

In addition, we must ensure that the forum messages are deleted from the t_messages table:

  <sql:update>     delete from t_messages where c_forum_code = ?   <sql:param value="${param.target}" />   </sql:update> </sql:transaction> 

If both of these SQL operations can be carried out, then we consider the operation a success.

We have now seen how the forum example can be implemented using only JSTL tags. This approach is good for a small, or prototype, application. For larger applications, you should move all database access away from the JSP pages and use JSP for display only. In the next few chapters, we bring this program to that level. Chapter 10, "Understanding JSTL Internationalization," will add multilingual abilities to our program. Chapter 11 will show you how to use your own tag library to perform all database access and leave presentation to the JSP.


    printer-friendly version of this section  Print  e-mail this section  E-Mail  add a public, group or private note  Add Note  add a bookmark about this section  Add Bookmark    
    Top

    [0672324504/ch07lev1sec4]

     
     


    JSTL. JSP Standard Tag Library Kick Start
    JSTL: JSP Standard Tag Library Kick Start
    ISBN: 0672324504
    EAN: 2147483647
    Year: 2001
    Pages: 93
    Authors: Jeff Heaton

    flylib.com © 2008-2017.
    If you may any questions please contact us: flylib@qtcs.net