1.概述
这篇文章主要通过一步一步的操作来讲述在Windows系统中开发Struts程序的过程。本篇文章注重实践,相关概念不会详细讲述。本文并没有提到有关CVS的安装和配置,如果感兴趣,可以参考另外一篇文档:CVS的配置和使用
2.相关工具
在开发过程中我们主要使用以下工具:
l Apache 2.0.46 主页:http://httpd.apache.org/
l JDK 1.4.2 主页:http://java.sun.com/j2se/index.jsp
l Tomcat 5.0.12 主页:http://jakarta.apache.org/tomcat/index.html
l Struts1.1 主页:http://struts.apache.org/
l Ant 1.5.2 主页:http://ant.apache.org/
l Log4j 1.2.8 主页:http://logging.apache.org/log4j/docs/index.html、
l Eclipse3.0 主页:http://www.eclipse.org/
l Lomboz3.01 主页:http://www.objectlearn.com/index.jsp
l MySQL Standard 4.0.20 主页:http://www.mysql.com
以上工具都是开源的,可以从相应的主页上免费下载。其中Ant在Eclipse3.0(一个十分出色的JAVA IDE)中已经集成,可以不用下载。如果想了解更多的信息,可以到主页上查看相关的文档。
3.环境搭建
3.1 安装JDK
安装JDK可以按着提示进行安装,没有什么特别需要注意的,安装的时候我个人喜欢安装JDK的源码,这样查东西的时候方便一些。从sun的网站上也可以下载J2SDK的API文档,把文档解压到JDK的安装目录中,这些文档在以后的开发过程中十分重要,我们会经常查阅。安装之后,需要一些配置工作。下面主要讨论一下如何配置。
增加环境变量:右键点击我的电脑->属性->高级->环境变量
增加JAVA_HOME系统变量,内容为jdk的安装路径,如下图所示:
图 1
增加了JAVA_HOME环境变量之后,就可以利用JAVA_HOME增加其他的环境变量了,这样如果JDK重新安装到其他的目录(比如更换版本),就不用修改所有的环境变量了,只修改一个JAVA_HOME就可以了。
增加CLASSPATH环境变量。内容为
.;%JAVA_HOME%/lib/dt.jar;%JAVA_HOME%/lib/tools.jar
CLASSPATH环境变量表示在java程序运行的时候需要调用的包,如果加入到环境变量中就不用在每次执行的时候都用命令行参数指出(-classpath)。最开始的英文句号代表当前目录,表示如果运行java程序的时候要在当前目录中寻找相应的类或者包。有些人在命令行下调试java程序的时候经常出现java.lang.NoClassDefFoundError错误,就很有可能是CLASSPATH环境变量设置出错。
增加环境变量PATH。环境变量PATH是表示在命令行下运行的命令的寻找路径。设置好PATH之后,就可以在任何目录下运行java和javac等命令了。如果不闲麻烦,也可以每次运行的时候都%JAVA_HOME%/bin/java。PATH是系统自带的环境变量,只要在已有的PATH中增加%JAVA_HOME%/bin就可以了,注意用分号与其他的路径分开。
现在JDK的安装基本上就完成了。
3.2 安装Apache2
安装Apache2的过程中,需要填写一些信息,比如域名之类的,随便填写一下就可以了,servername填写本机的机器名就可以了,如图2 所示。
图 2
下一步安装的时候选择自定义安装,这样可以修改Apache2的安装路径。选择D:/根目录,这样安装之后是的目录是D:/Apache2。安装之后在系统托盘中会出现Aapche Monitor的图标,可以通过这个图标重启Apache的服务。
为了避免和IIS冲突,我们把Apache的启动端口更改为8024,当然也可以关闭IIS的服务,或者更改IIS的启动端口。编辑Apache安装目录中的conf/httpd.conf文件,找到Listen 80,把80修改成8024,重新启动Apache服务即可。访问http://localhost:8024,如果出现如图3所示页面,表示Apache安装成功。
图3
3.3 安装Tomcat
安装Tomcat之前,必须正确安装了JDK。
安装的时候选择安装成服务,如图4所示:
图4
选择完安装目录之后,会有一个配置界面,如图5所示,选择安装服务的端口后,以及管理员的用户名和密码。默认的端口号是8080,我们保持默认值。记住填写的用户名和密码,在以后的管理工作中需要用到。如果忘记的话,可以在tomcat的安装路径中的conf/tomcat-users.xml文件中找到。
图5
下一个界面是JAVA虚拟机(JVM)的路径,默认的情况下,应该是JDK的安装路径,如果没有默认值,通过浏览也可以选择。
安装完毕之后,在系统托盘中会出现Apache Tomcat的图标,可以利用这个图标启动和关闭服务。
启动tomcat服务,访问http://localhost:8080,如果出现如图6所示的页面,表示安装成功。
图 6
3.4 安装Eclipse3.0
Eclipse是由IBM等多家公司资助的开源项目,包括一个核心的平台,其他的功能都是一些plugins,系统很容易扩展,并且支持本身插件的开发。Eclipse有支持java开发JDT的开发,同时也有支持C++开发的CDT。Eclipse最新的稳定版本是3.0。
Eclipse安装十分简单,只要正确安装了JDK,把下载的Eclipse压缩包解压到一个目录中,执行目录中的eclipse.exe文件即可。第一次执行,Eclipse会做一些初始化的工作。要设定系统得工作目录,就是工程的存放目录。默认的是Eclipse目录中的workspace目录,我们采用默认值。
进入之后,是一个Welcome界面,里面有一些功能介绍等。关掉之后可以看到以下界面,如图7所示
图 7
第一步工作就是设置JDK。打开菜单Window->Preferences,打开节点Java->Installed JREs,如图8所示。
图 8
默认的情况下应该已经有了系统安装的默认的JDK列表。选择之后,点击Edit…,弹出Edit JRE对话框,如图9所示。
图 9
大部分信息不用修改,我们只修改Javadoc URL的内容。Eclipse默认的情况下指向java.sun.com网站。点击Browse…弹出对话框,选择我们刚才解压的javadoc的目录。注意一定要指到api的那一层,否则Eclipse不能找到相应的API文档,如图10所示。
图 10
在Eclipse中有一个名词叫作Perspective,我个人觉得就是不同的界面表现形式。Eclipse默认的采用Resource Perspective,如果开发JAVA程序,还是采用Java Perspective比较好用。想切换Perspective,可以点击右上角的图标,如图11所示。
图 11
3.5 安装Lomboz
Eclipse开发JAVA的程序比较得心应手,但是开发Web程序就显得力不从心了。我们需要Lomboz插件的帮忙。Lomboz支持jsp语法的高亮和提示,并且支持自定义的taglib。同时利用Lomboz开发EJB也是不错的选择。Lomboz安装之前需要EMF插件。所以要想Lomboz可用,必须也要安装EMF。安装方法也很简单,把下载的ZIP包解压到Eclipse目录下,覆盖plugins和features目录就可以了。然后重新启动Eclipse。Lomboz要想正常使用还需要做一些配置。配置方法如下:
选择Window->Preferences,选择Lomboz节点,修改JDK Tools.jar的内容,指向$JAVA_HOME$/lib/tools.jar,如图12所示。
图 12
我们这里主要用Lomboz编辑JSP文件的功能,如果想开发J2EE的程序,Lomboz还需要一些其他的设置,由于篇幅的原因,我就在这里不再详细讲述,如果感兴趣,可以参考Lomboz Tutorials(http://www.objectlearn.com/support/docs/index.jsp),这里有比较详细的配置和开发方法。
3.6 安装MySQL
安装MySQL按着向导安装即可,安装之后运行MySQL安装目录中的/bin/winmysqladmin.exe文件,第一次运行的时候会显示如图13所示的对话框,填写用户名密码,这个用户名密码不知道有什么用,MySQL默认的用户是root,密码为空。在实际的部署过程中,要注意修改默认密码。
图 13
如果在系统托盘中的红绿灯图标中显示绿灯,那么表示MySQL正常启动。为了方便以后使用,建议把MySQL/bin目录添加到PATH环境变量中,参看3.1。
至此,开发工具已经全部安装完毕,Struts、MySQL JDBC Driver和log4j我们只是需要相应得jar文件,我们在开发struts应用的时候放到相应的目录中即可。
4.程序开发
前面说了一大堆废话,下面我们就进入实质性的工作,开发程序。我们的应用十分简单,就是一个用户注册和用户登录的功能。应用的名字为mystruts。
4.1 配置tomcat连接池
首先我们在tomcat的目录中安装MySQL JDBC Driver。解开从MySQL网站下载的最新的JDBC Driver 安装包:mysql-connector-java- 3.0.14 -production.zip,找到文件mysql-connector-java-3.0.14-production-bin.jar,这个就是我们需要的JDBC Driver,把这个文件拷贝到tomcat/common/lib目录中即可。
接下来要配置JDBC的连接池。修改tomcat/conf/server.xml文件。
在文件的最后面</Host>之前增加以下的内容:
<Context path="/mystruts" docBase="mystruts" debug="0" reloadable="true"
crossContext="true">
<Resource name="jdbc/mystruts" auth="Container"
type="javax.sql.DataSource"/>
<ResourceParams name="jdbc/mystruts">
<parameter><name>username</name><value>mystruts</value></parameter>
<parameter><name>password</name><value>mystruts</value></parameter>
<parameter><name>driverClassName</name><value>com.mysql.jdbc.Driver</value></parameter>
<parameter><name>url</name><value>jdbc:mysql://localhost/mystruts?useUnicode=true&characterEncoding=iso-8859-1</value></parameter>
</ResourceParams>
</Context>
这里面存储的访问数据库的用户名密码和MySQL所在的机器地址等信息。做完以上工作,需要重新启动tomcat才会生效。
4.2 增加MySQL的访问用户
上面的连接池中配置了访问MySQL的用户名密码,要想正确的访问,那么就需要在MySQL中增加相应的用户。
在命令行中执行mysql命令,进入mysql。首先我们先创建mystruts数据库,命令如下:
mysql> create database mystruts;
系统会提示:Query OK, 1 row affected (0.06 sec),表示创建成功。然后我们为这个数据库添加访问用户。命令如下:
mysql> grant all on mystruts.* to mystruts@localhost identified by 'mystruts';
grant all是表示把所有的权限(增加、删除、修改表和用户授权的操作)付给制定的用户,on mystruts.*表示mystruts库中的所有的表,to mystruts@localhost表示权限是付给本机的mystruts用户,也就是说mystruts只能在本机访问数据库,从其他的机器上访问,即便用户名密码正确也是没有权限的。identified by ‘mysturts’表示用户的密码是mystruts。通过以上的操作,就建立了一个只能在localhost上对mystruts数据库进行完全操作的mystruts用户。为了验证建立用户是否正确,我们可以退出mysql,在命令行下运行如下命令:
C:/>mysql mystruts -umystruts -pmystruts
如果提示成功,那么表示建立的用户是正确的。
创建user表,我们将在mystruts web程序中使用这个表。创建语句如下:
mysql> create table user (id int(11) auto_increment not null default 0 primary key ,
-> name varchar(20) not null default '',
-> passwd varchar(20) not null default '',
-> email varchar(30) not null default '');
4.3 在Eclipse中建立工程
现在我们打开Eclipse,File->new->Project,显示新建工程对话框,我们选择Java Project工程。单击Next。下一个对话框需要填写工程名称,我们定义为mystruts,其他的选项保持默认值。单击Next。我们在这个对话框中选择Source,然后单击Add Folder按钮,增加src目录作为源代码目录。同时修改下面的Default Output Folder改成mystruts/classes目录,然后点击Finish,工程建立完成。
在工程中,我们应该有以下几个目录:
src目录:存放JAVA源代码和一些必要的配置文件
jsp目录:存放jsp文件
html目录:存放静态的html文件和图片文件,这个目录的东西在部署的时候需要进行拷贝到Apache目录中。
WEB-INF目录:存放配置文件。
WEB-INF/lib目录:存放我们需要引用的第三方类库jar文件,struts和log4j中解压出来的文件也放到这个目录中,文件分别是struts.jar、struts-legacy.jar、log4j- 1.2.8 .jar。
WEB-INF/classes目录:存放我们写的程序的编译出来的class文件,第三方的没有大包成jar文件的包也放到这个目录。
WEB-INF/tld目录:存放struts需要用到的标签库。
工程根目录中还有两个文件:build.xml和build.properties文件,这两个文件是在ant编译部署的时候使用。
添加工程需要的类库。Project->Properties,选择Java Build Path->Libraries,然后单击Add JARs…按钮,将WEB-INF/lib目录下的所有jar文件添加到Libraries中。如图14所示。
图 14
确定之后,还要添加一个外部jar(不在工程目录中的),单击Add External JARs,把tomcat/common/lib/servlet-api.jar文件添加进来。
编辑WEB-INF目录中struts-config.xml文件,文件的内容如下:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts-config PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 1.1//EN" "http://jakarta.apache.org/struts/dtds/struts-config_1_1.dtd">
<struts-config>
<form-beans>
</form-beans>
<global-forwards>
</global-forwards>
<action-mappings>
</action-mappings>
<message-resources parameter="mystruts"/>
</struts-config>
主要分为四个部分:form-beans,global-forwords,action-mapping,message-resource。其中message-resource是用来指定struts指定的资源文件的名字。如上所示,mystruts表示资源文件是在WEB-INF/classes/mystruts.properties,同理,如果写成com.testing.hao2k.mystruts,那么资源文件就应该是WEB-INF/classes/com/testing/hao2k/mystruts.properties。利用这种方式可以很容易的实现国际化,让中文用户访问的时候看到中文界面,英文用户访问同一个网站的时候显示英文界面,具体方法我们在以后再介绍。
4.4 编写代码
在src目录中建立三个package:com.testing.hao2k,com.testing.hao2k.forms,com.testing.hao2k.actions,分别存放数据库操作类、struts中的ActionForm类、struts中的Action类。
我们先完成用户注册的模块。
用户注册需要以下信息:用户名、密码、电子邮件等信息。
进入系统之后首先是欢迎的页面,文件名是index.jsp,我们把这个文件放到jsp目录中,文件的代码如下:
<%response.setContentType("text/html");%>
<%@taglib uri="/WEB-INF/tld/struts-bean.tld" prefix="bean"%>
<html>
<head>
<title><bean:message key="jsp.index.title"/></title>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312">
</head>
<body leftmargin="0" topmargin="0" align="center">
<p>
<bean:message key="jsp.index.welcome"/>
</p>
<p>
<a href="login.jsp"><bean:message key="jsp.index.login"/></a>
</p>
<p>
<a href="register.jsp"><bean:message key="jsp.index.register"/></a>
</p>
</body>
</html>
第一句是设置这个页面的contentType,语言环境主要没有设置,默认的是ISO-8859-1,我们采用默认值,经验证明,这样做可以解决大部分的JAVA Encoding问题。第二句是声名使用到的struts标签。bean:message是用来从配置文件中读取内容,然后把内容显示到页面上。只要我们修改相应的配置文件,界面上的文字就会改变,我们并不需要修改源代码。
下面是register.jsp页面的内容:
<%response.setContentType("text/html");%>
<%@ taglib uri="/WEB-INF/tld/struts-bean.tld" prefix="bean"%>
<%@ taglib uri="/WEB-INF/tld/struts-html.tld" prefix="html"%>
<html>
<head>
<title><bean:message key="jsp.register.title"/></title>
<meta http-equiv="Content-Type" content="text/html; charset=GBK">
</head>
<body leftmargin="0" topmargin="0" align="center">
<p align="center">
<bean:message key="jsp.register.welcome"/>
</p>
<p align="center">
<font color=red align="center"><html:errors /></font>
</p>
<html:form action="regAction" method="post">
<table align="center">
<tr>
<td><bean:message key="jsp.register.username"/></td>
<td><html:text property="username"></html:text></td>
</tr>
<tr>
<td><bean:message key="jsp.register.passwd"/></td>
<td><html:password property="passwd" ></html:password></td>
</tr>
<tr>
<td><bean:message key="jsp.register.repasswd"/></td>
<td><html:password property="repasswd" ></html:password></td>
</tr>
<tr>
<td><bean:message key="jsp.register.email"/></td>
<td><html:text property="email" ></html:text></td>
</tr>
<tr>
<td>
<html:submit>
<bean:message key="jsp.register.save"/>
</html:submit>
</td>
<td>
<html:reset>
<bean:message key="jsp.register.reset"/>
</html:reset>
</td>
</tr>
</table>
</html:form>
</body>
</html>
在这个jsp文件中,我们需要几个地方需要注意。代码中的<html:errors/>是根据FormAction中的validate方法中是否有错误添加,如果有,那么会在这个地方显示,具体的实现我们会在介绍FormAction的时候讨论。
另外一个地方就是<html:form action="regAction" method="post">。这个是Struts中的一个标签,经过转化之后相当于html中的<form>语句。这里面的action中的值是与struts-config.xml配置文件相对应的。代码如下所示:
<action-mappings>
<action path="/regAction" type="com.testing.hao2k.actions.RegisterAction" name="RegisterForm" input="/jsp/register.jsp" scope="request">
<forward name="success" path="/jsp/success.jsp" redirect="false">
</forward>
</action>
</action-mappings>
找到path为resAction的action节点,这里面有关于这个action的一些信息。Type为这个action对应的类的完全路径,input对应是从哪个页面访问这个action的,如果在ActionForm中出现数据验证错误,会自动返回到这个页面,并且把用户输入的信息保留下来,填写到适当的地方。以前我们为了实现这个功能,都是要在servlet中设置相应得属性,然后再jsp页面中再读取,现在Struts帮助我们作了这部分的工作。Forword标签是根据操作的状态,在action操作之后返回到相应得页面。name中对应的属性是指这个action对应的ActionForm类。这个值与struts-config.xml文件中的formbean定义相关联。如下所示:
<form-beans>
<form-bean name="RegisterForm" type="com.testing.hao2k.forms.RegisterForm">
</form-bean>
</form-beans>
其中的type对应实际的ActionForm类。RegisterForm.java文件的内容如下所示:
/*
* Created on 2004-9-3
*/
package com.testing.hao2k.forms;
import javax.servlet.http.HttpServletRequest;
import org.apache.struts.action.ActionError;
import org.apache.struts.action.ActionErrors;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionMapping;
public class RegisterForm extends ActionForm {
private String username;
private String passwd;
private String repasswd;
private String email;
/**
* @return Returns the email.
*/
public String getEmail() {
return email;
}
/**
* @param email
* The email to set.
*/
public void setEmail(String email) {
this.email = email;
}
/**
* @return Returns the name.
*/
public String getUsername() {
return username;
}
/**
* @param name
* The name to set.
*/
public void setUsername(String name) {
this.username = name;
}
/**
* @return Returns the passwd.
*/
public String getPasswd() {
return passwd;
}
/**
* @param passwd
* The passwd to set.
*/
public void setPasswd(String passwd) {
this.passwd = passwd;
}
/**
* @return Returns the repasswd.
*/
public String getRepasswd() {
return repasswd;
}
/**
* @param repasswd
* The repasswd to set.
*/
public void setRepasswd(String repasswd) {
this.repasswd = repasswd;
}
public ActionErrors validate(ActionMapping mapping, HttpServletRequest request) {
ActionErrors errors = new ActionErrors();
if (username == null || username.length() < 1) {
errors.add("username", new ActionError("error.username.input"));
}
if (passwd == null || passwd.length() < 1) {
errors.add("passwd", new ActionError("error.passwd.input"));
}
if (passwd != null && !passwd.equals(repasswd)) {
errors.add("repasswd", new ActionError("error.password.match"));
}
if (email == null || email.length() < 1 || email.indexOf("@") < 1) {
errors.add("email", new ActionError("error.email.input"));
}
return errors;
}
}
这个类主要分为两个部分,前面是所有属性的getter和setter函数。这些函数的命名需要与jsp文件的form中的变量相对应。例如form中有username变量,那么在ActionForm就要有对应于username的getter和setter函数。分别命名为getUsername()和setUsername()。规则是变量名的第一个字母大写,其他的不变,然后在前面加上get和set。ActionForm之所以可以自动读取jsp页面中的变量,就是利用这种对应关系实现的。这种对应关系在ActionForm中是十分重要的,如果对应不正确,那么就不能正常工作。
第二部分主要是validate函数,这个函数会在用户提交之后自动调用,主要的功能是来验证用户输入的数据是否正确,如果出现非法的数据,那么会把相应的错误加入到ActionErrors对象中,也就是这个函数的返回值。如果有错误,那么就会返回到input页面中,通过<html:errors/>来显示错误信息。在这一层直接返回,就不需要进入到action类中,减少系统负载。理论上说,如果在这里加入了足够的条件判断,那么在以后的数据处理当中就可以把数据当成是完全合法的,不用再做任何合法性的判断。如果在这个函数种没有任何的数据错误,那么ActionErrors对象中就为空,这样Sturts会自动判断,直接进入Action类中。
接下来,我们在com.testing.hao2k.entity包中创建User类。这个类是与数据库中的user表相对应,是数据持久层,类似于EJB中的实体bean。代码如下所示:
/*
* Created on 2004-9-5
*/
package com.testing.hao2k.entity;
/**
* @author Administrator
*/
public class User {
private String username;
private String passwd;
private String email;
/**
* @return Returns the email.
*/
public String getEmail() {
return email;
}
/**
* @param email
* The email to set.
*/
public void setEmail(String email) {
this.email = email;
}
/**
* @return Returns the passwd.
*/
public String getPasswd() {
return passwd;
}
/**
* @param passwd
* The passwd to set.
*/
public void setPasswd(String passwd) {
this.passwd = passwd;
}
/**
* @return Returns the username.
*/
public String getUsername() {
return username;
}
/**
* @param username
* The username to set.
*/
public void setUsername(String username) {
this.username = username;
}
}
这个类的主要组成部分也是setter和getter函数。可能大家认为这个类和前面的RegisterForm类很象,为什么不共用这个类?表面上看,这两个类还是很象的,但是有着本质上的差别。RegisterForm是与表现层相关联的,是用户输入数据的抽象数据,用户输入的数据并不一定要加入到数据库中,比如验证密码。而User则是和数据库相对应的,每一个属性都对应于数据库中一个字段,它是数据持久层的类。
RegisterAction是Struts中的Action类,主要负责流程的控制。代码如下所示:
/*
* Created on 2004-9-3
*
*/
package com.testing.hao2k.actions;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
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 com.testing.hao2k.UserOP;
import com.testing.hao2k.forms.RegisterForm;
/**
* @author Administrator
*
*/
public class RegisterAction extends Action {
public ActionForward execute(ActionMapping mapping, ActionForm form, HttpServletRequest request,
HttpServletResponse response) throws Exception {
ActionErrors errors = new ActionErrors();
UserOP userOP = new UserOP();
try {
int result = userOP.add((RegisterForm) form);
if (result == 1) {
errors.add(ActionErrors.GLOBAL_MESSAGE, new ActionError("error.name.repeat"));
saveErrors(request, errors);
return mapping .findForward("failed");
} else {
errors.add(ActionErrors.GLOBAL_MESSAGE, new ActionError("success.register.info"));
saveErrors(request, errors);
return mapping.findForward("success");
}
} catch (Exception e) {
errors.add(ActionErrors.GLOBAL_MESSAGE, new ActionError("error.register.dberror"));
saveErrors(request, errors);
return mapping.findForward("failed");
}
}
}
这个Action会调用相应得数据库操作类(我们会在下面介绍),根据操作的结果转向到不同的页面。同时在转向页面的过程中,还可以设定提示信息等。
下面我们构建一个类UserOP,专门用来对user表进行数据库操作的。在这个类中主要有四个方法:add,getUserByID,getAllUsers,validateUser。分别用于注册用户、根据用户ID得到用户、得到所有用户以及验证用户登录。代码如下所示:
/*
* Created on 2004-9-6 11:11:52
*/
package com.testing.hao2k;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.ArrayList;
import org.apache.log4j.Logger;
import com.testing.hao2k.entity.User;
import com.testing.hao2k.forms.LoginForm;
import com.testing.hao2k.forms.RegisterForm;
/**
* @author Administrator
*/
public class UserOP {
//实现日志操作的类
private static Logger logger = Logger.getLogger(UserOP.class);
/**
* 实现注册用户的功能
*
* @param form
* 保存着用户在HTML页面中填写的注册信息
* @return 返回注册用户的状态值,成功返回0 如果数据库中已经有该用户,那么返回1
* @throws Exception
* 如果出现错误,那么抛出异常。
*/
public int add(RegisterForm form) throws Exception {
int result = 1;
Connection conn = null;
try {
conn = DBConnection.getConnection();
//查找是否在数据库中已经有重复的名字。
String query = "select count(id) from user where name=?";
PreparedStatement ps = conn.prepareStatement(query);
ps.setString(1, form.getUsername());
ResultSet rs = ps.executeQuery();
if (rs.next()) {
if (rs.getInt(1) > 0) {
//如果数据库中已经有该用户,那么返回1
result = 1;
} else {
// 添加新的用户
query = "insert into user (name,passwd,email) values (?,?,?)";
ps = conn.prepareStatement(query);
ps.setString(1, form.getUsername());
ps.setString(2, form.getPasswd());
ps.setString(3, form.getEmail());
ps.executeUpdate();
result = 0;
}
}
rs.close();
ps.close();
} catch (Exception e) {
logger.error(e);
throw e;
} finally {
if (conn != null) {
conn.close();
}
}
return result;
}
/**
* 根据用户的id返回用户对象
*
* @param id
* 用户的id
* @return 符合条件的用户对象,如果没有符合条件的用户返回null
* @throws Exception
* 如果出现异常,那么抛出
*/
public User getUserByID(int id) throws Exception {
User user = null;
Connection conn = null;
try {
conn = DBConnection.getConnection();
String query = "select * from user where id=?";
PreparedStatement ps = conn.prepareStatement(query);
ps.setInt(1, id);
ResultSet rs = ps.executeQuery();
if (rs.next()) {
user = new User();
user.setId(rs.getInt("id"));
user.setUsername(rs.getString("name"));
user.setPasswd(rs.getString("passwd"));
user.setEmail(rs.getString("email"));
}
rs.close();
ps.close();
} catch (Exception e) {
logger.error(e);
throw e;
} finally {
if (conn != null) {
conn.close();
}
}
return user;
}
/**
* 返回所有的用户,这是一个简单的例子,在实际应用中不建议返回所有的数据库记录 <br>
* 这样会造成消耗大量的内存
*
* @return 返回ArrayList对象,里面存储着所有的用户。
* @throws Exception 如果出现异常,那么抛出
*/
public ArrayList getAllUsers() throws Exception {
ArrayList allUsers = new ArrayList();
Connection conn = null;
try {
conn = DBConnection.getConnection();
String query = "select * from user";
PreparedStatement ps = conn.prepareStatement(query);
ResultSet rs = ps.executeQuery();
while (rs.next()) {
User user = new User();
user.setId(rs.getInt("id"));
user.setUsername(rs.getString("name"));
user.setPasswd(rs.getString("passwd"));
user.setEmail(rs.getString("email"));
allUsers.add(user);
}
rs.close();
ps.close();
} catch (Exception e) {
logger.error(e);
throw e;
} finally {
if (conn != null) {
conn.close();
}
}
return allUsers;
}
/**
* 验证登录用户是否合法
*
* @param name
* 用户的用户名
* @return 验证通过,返回0,否则返回1
* @throws Exception
* 如果出现异常,那么抛出
*/
public int validateUser(LoginForm form) throws Exception {
int result = 1;
Connection conn = null;
try {
conn = DBConnection.getConnection();
String query = "select * from user where name=? and passwd=?";
PreparedStatement ps = conn.prepareStatement(query);
ps.setString(1, form.getUsername());
ps.setString(2,form.getPasswd());
ResultSet rs = ps.executeQuery();
if (rs.next()) {
result = 0;
}
rs.close();
ps.close();
} catch (Exception e) {
logger.error(e);
throw e;
} finally {
if (conn != null) {
conn.close();
}
}
return result;
}
}
这个类主要是通过action类调用的,不过也有同jsp调用的,比如getAllUsers方法。我们注意到在这个类中,数据库操作的时候都用到PreparedStatement类。这个类主要有两个好处,第一个是这个类会让数据库服务器事先编译sql语句,这在大用户量的情况下是十分有效的,其次通过setXXX方法,一些针对sql的特殊字符会进行转义,增强了系统的安全性。所以,我们建议,在数据库操作中尽量使用这个类去代替Statement类。
显示所有用户信息的jsp页面的代码如下:
<%response.setContentType("text/html");%>
<%@taglib uri="/WEB-INF/tld/struts-bean.tld" prefix="bean"%>
<%@taglib uri="/WEB-INF/tld/struts-logic.tld" prefix="logic"%>
<html>
<head>
<title><bean:message key="jsp.showallusers.title"/></title>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312">
</head>
<body leftmargin="0" topmargin="0" align="center">
<p align="center">
<bean:message key="jsp.showallusers.welcome"/>
</p>
<jsp:useBean id="allUserList" class="com.testing.hao2k.UserOP"/>
<table align="center" border=1>
<tr>
<td><bean:message key="jsp.register.username"/></td>
<td><bean:message key="jsp.register.passwd"/></td>
<td><bean:message key="jsp.register.email"/></td>
</tr>
<logic:iterate id="user" type="com.testing.hao2k.entity.User" name="allUserList" property="allUsers" >
<tr>
<td><bean:write name="user" property="username"/></td>
<td><bean:write name="user" property="passwd"/></td>
<td><bean:write name="user" property="email"/></td>
</tr>
</logic:iterate>
</table>
</body>
</html>
其中用到了logic:iterate标签。这是一个比较常用的标签,用来做循环的。循环是针对一个collection的,对collection中的内容作遍历,然后处理其中的内容。name属性用来标示一个已有的类,对这个类调用一个方法,返回collection,调用的方法在property属性中指定,对应类中的getAllusers()方法。type表示从collection中取得的元素要转换得类型。id表示collection中取得的元素转换之后生成的实例,在循环体内可以当作java变量使用。
bean:write标签表示要在页面上输出指定实例的属性。
登录的程序实现与注册的原理类似,大家可以参照源代码。
4.5 编译和部署程序
代码开发完毕,我们需要编译和部署程序,我们采用ant进行编译和部署。
Jakarta Project 将 Ant 工具说成“不带 make 缺点的 make”,(make是编译C语言的一个工具)。Ant 正在成为开放源代码世界中实际上的标准。原因很简单:Ant 是使用 Java 语言编写的,这种语言可以让构建过程在多种平台上使用。这种特性简化了在不同 OS 平台之间的程序员的合作,而合作是开放源代码社区的一种需要。您可以在自己选择的平台上进行开发和构建。Ant 的特性包括:
- 类可扩展性:Java 类可用于扩展构建特性,而不必使用基于 shell 的命令。
- 开放源代码:因为 Ant 是开放源代码,因此类扩展示例很充足。我发现通过示例来学习非常棒。
- XML 可配置:Ant 不仅是基于 Java 的,它还使用 XML 文件配置构建过程。假设构建实际上是分层的,那么使用 XML 描述 make 过程就是其逻辑层。另外,如果您了解 XML,要学习如何配置构建就更简单一些。
图15简要介绍了一个配置文件,配置文件是标准的XML格式,由目标树构成。每个目标都包含了要执行的任务,其中任务就是可以执行的代码。在本例中,mkdir 是目标 compile 的任务。mkdir 是建立在 Ant 中的一个任务,用于创建目录。 Ant 带有一套健全的内置任务。您也可以通过扩展 Ant 任务类来添加自己的功能。
每个目标都有唯一的名称和可选的相关性。目标相关性需要在执行目标任务列表之前执行。如图15所示,在执行 compile 目标中的任务之前需要先运行 JUNIT 目标。这种类型的配置可以让您在一个配置中有多个树。
图 15
Eclipse对ant有着很好的支持,只要右键点击builid.xml,然后选择Ant Build,就可以执行默认的任务。
4.6 用struts轻松实现国际化
也许大家都看到过google的强大的国际化支持吧。有了struts我们就可以轻松的实现这种企业级网站的需求了。
前面大家已经看到,我们把所有页面中需要显示的信息都写到了一个叫做mystruts.properties的文件中,这就是为实现国际化做准备。如果要实现中文和英文用户访问看到不同界面语言的功能,我们就需要另外建立一个文件mystruts_zh.properties。从名字就可以看出,这个文件是用来存放中文信息的。我们把先前写到mystrut.properties文件中的内容复制到这个文件中,然后把mystruts.properties文件中的中文部分改成英文,然后部署到服务器上,重新启动tomcat就可以了。之所以重新启动tomcat,是因为这种机制是通过session实现的,session在用户第一次访问的时候记录的用户的语言信息。
现在让我们试一下,IE->工具->Internet选项->常规->语言->删除默认的中文,添加en_us,确定。然后再访问刚才的页面,就可以看到英文的页面了。在另外一台中文系统的机器上访问,看到的依然是中文界面。不过这种在配置文件中直接写中文的方法只适合与jsp页面中设置的语言是默认的iso-8859-1,如果设置成utf-8的,那么就需要对mystruts_zh.properties文件进行转换,否则页面显示将都是问号。利用native2ascii工具可以完成这个工作。
如果服务器端没有客户端IE使用的语言,那么struts会默认的找没有语言后缀的资源文件,比如如果有德语用户访问mystruts,那么就会显示mystruts.properties文件中的内容。
如果大家以后做的软件需要这种国际化的需求,那么用struts实现是再简单不过的了。
5.总结
上面我只是谈到了struts中的一部分功能,还有其他很实用的,包括template和生成JavaScript验证脚本的功能等,如果大家有兴趣可以参看struts中自带的例子。用struts开发,我个人认为最大的好处就是代码的模式化,每个人的代码都是十分相似的,即便是新加入到开发团队的人员,在其他团队成员的指导之下,也可以很快的掌握这一套开发流程。另外,struts具有很好的可扩展性,struts不仅可以和Hibernate联合使用,甚至也可以和EJB一起使用。