容器是基于面向服务架构(SOA)的特定规范框架,J2EE大量运用了容器和组件技术来构建分层的企业级应用。在J2EE规范中,相应的有WEB Container和EJB Container等。
WEB Container,给处于其中的应用程序组件(JSP,SERVLET)提供一个环境,使JSP、SERVLET直接跟容器中的服务接口交互,不必关注其它系统问题。WEB Container主要有WEB服务器来实现。例如:TOMCAT,WEBLOGIC,WEBSPHERE等。比如,Resin 2.1.x以上版本提供的Servlet Container就实现了J2EE的Servlet 2.3规范。我们把遵守以上标准的WEB服务器就叫做J2EE中的WEB容器。
WEB容器更多的是跟基于HTTP的请求打交道。而EJB容器不是。它是更多的跟数据库、其它服务打交道。但他们都是把与外界的交互实现从而减轻应用程序的负担。例如SERVLET不用关心HTTP的细节,直接引用环境变量session,request,response就行、EJB不用关心数据库连接速度、各种事务控制,直接由容器来完成。
容器的职责
容器的职责因具体执行的服务调用规范的不同而有差别,比如Servlet Container只需实现Servlet 2.3规范。而Portlet Container,如Pluto,则需要具体实现基于JSR 168
portlet 规范,具体的技术规范,比如需要实现基于容器级的事件处理机制Action Event、Message Event等。从水平的方向来看,通常容器提供系统级的服务调用。
容器与应用服务器
容器是服务调用规范的具体实现,比如EJB Container是对EJB 2.0规范的实现。然而,实现只是衡量规范的执行程度,通常容器是由应用服务器来具体执行,从这个层面来说,应用服务器又可以称之为容器的容器。
容器与IOC原则
IOCInversion Of Control,即倒置控制,IOC自面向对象诞生起就存在,并不是最新技术,象SRPOCPDIP等面向对象的基本法则一样。Inversion Of Control,这个短语是由Brian Foote在他的一篇论文中最先使用的(http://www.laputan.org/drc/drc.html)。组件所需的一切通过Contexts、Configurations和Loggers的方式赋予组件。

在组件容器中,组件不需要实现或扩展(不依赖)容器类和接口,由容器在组件需要时提供其它依赖组件实例。反例:EJB其中的EJB组件需要实现几个接口,需要用JNDI或全局注册表得到其它EJB实例。

IOC,实现了组件与容器间的解耦,意味着在开发组件时同样可以采用从上至下的方法。不需要建立一个注册类,客户端必须调用此注册类才能获得组件实例。

容器与AOP技术

Aspect Oriented Programming,即“面向方面编程”。诞生于业界非常著名的施乐Palo Alto研究中心(Palo Alto Research Center,简称PARC),从AOP的概念雏形到2001AspectJ 1.0版本仅仅花了7年时间。AOP起源于Gregor Kiczales领导的一个研究反射(reflection)和元对象协议(metaobject protocol)的小组,小组的研究领域曾被认为是在面向对象程序中提供灵活性至关重要的技术。然而,在多年以后,他们才认识到横切(crosscutting)正在他们寻找的技术。

目前,基于Aspect研究技术,诞生了很多基于AspectFramework。具体请参见:AOSDAspect Oriented Software Developmenthttp://www.aosd.net/

下表为当前三种成熟Aspect Framework比较:

Framework Language Pointcuts Weaving method Dynamic/Fluid
Nanning Java (or XML) Method calls,

instantiation

Dynamic proxies Yes
AspectJ Language extension to Java Anything Source code No
Aspectwerkz Java and XML Method calls,

instantiation,

field access,

more

Byte code Yes

当前,基于AOP的容器不多, 构建在PicoContainer之上的NanoContainer则使用了Nanning的Aspect Framework。

Portal实现原理

1.Portal用例
读者可以在下面三个网站上注册自己的用户,体会Portal的功能。
http://my.msn.com
http://my.yahoo.com
http://my.liferay.com

My MSN的功能最灵活强大,用户可以任意拖放操作栏目(column)和内容版块(content)的位置和个数。
My Liferay只能选择固定的栏目(column)布局,但可以在本栏目(column)内移动内容版块(content)的位置。
My Yahoo只能选择固定的栏目(column)布局,而且不能移动内容版块(content)的位置。

Portal的结构分为三层。
(1) Page
(2) Column,或者称为Pane
(3) Content,或者称为Portlet

我们来看看Portal的整个操作流程。
(1) 每个Column的下方都有一个[Add Content]按钮,让用户选择加入自己喜欢的内容。
从这里,我们知道,Portal系统里面有一个公用的Common Portlet Repository,供用户选用。

JSR168 Portlet规范里面定义了Portlet Deployment Discriptor。Common Portlet Repository以这个Portlet Deployment Discriptor的格式存放。

开源项目JetSpeed的XReg文件用来存放Common Portlet Repository的定义。

(2) 加入Content之后,用户的Page和Column里面就多了这个Content。下次用户登陆的时候,就会看到自己订制的Portal版面。
从这里,可以看出,Portal系统会纪录用户的个人Portal配置信息 � User Portal Config。

开源项目JetSpeed的PSML文件用来存放User Portal Config的定义。

——- 综上。
Add Content的整个流程为:
Common Portlet Repository –> Add Content –> Personal Portal Config

Display Portal的整个流程为:
从Personal Portal Config读取用户配置的Portlet ID –> 根据Portlet ID,从Common Portlet Repository查找详细的Portlet定义 –> 根据这个详细的Portlet定义显示这个Portlet。

2.Portal实现
我们考虑如何用Java来实现Portal。

2.1 Dynamic Include
首先,我们采用最简单的思路,我们用100个JSP文件(1.jsp, 2.jsp, 3.jsp, … 100.jsp等),代表100个Portlet。
用户页面MyPage.jsp包含用户选定的多个Portlet。
现在,假设用户选取的Portlet为1.jsp, 3.jsp, 7.jsp等3个Portlet,那么我们如何在MyPage.jsp中显示这些Portlet?最直观的做法是,用jsp:include。比如:

<table>
<tr><td>
<jsp:include page=”1.jsp” />
</td></tr>
<tr><td>
<jsp:include page=”3.jsp” />
</td></tr>
<tr><td>
<jsp:include page=”7.jsp” />
</td></tr>
</table>

由于<jsp:include>只能指定固定的jsp文件名,不能动态指定jsp文件名。我们需要把<jsp:include>翻译为Java code � RequestDispatcher.include();
下面我们换成这种写法。

java代码:
<table>
<tr><td>
<% request.getRequestDispatcher(”1.jsp”).include(request, response); />
</td></tr>
<tr><td>
<% request.getRequestDispatcher(”3.jsp”).include(request, response); />
</td></tr>
<tr><td>
<% request.getRequestDispatcher(”7.jsp”).include(request, response); />
</td></tr>
</table>

进一步改进MyPage.jsp。

java代码:
<% String[] fileNames = {“1.jsp”, “3.jsp”, “7.jsp”}; %>
<table>
<% for(int i = 0; i < fileNames.length; i++) {
String fileName = fileName s[i]; %>
<tr><td>
<% request.getRequestDispatcher(fileName).include(request, response); />
</td></tr>
<% } // end for %>
</table>

其中的fileNames的内容可以各种各样,只要RequestDispatcher能够处理。
比如Velocity,fileNames = {“1.vm”, “3.vm”, “7.vm”};
比如URL,fileNames = {“/portlet1.do”, “/portlet3.do”, “/portlet4.do”};
我们可以看到,如果我们从用户配置中读取fileNames的内容,这就是一个简单的Portal实现。

java代码:
<% String[] fileNames = (String[])session.getAttribute(“portlets.config”); %>
<table>
<% for(int i = 0; i < fileNames.length; i++) {
String fileName = fileNames[i]; %>
<tr><td>
<% request.getRequestDispatcher(fileName).include(request, response); />
</td></tr>
<% } // end for %>
</table>

2.2 Portlet Interface
下面我们来扩展这个例子。
假设每个Portlet都规定实现一个Portlet接口。

java代码:
interface Portlet {
void render(request, response);
};

MyPage.jsp如下:

<% String[] portletClassNames = (String[])session.getAttribute(“portlets.config”); %>
<table>
<% for(int i = 0; i < portletClassNames.length; i++) {
String className = portletClassNames[i];
Portlet portlet = (Portlet)Class.forName(className).newInstance(); %>
<tr><td>
<% portlet. render (request, response); />
</td></tr>
<% } // end for %>
</table>

Portlet类的示例代码如下:

public class Portlet7{
public void render(request, response){
request.getRequestDispatcher(“7.jsp”).include(request, response);
}
};

上述代码是Portal显示Portlet的核心流程的一个简化版本。
JSR168 Portlet规范里面定义了真正的Portlet接口定义。

2.3 Portlet Action
Portlet的操作包括,最大化/最小化/恢复/关闭/编辑/帮助/上下移动,等等。
这些操作都有对应的Action类。
开源项目JetSpeed的module/actions/controls目录下面包含Maximize, Minimize, Close等Action类。
开源项目Liferay的portal/action目录下面包含Maximize, Minimize, Close等Action类。

Portal的操作不仅包括上述Portlet的操作,而且包括其它更高级别的操作。
比如,Add/Move Page, Add/Move Column, 换Layout, 换Skin,之类。

2.4 Portlet Cache
我们操作Portlet的时候,往往只操作某个特定的Portlet,或者只是变化Portlet的位置。这时候,页面中大多数的Porlet的内容是不变的,只有一小块Portlet变化。
我们需要把Portlet的内容缓存起来。Portlet接口有一个render(request, response)方法,我们可以订制定制response类,截获portlet的输出,保存到Portal系统的内容Cache当中。
比如,前面提到liferay开源项目,其StringServletResponse类把Portlet的输出保存到一个String当中。

相关摘要
  • (一蓑烟雨任平生)Portal Server的机制与一般的Web Framework是独立的,Portal Server有自己的容器或者引擎来对Portlet进行处理,每个Portlet类似于Servlet。Portlet现在有两种标准,一种是以Jetspeed为主的老版本,IBM的Websphere Portal Server原先的核心API也采用Jetspeed的API,另一种是目前JCP组织制订的JSR 168标准,BEA和IBM都在自己的产品里实现了该标准,但还没有成熟。IBM的WSAD开发工具里对Portal有两种项目类型,分别支持这两种标准。

    可以将Portal做为表现层的一种类型集成到你的Web Framework中。

  • (一蓑烟雨任平生)Jetspeed是一个门户的应用管理系统,应用程序是构建在Turbine这个Web Framework上面的,可以认为Jetspeed是个用Turbine Framework开发的一个应用程序。
  • (whitehorse)portal 包括 portal server 和 portlet container ;JSR-168定义了portlet 通用api ,portlet container 的提供商需要遵循这个API,这样开发出的portlet 可以在任何一个实现jsr-168规范的portlet container下顺利移植。
    portal server 是各个开发商自行提供的,用来接受用户用求转发给相应的portlet,调整portal page 布局,单点登录等等;
    portlet container就是在servlet container上又包装了一层,portlet 类似于servlet;
    portal server 的实现一般采用 web framework 技术来构建; 比如liferay采用了struts + tiles;exo poral 采用了 jsf 等等。portlet开发在遵循规范的基础上可以采用web framework .
  • (kingkii)free portal server: Jetspeed, liferay, Jportal, etc
  • (flyisland)
  • baichenhong 写道:
    我觉的Portal的作用就是整合,故名意思 门户 嘛就是把所有的集成起来放到一起,你有oa,erp,crm 但是你觉得分开使用很不方便,那么好我可以把他们整合到一起,只要你登陆一次就可以使用所有的系统,这应该是一个很有用的东西

    你短短一句话包含的东西可是超级多。

    所谓集成分为很多层次的,Portal关注的是用户集成,包括访问界面、访问手段等。访问界面的集成并不要求应用程序一定要部署在一起。

    至于“只要你登陆一次就可以使用所有的系统”,一般称之为单点登陆“Single Sign-on”。Portal服务器基本都提供了认证框架,在此框架下开发的新应用实现SSO是很简单的;但如果对异构的系统进行SSO,这又是一个复杂而庞大的话题了。

  • (tommy_kin)拖放布局不是Portal的核心技术,只是一个personalize的功能而已,Portal功能在于应用的集成。所谓一站式访问。
参考资料:

[转]JSP运行内幕

三月 4, 2005

JSP的运行内幕
作者:◇ 赵科 本文选自:开放系统世界 2003年07月09日

经常有朋友问起,JSP和Servlet之间有什么区别,两者之间又有什么联系?其实Servlet技术的出现时间很早,是当时为了Java的服务器端应用而开发的。大家都知道Applet是应用小程序,Servlet就是服务器端小程序了。但在Microsoft公司的ASP技术出现后,使用Servlet进行响应输出时一行行的输出语句就显得非常笨拙,对于复杂布局或者显示页面更是如此。JSP就是为了满足这种需求在Servlet技术之上开发的。可见,JSP和Servlet之间有着内在的血缘关系,在学习JSP时,如果能够抓住这种联系,就能更深刻地理解JSP的运行机理,达到事半功倍的效果。

本文将通过对一个JSP运行过程的剖析,深入JSP运行的内幕,并从全新的视角阐述一些JSP中的技术要点。

HelloWorld.jsp

我们以Tomcat 4.1.17服务器为例,来看看最简单的HelloWorld.jsp是怎么运行的。

代码清单1:HelloWorld.jsp

HelloWorld.jsp
<%
String message = "Hello World!";
%>
<%=message%>

这个文件非常简单,仅仅定义了一个String的变量,并且输出。把这个文件放到Tomcat的webapps\ROOT\目录下,启动Tomcat,在浏览器中访问http://localhost:8080/HelloWorld.jsp,浏览器中的输出为“HelloWorld!”

让我们来看看Tomcat都做了什么。转到Tomcat的\work\Standalone\localhost\_目录下,可以找到如下的HelloWorld_jsp.java,这个文件就是Tomcat解析HelloWorld.jsp时生成的源文件:

代码清单2:HelloWorld_jsp.java

package org.apache.jsp;

import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.jsp.*;
import org.apache.jasper.runtime.*;

public class HelloWorld_jsp extends HttpJspBase {
......
public void _jspService(HttpServletRequest request,
HttpServletResponse response)throws java.io.IOException, ServletException
{
JspFactory _jspxFactory = null;
javax.servlet.jsp.PageContext pageContext = null;
HttpSession session = null;
ServletContext application = null;
ServletConfig config = null;
JspWriter out = null;
Object page = this;
JspWriter _jspx_out = null;

try {
_jspxFactory = JspFactory.getDefaultFactory();
response.setContentType("text/html;charset=ISO-8859-1");
pageContext = _jspxFactory.getPageContext(this, request, response,null, true, 8192, true);
application = pageContext.getServletContext();
config = pageContext.getServletConfig();
session = pageContext.getSession();
out = pageContext.getOut();
_jspx_out = out;

String message = "Hello World!";
out.print(message);
} catch (Throwable t) {
out = _jspx_out;
if (out != null && out.getBufferSize() != 0)
out.clearBuffer();
if (pageContext != null) pageContext.handlePageException(t);
} finally {
if (_jspxFactory != null) _jspxFactory.releasePageContext(pageContext);
}
}
}

从上面可以看出,HelloWorld.jsp在运行时首先解析成一个Java类HelloWorld_jsp.java,该类继承于org.apache.jasper.runtime.HttpJspBase基类,HttpJspBase实现了HttpServlet接口。可见,JSP在运行前首先将编译为一个Servlet,这就是理解JSP技术的关键。

我们还知道JSP页面中内置了几个对象,如pageContext、application、config、page、session、out等,你可能会奇怪,为什么在JSP中的代码片断中可以直接使用这些内置对象。观察_jspService()方法,实际上这几个内置对象就是在这里定义的。在对JSP文件中的代码片断进行解析之前,先对这几个内置对象进行初始化。

首先,调用JspFactory的getDefaultFactory()方法获取容器实现(本文中指Tomcat 4.1.17)的一个JspFactory对象的引用。JspFactory是javax.servlet.jsp包中定义的一个抽象类,其中定义了两个静态方法set/getDefaultFactory()。set方法由JSP容器(Tomcat)实例化该页面Servlet(即HelloWorld_jsp类)的时候置入,所以可以直接调用JspFactory.getDefaultFactory()方法得到这个JSP工厂的实现类。Tomcat是调用org.apache.jasper.runtime.JspFactoryImpl类。

然后,调用这个JspFactoryImpl的getPageContext()方法,填充一个PageContext返回,并赋给内置变量pageConext。其它内置对象都经由该pageContext得到。具体过程见上面的代码,这里不再赘述。该页面Servlet的环境设置完毕,开始对页面进行解析。HelloWorld.jsp页面仅仅定义了一个String变量,然后直接输出。解析后的代码如下:

代码清单3:JSP页面解析后的代码片断

String message = "Hello World!";
out.print(message);

定制标签的解析过程

在一个中大型的Web应用中,通常使用JSP定制标签来封装页面显示逻辑。剖析容器对定制标签的解析过程,对我们深入理解定制标签的运行机理非常有帮助。下面我们以Struts1.1b中附带的struts-example应用的主页运行为例加以说明。

包含定制标签的index.jsp

Struts1.1b的下载地址是http://jakarta.apache.org/struts/index.html。将下载的包解压,在webapps目录下可以找到struts-example.war。将该War包拷贝到Tomcat的webapps目录下,Tomcat会自动安装此应用包。在浏览器中通过http://localhost:8080/struts-example访问struts-example应用,将显示应用的首页(见图1)。

图一 应用的首页

代码清单4:index.jsp

<%@ page contentType="text/html;charset=UTF-8" 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" %>
<html:html locale="true">
<head>
<title><bean:message key="index.title"/></title>
<html:base/>
</head>
<body bgcolor="white">
……
</body>
</html:html>

我们仅以index.jsp中的<bean:message/>标签的解析为例进行分析,看容器是怎样把这个自定义标签解析成HTML输出的。上面代码省略了页面的其它显示部分。首先,查看上面浏览器中页面的源文件:

<html lang="zh">
<head>
<title>MailReader Demonstration Application (Struts 1.0)</title>
</head>
<body bgcolor="white">
……
</body>
</html>

可见,容器已经把<bean:message key=”index.title”/>替换成一个字串,显示为页面的标题。

解析过程

那么,JSP容器是怎样完成解析的呢?查看在工作目录jakarta-tomcat-4.1.17\work\Standalone\localhost\struts-example下解析后的index_jsp.java文件:

代码清单5:index_jsp.java

package org.apache.jsp;

import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.jsp.*;
import org.apache.jasper.runtime.*;
public class index_jsp extends HttpJspBase {
//为所有的定制标签定义处理器池类的引用
private org.apache.jasper.runtime.TagHandlerPool ;
_jspx_tagPool_bean_message_key;
……
//页面类构造方法
public index_jsp() {
_jspx_tagPool_bean_message_key =
new org.apache.jasper.runtime.TagHandlerPool();
……
}

public void _jspService(HttpServletRequest request,
HttpServletResponse response)
throws java.io.IOException, ServletException {
……
_jspxFactory = JspFactory.getDefaultFactory();
response.setContentType("text/html;charset=UTF-8");
pageContext = _jspxFactory.getPageContext(this,
request, response,null, true, 8192, true);
application = pageContext.getServletContext();
config = pageContext.getServletConfig();
session = pageContext.getSession();
out = pageContext.getOut();
_jspx_out = out;
……
if (_jspx_meth_html_html_0(pageContext))
return;
……
}
//页面在处理退出时释放所有定制标签的属性
public void _jspDestroy() {
_jspx_tagPool_bean_message_key.release();
……
}
}

生成的index_jsp.java继承于org.apache. jasper.runtime.HttpJspBase。研究这个文件为我们了解定制标签的运行机理提供了途径。

从上面可以看出,Tomcat在解析一个JSP页面时,首先为每一个定制标签定义并实例化了一个TagHandlerPool对象。页面的处理方法覆盖父类的_ jspService()方法,_jspService方法首先初始化环境,为内置对象赋值。由于index.jsp页面整体由一个<html:html/>标签包裹,Tomcat对每一个标签都产生一个私有方法加以实现。<html:html/>标签的处理方法是_jspx_meth_html_html_0()。这个方法的命名规范大家也可以从这里看出,就是“_jspx_meth + 标签的前缀 + 标签名 + 该标签在JSP页面同类标签中出现的序号”。其它标签都被包含在该标签中,所以其它标签在_jspx_meth_html_html_0()方法中进行解析。具体的代码实现请参见赛迪网http://linux.ccidnet.com期刊浏览2003年第6期。

在_jspx_meth_html_html_0()方法中,首先从_jspx_tagPool_html_html_locale池中得到一个org.apache.struts.taglib.html.HtmlTag的实例,然后设置这个tag实例的页面上下文及上级标签,由于html:html标签是页面的最顶层标签,所以它的parent是null。然后对该标签的内容进行解析。HTML代码直接输出,下面主要看看<html:html></html:html>标签之间包含的<bean:message key=”index.title”/>标签的解析。对bean:message标签的解析类似于html:html,Tomcat也将其放入一个单独的方法_jspx_meth_bean_message_0()中进行。

bean:message标签的解析

代码清单7:_jspx_meth_bean_message_0()方法片断

//对message定制标签的处理方法
private boolean _jspx_meth_bean_message_0(
javax.servlet.jsp.tagext.Tag _jspx_th_html_html_0,
javax.servlet.jsp.PageContext pageContext) throws Throwable {
JspWriter out = pageContext.getOut();
/* ----  bean:message ---- */
org.apache.struts.taglib.bean.MessageTag
_jspx_th_bean_message_0 =
(org.apache.struts.taglib.bean.MessageTag)
_jspx_tagPool_bean_message_key.get(
org.apache.struts.taglib.bean.MessageTag.class);
_jspx_th_bean_message_0.setPageContext(pageContext);
_jspx_th_bean_message_0.setParent(_jspx_th_html_html_0);
_jspx_th_bean_message_0.setKey("index.title");
int _jspx_eval_bean_message_0 = _jspx_th_bean_message_0.doStartTag();
if (_jspx_th_bean_message_0.doEndTag()== javax.servlet.jsp.tagext.Tag.SKIP_PAGE)
return true;
_jspx_tagPool_bean_message_key.reuse(_jspx_th_bean_message_0);
return false;
}

同样,对html:bean也需要从池中得到一个标签类的实例,然后设置环境。这里不再赘述。我们只专注对MessageTag定制标签类特殊的处理部分。定制标签类的开发不在本文讨论范围之内。在index.jsp中定义了一个bean:message标签,并设置了一个属性:<bean:message key=”index.title”/>。Tomcat在解析时,调用MessageTag对象的key属性设置方法setKey(),将该属性置入。然后调用MessageTag的doStartTag()和doEndTag()方法,完成解析。如果doEndTag()方法的返回值为javax.servlet.jsp.tagext.Tag. SKIP_PAGE,表明已经完成解析,返回true,Tomcat将立即停止剩余页面代码的执行,并返回。否则把该MessageTag的实例放回池中。

标签类对象实例的池化

为了提高运行效率,Tomcat对所有的定制标签类进行了池化,池化工作由org.apache.jasper. runtime.TagHandlerPool类完成。TagHandlerPool类主要有两个方法,代码如下:

代码清单8:TagHandlerPool.java

public class TagHandlerPool {
private static final int MAX_POOL_SIZE = 5;
private Tag[] handlers;
public synchronized Tag get(Class handlerClass) throws JspException {……}
public synchronized void reuse(Tag handler) {……}
}

TagHandlerPool简单地实现了对标签类的池化,其中MAX_POOL_SIZE是池的初始大小,handlers是一个Tag的数组,存储标签类的实例。get(Class handlerClass)得到一个指定标签类的实例,如果池中没有可用实例,则新实例化一个。reuse(Tag handler)把handler对象放回池中。

至此,我们对JSP在容器中的运行过程已经了然于胸了。虽然每种JSP容器的解析结果会有差异,但其中的原理都雷同。对于编写JSP应用,我们并不需要干涉容器中的运行过程,但如果你对整个底层的运行机制比较熟悉,就能对JSP/Servlet技术有更深的认识。

Spring中的异常

三月 2, 2005
public class BeanDefinitionStoreException
extends FatalBeanException

Exception thrown when a BeanFactory encounters an internal error, and its definitions are invalid: for example, if an XML document containing bean definitions isn’t well-formed.

程序中抛出了这个异常,检查了半天也没发现原因,后来仔细看了一下print stack信息,发现原来我同时在最外层的类和其中引用的其他类中使用了spring,出错发生在引用类中,所以是引用类的spring bean的xml文件出错了,出错的原因用XML SPY配合spring-bean.dtd一检查,原来是把java的注释符号//当成xml中的注释符号<!– –>来用了~

在Struts中reset方法有什么作用(转)

创建人:王艺
创建时间:2003年6月15日星期日

第一步:
对象的可视范围:request、session、application、page。
Request:在一个请求周期内有效。就是从你点击页面上的一个按钮开始到服务器返回响应页面为止(包括响应页面)。
Session:在一个用户与服务器建立连接的整个过程中有效。
Application:在整个web应用程序内有效。
Page:仅在一个jsp页面内有效。

第二步:
ActionForm在你确定的有效期(可视范围)内是唯一的。

第三步:
在每次为ActionForm赋值前调用它的reset方法。作用是使ActionForm中的值恢复初始状态。在应用中我们可以通过在reset中为变量赋初值的方式,使得页面上的某个对象有显示值。

第四步:
可视范围与赋值前的初始化结合。
由于第二步所述特性,如果可视范围是request,则reset方法并不是很重要,因为你每次调用时都会产生一个新的ActionForm实例,所以你所操作的ActionForm不会与别人分享同时也就不会受别人的影响;如果可视范围是session,由于在session范围内此ActionForm是唯一的,所以你在session范围内需要用到此ActionForm的地方调用的都是同一个ActionForm,要是你没有在reset中对变量赋初值那么前一次调用ActionForm是为它赋的值将在此次调用时有效,这到也没什么。但是,如果恰巧再次调用时你仅仅需要为ActionForm中的一部分变量赋值,那么其余的变量将保持上一次得到的值,这样你就得到了一个“新旧混合体”,我想这多半不是你所期望的;如果可视范围是application,那其影响就更是不难理解了,这时不但是你自己会影响你自己,使用应用的其他用户的操作也会影响到你。

第五步:
知道了reset方法的作用和ActionForm在scope内唯一的特性后就为我们灵活处理ActionForm的行为提供了基础。比如说你现在需要跨过多个页面收集数据信息,这时你就可以把scope设置为session,并且不实现reset方法��这样在每个页面put数据时都不会将之前收集的数据清空,最后在你收集完数据后在Action中调用ActionForm中你自定义的初始化方法,如:resetField。
在具体的我也想不出了,还是要大家在应用时多多体会这些特性,这样才能把架构的威力发挥到最大。

在网上查文章的时候不断的看到IBM的developerWorks 中国网站上面的文章,很多都写的很好。下面这位的文章我已经n次找到了,可以去devoloperWorks上面搜索一下“Uche Ogbuji”,可以找到他写的很多文章,都是XML方面相关的,很不错。

关于作者
Uche Ogbuji 的照片Uche Ogbuji 是 Fourthought Inc. 的顾问兼共同创始人,该公司是专为企业知识管理提供 XML 解决方案的软件供应商和咨询公司。Fourthought 开发了 4Suite,这是一个用于 XML、RDF 和知识管理应用程序的开放源码平台。Ogbuji 先生是一名出生于尼日利亚的计算机工程师兼作家,他生活和工作在美国科罗拉多州博耳德。可以通过 uche.ogbuji@fourthought.com 与 Ogbuji 先生联系。

[转]使用Java与XSLT的10条技巧
2005-2-12 1:07:38

使用Java与XSLT的10条技巧

作者:Eric M. Burke
翻译:家居猫

1、 尽可能使用缓存。

2、部署前做测试。

3、尽量让XSLT样式表简单。

4、和XSLT一起使用CSS。

5、小心处理不间断空格。

6、写XML生成器类。

7、假设Cookie是被禁止的。

8、把XSLT作为一个代码生成器使用。

9、对于i18n用<xsl:import>

10、设立StreamSource来解析相关的URI。

Web Application Form Design
by Luke Wroblewski

“Input elements should be organized in logical groups so that your brain can process the form layout in chunks of related fields.” �HTML: the Definitive Guide

Quite rare is the Web application that doesn’t make extensive use of forms for data input and configuration. But not all Web applications use forms consistently. Variations in the alignment of input fields, their respective labels, calls to action, and their surrounding visual elements can support or impair different aspects of user behavior.

Form Layouts
When the time to complete a form needs to be minimized and the data being collected is mostly familiar to users (for instance, entering a name, address, and payment information in a check-out flow), a vertical alignment of labels and input fields is likely to work best. Each label and input field is grouped by vertical proximity and the consistent alignment of both input fields and labels reduces eye movement and processing time. Users only need to move in one direction: down.

vertical labels

In this layout, it’s advisable to use bold fonts for input field labels. This increases their visual weight and brings them to the foreground of the layout. When they are not bold, labels may compete with input fields for a user’s attention as they have almost equal visual weight.

When the data being collected by a form is unfamiliar or does not fall into easy to process groups (such as the various parts of an address), left-justifying input field labels makes scanning the information required by the form easier. Users can just scan the left column of labels up and down without being interrupted by input fields. However, the distance between the labels and input fields is often elongated by long labels, and as a result, completion times may suffer. Users have to “jump” from column to column in order to find the right association of input field and label before inputting data.

Left-Justified Horizontal Labels

An alternative layout, right aligns the input field labels so the association between input field and label is clear. However, the resulting left rag of the labels reduces the effectives of a quick scan to see what information the form requires. In the Western world, we read from left to right, so our eyes prefer a hard edge along the left side.

Right-Justified Horizontal Labels

Using Visual Elements
Due to the advantages of a “left-justified horizontal label” layout (easy scanning of input labels and reduced vertical screen space), it may be tempting to attempt to rectify its primary shortcoming: the separation of input fields and their respective labels.

One such approach features the addition of background colors and rules: the different background colors create a vertical unit of labels and a vertical unit of inputs; the horizontal rules form a relationship between each label and input field pair. Though this approach may seem desirable, it actually creates a few problems.

Through gestalt (our innate rules of visual perception), an additional 15 visual elements are added to the layout: the centerline, each background box, and each horizontal line. These elements begin to distract our eye and make it more difficult to focus on the most important elements in the layout: the labels and input fields. As Edward Tufte points out: “Information consists of differences that make a difference.” In other words, any visual element that is not helping your layout ends up hurting it. This can be seen when you try to scan the left column of labels. Your eye repeatedly pauses to consider each horizontal line and the box created by each combination of line and background color.

Backgrounds & Rules

Of course this doesn’t mean that background colors and rules should never be used within form layouts. When there is value in pointing out related groupings of information to users, a thin horizontal rule or light background color can visually unite related data. Both of these elements (rules and background colors) can be especially useful for drawing attention to the primary call to action of a form.

Seperating Related Content

Primary & Secondary Actions
The primary action associated with a form (most commonly “submit” or “save”) needs to carry a stronger visual weight (in the example above bright color, bold font, background color, etc.) than the other form elements and should vertically align with the input fields. This illuminates a path for users and guides them to competition of the form.

When a form has multiple actions such as “Continue” and “Go Back” it may be wise to reduce the visual weight of the secondary action. This minimizes the risk for potential errors and further directs users to completion.

Primary & Secondary Actions

Though these guidelines can help better position a form for your specific purpose, the combination of layout, visual elements, and content that’s right for you should still be verified through user testing or data analysis (completion rates, errors, etc.).

Contact Info
More Articles & Papers

Male jeen
Sesame developer

If you store the files in seperate repositories, you will not be able to do queries that return information from both files (since a query is always evaluated against a single repository). On the other hand, if you keep them seperate it is easier to modify one file without disturbing the other.

So it depends on what you want to do. In most cases where querying is involved, putting files in a single repository is the most logical choice though.

« 上一页下一页 »