JSP Controls Tag Library: Login Component Full Source Code
Composite Page, index.jsp
First goes the composite page, index.jsp, that aggregates the Login Component:
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <body> <style type='text/css'> .dottedframe {border: 2px dotted #fa9010; min-width: 30em; padding: 5px;} </style> <p class="dottedframe">This paragraph is defined directly in the parent page and should <strong>precede</strong> the content of login control.</p> <div class="dottedframe" id="LoginComponent"> <jsp:include page="loginComponent.jsp"/> </div> <p class="dottedframe">This paragraph is defined directly in the parent page and should <strong>follow</strong> the content of login control.</p> </body> </html>
The component is inserted into a composite page dynamically using <jsp:include> action. This means, that servlet/JSP container inserts the actual HTML response generated by the component, not JSP code. Two plain text paragraphs are defined in the page to make sure that content from the main page, surrounding the component, is not lost after <jsp:include> action returns.
Login Component, loginComponent.jsp
The Login Component is defined in loginComponent.jsp file:
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <%@ page import="java.util.ArrayList, net.jspcontrols.util.Constants"%> <%@ taglib uri="http://java.sun.com/jstl/core" prefix="c" %> <%@ taglib uri="http://jspcontrols.net/tags-core" prefix="jc" %> <span id="LoginComponent_def"> <%-- ********************************************************************** The stub for authentication service; allows only "user"/"pass" account ********************************************************************** --%> <%! public boolean authenticate(String username, String password){ return "user".equals(username) && "pass".equals(password); } %> <%-- ********************************************************************** Input phase, either postback or regular link containing an event ********************************************************************** --%> <%-- Processing login --%> <jc:handler event="login"> <% // Log out current user first session.removeAttribute("USER"); // Read username and password submitted from dialog form String username = request.getParameter("username"); String password = request.getParameter("password"); // Store user name in session if needed to redisplay. // No need to redisplay password, so it is not stored. session.setAttribute("username", username); // Log the user in if (authenticate(username, password)) { session.removeAttribute("username"); session.setAttribute("USER", username); // User accout is not found, generate error messages } else { ArrayList messages = new ArrayList(); String message = "Account not found."; messages.add(message); session.setAttribute("MESSAGES", messages); } %> </jc:handler> <%-- Processing logout --%> <jc:handler event="logout"> <% // Log out current user first session.removeAttribute("USER"); %> </jc:handler> <%-- Accept phase has finished. Reload the composite page to render a view --%> <jc:reload/> <%-- ********************************************************************** Prerender Phase: URL housekeeping; You can choose a proper view ********************************************************************** --%> <jc:prerender> <% pageContext.setAttribute(Constants.SELECTED_VIEW_NAME, session.getAttribute("USER") != null ? "loggedin" : "notloggedin" ); %> </jc:prerender> <%-- ********************************************************************** Common Render Phase: write out error messages and remove them from session ********************************************************************** --%> <jc:render> <c:if test='${not empty sessionScope.MESSAGES}'> <c:forEach var='message' items='${sessionScope.MESSAGES}'> <ul> <li><b><c:out value='${message}'/></b></li> </ul> </c:forEach> <% session.removeAttribute("MESSAGES"); %> </c:if> </jc:render> <%-- ********************************************************************** Render Phase: User is not logged in. Display login form. ********************************************************************** --%> <jc:render view="notloggedin"> <jsp:include page="loginComponent-viewLogin.jsp" /> </jc:render> <%-- ********************************************************************** Render Phase: User is logged in. Display user info and logout form. ********************************************************************** --%> <jc:render view="loggedin"> <jsp:include page="loginComponent-viewLogout.jsp" /> </jc:render> <%-- ********************************************************************** Render Phase: Clean messages so they won't display on refresh. ********************************************************************** --%> <jc:render> <% session.removeAttribute("MESSAGES"); %> </jc:render> </span>
This does not differ much from the sample code used in the "Component lifecycle" section. The major change is that the views are factored out to separate JSP files. The same can be done for any component. Including one file from another is OK, but do not try to forward from included file, this will not work in most servlet containers (forwarding from included JSP fragment works on Resin though).
Login Panel, loginComponent-viewLogin.jsp
The login panel is defined in loginComponent-viewLogin.jsp file:
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <%@ taglib uri="http://java.sun.com/jstl/core" prefix="c" %> <h3>Log In</h3> <form action="loginComponent.jsp" focus="username"> <table> <!-- username and password --> <tr> <td align="left">Username:</td> <td><input type="text" name="username" maxlength="20" size="20" value="<c:out value='${username}'/>" /></td> </tr> <tr> <td align="left">Password:</td> <td><input type="password" name="password" maxlength="20" size="20" value="" /></td> </tr> <!-- Login button--> <tr> <td></td> <td align="left"> <input type="submit" name="login" value="Log In" /> </td> </tr> </table> </form> <p><em>Username is "user", password is "pass".</em></p>
Logout Panel, lloginComponent-viewLogout.jsp
The logout panel is defined in loginComponent-viewLogout.jsp file and looks similar:
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <%@ taglib uri="http://java.sun.com/jstl/core" prefix="c" %> <h3>Log Out</h3> <form action="loginComponent.jsp"> <table> <!-- User information --> <tr> <td align="left">Username:</td> <td><c:out value="${sessionScope.USER}"/></td> </tr> <!-- Logout button--> <tr> <td></td> <td align="left"> <input type="submit" name="logout" value="Log Out" /> </td> </tr> </table> </form>
When the browser navigates to index.jsp page, the server evaluates the included component, and renders its view as an included fragment. If the user has not logged in yet, the resulting HTML looks like this:
<html> <body> <style type='text/css'> .dottedframe {border: 2px dotted #fa9010; min-width: 30em; padding: 5px;} </style> <p class="dottedframe">This paragraph is defined directly in the parent page and should <strong>precede</strong> the content of login control.</p> <div class="dottedframe" id="LoginComponent"> <h3>Log In</h3> <form action="loginComponent.jsp" focus="username"> <table> <!-- username and password --> <tr> <td align="left">Username:</td> <td><input type="text" name="username" maxlength="20" size="20" value="" /></td> </tr> <tr> <td align="left">Password:</td> <td><input type="password" name="password" maxlength="20" size="20" value="" /></td> </tr> <!-- Logoff and cancel buttons--> <tr> <td></td> <td align="left"> <input type="submit" name="login" value="Log In" /> </td> </tr> </table> </form> <p><em>Username is "user", password is "pass".</em></p> </div> <p class="dottedframe">This paragraph is defined directly in the parent page and should <strong>follow</strong> the content of login control.</p> </body> </html>
See detailed explanation of how this code works in the "Component lifecycle" section.