如何建立一个带登陆页面及角色的Struts数据库应用程序
[目标]
本例的目标是实现一个用户登陆应用程序。用SQL Server 2000数据库保存用户信息。实现用户登陆页面、用户登陆验证、登陆检查标签等功能。
定义一个名为“users”表的字段:
录入一些测试数据:
例如上面的数据,一个用户可能有一个角色,也可以有多个角色。对于多个角色,可以用多条记录来表示,一条记录表示一个角色,也可以用一条记录表示多个角色,每个角色用“;”来分开。
[效果]
欢迎页面:
登陆页面:
登陆完成后主菜单页面:
如果不登陆而是直接运行主菜单页面用户查询页面,将会自动先转到用户登陆页面,这里不再给出演示效果图。
[背景知识]
[步骤]
本例与《如何实现Struts 数据库应用程序》中的步骤相比,除了在建立新项目时一个选择“带登陆页面及角色的Struts数据库应用模板”而另一个选择“空的Struts数据库应用模板”,以及在JSP页面中需要检查用户是否已登陆的地方加一个标签“<app:checkLogon role=“system”/>”之外,其它步骤完全一样,这样相同的步骤详情见《如何实现Struts 数据库应用程序》。
1、打开Visual Struts开发环境:
从桌面JavaWebStudio快揵或BIN目录下的JavaWebStudio.exe文件启动JavaWebStudio的Visual Struts开发环境。
2、建立一个“空的Struts数据库应用模板”应用程序:
选择菜单“文件”—“新建”—“新建项目”,弹出新建项目对话框,如下图1所示:
在对话框中选择“空的Struts数据库应用模板”,在项目名称中输入“Logon”,package (包名)和位置(项目的路径)采用默认的值就行,当然也可以根据需要改变。最后点击“确定”按钮完成新项目的建立。
在Logon项目根目录下包含四个子目录和两个文件,这是JavaWebStudio项目的标准结构,最好不要改变它们默认的名称,否则会出现问题。
利用“带登陆页面及角色的Struts数据库应用模板”生成的项目,自动生成了用户登陆所需的logon.jsp和logonAction.java文件,同时还生成了用于用户登陆演示的文件,其中index.htm是带有一个“登陆”按钮,点击“登陆”按钮转到logon.jsp登陆输入页面,登陆输入完成并提交,如果登陆通过,则转到mainMenu.jsp主菜单页面。在主菜单页面</head>标签后加一个标签“<app:checkLogon role="system"/>”用于检查用户是否已经登陆,其中role属性用于指定用户角色,这里表示只有角色是"system"的用户才能通过。如果已登陆就继续显示页面,否则自动转到登陆页。
logon.jsp文件:
index.htm文件:
mainMenu.jsp文件:
3、利用Struts数据库应用文件向导建立新的应用:
在JavaWebStudio文件管理器内点击鼠标右键,在弹出的菜单中选择“Struts数据库应用文件向导”进入Struts文件向导对话框,也可以选择菜单“文件”—“新建”—“Struts数据库应用文件向导”进入Struts文件向导对话框。
在Struts文件向导对话框JSP文件标签下的文件名输入栏中输入“UserEdit”文件名,其它文件采用默认的设置。
(1)输入文件名:
(2)从数据源中导入SQL语句及数据表的字段信息(字段名和字段类型):
(3)从数据据表中选择所需的表“Users”。
需要特别注意的是,这里的“从数据源中导入SQL语句及数据表的字段信息”及“从数据据表中选择所需的表”仅仅是为了自动生成SQL语句及读取字段信息,这里完成可以直接手工输入,与该项目的数据库连接池的配置无关,下面第(4)点将另行配置数据库连接池。
接下来配置数据库连接池,其它属性页可采用默认的就行了,下面直接转去数据连接配置属性页即可。
(4)JSPOUT属性页设置:
JSPOUT属性页的设置是唯一与《如何实现Struts 数据库应用程序》中的步骤不同之处,这是本例的核心内容。从上图可看出,我们要做的仅仅是把JSPOUT属性页的设置中把“记录操作”选择项中分别选定记录的中添加即可。
(5)配置数据库连接池:
这里需要注意的是用户登陆也是用到这个数据库连接配置。
(6)在新生成的JSP文件中加上用户登陆检查标签<app:checkLogon role=“system”/>:
新生成的JSP文件有三个,查询条件输入文件UserEdit.jsp、添加新记录输入文件UserEditInsert.jsp和查询结果显示文件UserEditOut.jsp。分别在这三个文件的</head>标签后加上用户登陆检查标签<app:checkLogon role=“system”/>。
4、项目文件结构
项目目录结构分析见《如何实现最简单的Struts程序》,这次Struts数据库应用文件向导自动生成了六个文件,其中web目录下是输入、输出两个JSP文件,src目录下是Java文件。除了文件名是我们输入之外,所有程序源代码都是文件向导自动生成的,所有的配置也是自动完成的。
刷新JavaWebStudio文件管理器,这时发现web目录下自动生成了三个文件,分别是UserEdit.jsp和UserEdit.jsp和UserEditInsert.jsp,前者是输入JSP文件,中间是输出JSP文件,后者是添加记录页面文件;src/emptyprj目录下自动生成了四个文件,分别是UserEdit Action.java、UserEdit Form.java,前者是Action文件,后者是FormAction文件;还有是数据库操作文件UserEdit.java和UserEditDAO.java,前者用于保存数据表记录的Bean,后者是数据库操作DAO文件。
4.1、修改DAO文件:
如果数据选择的是SQL Server 2000,需要把DAO文件中的下面代码:
//用SQL Server请加入下行:
//con.setAutoCommit(true);
//SQL Server
都改写成如下代码:
//用SQL Server请加入下行:
con.setAutoCommit(true); //注意啦!!就是这一行,原来是注解掉了,现在是把注解去掉!!
//SQL Server
通过上述改写,才能通过JDBC对SQL Server 2000进行记录更新、删除和添加等操作。
4.2 在需要进行用户登陆识别的地方加入登陆识别标签
(1)UserEdit.jsp文件:
在<body>前加上<app:checkLogon role=“system”/>标签
<%@ page contentType="text/html;charset=GB2312" language="java" %>
<%@ taglib uri="/WEB-INF/struts-bean.tld" prefix="bean" %>
<%@ taglib uri="/WEB-INF/struts-html.tld" prefix="html" %>
<%@ taglib uri="/WEB-INF/struts-logic.tld" prefix="logic" %>
<%@ taglib uri="/WEB-INF/struts-template.tld" prefix="template" %>
<html:html>
<head>
<title></title>
<html:base/>
</head>
<app:checkLogon role=“system”/>
<body bgcolor="white">
<html:form action="/UserEditAction.do?action=search&search=search&expression=NULL" method="post">
请输入要查找的 username : <html:text property="username" />
<html:submit value="查找" />
<html:reset value="重写" />
</html:form>
<html:form action="UserEditAction.do?action=search&expression=NULL" method="post">
<html:submit value="全部显示" />
</html:form>
</body>
</html:html>
4.3 在mainMenu.jsp主菜单页面的左页面left.htm中加入一个新菜单项“用户查查询”:
加入的代码主要是:<A href="UserEdit.jsp" target=main>用户查询</A>
5、编译、启动服务器、运行:
通过工具条上的按键分别编译项目及启动服务器,然后把开index.htm并通过工具条上的“运行”按键运行index.htm,并输入相应的数据:
点击“登陆”:
输入正确的用户名和密码,选择“发送”,转到主菜单页面:
如果不登陆而是直接运行mainMenu.jsp主菜单页面或UserEdit.jsp查询页面,将会自动先转到用户登陆页面,这里不再演示。
另外,如果用户没有这样我角色,也无法登陆该页面。
通过上述步骤,实现了预计的目标功能。
[程序源代码]
与《如何实现Struts 数据库应用程序》相比,本例主要是多了用户登陆所需的logon.jsp、logonAction.java文件以及用于检查用户是否已登陆的自定义标签文件CheckLogonTag.java,由于logon.jsp文件没有什么特别之处,所以这里就不列出来。
logonAction.java文件:
package emptyprj;
import emptyprj.jdbc.util.ConnectionPool;
import java.util.Locale;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.struts.action.Action;
import org.apache.struts.action.ActionError;
import org.apache.struts.action.ActionErrors;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
import org.apache.struts.util.ModuleException;
import org.apache.struts.util.MessageResources;
import org.apache.commons.beanutils.PropertyUtils;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Collection;
/**
* Implementation of <strong>Action</strong> that validates a user logon.
*
* @author Craig R. McClanahan
* @version $Revision: 1.14 $ $Date: 20 03/01/11 03:08:23 $
*/
public final class LogonAction extends Action {
// ----------------------------------------------------- Instance Variables
/**
* The <code>Log</code> instance for this application.
*/
private Log log =
LogFactory.getLog("org.apache.struts.webapp.Example");
private ConnectionPool pool;
public LogonAction() {
pool = ConnectionPool.getInstance();
}
// --------------------------------------------------------- Public Methods
/**
* Process the specified HTTP request, and create the corresponding HTTP
* response (or forward to another web component that will create it).
* Return an <code>ActionForward</code> instance describing where and how
* control should be forwarded, or <code>null</code> if the response has
* already been completed.
*
* @param mapping The ActionMapping used to select this instance
* @param form The optional ActionForm bean for this request (if any)
* @param request The HTTP request we are processing
* @param response The HTTP response we are creating
*
* @exception Exception if business logic throws an exception
*/
public ActionForward execute(ActionMapping mapping,
ActionForm form,
HttpServletRequest request,
HttpServletResponse response)
throws Exception {
// Extract attributes we will need
Locale locale = getLocale(request);
MessageResources messages = getResources(request);
// Validate the request parameters specified by the user
ActionErrors errors = new ActionErrors();
String username = (String)
PropertyUtils.getSimpleProperty(form, "username");
String password = (String)
PropertyUtils.getSimpleProperty(form, "password");
String getusername=CheckUser(username,password);
if ("".equals(getusername))
{
errors.add(ActionErrors.GLOBAL_ERROR,
new ActionError("error.password.mismatch"));
}
getusername=username+getusername;
// Report any errors we have discovered back to the original form
if (!errors.isEmpty()) {
saveErrors(request, errors);
return (mapping.getInputForward());
}
// Save our logged-in user in the session
HttpSession session = request.getSession();
session.setAttribute(Constants.USER_ KEY , getusername);
if (log.isDebugEnabled()) {
log.debug("LogonAction: User '" + username +
"' logged on in session " + session.getId());
}
// Remove the obsolete form bean
if (mapping.getAttribute() != null) {
if ("request".equals(mapping.getScope()))
request.removeAttribute(mapping.getAttribute());
else
session.removeAttribute(mapping.getAttribute());
}
// Forward control to the specified success URI
return (mapping.findForward("success"));
}
// ------------------------------------------------------ Protected Methods
/**
* Look up the user, throwing an exception to simulate business logic
* rule exceptions.
*
* @param database Database in which to look up the user
* @param username Username specified on the logon form
*
* @exception ModuleException if a business logic rule is violated
*/
public String CheckUser(String username,String password)
{
Connection con = null;
try
{
con = pool.getConnection();
String sql = "SELECT * from dbo.users WHERE username = ? AND password= ?";
PreparedStatement ps = null;
ResultSet rs = null;
try {
if (con.isClosed()) {
throw new IllegalStateException("error.con.isClosed");
}
ps = con.prepareStatement(sql);
ps.setString(1,username);
ps.setString(2,password);
rs = ps.executeQuery();
String returnstr="";
while(rs.next())
{
returnstr+=";"+rs.getString("role");
}
return returnstr;
} catch (SQLException e) {
e.printStackTrace();
throw new RuntimeException("error.ps.executeQuery");
} finally {
try {
if (ps != null)
ps.close();
if (rs != null)
rs.close();
} catch (SQLException e) {
e.printStackTrace();
throw new RuntimeException("error.rs.close");
}
}
}
catch (SQLException e)
{
e.printStackTrace();
throw new RuntimeException("Unable to get connection.");
}
finally
{
try
{
if (con != null)
con.close();
}
catch (SQLException e)
{
throw new RuntimeException(e.getMessage());
}
}
}
}
CheckLogonTag.java文件:
用于检查用户是否已登陆的自定义标签原代码。
package emptyprj;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpSession;
import org.apache.struts.util.RequestUtils;
import org.apache.struts.util.ResponseUtils;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.TagSupport;
import org.apache.struts.config.ModuleConfig;
/**
* Check for a valid User logged on in the current session. If there is no
* such user, forward control to the logon page.
*
* @author Craig R. McClanahan
* @author Marius Barduta
* @version $Revision: 1.8 $ $Date: 20 03/04/09 02:28:24 $
*/
public final class CheckLogonTag extends TagSupport {
private String role="";
// --------------------------------------------------- Instance Variables
/**
* The key of the session-scope bean we look for.
*/
private String name = Constants.USER_ KEY ;
/**
* The page to which we should forward for the user to log on.
*/
private String page = "/logon.jsp";
// ----------------------------------------------------------- Properties
/**
* Return the bean name.
*/
public String getName() {
return (this.name);
}
/**
* Set the bean name.
*
* @param name The new bean name
*/
public void setName(String name) {
this.name = name;
}
/**
* Return the forward page.
*/
public String getPage() {
return (this.page);
}
/**
* Set the forward page.
*
* @param page The new forward page
*/
public void setPage(String page) {
this.page = page;
}
public void setRole(String newrole)
{
role=newrole;
}
public String getRole()
{
return role;
}
// ------------------------------------------------------- Public Methods
/**
* Defer our checking until the end of this tag is encountered.
*
* @exception JspException if a JSP exception has occurred
*/
public int doStartTag() throws JspException {
return (SKIP_BODY);
}
/**
* Perform our logged-in user check by looking for the existence of
* a session scope bean under the specified name. If this bean is not
* present, control is forwarded to the specified logon page.
*
* @exception JspException if a JSP exception has occurred
*/
public int doEndTag() throws JspException {
// Is there a valid user logged on?
boolean valid = false;
HttpSession session = pageContext.getSession();
if ((session != null) && (session.getAttribute(name) != null)) {
String str="null";
String getusername="null";
String getrole="null";
try
{
str=(String)session.getAttribute(name);
getusername=str.substring(0, str.indexOf(";"));
getrole=str.substring(str.indexOf(";")+1,str.length()).trim();
if(CheckRole(role,getrole))
{
valid = true;
}
}
catch (Exception e) {
valid = false;
}
/*
ResponseUtils.write(pageContext, str);
ResponseUtils.write(pageContext, "<p></p>");
ResponseUtils.write(pageContext, getusername);
ResponseUtils.write(pageContext, "<p></p>");
ResponseUtils.write(pageContext, getrole);
ResponseUtils.write(pageContext, "<p></p>");
ResponseUtils.write(pageContext, role);
*/
}
// return SKIP_BODY;
// Forward control based on the results
if (valid) {
return (EVAL_ PAGE );
} else {
ModuleConfig config =
(ModuleConfig) pageContext.getServletContext().getAttribute(
org.apache.struts.Globals.MODULE_ KEY );
try {
pageContext.forward(config.getPrefix() + page);
} catch (ServletException e) {
throw new JspException(e.toString());
} catch (IOException e) {
throw new JspException(e.toString());
}
return (SKIP_ PAGE );
}
}
/**
* Release any acquired resources.
*/
public void release() {
super.release();
this.name = Constants.USER_ KEY ;
this.page = "/logon.jsp";
this.role="";
}
public boolean CheckRole(String role,String getrole)
{
getrole=getrole.trim();;
role=role.trim();
//if("".equals(getrole))return false;
String thisrole;
while(getrole.indexOf(";")>1)
{
thisrole=getrole.substring(0,getrole.indexOf(";")).trim();
getrole=getrole.substring(getrole.indexOf(";")+1,getrole.length()).trim();
if(role.equals(thisrole))
{
return true;
}
}
thisrole=getrole;
if(role.equals(thisrole))
{
return true;
}
return false;
}
}
[扩展内容]
上面是用<app:checkLogon role=“system”/>标签来检查用户是否已登陆以及用户是否含有role属性指定的用户角色,这里只能放置一个角色,如果要放置多个角色,如何处理?
其它非常简单。只要对上述程序进行如下两步改进就行了:
1、 标签用<app:checkLogon role=“角色1”; “角色2”; “角色3”/>这种方式表示。每个角色用“;”分开即可,表示只要登陆用户有这个role属性指定的角色之中的一个角色即可通过。
2、 把CheckLogonTag.java文件的CheckRole()函数改成如下:
package emptyprj;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpSession;
import org.apache.struts.util.RequestUtils;
import org.apache.struts.util.ResponseUtils;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.TagSupport;
import org.apache.struts.config.ModuleConfig;
import org.apache.struts.Globals;
import org.apache.struts.util.MessageResources;
import org.apache.struts.action.ActionError;
import org.apache.struts.action.ActionErrors;
public final class CheckLogonTag extends TagSupport {
private String role="";
private String name = Constants.USER_ KEY ;
private String page = "/logon.jsp";
public String getName() {
return (this.name);
}
public void setName(String name) {
this.name = name;
}
public String getPage() {
return (this.page);
}
public void setPage(String page) {
this.page = page;
}
public void setRole(String newrole)
{
role=newrole;
}
public String getRole()
{
return role;
}
public int doStartTag() throws JspException {
return (SKIP_BODY);
}
public int doEndTag() throws JspException {
// Is there a valid user logged on?
boolean valid = false;
HttpSession session = pageContext.getSession();
if ((session != null) && (session.getAttribute(name) != null)) {
String str="null";
String getusername="null";
String getrole="null";
try
{
str=(String)session.getAttribute(name);
getusername=str.substring(0, str.indexOf(";"));
getrole=str.substring(str.indexOf(";")+1,str.length()).trim();
if(CheckRole(role,getrole)) //role是标签指定的角色,getrole是从数据库读取出来的用户角色。
{
valid = true;
}
}
catch (Exception e) {
valid = false;
}
/*
ResponseUtils.write(pageContext, str);
ResponseUtils.write(pageContext, "<p></p>");
ResponseUtils.write(pageContext, getusername);
ResponseUtils.write(pageContext, "<p></p>");
ResponseUtils.write(pageContext, getrole);
ResponseUtils.write(pageContext, "<p></p>");
ResponseUtils.write(pageContext, role);
*/
}
// return SKIP_BODY;
// Forward control based on the results
if (valid) {
return (EVAL_ PAGE );
} else {
ActionErrors errors = new ActionErrors();
errors.add(ActionErrors.GLOBAL_ERROR,
new ActionError("error.password.mismatch"));
pageContext.getRequest().setAttribute(Globals.ERROR_ KEY , errors); //保存出错信息
ModuleConfig config =
(ModuleConfig) pageContext.getServletContext().getAttribute(
org.apache.struts.Globals.MODULE_ KEY );
try {
pageContext.forward(config.getPrefix() + page);
} catch (ServletException e) {
throw new JspException(e.toString());
} catch (IOException e) {
throw new JspException(e.toString());
}
return (SKIP_ PAGE );
}
}
/**
* Release any acquired resources.
*/
public void release() {
super.release();
this.name = Constants.USER_ KEY ;
this.page = "/logon.jsp";
this.role="";
}
public boolean CheckRole(String role,String getrole) //role是标签指定的角色,getrole是从数据库读取出来的用户角色。
{
getrole=getrole.trim();;
role=role.trim();
//if("".equals(getrole))return false;
String thisrole;
role=";"+role+";";
while(getrole.indexOf(";")>1)
{
thisrole=getrole.substring(0,getrole.indexOf(";")).trim();
getrole=getrole.substring(getrole.indexOf(";")+1,getrole.length()).trim();
thisrole=";"+thisrole+";";
if(role.indexOf(thisrole,0)>-1)
{
return true;
}
}
thisrole=getrole;
thisrole=";"+thisrole+";";
if(role.indexOf(thisrole,0)>-1)
{
return true;
}
return false;
}
}