·您的位置: 首页 » 资源教程 » 编程开发 » JAVA、JSP » 使用JAVABEAN高效处理JSP

使用JAVABEAN高效处理JSP

类别: JSP教程  评论数:0 总得分:0
摘要:JavaServer Pages Model II的一个基本思想就是将表现(HTML)和处理逻辑分开。这篇文章介绍的是一个高效、可重用的设计方法,将动态的内容、处理和验证由JavaServer Page中分离出来,放到一个相应的JavaBean中。它使用Template Method的设计方法,可提高代码在整个Web应用中的重用性。此外,它还介绍了在一个HTTP Session中bean间如何通信的简单技巧。

  JavaServer Pages(JSP)技术提供了许多的特性,可让你简易和快速地开发Web应用。不过,如果你无计划和结构地使用这些技术,你的JSP代码将会是各种HTML标记、JSP标记和Java代码的混合,很难于看懂、调试和维护。

  这里的目标是将全部的JSP处理代码封装到JavaBean中。这种方法的好处是HTML编程者和美工可以做表现的开发(使用HTML编辑器),而Java编程者可以集中开发编程逻辑。此外,这种方法可便于你为同一个Web应用提供不同的外观。

  我将介绍的架构使用Template Method方法,可集中实现整个应用的共有设计部分和实现每个JSP的共有处理。就这个例子,共有的处理包括有页面状态管理、共有的页面处理、共有的错误处理,以及在页面间共享信息的技术。所有这些仅是定义一次,你可在页面设计时再处理特定的细节。

  我将以一个简单的"投票"应用为例,介绍如何使用这个架构。你应有基本的JSP和Java知识,并且最好懂得一些UML知识。

  总的静态结构

  这个部分将介绍该架构核心部分的概观,以及投票应用的例子。图一显示了该架构的一个UML框图:



