前言
在上一篇实战EJB教程里,我们学写了一个CMP的实体Bean和sessionBean,sessionBean通过模型来操作实体Bean,基于Struts的jsp Framework 在javabean中访问EJB,得出最终结果在JSP视图层中显示,虽然简单,但这也是基本的流程!在完成这篇教程之后,我就在思量如何再写一个完整的应用,恰好论坛中的深空小妖写了一个基于php的留言本!于是我就想到也写一篇留言本的文章吧,留言本虽然很简单,但它却是一个基础,增加管理回复等就相当于一个小型的BBS,稍做修改也可以将它变成一个文章发布系统!
在我考虑之下,我决定写一个基于j2ee的留言本!
用于此次教学的就是留言本的tech版,它相当简单,只具有留言和查看的功能!但是对初学者来说这却是最好的入门捷径!
广告
在此tech版留言本的基础上我二次开发了它的商业版(数据库采用Oracle9i)!在完成我的tech版后,大家可以根据我下面的提示来定制自己的商业版!
1。商业版支持国际化功能,根据客户端IE语言自动切换相对应的语言信息资源,采用UTF-8的编码!
(利用struts的国际化功能)
2。完整的后台管理功能,以管理员登陆留言本后,可对留言进行删除,编辑,回复
(增加管理员权限的表,和实体BEAN)
3。LOG写日志功能
(利用log4J)
4。数据库转为xml文件导入导出
(看看JDOM,会有不小的收获)
5。上传下载功能
(jspsmartupload.jar)
6。留言查找功能
(我的方法是再写出一个搜索的sessionBean,当然也可以看看lUCene,一个开源的搜索引擎包)
7。个性化设置
(能完成以上的相信这个就不成问题)
本人已经注册了j2eestudio.com的域名,希望能与志同道合的朋友共同合作,请PM我!
PS又PS,如果有独立服务器的朋友帮忙最好!
相关知识
本篇立足于初学者,因此对一些相关概念的东西我会提一下,更具体的当然希望你在完成本教程后去Google上搜一下,这样印像更深刻!
J2EE:适用于创建服务器应用程序和服务的Java 2平台企业版(Java 2 Platform EnterPRise Edition,J2EE)
EJB:商业组件的部署环境,在EJB Server中提供了分布式计算环境中组件需要的所有服务,例如组件生命周期的管理、数据库连接的管理、分布式事务的支持、组件的命名服务等等。
Weblogic:BEA公司出品的J2ee平台应用服务器,全面支持J2EE标准,从6.0版开始率先支持EJB2.0规范,内置jdk为1.3.1版,虽然目前该产品已经出到了8.1,但我仍对小巧的6.1sp2版本情有独钟,基本上能满足我学习和工作的需要,不过它的软肋就是JDK的版本太低,虽然也可以自己将JDK的版本换成JDK1.4.X,但是或多或少会出现些问题,也因由此,我的struts一直使用的是1.1-b1版,因为在此后的正式版无法在weblogic6.1上运行!不得不说是遗憾!!
Struts:Struts是采用Java Servlet/JavaServer Pages技术,开发Web应用程序的开放源码的framework。Struts是apache.org开源组织Jakarta项目的一部分,在论坛中见到有人说它最终会被淘汰,其实鼓吹这种论点的早就见到过,Struts也许的确不算是最高效的JSP framework,学起来有些困难,但当你真正掌握,你才会发现它的灵活与强大,也甚至有人说SUN的JSP幸亏有struts这颗救命稻草,不然早就完了一说呢,不管怎么说,Struts已经有了相当广泛的商业应用,而且网上的资料也很多,希望大家认真学学,大家可以到官方网站上看看
jakarta.apache.org/struts
题外话:struts1.1允许多个控制文件,不像我们原来为了写一个控制文件经常check in/out啦!可我选择weblogic6.1就没法用struts1.1郁闷呀!
JSP:这个相信不用我说了吧,它可以像asp,PHP那种写法,将控制语句代码夹杂在Html代码中间,相对于比较复杂的JSP页面,比如JIVE论坛的JSP页面吧,你就会明白,看了就会犯晕,所以我们完全可以把控制语句交给struts来处理,这样我们在页面中看到的就是干净“代码”,更利于团体合作,发挥各人所才,程序员可以专心致志的写代码,而网页设计师则可以设计漂亮的页面!
相关工具
MySQL:今次学习版的数据库就用它了。
weblogic6.1sp2:我已经介绍N次了吧,呵呵,相关配置看看我以前的贴子。
Jbuilder7:EJB,JSP全在这里搞定啦!
Struts1.1-b1:去下载吧,不过我会提供一个经我修改支持中文的struts.jar
Struts console:写Struts-config.xml的好工具,真是太方便了
mysql.jar:提供连接mysql的JDBC驱动
平台搭建请参看我以前的相关贴子,一些工具包我会试着找空间下载的,OK,今天暂到这里,明天我们进入代码实战篇!有什么问题请进论坛PM我!
进入讨论组讨论。
代码实战篇
建立后台数据库
在最初的时候,我并没有打算用到数据库,我以XML为数据源,但遇到点麻烦,当初为了支持国际化的留言,必须使XML的编码使用UTF-8,但是在Struts中操作XML文件时,始终是以ANSI写入的,最后我引入了JDOM来操作写入XML文件,可以直接指定XML的编码格式获得成功,而且JDOM操作XML真的是相当方便,大家可以到它的官方网站去看看http://www.jdom.org。在完成之后,以我对XML有限的理解,我认为它作为数据信息描述、交换、存诸是强项,但真的把它用作数据服务在性能上也许是瓶颈,因为它在内存中不断增大,虽说手头上的资料有XML数据服务器一说,但没有进一步作研究,所以我改换MySQL做为数据库服务。MySql真的很小巧好用,不过我不知道如何在Mysql里更改数据库的编码,在Oracle里是可以直接指定数据库的默认编码,也就是我存入的UTF-8编码格式的信息在Oracle里可以正常显示,但在Mysql里就做不到了,它们都是“乱码",而且取出来也是乱码,我只有在数据库连接池里转码一次,使取出数据的都是正常的!不过此次TECH版不涉及国际化功能,不必伤此脑筋,让我们看看数据库表的设计吧!
像上次一样,我使用Navicat工具在Mysql中建立了guestbook的数据库,并且建立了留言所使用的book表.
接下来就是设计book表中的字段,下面是基本的信息,大家也可以根据自己的需要自行修改
id(留言自动编号,主键)
name(留言姓名,varchar,不允许为空)
email(留言者电邮,varchar,允许为空)
QQ(留言者QQ号码,varchar,允许为空)
posttime(留言提交时间,datetime,不允许为空)
comment(留言内容,varchar,不允许为空)
ip(留言者IP,varchar,不允许为空)
下面是我用Navicat导出的SQL脚本!
/*
MySQL Backup
Source Host: localhost
Source Server Version: 4.0.12-nt
Source Database: guestbook
Date: 2003-09-14 15:09:17
*/
use guestbook ;
#----------------------------
# Table structure for book
#----------------------------
create table book (
id int(11) not null auto_increment,
name varchar(100) not null,
email varchar(50),
qq varchar(50),
posttime datetime not null default '0000-00-00 00:00:00',
`comment` text not null,
ip varchar(50) not null,
primary key (id))
type=MyISAM;
#----------------------------
# No records for table book
#----------------------------
进入讨论组讨论。
创建实体Bean
和上篇实战EJB一样,我们在Jbuilder中先建立一个guestbook.jpx项目,然后再利用向导建立EJB名为book,接着我们需要建立它的数据源,也命名为book,当然你想取什么名字都行,不过以后在weblogic中的数据源配置要和这里写的一样,由于这些配置和上一篇相同,所以这里我都省去了,请大家仔细看上篇的贴子,有问题请PM我!
首先创建book表的CMP实体Bean文件,由于ID是在数据库中自动增加,在此我们可以将它删除,而指定name为主键,同时我们修改posttime的类型为java.lang.String.
点击查看大图
接下来我们设计模型,这里放在value中,下面是BookValue.java的源代码
package guestbook.maxuan.ejb.entity.value;
import java.io.*;
public class BookValue implements Serializable{
public java.lang.String name;
public java.lang.String email;
public java.lang.String qq;
public java.lang.String posttime;
public java.lang.String comment;
public java.lang.String ip;
public java.lang.String action;
private void writeObject(ObjectOutputStream oos)
throws IOException {
oos.defaultWriteObject();
}
private void readObject(ObjectInputStream ois)
throws ClassNotFoundException,
IOException {
ois.defaultReadObject();
}
public String getAction() {
return action;
}
public void setAction(String action) {
this.action = action;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getQq() {
return qq;
}
public void setQq(String qq) {
this.qq = qq;
}
public java.lang.String getPosttime() {
return posttime;
}
public void setPosttime(java.lang.String posttime) {
this.posttime = posttime;
}
public String getIp() {
return ip;
}
public void setIp(String ip) {
this.ip = ip;
}
public String getComment() {
return comment;
}
public void setComment(String comment) {
this.comment = comment;
}
}
book.java的源代码
package guestbook.maxuan.ejb.entity;
import javax.ejb.*;
import java.util.*;
import guestbook.maxuan.ejb.entity.value.*;
public interface Book extends javax.ejb.EJBLocalObject {
public void setName(String name);
public String getName();
public void setEmail(String email);
public String getEmail();
public void setQq(String qq);
public String getQq();
public void setPosttime(String posttime);
public String getPosttime();
public void setComment(String comment);
public String getComment();
public void setIp(String ip);
public String getIp();
public BookValue getValue();
public void setValue(BookValue value);
}
BookBean.java的源代码
package guestbook.maxuan.ejb.entity;
import javax.ejb.*;
import guestbook.maxuan.ejb.entity.value.*;
abstract public class BookBean implements EntityBean {
EntityContext entityContext;
public java.lang.String ejbCreate(java.lang.String name)
throws CreateException {
setName(name);
return null;
}
public java.lang.String ejbCreate(BookValue value)
throws CreateException {
setValue(value);
return null;
}
public void ejbPostCreate(java.lang.String name)
throws CreateException {
/**@todo Complete this method*/
}
public void ejbPostCreate(BookValue value)
throws CreateException {
}
public void ejbRemove() throws RemoveException {
/**@todo Complete this method*/
}
public abstract void setName(java.lang.String name);
public abstract void setEmail(java.lang.String email);
public abstract void setQq(java.lang.String qq);
public abstract void setPosttime(java.lang.String posttime);
public abstract void setComment(java.lang.String comment);
public abstract void setIp(java.lang.String ip);
public abstract java.lang.String getName();
public abstract java.lang.String getEmail();
public abstract java.lang.String getQq();
public abstract java.lang.String getPosttime();
public abstract java.lang.String getComment();
public abstract java.lang.String getIp();
public void ejbLoad() {
/**@todo Complete this method*/
}
public void ejbStore() {
/**@todo Complete this method*/
}
public void ejbActivate() {
/**@todo Complete this method*/
}
public void ejbPassivate() {
/**@todo Complete this method*/
}
public void unsetEntityContext() {
this.entityContext = null;
}
public void setEntityContext(EntityContext entityContext) {
this.entityContext = entityContext;
}
public BookValue getValue(){
BookValue value = new BookValue();
value.setName(getName());
value.setEmail(getEmail());
value.setQq(getQq());
value.setPosttime(getPosttime());
value.setComment(getComment());
value.setIp(getIp());
return value;
}
public void setValue(BookValue value){
setName(value.getName());
setEmail(value.getEmail());
setQq(value.getQq());
setPosttime(value.getPosttime());
setComment(value.getComment());
setIp(value.getIp());
}
}
BookHome.java的源代码
package guestbook.maxuan.ejb.entity;
import javax.ejb.*;
import java.util.*;
import guestbook.maxuan.ejb.entity.value.*;
public interface BookHome extends javax.ejb.EJBLocalHome {
public Book create(String name) throws CreateException;
public Book create(BookValue value) throws CreateException;
public Collection findAll() throws FinderException;
public Book findByPrimaryKey(String name)
throws FinderException;
}
记得要写findall的Query语句:SELECT OBJECT(o) FROM Book AS o
接下来我们设计模型,这里放在value中,下面是BookValue.java的源代码
<textarea columns=100 rows=50>
package guestbook.maxuan.ejb.entity.value;
import java.io.*;
public class BookValue implements Serializable{
public java.lang.String name;
public java.lang.String email;
public java.lang.String qq;
public java.lang.String posttime;
public java.lang.String comment;
public java.lang.String ip;
public java.lang.String action;
private void writeObject(ObjectOutputStream oos)
throws IOException {
oos.defaultWriteObject();
}
private void readObject(ObjectInputStream ois)
throws ClassNotFoundException,
IOException {
ois.defaultReadObject();
}
public String getAction() {
return action;
}
public void setAction(String action) {
this.action = action;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getQq() {
return qq;
}
public void setQq(String qq) {
this.qq = qq;
}
public java.lang.String getPosttime() {
return posttime;
}
public void setPosttime(java.lang.String posttime) {
this.posttime = posttime;
}
public String getIp() {
return ip;
}
public void setIp(String ip) {
this.ip = ip;
}
public String getComment() {
return comment;
}
public void setComment(String comment) {
this.comment = comment;
}
}
</textarea>
book.java的源代码
<textarea columns=100 rows=50>
package guestbook.maxuan.ejb.entity;
import javax.ejb.*;
import java.util.*;
import guestbook.maxuan.ejb.entity.value.*;
public interface Book extends javax.ejb.EJBLocalObject {
public void setName(String name);
public String getName();
public void setEmail(String email);
public String getEmail();
public void setQq(String qq);
public String getQq();
public void setPosttime(String posttime);
public String getPosttime();
public void setComment(String comment);
public String getComment();
public void setIp(String ip);
public String getIp();
public BookValue getValue();
public void setValue(BookValue value);
}
</textarea>
BookBean.java的源代码
<textarea columns=100 rows=50>
package guestbook.maxuan.ejb.entity;
import javax.ejb.*;
import guestbook.maxuan.ejb.entity.value.*;
abstract public class BookBean implements EntityBean {
EntityContext entityContext;
public java.lang.String ejbCreate(java.lang.String name)
throws CreateException {
setName(name);
return null;
}
public java.lang.String ejbCreate(BookValue value)
throws CreateException {
setValue(value);
return null;
}
public void ejbPostCreate(java.lang.String name)
throws CreateException {
/**@todo Complete this method*/
}
public void ejbPostCreate(BookValue value)
throws CreateException {
}
public void ejbRemove() throws RemoveException {
/**@todo Complete this method*/
}
public abstract void setName(java.lang.String name);
public abstract void setEmail(java.lang.String email);
public abstract void setQq(java.lang.String qq);
public abstract void setPosttime(java.lang.String posttime);
public abstract void setComment(java.lang.String comment);
public abstract void setIp(java.lang.String ip);
public abstract java.lang.String getName();
public abstract java.lang.String getEmail();
public abstract java.lang.String getQq();
public abstract java.lang.String getPosttime();
public abstract java.lang.String getComment();
public abstract java.lang.String getIp();
public void ejbLoad() {
/**@todo Complete this method*/
}
public void ejbStore() {
/**@todo Complete this method*/
}
public void ejbActivate() {
/**@todo Complete this method*/
}
public void ejbPassivate() {
/**@todo Complete this method*/
}
public void unsetEntityContext() {
this.entityContext = null;
}
public void setEntityContext(EntityContext entityContext) {
this.entityContext = entityContext;
}
public BookValue getValue(){
BookValue value = new BookValue();
value.setName(getName());
value.setEmail(getEmail());
value.setQq(getQq());
value.setPosttime(getPosttime());
value.setComment(getComment());
value.setIp(getIp());
return value;
}
public void setValue(BookValue value){
setName(value.getName());
setEmail(value.getEmail());
setQq(value.getQq());
setPosttime(value.getPosttime());
setComment(value.getComment());
setIp(value.getIp());
}
}
</textarea>
BookHome.java的源代码
<textarea columns=100 rows=50>
package guestbook.maxuan.ejb.entity;
import javax.ejb.*;
import java.util.*;
import guestbook.maxuan.ejb.entity.value.*;
public interface BookHome extends javax.ejb.EJBLocalHome {
public Book create(String name) throws CreateException;
public Book create(BookValue value) throws CreateException;
public Collection findAll() throws FinderException;
public Book findByPrimaryKey(String name)
throws FinderException;
}
</textarea>
记得要写findall的Query语句:SELECT OBJECT(o) FROM Book AS o
进入讨论组讨论。
创建sessionBean
在昨天,我们完成了实体Bean,它实际上是映射到数据库行并为行的每个列定义了getter和setter方法,今天我们来完成sessionBean。
BookControl.java的源代码
package guestbook.maxuan.ejb.control;
import javax.ejb.*;
import java.util.*;
import java.rmi.*;
import guestbook.maxuan.ejb.entity.value.*;
public interface BookControl extends javax.ejb.EJBObject {
public void savely(BookValue value) throws RemoteException;
public ArrayList getLyList() throws RemoteException;
}
BookControlBean的源代码
package guestbook.maxuan.ejb.control;
import javax.ejb.*;
import java.util.*;
import guestbook.maxuan.ejb.entity.*;
import guestbook.maxuan.ejb.entity.value.*;
public class BookControlBean implements SessionBean {
SessionContext sessionContext;
public void ejbCreate() throws CreateException {
/**@todo Complete this method*/
}
public void ejbRemove() {
/**@todo Complete this method*/
}
public void ejbActivate() {
/**@todo Complete this method*/
}
public void ejbPassivate() {
/**@todo Complete this method*/
}
public void setSessionContext(SessionContext sessionContext) {
this.sessionContext = sessionContext;
}
public void savely(BookValue value) {
Book book=null;
try {
javax.naming.Context context =
new javax.naming.InitialContext();
BookHome bookHome= (BookHome)context.lookup("Book");
if(value.getAction().equals("add")){
book=bookHome.create(value);
}else{
try{
book=bookHome.findByPrimaryKey(value.getName());
book.setValue(value);
}catch(FinderException fe){
}
}
}catch (Exception ex) {
throw new EJBException(ex);
}
}
public ArrayList getLyList(){
ArrayList LyList=new ArrayList();
try {
javax.naming.Context context = new
javax.naming.InitialContext();
BookHome bookHome= (BookHome)context.lookup("Book");
Collection lyCntl = bookHome.findAll();
Iterator iterator = lyCntl.iterator();
while(iterator.hasNext()){
Book book = (Book) iterator.next();
LyList.add(book.getValue());
}
}catch (Exception ex) {
throw new EJBException(ex);
}
return LyList;
}
}
BookControlHome的源代码
package guestbook.maxuan.ejb.control;
import javax.ejb.*;
import java.util.*;
import java.rmi.*;
public interface BookControlHome extends javax.ejb.EJBHome {
public BookControl create() throws CreateException,
RemoteException;
}
这样我们就完成了sessionBean的编写,它操作实体Bean赋于value的值,
这里比上次的教程多了写入的操作!
进入讨论组讨论。
struts部份
首先,请大家下载jakarta-struts-1.1-b1.zip,直接在google里键入搜索即可,此版本可应用布署在weblogic6.1中。记得顺便把jakarta-struts-1.1-b1-src.zip也下了,这是它的源码文件,方便我们修改!!
打开jakarta-struts-1.1-b1.zip这个压缩包文件,INSTALL、LICENSE、README三个文件不用说了自己看,lib文件夹中就是所需要的库文件和标签文件,webapps中有几个示例文件,struts-documentation.war可装配到weblogic中,一定要看看,详尽的文档!
首先,我们要在JBuilder中定义struts库文件的位置,点击TOOLS菜单在下拉中选中Configure Libraries,在弹出的窗口中新定义一个LIB,我们取名为struts 1.1-b1,定义到Project中,当然为了以后方便,你可以指定为User home!
这里我是把jakarta-struts-1.1-b1.zip文件夹直接解压到应用目录guestbook的lib中,将struts包中所有的*.jar文件选中加入,然后点OK即完成了struts 1.1-b1库文件的定义!
然后我们需要指定在此次guestbook的项目应用中引入struts 1.1-b1,在打开guestbook.jpx后,在Project菜单中下拉选中Project Properties,在弹出的窗口中,在下面点击Required Libraries,出现画面如下图所示:
点右边的ADD,将刚才我们定义的struts 1.1-b1库文件加入,如下图
完成后如下图所示:
以上部分,我们完成了Struts1.1-b1在此次教程应用中的配置!
进入讨论组讨论。
有了Struts资源的调用,我们继续来完成JAVABEAN部分的编写!
首先,我们编写PAction.java文件来完成连接等初始化工作,源代码如下:
PAcation.java的源代码
package guestbook.maxuan.action;
import javax.naming.*;
import java.util.Properties;
import java.util.*;
import javax.rmi.PortableRemoteObject;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.util.Locale;
import java.util.Vector;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.beanutils.PropertyUtils;
import org.apache.struts.action.ActionError;
import org.apache.struts.action.ActionErrors;
import org.apache.struts.action.Action;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
import org.apache.struts.action.ActionServlet;
import org.apache.struts.util.MessageResources;
import guestbook.maxuan.ejb.control.*;
public class PAction extends Action{
//public ActionErrors errors = new ActionErrors();
public BookControl control = null;
public Context getInitialContext() {
String url = "t3://127.0.0.1:";
String user = null;
String passWord = null;
Properties properties = null;
ActionServlet actionServlet = this.getServlet();
String port = actionServlet.getServletConfig().
getInitParameter("port");
url = url + port;
try {
properties = new Properties();
properties.put(Context.INITIAL_CONTEXT_FACTORY,
"weblogic.jndi.WLInitialContextFactory");
properties.put(Context.PROVIDER_URL, url);
if (user != null) {
properties.put(Context.SECURITY_PRINCIPAL, user);
properties.put(Context.SECURITY_CREDENTIALS,
password == null ? "" : password);
}
return new InitialContext(properties);
}
catch(Exception e) {
e.printStackTrace();
}
return null;
}
public BookControl getInitControl( ){
BookControl control = null;
Context ctx = getInitialContext();
try{
Object object = ctx.lookup("BookControl");
BookControlHome bookcHome =
(BookControlHome) PortableRemoteObject.narrow(object,
BookControlHome.class);
control = bookcHome.create();
}catch(Exception e){
e.printStackTrace();
}
return control;
}
}
接着我们编写LyListAction.java文件,得到所有的留言信息LIST。
LyListAction.java的源代码
package guestbook.maxuan.action;
import javax.naming.*;
import java.util.Properties;
import javax.rmi.PortableRemoteObject;
import java.util.*;
import java.util.Locale;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.ServletConfig;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpServletResponse;
import org.apache.struts.action.Action;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionMapping;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ForwardingActionForward;
import org.apache.struts.action.ActionServlet;
import org.apache.struts.util.MessageResources;
import guestbook.maxuan.ejb.control.*;
public class LyListAction extends PAction{
public ActionForward perform(ActionMapping mapping,
ActionForm form,
HttpServletRequest request,
HttpServletResponse response) {
Locale locale = getLocale(request);
HttpSession session = request.getSession();
Context ctx = (Context)session.getAttribute("ctx");
if(ctx==null){
ctx = getInitialContext();
session.setAttribute("ctx",ctx);
}
try{
Object object = ctx.lookup("BookControl");
BookControlHome bookHome =
(BookControlHome) PortableRemoteObject.narrow(object,
BookControlHome.class);
BookControl bookControl = bookHome.create();
ArrayList lyList = bookControl.getLyList();
session.setAttribute("lyList",lyList);
}catch(Exception e){
e.printStackTrace();
}
return (mapping.findForward("success"));
}
}
由于我们需要新加留言,所以这次比上次的EJB教程多出了存储部份,留言需要一个FORM来提交,最后进行
存储,所以我们需要新加入LyForm.java、LyEditAction.java、LySaveAction.java三个文件的编写,源代
码如下:
LyForm.java的源代码
package guestbook.maxuan.action;
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;
import guestbook.maxuan.ejb.entity.value.*;
public final class LyForm extends ActionForm{
public String action="add";
public String name;
public String email;
public String qq;
public String comment;
private BookValue value = new BookValue();
public String getAction() {
return action;
}
public void setAction(String action) {
this.action = action;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getQq() {
return qq;
}
public void setQq(String qq) {
this.qq = qq;
}
public String getComment() {
return comment;
}
public void setComment(String comment) {
this.comment = comment;
}
public BookValue getValue(){
value.setName(name);
value.setEmail(email);
value.setQq(qq);
value.setComment(comment);
value.setAction(action);
return value;
}
public void setValue(BookValue value){
name = value.getName();
email = value.getEmail();
qq = value.getQq();
comment = value.getComment();
action = value.getAction();
}
}
LyEditAction.java的源代码
package guestbook.maxuan.action;
import javax.naming.*;
import java.util.Properties;
import java.util.*;
import javax.rmi.PortableRemoteObject;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.util.Locale;
import java.util.Vector;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.beanutils.PropertyUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.struts.action.Action;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
import org.apache.struts.action.ActionServlet;
import org.apache.struts.util.MessageResources;
import guestbook.maxuan.action.PAction;
import guestbook.maxuan.ejb.entity.value.*;
import guestbook.maxuan.ejb.entity.*;
import guestbook.maxuan.ejb.control.*;
import java.util.Collection;
public class LyEditAction extends PAction{
public ActionForward execute(ActionMapping mapping,
ActionForm form,
HttpServletRequest request,
HttpServletResponse response)
throws Exception {
Locale locale = getLocale(request);
MessageResources messages = getResources(request);
HttpSession session = request.getSession();
String action = request.getParameter("action");
Context ctx = (Context)session.getAttribute("ctx");
BookValue value =(BookValue) request.getAttribute("value");
//errors.clear();
if (form == null) {
form = new LyForm();
if ("request".equals(mapping.getScope())) {
request.setAttribute(mapping.getAttribute(), form);
} else {
session.setAttribute(mapping.getAttribute(), form);
}
}
if(ctx==null){
ctx = getInitialContext();
session.setAttribute("ctx",ctx);
}
LyForm lyForm = (LyForm) form;
if(action!=null){
lyForm.setAction(action);
}
if (value!=null){
try {
PropertyUtils.copyProperties(lyForm, value);
} catch (Exception e) {
}
}
return (mapping.findForward("success"));
}
}
LySaveAction.java的源代码
package guestbook.maxuan.action;
import javax.naming.*;
import java.util.Properties;
import java.util.*;
import java.text.*;
import javax.rmi.PortableRemoteObject;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.util.Locale;
import java.util.Vector;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.beanutils.PropertyUtils;
import org.apache.struts.action.ActionError;
import org.apache.struts.action.ActionErrors;
import org.apache.struts.action.Action;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
import org.apache.struts.action.ActionServlet;
import org.apache.struts.util.MessageResources;
import guestbook.maxuan.action.PAction;
import guestbook.maxuan.ejb.entity.value.*;
import guestbook.maxuan.ejb.entity.*;
import guestbook.maxuan.ejb.control.*;
import java.sql.*;
public final class LySaveAction extends PAction{
public ActionForward execute(ActionMapping mapping,
ActionForm form,
HttpServletRequest request,
HttpServletResponse response)
throws Exception {
Locale locale = getLocale(request);
MessageResources messages = getResources(request);
HttpSession session = request.getSession();
BookValue value=null;
LyForm lyForm = (LyForm) form;
Context ctx = (Context)session.getAttribute("ctx");
//errors.clear();
if(control==null){
control=getInitControl();
session.setAttribute("control",control);
}
//errors = lyForm.check();
try {
Calendar cal = Calendar.getInstance();
SimpleDateFormat formatter=
new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");//设置留言时间格式
String datestr = formatter.format
(new Timestamp(cal.getTime().getTime()));
value = lyForm.getValue();
value.setIp(request.getRemoteAddr());//写入访问者IP
value.setPosttime(datestr);
control.savely(value);
}catch(Exception e){
e.printStackTrace();
}
return (mapping.findForward("success"));
}
}
在上面,我将原本写在里面的检查语句都注释掉了,大家可以自己写进去,也就是对邮件,留言不能为空等检查,当然也可以在页面中写Javascript小脚本,不过这对有心恶意捣乱的人没什么用!
PAction.java完成一些连接等初始动作,其它的分别为显示留言,提交留言等动作,也可以自行定义添加其它动作在里面!例如删除!进入讨论组讨论。
JSP部份
JSP在本篇教程应用中作为视图层,在它里面,你看不到传统的<% %>包含的控制语句,取而代之的是Struts的标签控制!
首先,我们需要在guestbook.jpx的应用中建立web application应用,命名为guestbook,点开它下面的Deployment descriptors,我们会看到web.xml和weblogic.xml两个文件,它们都是建立web application后自动产生的(当你配置的项目应用服务为weblogic时,才会生成weblogic.xml文件,具体配置请见拙作一)
现在我们双击weblogic.xml文件来编辑它,这里我们主要是能让它支持中文!
weblogic.xml源代码
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE weblogic-web-app PUBLIC "-//BEA Systems,
Inc.//DTD Web Application 6.1//EN"
"http://www.bea.com/servers/wls610/dtd/weblogic-web-jar.dtd">
<weblogic-web-app>
<jsp-descriptor>
<jsp-param>
<param-name>encoding</param-name>
<param-value>GBK</param-value>
</jsp-param>
</jsp-descriptor>
</weblogic-web-app>
接着我们需要编辑web.xml文件,主要是配置默认的首页文件,Servlets和Tag Libraries。你可以在WebApp DD Editor项目中配置,也可以直接在Source面板中直接编写源代码
web.xml源代码
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE web-app PUBLIC "-//Sun Microsystems,
Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd">
<web-app>
<servlet>
<servlet-name>action</servlet-name>
<servlet-class>org.apache.struts.action.ActionServlet
</servlet-class>
<init-param>
<param-name>config</param-name>
<param-value>/WEB-INF/struts-config.xml</param-value>
</init-param>
<init-param>
<param-name>debug</param-name>
<param-value>2</param-value>
</init-param>
<init-param>
<param-name>detail</param-name>
<param-value>2</param-value>
</init-param>
<init-param>
<param-name>port</param-name>
<param-value>7001</param-value>
</init-param>
<load-on-startup>2</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>action</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
<taglib>
<taglib-uri>/WEB-INF/struts-bean.tld</taglib-uri>
<taglib-location>/WEB-INF/struts-bean.tld</taglib-location>
</taglib>
<taglib>
<taglib-uri>/WEB-INF/struts-html.tld</taglib-uri>
<taglib-location>/WEB-INF/struts-html.tld</taglib-location>
</taglib>
<taglib>
<taglib-uri>/WEB-INF/struts-logic.tld</taglib-uri>
<taglib-location>/WEB-INF/struts-logic.tld</taglib-location>
</taglib>
</web-app>
在完成以上两个文件的编写后,我们把struts1.1-b1中的所有控制标签文件(除*.jar外的所有文件)拷贝到留言本的应用目录WEB-INF目录中(当你在JBuilder的项目应用中建立web application时,它就会自己帮你建立WEB-INF),如果你以目录形式来发布此次应用,你必须手动在WEB-INF目录下建立一个lib目录,将所有需要的LIB资源文件拷进去,当然如果你在JBuilder中编译此web application它除了会自动将WEB应用打包为guestbook.war文件外,还会自动在WEB-INF中建立LIB文件夹,并将相关的LIB资源文件拷进去!
进入讨论组讨论。
接着我们需要建立struts-config.xml文件,它是配置struts控制的重要文件,编写Struts-config.xml的利器非Struts Console不可,下边是详细的图解:
首先我们新建一个struts config文件,我们选用Struts1.1 Config File,点OK
点击Form Beans新建一个lyForm,NAME:lyForm,Type:guestbook.maxuan.action.LyForm
然后我们在Action Mappings分别加入lyList、saveLy、editLy三个Action!
lyList Action主要是列出所有的留言信息,在path填入/lyList,Type对应它在JAVABEAN中的文件guestbook.maxuan.action.LyListAction(写出完整的文件信息位置),在Forwards加入success,指向正确的JSP文件,这里命名为indexCnt.jsp,我们追溯到/lyList对应的LyListAction.java文件,在最后我们看到的"return (mapping.findForward("success"));"即与此处的success命名对应,也就是成功后即指向success,
而在Struts-config.xml释诠了success指向的实际JSP文件是indexCnt.jsp文件!
按以上方式我们继续编辑saveLy、editLy,图示如下:
saveLy、editLy相对应的是FORM Beans,所以我们必须在它们的Form Bean中指定
在完成后,我们再看Form Beans中的lyForm的Referencing Actions就会看到path中已经有了/saveLy和/editLy
最后,我们需要编辑信息资源项目,在Message Resources下新加入New Message Resource,parameter为ApplicationResources,Messages Key为org.apache.struts.action.MESSAGE!
进入讨论组讨论。
由于在此篇教程中并没有涉及到国际化应用,应此我们并没有编写相应的资源文件!
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-bean name="lyForm" type="guestbook.maxuan.action.LyForm" />
</form-beans>
<action-mappings>
<action path="/lyList"
type="guestbook.maxuan.action.LyListAction">
<forward name="success" path="/indexCnt.jsp" redirect="false" />
</action>
<action path="/saveLy" type="guestbook.maxuan.action.LySaveAction"
name="lyForm" input="/ly.jsp"
scope="request">
<forward name="success" path="/index.jsp" redirect="true" />
</action>
<action path="/editLy" type="guestbook.maxuan.action.LyEditAction"
name="lyForm" scope="request">
<forward name="success" path="/ly.jsp" redirect="false" />
</action>
</action-mappings>
<message-resources parameter="ApplicationResources"
key="org.apache.struts.action.MESSAGE" />
</struts-config>
以上,我们完成了此次教程应用的struts-config.xml的编写,我们看到使用struts console工具编写Struts-config.xml是多么的轻松容易,如果用纯文本编辑工具来写一个大型的struts配置文件,我想恐怕是一个噩梦!
在完成了配置后,我们开始写JSP页面,首先我们定义template,它是struts的模板,所有相同的部份都可以使用template!
template.jsp的源代码
<%@ taglib uri='/WEB-INF/struts-template.tld' prefix='template' %>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=GBK">
<title>留言本教程范例</title>
</head>
<body bgcolor="#ffffff" leftmargin="0" topmargin="0"
marginwidth="0" marginheight="0">
<template:get name='header'/>
<template:get name='content'/>
<template:get name='footer'/>
</body>
</html>
接着完成首页index.jsp文件,它的模板使用template.jsp,定义了页首(header.htm),页尾(footer.htm),及内容显示(由/lyList.do映射到indexCnt.jsp)
index.jsp的源代码
<%@ taglib uri='/WEB-INF/struts-template.tld' prefix='template' %>
<%@ taglib uri="/WEB-INF/struts-bean.tld" prefix="bean" %>
<template:insert template='/template.jsp'>
<template:put name='header' content='/header.htm'/>
<template:put name='content' content='/lyList.do'/>
<template:put name='footer' content='/footer.htm'/>
</template:insert>
页首header.htm的代码(由于只是教程,我并没有进行页面美化工作,大家可以根据自己的喜爱自定义)
<table width="90%" height="50" border="0" align="center"
cellpadding="0" cellspacing="0">
<tr>
<td align="center"><strong>留 言 本</strong></td>
</tr>
</table>
页尾footer.htm的源代码
<table width="90%" border="0" align="center" cellpadding="0"
cellspacing="0">
<tr>
<td align="center">留言本教程范例 2003-9-21</td>
</tr>
</table>
留言内容显示indexCnt.jsp的源代码
<%@ 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" %>
<jsp:useBean id="lyList" scope="session"
type="java.util.ArrayList"/>
<table width="90%" border="0" align="center" cellpadding="0"
cellspacing="0">
<tr>
<td align="right"><html:link page="/editLy.do?action=Add">我要
留言</html:link> </td>
</tr>
</table>
<logic:iterate id="value" name="lyList"
type="guestbook.maxuan.ejb.entity.value.BookValue"
indexId="index">
<table width="90%" border="0" align="center"
cellpadding="5" cellspacing="2">
<tr>
<td><font size="4"><b><bean:write
name="value" property="name"/></b></font><br>
Email:<a href='mailto:<bean:write
name="value" property="email"/>'><bean:write name="value"
property="email"/></a>
QQ:<bean:write name="value" property="qq"/> <br>
留言时间:<bean:write name="value"
property="posttime"/><br><br>
<bean:write name="value" property="comment"/></td>
</tr>
<tr>
<td height="1"><hr size="1" noshade></td>
</tr>
</table>
</logic:iterate>
留言输入页面ly.jsp的源代码
<%@ taglib uri="/WEB-INF/struts-html.tld" prefix="html" %>
<%@ taglib uri="/WEB-INF/struts-bean.tld" prefix="bean" %>
<%@ taglib uri="/WEB-INF/struts-logic.tld" prefix="logic" %>
<html>
<head>
<title>留言</title>
<meta http-equiv="Content-Type"
content="text/html; charset=gb2312">
</head>
<body>
<table width="70%" border="1" align="center" cellpadding="2"
cellspacing="2"
bordercolor="#000000">
<html:form action="/saveLy">
<tr>
<td width="21%" height="20">姓名</td>
<td width="79%" height="20"><html:text property="name"
size="20"/></td>
</tr>
<tr>
<td height="20">email</td>
<td height="20"><html:text property="email" size="20"/></td>
</tr>
<tr>
<td height="20">qq</td>
<td height="20"><html:text property="qq" size="20"/></td>
</tr>
<tr>
<td height="20">留言内容</td>
<td height="20"><html:textarea property="comment" rows="5"
cols="50"/></td>
</tr>
<tr align="center">
<td height="20" colspan="2"><html:submit>保存</html:submit>
<html:reset>重置</html:reset></td>
</tr>
</html:form>
</table>
</body>
</html>
最后效果如图:
此时我们的j2ee体系的留言本教程也就告于段落!
从这篇教程我们可以窥见j2ee多层体系结构的端倪,
本篇教程只是一个基石,在此之上,你可以灵活地搭建更大型的应用,
这才是我写此文的最终目的!
后记:幻想曲花了30多分钟的时间从经典论坛中将maxuan9的帖子整理到了文档区,
希望对那些想学J2EE和正在学J2EE的朋友一点启示、一点帮助!
进入讨论组讨论。
补遗篇
在完成之后,我想我有几个地方得交待一下!
1.留言排序的问题
按照上面的教程完成之后,我们发现最新的留言总在后面,而不是最上方,这是因为我们没有进行排序(我们将信息加入LyList中,它的顺序总是add(),最后加入的总排在最后面,而logic:iterator标签都是从索引0开始显示到最末,因此我们必须要对此LyList进行排序)
从BookControlBean.java中可以看出,我们使用ejbFinder得到Collection,ArrayList类接受Collection对象构造函数,使Collection转换为了List。因此我们可以相当简单的使用Collections.sort()、Collections.reverse()进行排序!
PS:最后一幅完成图即为排序后的页面!
2.留言本页面中文的显示问题
在前面我们说过为了直接在页面上输入中文,我们必须对struts.jar包进行一下改装
具体的文件为:PropertyMessageResources.java
将第289行的:messages.put(messageKey(localeKey, key),props.getProperty(key));
改成下面的代码:
String sProps = props.getProperty(key);
try
{
sProps = new String(sProps.getBytes("ISO-8859-1"),"GBK");
}
catch (Exception e)
{
e.printStackTrace();
}
messages.put(messageKey(localeKey, key),sProps);
然后重新编译生成新包。
为了方便大家,这里我直接提供新包下载
3.留言分页问题
在此教程中我并没有写分页,其实写分页相当简单,看看文档中的logic:iterator,提示:length和offset,发挥一下想像就能写出来!呵呵,自己慢慢进级吧,自己独立解决才是真正的乐趣所在!
至此,如果您对此教程还有什么疑问的话请PM我!!
拷贝代码的话可以去下面这个地址:
实战留言簿(EJB,Struts应用篇)
[全文完]
进入讨论组讨论。
(出处:http://www.knowsky.com)