首页 >> 读书频道 >> 电脑 >> Jakarta Struts学习之实战演示
 
· JavaBean使用技巧
· JSP与Servlets
· JAVA和C++区别
· 应用Java技术实现数据
· Java能够成为完美的技
· 一个读取xml文件内容的
· java打包详解
· 如何寻一个类X实例中类的
· 为什么extends是有
· JAVA中用动态代理类实
· 非阻塞套接字(Nonbl
· Vector还是Arra
 
· 红楼梦:120回全本[清
· 素质教育在美国
· 全唐诗卷四十六
· 韩剧《布拉格恋人》剧情介
· 夜航船[作者:明·张岱]
· 局外人[作者:韩·可爱淘
· 现场流行病学
· 源氏物语[日本:紫式部]
· 武林寓言故事
· 2006高考录取规则
· 首批中国世界名牌产品和2
· 济南美食大全
 
· (出租)中动商场部分及写
· (出租)中动动漫基地&#
· 喜剧学院
· 《善德女王》剧情介绍
· 魔女18号 剧情
· 丑女无敌剧情介绍
· 魔女幼熙剧情介绍
· 龙游天下剧情介绍
· 震撼世界的七日剧情介绍
· 静静的白桦林剧情介绍
· 心情日记—老公今天我想对
· 旗舰剧情介绍
欢迎来到月影社区!如果您觉得这里不错,请推荐给您的朋友们。月影社区:http://wf66.com/

Jakarta Struts学习之实战演示


查看有无更新版本

关键字:JAVA 2006-8-31

 

本文是三篇学习Struts框架系列文章的最后一篇。在第一篇文章《Jakarta Struts简介》中,我大致分析了Struts框架,讨论了它所能完成的功能,还浏览了组成Struts的各个组成部分。在第二篇文章《学习Jakarta Struts》中,我开始详细描述如何利用Struts来构建一个简单应用的过程步骤。而本篇文章将会向大家演示如何将ApplicationResource文件中的文本信息,通过Struts标签在JSP页面中显示出来。
Action类是连接Struts架构和应用中业务逻辑代码的桥梁。所以你应该尽可能让Action类小巧简单,因为真实应用中的逻辑处理应该是由单独分离出来的逻辑层来完成的。如果你正在从事n层应用的开发,你当然希望层与层之间的接口越简单越好。而事实上,Action类中的主要方法"perform()"(1.1中为execute())却有点暗示应该在本方法中做点什么的意思。我们知道,每个Action类都需要从 org.apache.struts.action.Action 继承而来。在小型应用中,我们的Action类很可能就只要继承org.apache.struts.action.Action就足够了;而在某些特定的复杂应用中,我就从我们所实现的Action类中总结出来了一些通用特性。因此,在我看来,构造一个基类将这些通用特性的代码实现出来,让应用中所用到的所有Action类不直接继承org.apache.struts.action.Action,而继承这个完成了一些通用特性的基类以实现代码重用,是一个相当不错的设计。我在StrutsSample中就应用了这种方法,构造了这样的一个基类,该基类的方法在完成复杂逻辑的和简单转发请求的Action类中都可以使用。
package com.oreilly.actions;
import java.io.IOException;
import java.util.Properties;
import java.util.ResourceBundle;
import java.util.MissingResourceException;
import java.util.Enumeration;
import java.util.Properties;
import java.rmi.RemoteException;
import javax.ejb.EJBHome;
import javax.ejb.CreateException;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.struts.action.Action;
import org.apache.struts.action.ActionServlet;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
 
这个类就是使用Struts开发时,所有Action类都要继承的基类。它把一些通常在实际应用中最有可能被用到的东西都考虑进来了。就这篇文章而言, 类中一些与Struts并不是太紧密相关的方法将只做注释而不会完整的实现,而从事开发工作的你,有兴趣的话,请完成这些方法并应用这个类,将为你在实际项目中的开发快马加鞭。注意,因为所有的Action类都要从org.apache.struts.action.Action 继承而来,所以我们的这个类同样。
public abstract class AbstStrutsActionBase extends Action {
/ * 定义一些在struts-config.xml中记录在案的
* 全局应用中皆可可通用的forward标识*/
protected static final String SUCCESS = "success";
protected static final String FAILURE = "failure";
protected static final String ERROR = "error";
protected static final String LOGIN = "login";
protected static final String CONFIRM = "confirm";
protected Context jndiContext = null;
/**
* 默认构造方法
*/
public AbstStrutsActionBase() {
}
/**
 
下面这个查找EJB实例的方法将不会完整实现。
一般来说,Action类应该调用实现了应用的商务逻辑的EJB会话bean(或仅仅普通JavaBean)。在大型项目中,开发人员必须划清层与层之间的界限。在Action类中,我们应该拿到获取含有JNDI信息的环境的实例,然后通过EJB的JNDI名字去查询获取它的home接口。过程并不简单,所以下面这个代码片断只是个给出了必要实现的小例子。
参数类型String,传入的要查询JNDI的名字
返回类型Object,即查找到的home接口
如果查找失败,抛出NamingException异常
如果获取资源信息失败,抛出MissingResourceException异常
*/
public Object lookup(String jndiName)
throws NamingException, MissingResourceException {
// 为调用EJB对象,通过构建记录JNDI信息的Properties对象
// 来获得初始环境信息
if (jndiContext == null) {
ResourceBundle resource =
ResourceBundle.getBundle("strutssample.properties");
Properties properties = new Properties();
properties.setProperty(
Context.INITIAL_CONTEXT_FACTORY,
resource.getString(Context.INITIAL_CONTEXT_FACTORY));
properties.setProperty(
Context.PROVIDER_URL,
resource.getString(Context.PROVIDER_URL));
properties.setProperty(
Context.SECURITY_PRINCIPAL,
resource.getString(Context.SECURITY_PRINCIPAL));
properties.setProperty(
Context.SECURITY_CREDENTIALS,
resource.getString(Context.SECURITY_CREDENTIALS));
jndiContext = new InitialContext(properties);
}
 
注意:在真正的产品中,我们应该在此处考虑代码的健壮性,将代码加入到try/catch块内,并记录所有错误或重要信息到系统log中。而本例中,我们仅仅把异常往外抛,并假定一定会找到EJB对象的home接口并返回。
return (jndiContext.lookup(jndiName));
}
 
由于Action类将是由Struts来调用的。所以它的主要方法应该是一个抽象方法,而由每个继承的子类来具体实现,或者在其中做一些所有Action都会做的通用机制,例如记录log信息。在本例中,我们一切从简,将其抽象之。
参数mapping:其类型为ActionMapping,将在本Action做跳转选择用
参数actionForm:由Struts根据本次HTTP请求数据填充完成的ActionForm对象(可选,如果存在请求数据的话)
参数request:此Action所有处理的本次HTTP请求(对象)
参数response:此Action输出数据所要用到的HTTP响应(对象)
如果有I/O错误出现,则本方法抛出IOException异常
如果处理时发生servlet异常,则本方法抛出ServletException异常
本方法处理完请求后按照处理逻辑返回相应的页面导向(对象)
public abstract ActionForward perform(
ActionMapping mapping,
ActionForm form,
HttpServletRequest request,
HttpServletResponse response)
throws IOException, ServletException;
}
 
或者让这个抽象方法更有用一点,那就在里面干点什么吧,比如像下面这样在其中记录log。
{
ActionForward forward = null;
// 只是简单的记录一些提示信息到servlet log
getServlet().log(
"AbstStrutsActionBase.perform() [Action Class: "
+ this.getClass().getName()
+ " ]");
getServlet().log(
"AbstStrutsActionBase.perform() [Form Class : "
+ (form == null ? "null" : form.getClass().getName())
+ " ]");
}
 
然后,我们再编写的每个Action类都应该从AbstStrutsActionBase继承,并依照处理逻辑编写各自的perform方法。让我们用LoginAction为例,看看具体应该怎么应用吧。
package com.oreilly.actions;
import java.io.IOException;
import java.rmi.RemoteException;
import javax.ejb.CreateException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
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 org.apache.struts.action.ActionForward;
import com.oreilly.forms.LoginForm;
/*
 
LoginAction 将演示一个Action将如何被Struts架构所调用
在这个例子中,我们只是简单的演示perform方法是如何调用、执行并返回的
*/
public class LoginAction extends AbstStrutsActionBase {
 
接下来这个是验证用户的方法,本例中没有具体实现。但一个典型的应用方案是调用JavaBean或者EJB来完成。用来查找EJB的lookup方法(在基类中完成的)应该在本方法中被调用,其返回一个依据后台数据库验证用户的接口。
参数类型String,要验证的用户名
参数类型String,密码
返回类型boolean,如果验证通过为true,否则为false
public boolean authenticate(String username, String password) {
/* 本方法将先做一个查找动作,获得验证用户的EJB对象的接口并调用
* 由于本例只演示Action与商务逻辑层是如何交互的
* 所以具体实现代码本例中就不提供了:)
*/
return (true);
}
 
接下来我们在LoginAction中重载基类的perform方法。
参数mapping:其类型为ActionMapping,将在本Action做跳转选择用
参数actionForm:由Struts根据本次HTTP请求数据填充完成的ActionForm对象(可选,如果存在请求数据的话)
参数request:此Action所有处理的本次HTTP请求(对象)
参数response:此Action输出数据所要用到的HTTP响应(对象)
如果有I/O错误出现,则本方法抛出IOException异常
如果处理时发生servlet异常,则本方法抛出ServletException异常
本方法处理完请求后按照处理逻辑返回相应的页面导向(对象)
public ActionForward perform(
ActionMapping mapping,
ActionForm form,
HttpServletRequest request,
HttpServletResponse response)
throws IOException, ServletException {
// 先假定验证失败,那么要导向的forward当然是LOGIN了(见基类定义的全局变量)
boolean validLogin = false;
ActionForward actionForward = mapping.findForward(LOGIN);
// 构造出承载ActionError对象的容器——errors,以备错误出现时可用
ActionErrors errors = new ActionErrors();
// 从由本次请求构造的ActionForm中提取出所需要的数据
LoginForm loginForm = (LoginForm)form;
String userName = null;
String password = null;
if (loginForm != null) {
userName = loginForm.getUserName();
password = loginForm.getPassword();
validLogin = authenticate(userName, password);
}
if (validLogin) {
// 验证成功了,导向到struts-config.xml中定义的SUCCESS
actionForward = mapping.findForward(SUCCESS);
// 存点必要的东东到session,以备后用
request.getSession(true).setAttribute("USERNAME", userName);
} else {
errors.add("login", new ActionError("error.login.authenticate"));
}
// 系统如果用户界面友好一点,我们就应该将错误信息存入request对象中
// 然后到页面,通过在Struts的标签显示出来
if (!errors.empty()) {
saveErrors(request, errors);
}
// 本Action处理完成,导向到合适的forward
return (actionForward);
}
}
 
注意,这个LoginAction类就是在struts-config.xml中定义的用来处理登录事务的一个具体实现。当这个类被载入并有一个对象实例化后,Struts架构就会调用它的perform方法。这个方法是这样声明的:
public ActionForward perform(
ActionMapping mapping,
ActionForm form,
HttpServletRequest request,
HttpServletResponse response)
throws IOException, ServletException
 
其中,mapping是一个记录与此Action对应的forward导向的对象,form对象封装由客户端提交的此Action要处理的数据,还有标准的HttpServletRequest对象和HttpServletResponse对象。
有了这些对象的辅助,此Action就可以拿到需要的东东顺利开工了。我们的例子中,要处理的数据主要是用户名和密码,这些都由form对象提供。实现验证功能是本应用的主要业务逻辑,在方法中的具体实现应该是去取EJB的相应接口来操作或者直接去拿数据库数据来验证。前面那个AbstStrutsActionBase类中已经实现了一个简单的EJB接口查找动作,所以如果我们是在开发一个基于EJB实现的系统,它的可重用性就非常强了。
由验证方法(authenticate())的返回值,Action要接着做出合理的动作。如果验证通过,就要让用户进入正确的页面,那么我们就将一些后面可能会用到的信息存入request对象(译注:准确的讲,代码中是存到了session对象里,当然session对象是和当前request相关的),并向Struts返回success这个forward。这个forward是在struts-config.xml中定义的,然后由ActionMapping封装起来,在Action处理中可以从中拿出合适的forward做为返回值。如果回头去看看struts-config.xml中的定义,就会知道success这个forward会将用户导向至Welcome.jsp这个页面的。如果验证失败,则将一个错误信息存起来,然后导向到一个错误提示页面显示出来。
开发应用的业务逻辑
在一个真实的应用系统中,我们应该将业务逻辑层整合进来了。在我们这个例子里,我们就应该去开发LoginAction中的authenticae方法所调用到的EJB了。但是正如你所见的,我们完全可以把这一层暂时屏蔽掉,而利用Struts把前端部分构建并能够让它跑起来的。我其实相当推崇的是方法是先将应用框架搭建并运行起来,然后在开发后台实际的业务逻辑层。在应用框架完全恰当的构建起来的时候,后台的开发工作所有做的debug工作也少的多了。而且,业务逻辑的开发也不是本文所要函概的范围,所以此处我们略过,不过我相信你现在一定对应用的全局有了总体的把握了吧!
开发由ActionMapping定义的系统工作流程,完成对应的JSP页面
终于可以将所有这些东东整合在一起了。在struts-config.xml配置文件中定义的那些ActionMapping,我们要完成这些ActionMapping定义用到的JSP页面。本例中,包括Login.jsp、Welcome.jsp和Errorpage.jsp。还有,尽管我们在本例中都是将Action处理完成forward到JSP页面,这在这个简单的例子中是再恰当不过的逻辑流程了,而在实际利用Struts开发应用中呢,当然可以从Action forward到其他的Action。我们这个简单的Login.jsp页面内容是这样的:
<%@ page language="java" %>
<%@ taglib uri="/WEB-INF/struts-html.tld" prefix="html" %>
<%@ taglib uri="/WEB-INF/struts-form.tld" prefix="form" %>
<%@ taglib uri="/WEB-INF/struts-bean.tld" prefix="bean" %>
<html>
<head>
<title><bean:message key="login.title"/></title>
</head>
<body>
<html:errors/>
<h3>Enter your username and password to login:</h3>
<html:form action="login.action" focus="userName" >
<html:text property="userName" size="30" maxlength="30"/>
<html:password property="password" size="16" maxlength="16" redisplay="false"/>
<html:submit property="submit" value="Submit"/>
<html:reset/>
</html:form>
</body>
</html>
 
Struts在JSP自定义标签库的基础上提供了一套综合各种功能的标签库。利用这些标签库很容易的构建用户界面了。使用这些标签库的好处之一就是可以利用其提供的很多附加功能。比如在一般的JSP页面的表单里我们可以看到这样常见的HTML片断:
<input type="text" name="userName" value="">
 
如果我们使用Struts的标签库的话,就可以改成这样子:
<html:text property ="userName">
 
不过我们得现在页面中先声明Struts标签库的定义。
<%@ taglib uri="/WEB-INF/struts-html.tld" prefix="html" %>
 
在这个例子中,我们会用到一些Struts标签,但我不准备在此详细讲解Struts各种标签库的用法。相信在你不断使用Struts搭建功能复杂的JSP页面的过程中,你将会对所使用过的标签越来越熟悉的。到那时,你也将更能体会到Struts标签的益处,利用它们大大的缩短你的开发时间。目前,你可以从Struts Developers Guides了解到更多的细节。
在我们这个简单例子中,有两个重点。其一:
<title><bean:message key="login.title"/></title>
 
这就是在利用我们前面提到的资源文件ApplicationResource来在页面显示信息,而不是将信息文本硬编码到我们的应用中。
其二:
<html:errors/>
 
这就是在页面中显示出ActionErrors的信息,也就是我们在LoginForm的验证方法和LoginAction中产生的报错信息的集合对象。
页面中的表单,利用Struts,我们将用如下的标签来定义:
<html:form action="login.action" focus="userName">
 
这里的login.action,是和struts-config.xml中定义ActionMapping相匹配的。在页面标签中这样的定义,就将相关的Action、ActionForm和ActionForward完整的串了起来。当这个用标签定义的表单提交的时候,Struts中的ActionServlet就会将其交由login.action来处理。具体的过程我们下面慢慢深入。
在Welcome.jsp中,我们只演示如何将Action中的信息传递到页面加以利用的一般机制:
<html>
<title>Welcome to Struts</title>
<body>
<p>Welcome <%= (String)request.getSession().getAttribute("USERNAME") %></p>
</p>You have logged in successfully!</p>
</body>
</html>
 
还记得吗?我们在LoginAction中的perform()方法中将USERNAME放到了session中哦。
完成系统配置文件
我们已经就struts-config.xml谈了好多了。通常,这个文件中的信息会在开发过程中逐渐完善。但是到了开发过程的最后一部,我们更应该回头去检查这个至关重要的配置文件,以保证万无一失:Action、JSP页面还有ActionForm都应该在文件中正确的定义。此外,我们还不得不说到web.xml。这个文件是JSP容器(例如Tomcat)获取应用相关配置的重要文件。我们这个StrutsSample例子所用到的web.xml大致是这样的:
<?xml version="1.0" encoding="ISO-8859-1"?>
<!--
This is the web-app configuration that allow the strutsSample to work under
Apache Tomcat.
-->
<!DOCTYPE web-app
PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.2//EN"
"http://java.sun.com/j2ee/dtds/web-app_2_2.dtd";;>
<web-app>
<servlet>
<servlet-name>oreilly</servlet-name>
<servlet-class>org.apache.struts.action.ActionServlet</servlet-class>
<init-param>
<param-name>application</param-name>
<param-value>com.oreilly.ApplicationResources</param-value>
</init-param>
<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>validate</param-name>
<param-value>true</param-value>
</init-param>
<load-on-startup>2</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>oreilly</servlet-name>
<url-pattern>*.action</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>Login.jsp</welcome-file>
</welcome-file-list>
<!-- Struts Tag Library Descriptors -->
<taglib>
<taglib-uri>/WEB-INF/struts.tld</taglib-uri>
<taglib-location>/WEB-INF/struts.tld</taglib-location>
</taglib>
<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>
<taglib>
<taglib-uri>/WEB-INF/struts-form.tld</taglib-uri>
<taglib-location>/WEB-INF/struts-form.tld</taglib-location>
</taglib>
</web-app>
 
这里的标签定义了org.apache.struts.action.ActionServlet,而且在本例中,我们把这个定义的servlet叫作“oreilly”,并传了两个初始化参数给它:其一是我们为这个应用所需的显示字符串定义的资源文件,其二是指明struts-config.xml文件的位置。相信你也注意到了,在中为这个Servlet指明的相应请求处理串是*.action,这是和我们在页面中的表单定义的提交的URL是吻合的。也就是说,我们通过标签告诉Tomcat,所有后缀为.action的请求都交给“oreilly”这个Servlet来处理。你当然可以指定你喜欢的后缀。在Struts附带的例子中,你可能会看到通常以.do做为后缀,不过我认为.action更明确一些。标签中定义了本应用初始显示页面。最后呢,我们还要把会用到的Struts标签库列在后面。
编译/测试/发布
到此为止,编译/测试/发布应用之前的所有工作都完成了。用Ant来编译整个应用是相当容易的。如果你以前没有接触过Ant,那最好把这个研究一下。其实学习和应用Ant来管理一个应用编译环境并不难。我把这个编译应用所要用到的build.xml和例子放到了一起,这篇文章所要用到的所有东东,你都可以点此下载,到时候你到build.xml所在目录简单执行ant命令就可以完成编译,并打包成strutsSample.war包。当然要执行ant,你得先去下载Ant。将Ant下载回来并搭建好环境可能得花十几分钟的时间哦。
本应用的目录结构如下:
StrutsSample根目录
*.jsp
WEB-INF目录
Struts配置文件(struts-config.xml, web.xml)
classes目录(还是以Java程序文件包结构为路径)
lib目录(struts.jar)
拿到了应用的war包,我们就将它放到Tomcat的webapps路径下,然后启动Tomcat。war包会被自动展开,此应用的上下文环境也会由Tomcat自动建立起来。我们通过web.xml告知Tomcat这个应用所需的其他资源在哪里。现在,我们可以通过http://localhost:8080/strutsSample来访问我们的应用了。如果没有特别指定的话,Tomcat默认的端口是8080,我们定义的默认初始页面Login.jsp也将显示出来,现在我们来试试吧。
结论
通过本系列的文章,我们利用Struts从应用需求开始,一步步将整个应用搭建起来。和普通的JSP技术相比,通过Struts开发的应用涉及到更多的与之相关的各类文件,也正是依靠各类文件,我们才可能构建一个适合开发复杂应用的MVC架构。我们的第一个Struts应用花了如此多的时间,是为了要弄清楚Struts的各个部分到底是如何工作的。
希望本系列Struts文章,能够帮助你了解Struts是由哪些部分构成的,它们能够完成什么,也希望介绍一个比较好的开发流程可供你参考。Struts才诞生不久,我有信心它将成为我们构建J2EE应用的优秀工具。

Jakarta Struts学习之实战演示

[ 1 ]
Jakarta Struts学习之实战演示 num

打印本页 关闭

关于我们版权声明本站导航友情连结作品演示 TOP↑