**************图一*******************
(UML类框图)

  该架构的中心部分由两个共有的JSP包含文件和两个类组成,下面将会谈到。它们的作用是完成共有的处理。

   includeheader.jsp:这个JSP文件必须被静态包含在每个JSP文件的开头。

   includefooter.jsp:这个JSP文件必须被静态包含在每个JSP文件的末尾。

  AbstractJSPBean:这是一个抽象类,你应该将它作为所有JSP JavaBean类的一个超类使用。它是该架构的核心类。

   SharedSessionBean:在一个HTTP session中,为所有的JSP JavaBean对象提供关联。

  JSP网页只是用作表现的。每个JSP页面都应该使用一个相应的JavaBean来处理特定页面的逻辑。每个JSP页面都应该静态包含includeheader.jsp和includefooter.jsp。每个JavaBean都必须扩展AbstractJSPBean,该抽象类包含有模板方法,可完成共有的处理。

  这个投票的应用包含有以下的JSP和相应的JavaBean:

   login.jsp, LoginJSPBean:投票者认证和登录

   vote.jsp, VoteJSPBean: 执行投票

   confirmation.jsp, ConfirmationJSPBean: 显示确认和投票的结果

  我将不会详细讨论数据库和商业逻辑的部分((Voter, Candidate和VoteDB),不过它们对于这个例子是必需的。

  以上我们已经对整体有了一个概观,接着我们将讨论例子中的每个JSP页面。

  JSP例子

  每个页面都必须使用指定的结构,以符合整个架构。

  列表1。login.jsp

<%@ page import = "lbm.jsputil.*" %>
<jsp:useBean id="_loginJSPBean" class="lbm.examples.LoginJSPBean"
scope="session"/>
<jsp:setProperty name="_loginJSPBean" property="*"/>
<% AbstractJSPBean _abstractJSPBean = _loginJSPBean; %>
<%@ include file="includeheader.jsp" %>

<html>
<head><title>Vote Login</title></head>
<body bgcolor="white">

<font size=4>
Please enter your Voter ID and Password

</font>

<font size="3" color="Red">
<jsp:getProperty name="_loginJSPBean" property="errorMsg"/>

</font>

<font size=3>
<form method=post>
Voter ID <input type=text name=voterId value=<jsp:getProperty
name="_loginJSPBean" property="voterId"/>>

Password <input type=password name=password value=<jsp:getProperty
name="_loginJSPBean" property="password"/>>


<input type=submit value="Login">
</form>
</font>
</body>
</html>

<%@ include file="includefooter.jsp" %>


  该JSP页面的架构如下:由几个JSP语句开始。接着的HTML代码将没有多少JSP指令、语句和脚本等。除了几个必要的指令,它们负责由bean中得到动态的内容。最后,页面使用了一个JSP include指令。

  我们讨论其中一些重要的JSP语句:

<jsp:useBean id="_loginJSPBean" class="lbm.examples.LoginJSPBean" scope="session"/>
<jsp:setProperty name="_loginJSPBean" property="*"/>


以上的代码在JSP和相应的bean间建立了一个连接。第二个语句显式传送全部的form字段(存储为HTTP request参数)到bean中匹配的属性中。代码中使用了bean的setter方法。

<% AbstractJSPBean _abstractJSPBean = _loginJSPBean; %>
<%@ include file="includeheader.jsp" %>


  第一个语句让includeheader.jsp可执行共有的处理。第二个语句将includeheader.jsp静态包含进来。要注意到loginJSPBean和_abstractJSPBean现在指向同样的对象,只是带有不同的接口。

  列表2:includeheader.jsp

<%-- Set the SharedSessionBean --%>
<jsp:useBean id="_sharedSessionBean" class="lbm.jsputil.SharedSessionBean" scope="session"/>
<% _abstractJSPBean.setSharedSessionBean(_sharedSessionBean); %>

<%-- Set implicit Servlet objects --%>
<% _abstractJSPBean.setRequest(request); %>
<% _abstractJSPBean.setResponse(response); %>
<% _abstractJSPBean.setServlet(this); %>

<%-- Perform the processing associated with the JSP --%>
<% _abstractJSPBean.process(); %>

<%-- If getSkipPageOutput equals false, do not output the JSP page --%>
<% if (! _abstractJSPBean.getSkipPageOutput()) { %>



  includeheader.jsp是模板的核心元素之一。所有的JSP页面都使用这个共有的元素。

  列表2的前两个语句令不同页面但在同一HTTP session中的JSP bean之间互相进行通信。基本上,每个JSP将有两个与它关联的JavaBean:一个指定的JSP JavaBean(例如,LoginJSPBean)和共有的SharedSessionBean。SharedSessionBean作为一个共有的元素使用,用来连接所有的页面;我将在后面继续讨论它。

  includeheader.jsp中接着的三个语句与固有的Servlet对象有关。

<% _abstractJSPBean.setRequest(request); %>
<% _abstractJSPBean.setResponse(response); %>
<% _abstractJSPBean.setServlet(this); %>


  JSP规范提供访问Java Servlet规范中的固有对象,例如页面处理中常用到的request、response和servlet对象。因此它们被传送到JSP bean。

  <% _abstractJSPBean.process(); %>

  最后,通过上面的语句来触发相关JSP页面的处理。你看到我们调用的是抽象JSP bean上的方法,而不是实类LoginJSPBean上的。为什么?我将在以下的部分解释。

  运用Template Method设计方法

  AbstractJSPBean是Template Method设计的主体。每个实际的JSP JavaBean都必须继承这个类。

  列表 3. AbstractJSPBean.java

package lbm.jsputil;

import java.util.*;
import javax.servlet.http.*;
import javax.servlet.*;

public abstract class AbstractJSPBean {

/* constants used for _state */
public static final int NEW = 0;
public static final int FIRSTPASS = 1;
public static final int PROC = 2;
public static final int ERR = -1;

private int _state; // current state
private String _errorMsg; // current message that is being appended during validation
private boolean _skipPageOutput; // should the page output be skipped

private SharedSessionBean _sharedSessionBean; // used for associating the JSP Bean with the HTTP Session

/* standard Servlet objects that need to be setup for each JSP Bean */
protected HttpServletRequest _request;
protected HttpServletResponse _response;
protected Servlet _servlet;

public AbstractJSPBean () {
setState(NEW);
}

protected abstract void beanProcess() throws java.io.IOException;

protected abstract void beanFirstPassProcess() throws java.io.IOException;

protected abstract void beanFooterProcess() throws java.io.IOException;

protected abstract String getJSPCode();

public void process() throws java.io.IOException {
setSkipPageOutput(false); // by default do not skip page output. Specific bean process
// methods can override it.
if (getState() == NEW) {
setState(FIRSTPASS);
beanFirstPassProcess();
} else {
resetErrorMsg();
setState(PROC);
beanProcess();
}

// validation that all common fields have been properly set by the application
// this is actually checking that the code has been written properly
String l_err = "";
if (_sharedSessionBean == null) l_err = l_err + "; SharedSessionBean must be set";
if (_request == null) l_err = l_err + "; Request must be set";
if (_response == null) l_err = l_err + "; Response must be set";
if (_servlet == null) l_err = l_err + "; Servlet must be set";
if ( ! l_err.equals("")) throw new IllegalStateException(l_err);
}

public void footerProcess() throws java.io.IOException {
beanFooterProcess();
}

protected void addErrorMsg (String addErrorMsg) {
if (_errorMsg == null) _errorMsg = addErrorMsg;
else _errorMsg = _errorMsg + " <br> " + addErrorMsg;

setState(ERR);
}
protected void resetErrorMsg () {
_errorMsg = null;
}
public String getErrorMsg () {
if (_errorMsg == null) return "";
else return _errorMsg;
}

protected void setState (int newState) {
_state = newState;
}
public int getState () {
return _state;
}

public void setSharedSessionBean (SharedSessionBean newSharedSessionBean) {
if (_sharedSessionBean == null) {
_sharedSessionBean = newSharedSessionBean;
_sharedSessionBean.putJSPBean(getJSPCode(), this);
} else {
if (_sharedSessionBean != newSharedSessionBean) {
throw new IllegalStateException("SharedSessionBean is not set properly. SharedSessionBean must be the same for all PageBeans within the session");
}
}
}
public SharedSessionBean getSharedSessionBean () {
return _sharedSessionBean;
}

public void setSkipPageOutput (boolean newSipPageOutput) {
_skipPageOutput = newSipPageOutput;
}
public boolean getSkipPageOutput () {
return _skipPageOutput;
}

protected void redirect (String redirectURL) throws java.io.IOException {
// skip the page output since we are redirecting
setSkipPageOutput(true);
_response.sendRedirect(redirectURL);
}

public void setRequest (HttpServletRequest newRequest) {
_request = newRequest;
}
public void setResponse (HttpServletResponse newResponse) {
_response = newResponse;
}
public void setServlet (Servlet newServlet) {
_servlet = newServlet;
}
}


AbstractJSPBean包含有以下的抽象方法:beanFirstPassProcess(), beanProcess(), and beanFooterProcess()。这些方法被称为primitive方法。你必须在实际的JSP JavaBean子类中实现它们。每个都在JSP处理的一个特定阶段中执行。

  beanFirstPassProcess()--在页面被首次调用时进行的处理,它发生在页面开始输出之前。它适合用来初始化动态的内容和验证对页面的访问。可参见VoteJSPBean中该方法的实现,该Bean中用它来验证页面的访问,并且进行应用的流程控制。

  beanProcess()--发生在第二和后来的页面调用期间的处理,在页面输出开始之前。你可以用它来作HTML form验证和数据库更新。在LoginJSPBean类中,该方法被用作HTML form处理,在VoteJSPBean类中,用来保存信息到数据库中。

  beanFooterProcess()--在页面输出完成后进行的处理。你可以使用它来令session无效。在ConfirmationJSPBean类中,当投票完成后,通过实现该方法令session无效,并且显示确认的页面。

  接着我们将看一下process()方法:

public void process() throws java.io.IOException {
setSkipPageOutput(false); // by default do not skip page output. Specific bean process
// methods can override it.
if (getState() == NEW) {
setState(FIRSTPASS);
beanFirstPassProcess();
} else {
resetErrorMsg();
setState(PROC);
beanProcess();
}
....



  process()首先检查JSP的状态;然后,根据状态,它调用相应的primitive方法。它还设置了JSP相应的状态。

  process()和footerProcess()方法被称为template方法。它们由JSP中真正调用(在includeheader.jsp和includefooter.jsp中)。实体的bean不应该覆盖它们。template方法包含有共有的框架算法。一个典型模板方法的框架算法执行一个共有的处理,并且调用primitive(抽象)方法(beanFirstPassProcess()、beanProcess()和beanFooterProcess()),这些方法的实现在每个实际的JSP JavaBean中都是不同的。框架算法也可以称为AbstractJSPBean中实现的实体方法。以上的规则是Template Method设计方法的基本点。

  这种方法的好处是:

  1、通过在模板方法中分解出共有的处理,你可以做到代码重用

  2、你可以对整个应用进行共有的设计和处理

除了处理逻辑外,AbstractJSPBean还包含有以下具体的方法来帮助子类(实际的JSP JavaBean)来实现它们的处理任务,你不应该覆盖这些实际的方法。

  1、与用户错误管理相关的方法(addErrorMsg(), resetErrorMsg(), and getErrorMsg())

  2、与页面状态管理相关的方法(setState(), getState())

  3、管理与SharedSessionBean关联的方法


  4、控制JSP页面的HTML部分是否输出的方法(setSkipPageOutput(), getSkipPageOutput())

  5、重定向的方法

  6、访问Servlet对象的方法: request, response和servlet

form处理、动态内容和bean通信

  列表4展示了一个具体的JSP JavaBean--LoginJSPBean,用来实现特定的页面处理

  列表4。LoginJSPBean


package lbm.examples;

import lbm.jsputil.*;
import java.util.*;

public class LoginJSPBean extends AbstractJSPBean {

public static final String PAGE_CODE = "login";

private String _voterId;
private String _password;
private Voter _voter = null;

public LoginJSPBean() {
}

public void setVoterId (String newVoterId) {
_voterId = newVoterId;
}

public String getVoterId() {
if (_voterId == null) return "";
else return _voterId;
}

public void setPassword (String newPassword) {
_password = newPassword;
}

public String getPassword() {
if (_password == null) return "";
else return _password;
}

public Voter getVoter () {
return _voter;
}

protected void beanProcess () throws java.io.IOException {
if (_voterId == null || _voterId.equals("")) {
addErrorMsg("Voter must be entered");
}

if (_password == null || _password.equals("")) {
addErrorMsg("Password must be entered");
}

if (getState() != ERR) {
file://If all the fields are entered, try to login the voter
Voter voter = VoteDB.login(_voterId, _password);
if (voter == null) {
addErrorMsg("Unable to authenticate the Voter. Please try again.");
}
else {
_voter = voter;

if (_voter.getVotedForCandidate() != null) {
// if the voter has already voted, send the voter to the last page
redirect("confirmation.jsp");
}
else {
// go to the Vote page
redirect("vote.jsp");
}
}
}
}

protected void beanFirstPassProcess() throws java.io.IOException {
}

protected void beanFooterProcess() throws java.io.IOException {
}

protected String getJSPCode() {
return PAGE_CODE;
}
}



  观察LoginJSPBean类中的set和get方法。就象上面提及的,它们用作动态的匹配,并且用来在form字段(request参数)和bean属性间传送值。

  列表4中的beanProcess()方法,展示了form处理的一些基本点。这个方法发生在页面输出前,在第二和全部后来的页面调用期间执行。这意味着它将仅在用户按下登录按钮并且提交form后执行。

  你首先要验证voteId和password的输入,产生的错误将通过addErrorMsg方法记录下来。这个方法设置AbstractJSPBean类的errorMsg属性。该属性可被JSP用来显示用户的错误:

   <jsp:getProperty name="_loginJSPBean" property="errorMsg"/>

  如果数据的输入成功通过,beanProcess()方法将会调用数据库来验证用户。最后,它通过调用AbstractJSPBean类中实现的redirect()方法,将请求重定向到相应的页面。

  以下我们将讨论VoteJSPBean类中的一些方法。它们将可以解释该架构的一些其它方面,例如JSP JavaBean之间的通信和应用的流程控制。

  列表5。VoteJSPBean类中的beanFirstPassProcess()


protected void beanFirstPassProcess() throws java.io.IOException {
// get the Voter from Login page
_voter = null;

LoginJSPBean loginJSPBean =
(LoginJSPBean) getSharedSessionBean().getJSPBean(LoginJSPBean.PAGE_CODE);

if (loginJSPBean != null) {
_voter = loginJSPBean.getVoter();
}

if (_voter == null) {
// voter is not logged in yet. Send it to Login page
setState(NEW);
redirect("login.jsp");
}
}



以上的方法使用了AbstractJSPBean类中_sharedSessionBean对象。SharedSessionBean类通过使用一个简单的方法,让所有的JSP JavaBean对象在一个HTTP session中进行通信。它保存有一个session内的全部JSP JavaBean中的一个Map。Map是Java Collections框架的一个接口,它是Java 1.2推出的。对熟悉Java 1.1的人来说,它与Hashtable非常类似。一个JSP JavaBean的主键是它的PAGE_CODE,它作为一个常数存储在每个JSP JavaBean类中。

  在这个例子中,beanFirstPassProcess()方法首先定位到LoginJSPBean对象。接着,它由LoginJSPBean对象中得到Voter对象,并且存储一个到它的引用,以便以后使用。如果Voter为null,这意味着用户没有首先登录就进入Voter页面,因此它重定向到登录页面。这是一个应用流程控制的简单例子。你可以设计更复杂的方法,例如使用一个智能的调度程序,不过这些讨论已经超出了本文的范围。

  列表6。VoteJSPBean类的getCandidateList()方法


public String getCandidateList () {
StringBuffer candidateList = new StringBuffer();
Candidate candidate;

Iterator candidates = VoteDB.getCandidates();
while (candidates.hasNext()) {
candidate = (Candidate) candidates.next();

candidateList.append("<input type=radio name="candidateName" value="");
candidateList.append(candidate.getName());
candidateList.append(""> ");
candidateList.append(candidate.getName());
candidateList.append("<br> ");
}

return candidateList.toString();
}



  以上的getCandidateList()方法被vote.jsp调用,通过以下的方法:

   <jsp:getProperty name="_voteJSPBean" property="candidateList"/>

  根据由数据库得到的内容不同,该方法提供不同的动态HTML内容输出。它需要开发JavaBean的Java编程者懂得一些HTML知识。

  你也可以使用一个利用HTML的独立库来格式化HTML,它可以接受一个预定义的输入。例如Iterator,然后以预定义的格式产生HTML输出。另一个方法是使用标签库。

  最后的要点:框架

  通过将表现和逻辑分离开来,该架构可让你独立地修改表现(JSP)和逻辑(bean)。这意味着你可以修改bean中的逻辑而无需改动JSP,只要你保持bean的属性不变就行了。相反也是成立的,你可以将JSP代码交给HTML开发者和美工来改变站点的外观,而不会影响其中的Java代码。

  你可以稍微修改该框架的核心元素来满足你应用的特别需要。你可以加入新的或者修改现有的方法,或者修改模板的方法。重要的一点是,在你的整个应用中,全部的JSP和JSP JavaBean都应该使用这个架构。

  在刚开始时,这个架构看来比较复杂,特别是对于一个只有三页的例子应用来说。不过,如果你开始写你的应用,你将会发现当应用变复杂时,代码量的增长却没有预期的大。

  这个架构并没有谈到Web应用中通常用到的多层设计。它主要集中在JSP的表现层。要建立真正的三层或者多层的系统,JSP JavaBeamn将需要调用Enterprise JavaBean或者一些其它的商业逻辑实现。

  例子还介绍了让应用跟踪HTTP session的架构。不过,如果你不想依赖session的话,该架构仍然可以工作得很好。应用的页面和流程应该是分别设计的。你可能将不需要SharedSessionBean。你的页面只是用作表现,而独立的页面将仅用作处理和验证,而不会有任何的HTML输出。为此,你将主要使用beanFirstPassProcess() 方法。

  最后的要点:例子

  我使用Tomcat3.1来测试这个例子,Tomcat3.1符合JSP1.1和Servlet2.2规范。这篇文章将不会讨论如何在Tomcat中配置JSP应用的详细情况。

  在测试该例子时,你可以在VoteDB类的源代码中得到Voter ID,以便可以进行登录测试(密码和ID是一样的)。

  你必须在浏览器中允许cookies,否则不能成功运行例子。如果你需要在禁止cookies时仍然可以运行这个应用,你必须重新写URL(使用the javax.servlet.http.HttpServletResponse类的encodeURL()方法)。你需要重写全部应用中的URL,包括你的JSP中的链接,form标记中的action,以及在JSP JavaBean中用来重定向URL的HTTP请求。

  结论

  这篇文章介绍的架构为JSP的应用设计提供了一个全面的解决办法。它改进了代码重用,确定了应用的体系,并且便于扩展。一个最大的好处是将表现和逻辑分开,你可以独立改变它们,而不会影响另一方。 
-= 资 源 教 程 =-
文 章 搜 索
关键词:
类型:
范围:
纯粹空间 softpure.com
Copyright © 2006-2008 暖阳制作 版权所有
QQ: 15242663 (拒绝闲聊)  Email: faisun@sina.com
 纯粹空间 - 韩国酷站|酷站欣赏|教程大全|资源下载|免费博客|美女壁纸|设计素材|技术论坛   Valid XHTML 1.0 Transitional
百度搜索 谷歌搜索 Alexa搜索 | 粤ICP备19116064号-1