愚人码头

知耻而后勇,知不足而进
随笔 - 33, 文章 - 1, 评论 - 26, 引用 - 0
数据加载中……

2005年11月23日

对hibernate的新认识

     摘要:   阅读全文

posted @ 2008-01-30 11:14 船夫 阅读(1941) | 评论 (7)编辑 收藏

转:Javascript事件处理

     摘要:   阅读全文

posted @ 2007-12-26 13:00 船夫 阅读(337) | 评论 (0)编辑 收藏

转:提升JSP应用程序的七大绝招

提升JSP应用程序的七大绝招
你时常被客户抱怨JSP页面响应速度很慢吗?你想过当客户访问次数剧增时,你的WEB应用能承受日益增加的访 问量吗?本文讲述了调整JSP和servlet的一些非常实用的方法,它可使你的servlet和JSP页面响应更快,扩展性更强。而且在用户数增加的情 况下,系统负载会呈现出平滑上长的趋势。在本文中,我将通过一些实际例子和配置方法使得你的应用程序的性能有出人意料的提升。其中,某些调优技术是在你的 编程工作中实现的。而另一些技术是与应用服务器的配置相关的。在本文中,我们将详细地描述怎样通过调整servlet和JSP页面,来提高你的应用程序的 总体性能。在阅读本文之前,假设你有基本的servlet和JSP的知识。
方法一:在servlet的init()方法中缓存数据

当应用服务器初始化servlet实例之后,为客户端请求提供服务之前,它会调用这个servlet的init()方法。在一个servlet的生命周 期中,init()方法只会被调用一次。通过在init()方法中缓存一些静态的数据或完成一些只需要执行一次的、耗时的操作,就可大大地提高系统性能。

例如,通过在init()方法中建立一个JDBC连接池是一个最佳例子,假设我们是用jdbc2.0的DataSource接口来取得数据库连接,在通 常的情况下,我们需要通过JNDI来取得具体的数据源。我们可以想象在一个具体的应用中,如果每次SQL请求都要执行一次JNDI查询的话,那系统性能将 会急剧下降。解决方法是如下代码,它通过缓存DataSource,使得下一次SQL调用时仍然可以继续利用它:

public class ControllerServlet extends HttpServlet
{
private javax.sql.DataSource testDS = null;
public void init(ServletConfig config) throws ServletException
{
super.init(config);
Context ctx = null;
try
{
ctx = new InitialContext();
testDS = (javax.sql.DataSource)ctx.lookup("jdbc/testDS");
}
catch(NamingException ne)
{
ne.printStackTrace();
}
catch(Exception e)
{
e.printStackTrace();
}
}

public javax.sql.DataSource getTestDS()
{
return testDS;
}
...
...
}

方法 2:禁止servlet和JSP 自动重载(auto-reloading)

Servlet/JSP提供了一个实用的技术,即自动重载技术,它为开发人员提供了一个好的开发环境,当你改变servlet和JSP页面后而不必重启 应用服务器。然而,这种技术在产品运行阶段对系统的资源是一个极大的损耗,因为它会给JSP引擎的类装载器(classloader)带来极大的负担。因 此关闭自动重载功能对系统性能的提升是一个极大的帮助。

方法 3: 不要滥用HttpSession

在很多应 用中,我们的程序需要保持客户端的状态,以便页面之间可以相互联系。但不幸的是由于HTTP具有天生无状态性,从而无法保存客户端的状态。因此一般的应用 服务器都提供了session来保存客户的状态。在JSP应用服务器中,是通过HttpSession对像来实现session的功能的,但在方便的同 时,它也给系统带来了不小的负担。因为每当你获得或更新session时,系统者要对它进行费时的序列化操作。你可以通过对HttpSession的以下 几种处理方式来提升系统的性能:

? 如果没有必要,就应该关闭JSP页面中对HttpSession的缺省设置: 如果你没有明确指定的话,每个JSP页面都会缺省地创建一个HttpSession。如果你的JSP中不需要使用session的话,那可以通过如下的JSP页面指示符来禁止它:

<%@ page session="false"%>

? 不要在HttpSession中存放大的数据对像:如果你在HttpSession中存放大的数据对像的话,每当对它进行读写时,应用服务器都将对其进行 序列化,从而增加了系统的额外负担。你在HttpSession中存放的数据对像越大,那系统的性能就下降得越快。

? 当你不需要HttpSession时,尽快地释放它:当你不再需要session时,你可以通过调用HttpSession.invalidate()方法来释放它。

? 尽量将session的超时时间设得短一点:在JSP应用服务器中,有一个缺省的session的超时时间。当客户在这个时间之后没有进行任何操作的话, 系统会将相关的session自动从内存中释放。超时时间设得越大,系统的性能就会越低,因此最好的方法就是尽量使得它的值保持在一个较低的水平。

方法 4: 将页面输出进行压缩

压缩是解决数据冗余的一个好的方法,特别是在网络带宽不够发达的今天。有的浏览器支持gzip(GNU zip)进行来对HTML文件进行压缩,这种方法可以戏剧性地减少HTML文件的下载时间。因此,如果你将servlet或JSP页面生成的HTML页面 进行压缩的话,那用户就会觉得页面浏览速度会非常快。但不幸的是,不是所有的浏览器都支持gzip压缩,但你可以通过在你的程序中检查客户的浏览器是否支 持它。下面就是关于这种方法实现的一个代码片段:

public void doGet(HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException
{
OutputStream out = null
String encoding = request.getHeader("Accept-Encoding");
if (encoding != null && encoding.indexOf("gzip") != -1)
{
request.setHeader("Content-Encoding" , "gzip");
out = new GZIPOutputStream(request.getOutputStream());
}
else if (encoding != null && encoding.indexOf("compress") != -1)
{
request.setHeader("Content-Encoding" , "compress");
out = new ZIPOutputStream(request.getOutputStream());
}
else
{
out = request.getOutputStream();
}
...
...
}

方法 5: 使用线程池

应用服务器缺省地为每个不同的客户端请求创建一个线程进行处理,并为它们分派service()方法,当service()方法调用完成后,与之相应的 线程也随之撤消。由于创建和撤消线程会耗费一定的系统资源,这种缺省模式降低了系统的性能。但所幸的是我们可以通过创建一个线程池来改变这种状况。另外, 我们还要为这个线程池设置一个最小线程数和一个最大线程数。在应用服务器启动时,它会创建数量等于最小线程数的一个线程池,当客户有请求时,相应地从池从 取出一个线程来进行处理,当处理完成后,再将线程重新放入到池中。如果池中的线程不够地话,系统会自动地增加池中线程的数量,但总量不能超过最大线程数。 通过使用线程池,当客户端请求急剧增加时,系统的负载就会呈现的平滑的上升曲线,从而提高的系统的可伸缩性。

方法 6: 选择正确的页面包含机制

在JSP中有两种方法可以用来包含另一个页面:1、使用include指示符(<%@ includee file=”test.jsp” %>)。2、使用jsp指示符(<jsp:includee page=”test.jsp” flush=”true”/>)。在实际中我发现,如果使用第一种方法的话,可以使得系统性能更高。

方法 7:正确地确定javabean的生命周期

JSP的一个强大的地方就是对javabean的支持。通过在JSP页面中使用<jsp:useBean>标签,可以将javabean直接插入到一个JSP页面中。它的使用方法如下:

<jsp:useBean id="name" scope="page|request|session|application" class=
"package.className" type="typeName">
</jsp:useBean>

其中scope属性指出了这个bean的生命周期。缺省的生命周期为page。如果你没有正确地选择bean的生命周期的话,它将影响系统的性能。

举例来说,如果你只想在一次请求中使用某个bean,但你却将这个bean的生命周期设置成了session,那当这次请求结束后,这个bean将仍然 保留在内存中,除非session超时或用户关闭浏览器。这样会耗费一定的内存,并无谓的增加了JVM垃圾收集器的工作量。因此为bean设置正确的生命 周期,并在bean的使命结束后尽快地清理它们,会使用系统性能有一个提高

其它一些有用的方法

? 在字符串连接操作中尽量不使用“+”操作符:在java编程中,我们常常使用“+”操作符来将几个字符串连接起来,但你或许从来没有想到过它居然会对系统 性能造成影响吧?由于字符串是常量,因此JVM会产生一些临时的对像。你使用的“+”越多,生成的临时对像就越多,这样也会给系统性能带来一些影响。解决 的方法是用StringBuffer对像来代替“+”操作符。

? 避免使用System.out.println()方法:由于System.out.println()是一种同步调用,即在调用它时,磁盘I/O操作必 须等待它的完成,因此我们要尽量避免对它的调用。但我们在调试程序时它又是一个必不可少的方便工具,为了解决这个矛盾,我建议你最好使用Log4j工具 (http://Jakarta.apache.org ),它既可以方便调试,而不会产生System.out.println()这样的方法。

? ServletOutputStream 与 PrintWriter的权衡:使用PrintWriter可能会带来一些小的开销,因为它将所有的原始输出都转换为字符流来输出,因此如果使用它来作为 页面输出的话,系统要负担一个转换过程。而使用ServletOutputStream作为页面输出的话就不存在一个问题,但它是以二进制进行输出的。因 此在实际应用中要权衡两者的利弊。

总结

本文的目的是通过对servlet和JSP的一些调优技术来极大地提高你 的应用程序的性能,并因此提升整个J2EE应用的性能。通过这些调优技术,你可以发现其实并不是某种技术平台(比如J2EE和.NET之争)决定了你的应 用程序的性能,重要是你要对这种平台有一个较为深入的了解,这样你才能从根本上对自己的应用程序做一个优化! 

Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=1448910

posted @ 2007-12-25 17:04 船夫 阅读(221) | 评论 (0)编辑 收藏

转载一篇测试笔记,用于备忘

     摘要:   阅读全文

posted @ 2007-12-25 14:43 船夫 阅读(257) | 评论 (0)编辑 收藏

JSP编译过程

很久以来,都知道JSP其实就是Servlet,今天心血来潮,想把里面的具体代码看一遍,并记录心得。
一个编译好的JSP类如下:
public
 final class index_jsp extends HttpJspBase
    
implements JspSourceDependent
//上述类为index.jsp被编译后得到的类
//HttpJspBase是extends HttpServlet的一个类
//JspSourceDependent是一个接口,只声明了一个方法、、getDependants(),返回当前page所依赖的文件的名称,文件包括以下几种
//1) files that are included by page directives 
//2) files that are included by include-prelude and include-coda in jsp:config 
//3) files that are tag files and referenced 
//4) TLDs referenced
其核心方法为:
  public void _jspService(HttpServletRequest request, HttpServletResponse response)
        
throws IOException, ServletException{
.
}
该方法重载HttpJspBase中的_jspService方法,进行页面解析,包括对scriptlet的加载,html的生成,自定义Tag的解析等等
HttpJspBase的service再对_jspService再进行调用,最终生成HTML页面

posted @ 2007-12-18 12:06 船夫 阅读(1892) | 评论 (1)编辑 收藏

Annotation初步了解

今天在看Tapestry代码的时候,突然想了解一下annotation到底是干什么的,有什么好处?花了3个小时的时间,从JDK API开始,大致了解了一下。

annotation实际上就是给一些特定的类和其属性,方法等加上一些注释(annotation),这些注释是以属性name,value进行设置的,这些属性在Annotation Class中以方法的形式存在,如下:
@Documented                //是否需要产生javadoc
@Target(java.lang.annotation.ElementType.METHOD)   //应用目标,这里是应用到field属性上面
@Retention(RetentionPolicy.RUNTIME)   //该策略指明该注释会被加载到jvm中,即在运行时,我们可以得到该注释的内容,另外两个策略,SOURCE, CLASS都不会加载到jvm中
public @interface TestAnnoation {
    String value();   //属性value
    String time();     //属性time
}
以上为自定义的annotation,是应用在成员变量上的,使用该annotation情况如下
public class Test {
    @TestAnnoation(time
="12:30",value="20")
    
public String test(){
          System.out.println("test!");
          return null;
    };
}

可以使用java的反射来进行获取,通过:
Class cls = Class.forName("Test");
cls.isAnnotationPresent(AnnotationClass.
class);//判断是否存在annotation
TestAnnotation ta = (TestAnnotation)cls.getAnnotation(AnnotationClass.class);//获得AnnotationClass实例,后调用这个实例可以获得在AnnotationClass中定义的一些属性
System.out.println(ta.time()); //输出注释time内容
System.out.println(ta.value()); //输出注释value内容

我个人认为annotation的好处是将一些配置直接写在代码上,很直观;以前在使用hibernate的时候,PO对象和对应的mapping xml是分开的,不够直观,若是使用annotation就会很直观的看出这个对象的映射属性以及它的一些特殊属性(如lazy=true)之类的,在JPA中就把这种配置方式换成了annotation。

在JE上有很多关于使用annotation和xml的争论,我认为在小规模使用上可以使用annotation,就像JPA这种,每个PO上面都需要进行配置,即使使用XML也不能简化;而在大规模使用,如spring所维护的一些service的事务配置上避免使用annotation,因为每个service类中都需要配置,而使用AOP根据XML配置可以一下就搞定。

关于ElementType的其他属性:
TYPE(类型), FIELD(属性), METHOD(方法), PARAMETER(参数), CONSTRUCTOR(构造函数),LOCAL_VARIABLE(局部变量), ANNOTATION_TYPE,PACKAGE(包),其中的TYPE(类型)是指可以用在Class,Interface,Enum和 Annotation类型上.

posted @ 2007-12-17 16:33 船夫 阅读(309) | 评论 (1)编辑 收藏

禁食了,肾结石患者还能吃什么?

当肾结石、膀胱结石发生以后,患者在剧烈的疼痛中常向医生讨教:肾脏、尿道里那来的石头呢?手术之后要怎样才能预防它复发呢?
结石的形成,主要原因就是饮食。它是由饮食中可形成结石的有关成分摄入过多引起的。再细一点解释是:
草酸积存过多。体内草酸的大量积存,是导致肾尿结石的 因素之一。如菠菜、豆类、葡萄、可可、茶叶、桔子、番茄、土豆、李子、竹笋等这些人们普遍爱吃的东西,正是含草酸较高的食物。医生通过研究发现:200克 菠菜中,含草酸725.6毫克,如果一人一次将200克菠菜全部吃掉,食后8小时,检查尿中草酸排泄量为20-25毫克,相当于正常人24小时排出的草酸 平均总量。
嘌呤代谢失常。动物内脏、海产食品、花生、豆角、菠菜等,均含有较多的嘌呤成分。嘌呤进入体内后,要进行新陈代谢,它代谢的最终产物是尿酸。尿酸可促使尿中草酸盐沉淀。如果,一次过多地食用了含嘌呤丰富的食物,嘌呤的代谢又失常,草酸盐便在尿中沉积而形成尿结石
脂肪摄取太多。各种动物的肉类,尤其是肥猪肉,都是脂肪多的食品。多吃了体内脂肪必然增高,脂肪会减少肠道中可结合的钙,因而引起对草酸盐的吸收增多,如果一旦出现排泄功能故障,如出汗多、喝水少,尿量少,肾结石很可能就在这种情况下形成。所以,医生们常讲,为了预防得结石病,热天要多喝点水,吃了油水多的食物时,也要多喝点水,以促进排尿畅通,稀释尿液成分,就减少了得结石的危险。
糖分增高。糖是人体的重要养分,要经常适量增补,但一下子增加太多,尤其是乳糖,也会使结石形成创造条件。专家们发现:不论正常人或结石病人,在食用100克蔗糖后,过2小时去检查他们的尿,发现尿中的钙和草酸浓度均上升,若是服用乳糖,它更能促进钙的吸收,更可能导致草酸钙在体内的积存而形成尿结石
蛋白质过量。对肾结石成分进行化验分析,发现结石中的草酸钙占87.5%。这么大比重的草酸钙的来源就是因为蛋白质里除含有草酸的原料——甘氨酸、羟脯氨酸之外,蛋白质还能促进肠道功能对钙的吸收。如果经常过量食用高蛋白质的食物,便使肾脏和尿中的钙、草酸、尿酸的成分普遍增高。如果不能及时有效地通过肾脏功能把多余的钙、草酸、尿酸排出体外,这样,得肾脏结石、输尿管结石症的条件就形成了。当今世界经济发达国家肾结石发病率增高的主要原因就是如此。
从以上几种易形成肾结石的因素来看,要预防肾结石病 的发生,就必须改变只顾单求一种营养和追求营养过甚的观念。这就是说,在人类的日常饮食中,不能因为某种食物好吃、营养价值高,就一味地只顾去吃这种食 物。必须注意食物的搭配,各种食物都适量进食,即使是检查出身体缺乏某种营养素需要某种食物来补充时,也不宜一次大量进食,因为人体的消化、吸收功能是有限的。消化、吸收不了的养分就要通过排泄器官排泄出去,这样也会增加泌尿系统的负担,即便不患肾结石病,也对健康不利。特别是当检查出确认是肾结石症时,在患病期间,要限制病人吃那些易促使结石形成的食物。
结石是尿石症的一种,多在炎热的夏天形成,因为夏天大量出汗,甚至体内脱水,使排尿减少,再加之夏季暴露于阳光下时间长,紫外线照射皮肤有助于体内维生素D和维生素A合成增多,维生素D和维生素A可促进小肠吸收钙离子,尿液中排泄钙增多,尿内结石物质易产生结晶核,从而形成结石。冬季天气寒冷,人的尿量增多,已形成的小结石被尿液冲刷,向下移动,此时引起肾绞痛症状。所以,肾结石常为“夏季形成冬季发病”。

人们的饮食品种是多样的,人体新陈代谢是复杂的,所以肾结石的成分也是多样的。常见结石按成分可分为五种:一草酸钙结石:最为常见,占肾结石的80以上,在酸性或中性尿中形成,发病多为青壮年,以男性多见。二磷酸钙结石:占结石的6-9,在碱性尿中形成,也以男性青壮年多发。三尿酸结石:占结石的6,在酸性尿中形成,当尿PH值大于6.7时结石溶解,以男性多见。四磷酸镁胺结石:占结石的10,在碱性尿中形成,尿PH值小于7.2时结石溶解,以女性多见。五胱氨酸结石:少见,约占结石的1-2,在酸性尿中形成,尿PH值大于7.0时结石溶解。

大量饮水对所有成分尿石都有防治作用。在炎热的夏天,每日尿量少于1200毫升时,尿石生长的危险性显著增大。如能使每日饮水量在2000-4000毫升,这样可维持每日尿量在2000毫升以上。磁化水对防治草酸钙结石更有效,可将全日饮水量分别于晨起、餐间、睡前给予。清晨饮水量可达500-1000毫升。为了保持夜间尿量,睡前饮水500毫升,睡眠中起床排尿后再饮水300-500毫升,余下水分别于餐间饮服。大量饮水可促使小的结石排出,稀释尿液可防止尿石结晶形成,并能延缓结石增长速度。

1985年国外学者Vehlensieck认为,多饮水和饮食疗法可使2/3复发结石病人不再生新结石。下面介绍几种肾结石的饮食疗法。

⑴草酸钙结石:宜低钙及低草酸饮食。少食牛奶及乳制品、豆制品、肉类、动物内脏(如肝、心脏、肾、肠等),还有巧克力、浓茶、芝麻酱、蛋黄、香菇、菠菜、虾皮、萝卜、可可、芹菜、土豆等。近年来发现食物中纤维素可减少尿钙的形成,如麦麸食品中的麦麸面包、米糠也有同样作用,对复发性高钙尿结石有效,维生素B1、维生素B6缺乏使尿草酸增多,应增加富含此类维生素的食物,如谷物、干果、硬果等。

⑵磷酸钙结石及磷酸镁铵结石:其低钙饮食同草酸钙结石相同。在低磷食物中,宜少食肉类、鱼类及骨头汤。

⑶尿结石: 应限制蛋白质的摄入量,每日蛋白质的总摄入量应在48-80克(0.8-1.0克/公斤/日)之间。一般带叶的蔬菜每市斤约含10克蛋白质、瘦肉类每50 克约含蛋白质10克、谷类每市斤含蛋白质35-60克。要增加新鲜蔬菜和水果的食量。蔬菜和水果含维生素B1及维生素C,它们在体内最后代谢产物是碱性 的,尿酸在碱性尿内易于溶解,故有利于治疗。常规治疗:每隔1-2日用一次清凉饮食(生水果、果汁及生菜),至少每周1次清凉饮食。少食或忌用肉类、动物 内脏、肉汤、肉汁、沙丁鱼、蟹、菠菜、浓茶、咖啡,烈性的香料及调味品也宜少用。
现实生活中很多疾病的发生和日常饮食是密切相关的,如果能做到起居有时,饮食有节,甚至大部分癌症也可能避免。现在就肾结石病这一顽症来提醒大家如何用饮食来预防,或使已经患了肾结石者,结石增大的速度减慢,甚至缩小、溶解而排出体外。

(一)多饮白开水 多饮水使尿液得到稀释,钙离子和草酸根的浓度就会降低,形成不了草酸钙结石。研究表明,增加50%的尿量,可使肾结石发病率下降86%。

(二)合理补钙,尤其饮食上补钙 肾结石患者往往“谈钙色变”,错误地认为肾结石的元凶是钙,其实不然,肾结石患者也需要补钙。目前医学界从两个不同的角度来解释,肾结石患者为什么要补钙。

第一是补充钙能与胃肠道中蔬菜含有的草酸结合成不溶性的草酸钙,随粪便排出体外,减少了部分被肠胃吸收和经肾脏排出体外的草酸,从而减少了形成肾结石的几率。

第二是日本学者提出的“酸碱平衡学说”。即血液呈酸性时,结石容易形成。呈碱性时,抑制结石形成。缺钙时血液偏酸性,合理补钙,血液偏碱,这样反而有利于抑制结石形成。

(三)限量摄入糖类 美国科学家最新一项研究结果表明,高糖食品的摄入,可以使患肾结石的机会增加,因此,要注意少吃甜食。

(四)少吃草酸盐含量高的食物 含草酸盐高的食物有番茄、菠菜、草莓、甜菜、巧克力等,过高的草酸盐摄入也是导致肾结石的主要原因之一。

(五)少吃豆制品 大豆食品含草酸盐和磷酸盐都高,能同肾脏中的钙融合,形成结石

(六)睡前慎喝牛奶 睡眠不好的人,睡前喝杯牛奶有助于睡眠。但在睡眠后,尿量减少、浓缩,尿中各种有形物质增加。而饮牛奶后2~3小时,正是钙通过肾脏排泄的高峰。钙通过肾脏在短时间内骤然增多,容易形成结石。因此肾结石患者,睡前就不应喝含钙高的牛奶。

(七)勿过量服用鱼肝油 鱼肝油富含维生素D,有促进肠膜对钙磷吸收的功能,骤然增加尿液中钙磷的排泄,势必产生沉淀,容易形成结石

(八)多食黑木耳 黑木耳中富含多种矿物质和微量元素,能对各种结石产生强烈的化学反应,使结石剥脱、分化、溶解,排出体外。

posted @ 2007-12-17 12:04 船夫 阅读(1385) | 评论 (0)编辑 收藏

XSL取得当前循环的位置

最近在一个项目中用到了XSLT,目的是将返回的XML数据记录通过XSL转换为HTML,在for-each的循环中取得当前记录的位置,通过实践,找到了解决的办法,主要是使用xsl的position函数
1 <xsl:for-each select="QRoleInline-list/QRoleInline">
2 <xsl:if test="not(position() = 1)"><xsl:text>,</xsl:text></xsl:if><xsl:value-of select="@roleName"/>
3 </xsl:for-each>
使用position函数可以取得当前行在循环中的位置,从1开始。上述代码是判断如果位置为第一个, 则需要加逗号。

还有一个函数current()是负责取到当前节点对象的。

posted @ 2007-12-14 11:33 船夫 阅读(514) | 评论 (0)编辑 收藏

走出ClassLoader迷局 --转至sharajava的博克http://www.blogjava.net/sharajava/archive/2006/07/25/59946.html

: 这个问题经常出现在编写框架代码 , 需要动态加载很多类和资源的时候 . 通常当你需要动态加载资源的时候 , 你至少有三个 ClassLoader 可以选择 :

²        系统类加载器或叫作应用类加载器 (system classloader or application classloader)

²        当前类加载器

²        当前线程类加载器

上面的问题指的是最后一种类加载器 . 哪种类加载器是正确的选择呢 ?

第一种选择可以很容易地排除 : 系统类加载器 (system classloader). 这个类加载器处理 -classpath 下的类加载工作 , 可以通过 ClassLoader.getSystemClassLoader() 方法调用 . ClassLoader 下所有的 getSystemXXX() 的静态方法都是通过这个方法定义的 . 在你的代码中 , 你应该尽量少地调用这个方法 , 以其它的类加载器作为代理 . 否则你的代码将只能工作在简单的命令行应用中 , 这个时候系统类加载器 (system classloader) JVM 最后创建的类加载器 . 一但你把代码移到 EJB, Web 应用或 Java Web Start 应用中 , 一定会出问题 .

      所以我们来看第二种选择 : 当前上下文环境下的类加载器 . 根据定义 , 当前类加载器就是你当前方法所属的类的加载器 . 在运行时类之间动态联编 , 及调用 Class.forName,() Class.getResource() 等类似方法时 , 这个类加载器会被隐含地使用 . It is also used by syntactic constructs like X.class class literals.

    线程上下文类型加载器是在Java 2平台上被引入的. 每一个线程都有一个类加载器与之对应(除非这个线程是被本地代码创建的). 这个类加载器是通过Thread.setContextClassLoaser()方法设置的. 如果你不在线程构造后调用这个方法, 这个线程将从它的父线程中继承相应的上下文类加载器. 如果在整个应用中你不做任何特殊设置, 所有的线程将都以系统类加载器(system classloader)作为自己的线程上下文类加载器. 自从WebJ2EE应用服务器使用成熟的类加载器机制来实现诸如JNDI, 线程池, 组件热部署等功能以来, 这种在整个应用中不做任何线程类加载器设置的情况就很少了.

    为什么线程上下文类加载器存在于如此重要的位置呢? 这个概念在J2SE中的引入并不引人注目. 很多开发人员对这一概念迷惑的原因是Sun公司在这方面缺乏适当的指引和文档.

    事实上, 上下文类加载器提供了类加载机制的后门, 这一点也在J2SE中被引入了. 通常, JVM中的所有类加载器被组织成了有继承层次的结构, 每一个类加载器(除了引导JVM的原始类加载器)都有一个父加载器. 每当被请示加载类时, 类加载器都会首先请求其父类加载器, 只有当父类加载器不能加载时, 才会自己进行类加载.

   有时候这种类加载的顺序安排不能正常工作, 通常当必须动态加载应用程序开发人员提供的资源的时候. JNDI为例: 它的内容(J2SE1.3开始)就在rt.jar中的引导类中实现了, 但是这些JNDI核心类需要动态加载由独立厂商实现并部署在应用程序的classpath下的JNDI提供者. 这种情况就要求一个父classloader(本例, 就是引导类加载器)去加载对于它其中一个子classloader(本例, 系统类加载器)可见的类. 这时通常的类加载代理机制不能实现这个要求. 解决的办法(workaround)就是, JNDI核心类使用当前线程上下文的类加载器, 这样, 就基本的类加载代理机制的相反方向建立了一条有效的途径.

    另外, 上面一段可能让你想起一些其它的事情: XML解析Java API(JAXP). 是的, JAXP只是J2SE的扩展进, 它很自然地用当前类加载器来引导解析器的实现. 而当JAXP被加入到J2SE1.4的核心类库中时, 它的类加载也就改成了用当前线程类加载器, JNDI的情况完全类似(也使很多程序员很迷惑). 明白为什么我说来自Sun的指导很缺乏了吧?

   在以上的介绍之后, 我们来看关键问题: 这两种选择(当前类加载器和当前线程类加载器)都不是在所有环境下都适用. 有些人认为当前线程类加载器应该成为新的标准策略. 但是, 如果这样, 当多个线程通过共享数据进行交互的时, 将会呈现出一幅极其复杂的类加载的画面, 除非它们全部使用了同一个上下文的类加载器. 进一步说, 在某些遗留下来的解决方案中, 委派到当前类加载器的方法已经是标准. 比如对Class.forName(String)的直接调用(这也是我为什么推荐尽量避免对这个方法进行调用的原因). 即使你努力去只调用上下文相关的类加载器, 仍然会有一些代码会不由你控制. 这种不受控制的类加载委派机制是混入是很危险的.

    更严重的问题, 某些应用服务器把环境上下文及当前类加载器设置到不同的类加载器实例上, 而这些类加载器有相同的类路径但却没有委派机制中的父子关系. 想想这为什么十分可怕. 要知道类加载器定义并加载的类实例会带有一个JVM内部的ID. 如果当前类加载器加载一个类X的实例, 这个实例调用JNDI查找类Y的实例, 些时的上下文的类加载器也可以定义了加载类Y实例. 这个类Y的定义就与当前类加载器看到的类Y的定义不同. 如果进行强制类型转换, 则产生异常.

   这种混乱的情况还将在Java中存在一段时间. 对于那些需要动态加载资源的J2SEAPI, 我们来猜想它们的类加策略. 例如:

Ø         JNDI 使用线程上下文类加载器

Ø         Class.getResource() Class.forName()使用当前类加载器

Ø         JAXP(J2SE 1.4 及之后)使用线程上下文类加载器

Ø         java.util.ResourceBundle 使用调用者的当前类加载器

Ø         URL protocol handlers specified via java.protocol.handler.pkgs system property are looked up in the bootstrap and system classloaders only

Ø         Java 序列化API默认使用调用者当前的类加载器

这些类及资源的加载策略问题, 肯定是J2SE领域中文档最及说明最缺乏的部分了.

posted @ 2006-07-27 15:23 船夫 阅读(299) | 评论 (0)编辑 收藏

看星星的日子

今天晚上吃完晚饭,往回走的路上,不经意间抬头,看到了很多的星星,我跟同事都停下脚步,抬头分辨哪个是北极星,哪里是北斗七星,聊得非常兴起。
想起来自从到了成都之后,算上这次都只看过两次星星,第一次是大一军训的时候,在华阳看到的,第二次就是今天晚上了。成都市里面不要指望会看到星星,因为浓密的云把所有的星星都遮住了。
昨天听老唐说他看到夜空中有一条“白带”,他说好像是银河,他之前从来都没有看过银河,跟他比起来我真可以算是幸运多了。小时候,到了夏天,家里人和邻居都跑到院子里面纳凉,我就躺在母亲的怀里面,边享受母亲扇子带来的凉爽,边抬头看星星,东北的星空真的是非常清晰,那时候,母亲给我讲哪个是银河,哪个是牛郎织女,哪个是勺子星(北斗七星),还给我讲牛郎织女的故事,说一到了七月初七就会下雨,那是因为牛郎和织女相会的泪水,还说从来没说过谎的小孩子趴在黄瓜架下面可以听到他们的哭声,想想现在认识的那几颗星星都是那个时候记下来的,书本上学的好像都不知道被我丢到哪里去了。那时候看到的星空现在回想起来真的是非常漂亮,就像冰心在繁星中描述的一样。
已经很多年没在家里面过夏天了,过年的时候倒是有回去,但是天气太冷,实在没那种兴致去看星星。
长大了,反而觉得快乐只存在于回忆中了,这是成长的代价吗?

posted @ 2006-07-25 23:53 船夫 阅读(250) | 评论 (0)编辑 收藏

惰性已经在充分的滋长

已经封闭开发了近三个月了,由刚开始的热情高涨到现在的热情全无,我已经逐渐被自己的惰性所吞噬,已经快慢慢的丢失了真正的自我。

经过了这么一段时间,曾经对新技术非常感兴趣的我已经完全失去了这种热情。

知耻而后勇,我要克服自己的这种情绪,重新开始,用崭新的眼光去对待每一天

posted @ 2006-07-25 23:22 船夫 阅读(209) | 评论 (0)编辑 收藏

项目中遇到的一个Spring事务管理的问题

今天从CVS上checkout项目的时候,出现了一个问题,我以前写的模块功能本来是好的,但是checkout之后就出了问题,我想一定是配置文件更新出错了,努力寻找,发现没有问题.后来经同事说他更改了一个方法,而我的代码中有对那个方法的调用,终于知道了问题的所在.
程序中抛出的异常是
java.lang.IllegalStateException: No value for key [org.hibernate.impl.SessionFactoryImpl@7a3d45f0] bound to thread [Servlet.Engine.Transports : 0]
我发现是在我spring的sevice方法中调用了他的方法,他的方法又调用了另一个service方法,导致出现了这个问题.

这个问题只要把他的那个方法修改一下,或者从我的service方法中移出就可以解决.

我想spring中肯定应该有些配置能使两个service方法处于同一个事务中,但是我还没找到.希望知道的高手能提点一下,谢谢

posted @ 2006-07-24 18:40 船夫 阅读(644) | 评论 (0)编辑 收藏

在WSAD 5.1中使用log4j遇到的问题

使用log4j作为日志输出工具,设置根级别为warn,然后分别设置了hibernate和spring等的级别为debug,自己项目的级别也设置为debug,但是很奇怪的事情出现了:
我启动wasd的测试服务器,打出来的日志只有我本项目的debug级以上的信息,spring和hibernate的都打不出来;
我使用main函数运行我项目中的一个方法,所有的debug信息,spring和hibernate以及我本项目的debug信息一样都没少。
我的配置是绝对没有问题的,我实在想不出来怎么会出现这种问题,见鬼了,哪位高手遇到过这种情况,告知一下解决方法,谢谢

posted @ 2006-07-21 01:23 船夫 阅读(541) | 评论 (4)编辑 收藏

好久没有思考过什么了,整个大脑都仿佛已经失去了这个能力,每天忙着要么是做项目,要么就是忙着发呆,发呆自己能想些什么,做些什么,脑袋真的已经生锈了。
整个人再也没有高中时候的那种反应,看来这个大学读的是亏了,直到现在还改变不了这种坏习惯。其实我很清楚,我这样对自己说完全是找个借口,这样才能使自己感到没有那么的空虚,少些对自己的自责。不过我发现,很久以来,都没有那种自责的心理了,不会在为自己的懒散感到自责,真的是很奇怪,在高中的时候,中午或周末多玩儿了一会儿,或是做错了一道不该做错的题,都会感到非常的愧疚,为此而一直自责。现在长大了,每天充斥在脑子里面的都是,怎样才能赚钱,学什么才能让自己更加有发展,思考的越来越现实,反而发现自己的动力越来越不足,天哪,我是怎么了?
买房子,结婚?现实围绕在我的身边,把我压得好紧,女友说我脾气太好,没有男子气概?难道我对她发脾气才是好的吗?两地分居,为了生活出去奔波,希望能赚回来一栋房子,难道我愿意吗?她爸和她妈对我的印象也不是很好,我知道我这个人太笨了,不会说话,不会讨别人喜欢,啊~~~~~~~~~~~我实在是受不了了,我已经对自己失望透顶了,谁能告诉我这个时候应该能做什么?????
我要改变这一切,我要改变自己,我要提高自己的能力,我要改变他人对我的看法,我要做一个让所有人都满意的人,我他妈的是为了什么活得这么累啊,爱情,不是应该两个人之间事吗?干嘛有那么多外在因素要影响我呢?
25岁,这个世界让我变得衰老~~~

posted @ 2006-07-21 01:14 船夫 阅读(188) | 评论 (0)编辑 收藏

表的外键约束[ZT]

1。创建测试表
SQL> create table lesson(lesson_name varchar2(20), classroom varchar2(10));

表已创建。

SQL> create table teacher(name varchar2(20),lesson_name varchar2(20));

表已创建。

SQL> alter table lesson add constraint pk_lesson primary key(lesson_name);

表已更改。

SQL> alter table teacher add constraint fk_lessonname foreign key(lesson_name)
2 references lesson(lesson_name);

表已更改。


2。插入测试数据
SQL> insert into lesson values('english','class 1');

已创建 1 行。

SQL> insert into lesson values('music','class 2');

已创建 1 行。


3。测试有外键的字段是否可以为空
SQL> insert into teacher values('wang','hello');
insert into teacher values('wang','hello')
*
ERROR 位于第 1 行:
ORA-02291: 违反完整约束条件 (SYSTEM.FK_LESSONNAME) - 未找到父项关键字

SQL> insert into teacher values('wang','music');

已创建 1 行。

SQL> insert into teacher values('wang',null);

已创建 1 行。


结论:有外键约束的字段可以为空。如果不为空的话,则一定要满足外键的约束关系

posted @ 2006-03-16 15:44 船夫 阅读(315) | 评论 (0)编辑 收藏

outer和left outer join有什么区别??

outer和left outer join有什么区别??

使用关系代数合并数据
1 关系代数
合并数据集合的理论基础是关系代数,它是由E.F.Codd于1970年提出的。
在关系代数的形式化语言中:
        用表、或者数据集合表示关系或者实体。
        用行表示元组。
        用列表示属性。
关系代数包含以下8个关系运算符
        选取――返回满足指定条件的行。
        投影――从数据集合中返回指定的列。
        笛卡尔积――是关系的乘法,它将分别来自两个数据集合中的行以所有可能的方式进行组合。
        并――关系的加法和减法,它可以在行的方向上合并两个表中的数据,就像把一个表垒在另一个表之上一样。
        交――返回两个数据集合所共有的行。
        差――返回只属于一个数据集合的行。
        连接――在水平方向上合并两个表,其方法是:将两个表中在共同数据项上相互匹配的那些行合并起来。
        除――返回两个数据集之间的精确匹配。
此外,作为一种实现现代关系代数运算的方法,SQL还提供了:
        子查询――类似于连接,但更灵活;在外部查询中,方式可以使用表达式、列表或者数据集合的地方都可以使用子查询的结果。
本章将主要讲述多种类型的连接、简单的和相关的子查询、几种类型的并、关系除以及其他的内容。
2 使用连接
2.1 连接类型
在关系代数中,连接运算是由一个笛卡尔积运算和一个选取运算构成的。首先用笛卡尔积完成对两个数据集合的乘运算,然后对生成的结果集合进行选取运算,确保只把分别来自两个数据集合并且具有重叠部分的行合并在一起。连接的全部意义在于在水平方向上合并两个数据集合(通常是表),并产生一个新的结果集合,其方法是将一个数据源中的行于另一个数据源中和它匹配的行组合成一个新元组。
SQL提供了多种类型的连接方式,它们之间的区别在于:从相互交叠的不同数据集合中选择用于连接的行时所采用的方法不同。
连接类型        定义
内连接        只连接匹配的行
左外连接        包含左边表的全部行(不管右边的表中是否存在与它们匹配的行),以及右边表中全部匹配的行
右外连接        包含右边表的全部行(不管左边的表中是否存在与它们匹配的行),以及左边表中全部匹配的行
全外连接        包含左、右两个表的全部行,不管另外一边的表中是否存在与它们匹配的行。
(H)(theta)连接        使用等值以外的条件来匹配左、右两个表中的行
交叉连接        生成笛卡尔积-它不使用任何匹配或者选取条件,而是直接将一个数据源中的每个行与另一个数据源的每个行都一一匹配
在INFORMIX中连接表的查询
如果FROM子句指定了多于一个表引用,则查询会连接来自多个表的行。连接条件指定各列之间(每个表至少一列)进行连接的关系。因为正在比较连接条件中的列,所以它们必须具有一致的数据类型。
SELECT语句的FROM子句可以指定以下几种类型的连接
FROM子句关键字        相应的结果集
CROSS JOIN        笛卡尔乘积(所有可能的行对)
INNER JOIN        仅对满足连接条件的CROSS中的列
LEFT OUTER JOIN        一个表满足条件的行,和另一个表的所有行
RIGHT OUTER JOIN        与LEFT相同,但两个表的角色互换
FULL OUTER JOIN        LEFT OUTER 和 RIGHT OUTER中所有行的超集

2.2 内连接(Inner Join)
内连接是最常见的一种连接,它页被称为普通连接,而E.FCodd最早称之为自然连接。
下面是ANSI SQL-92标准
select *
from  t_institution i
inner join t_teller t
on i.inst_no = t.inst_no
where i.inst_no = "5801"
其中inner可以省略。
等价于早期的连接语法
select *
from t_institution i, t_teller t
where i.inst_no = t.inst_no
and i.inst_no = "5801"

2.3 外连接
2.3.1        左外连接(Left Outer Jion)
select *
from  t_institution i
left outer join t_teller t
on i.inst_no = t.inst_no
其中outer可以省略。
2.3.2        右外连接(Rigt Outer Jion)
select *
from  t_institution i
right outer join t_teller t
on i.inst_no = t.inst_no
2.3.3        全外连接(Full Outer)
全外连接返回参与连接的两个数据集合中的全部数据,无论它们是否具有与之相匹配的行。在功能上,它等价于对这两个数据集合分别进行左外连接和右外连接,然后再使用消去重复行的并操作将上述两个结果集合并为一个结果集。
在现实生活中,参照完整性约束可以减少对于全外连接的使用,一般情况下左外连接就足够了。在数据库中没有利用清晰、规范的约束来防范错误数据情况下,全外连接就变得非常有用了,你可以使用它来清理数据库中的数据。
select *
from  t_institution i
full outer join t_teller t
on i.inst_no = t.inst_no
2.3.4        外连接与条件配合使用
当在内连接查询中加入条件是,无论是将它加入到join子句,还是加入到where子句,其效果是完全一样的,但对于外连接情况就不同了。当把条件加入到join子句时,SQL Server、Informix会返回外连接表的全部行,然后使用指定的条件返回第二个表的行。如果将条件放到where子句中,SQL Server将会首先进行连接操作,然后使用where子句对连接后的行进行筛选。下面的两个查询展示了条件放置位子对执行结果的影响:
条件在join子句
select *
from  t_institution i
left outer join t_teller t
on i.inst_no = t.inst_no
and i.inst_no = “5801”
结果是:
inst_no    inst_name            inst_no    teller_no  teller_name
5801       天河区               5801       0001       tom
5801       天河区               5801       0002       david
5802       越秀区
5803       白云区
条件在where子句
select *
from  t_institution i
left outer join t_teller t
on i.inst_no = t.inst_no
where i.inst_no = “5801”
结果是:
inst_no    inst_name            inst_no    teller_no  teller_name
5801       天河区               5801       0001       tom
5801       天河区               5801       0002       david

2.4 自身连接
自身连接是指同一个表自己与自己进行连接。这种一元连接通常用于从自反关系(也称作递归关系)中抽取数据。例如人力资源数据库中雇员与老板的关系。
下面例子是在机构表中查找本机构和上级机构的信息。
select s.inst_no superior_inst, s.inst_name sup_inst_name, i.inst_no, i.inst_name
from t_institution i
join t_institution s
on i.superior_inst = s.inst_no

结果是:
superior_inst sup_inst_name        inst_no    inst_name
800           广州市               5801       天河区
800           广州市               5802       越秀区
800           广州市               5803       白云区

2.5 交叉(无限制) 连接
交叉连接用于对两个源表进行纯关系代数的乘运算。它不使用连接条件来限制结果集合,而是将分别来自两个数据源中的行以所有可能的方式进行组合。数据集合中一的每个行都要与数据集合二中的每一个行分别组成一个新的行。例如,如果第一个数据源中有5个行,而第二个数据源中有4个行,那么在它们之间进行交叉连接就会产生20个行。人们将这种类型的结果集称为笛卡尔乘积。
大多数交叉连接都是由于错误操作而造成的;但是它们却非常适合向数据库中填充例子数据,或者预先创建一些空行以便为程序执行期间所要填充的数据保留空间。
select *
from  t_institution i
cross join t_teller t
在交叉连接中没有on条件子句

3 APPENDIX
3.1 A 参考资料与资源
        《Microsoft SQL Server 2000 Bile》Paul Nielsen
        Paul Nielsen的Web站点
www.isnotnull.com
3.2 注文章所有SQL在IBM Informix Dynamic Server Version 9.40.TC2E1测试通过

posted @ 2006-03-06 13:02 船夫 阅读(1633) | 评论 (0)编辑 收藏

HTML中Target的四个保留字

_parent:在当前FRAMESET位置显示新href。  
_top:在当前整个窗口位置显示新href,比如本身FRAMESET位于另一个FRAMESET中。  
_self:强制在当前FRAME中显示新href。  
_blank:在新窗口中显示href

posted @ 2005-12-21 09:40 船夫 阅读(2018) | 评论 (0)编辑 收藏

java实现文件传输

     摘要:   1import java.awt.*;   2import java.awt.event.*;   3import javax.swing.*;   4import javax.swing.event.*;   5i...  阅读全文

posted @ 2005-12-20 11:22 船夫 阅读(3042) | 评论 (5)编辑 收藏

Document 和 Document.all 分别什么时候用

如果与a,form对象,image对象,applet对象相对应的html标记中设定了name性质,它的值将被用作document对象的属性名,用来引用相应的对象,其他的对象则不可以。

  另外,input等如果作为form的子元素,则直接用inputName或者document.inputName来引用此对象就是错误的,必须使用formName.inputName引用,否则就可以使用inputName来引用.

  另外应该注意到有很多平时用的元素都没有name.

  如果想引用一个有id的元素,只能用Id或者document.getElementById,document.all.id来引用
但是象这样的元素,所以象<a href="......" name="linkname" id="linkid">......</a>这样的
可以用

linkid.href;
linkname.href;
document.all.linkid.href;
document.all.linkname.href;
document.getElementById("linkid").href;
document.getElementsByName("linkname")[0].href来引用

  all是一个集合,包含所有html对像的集合,写一个程式,可以存取到所有的对像。像这样:

<script language="javascript">
var obj="";
for(i=0;i<document.all.length;i++)
obj+=document.all[i].tagName+";";
alert(obj);
</script>

  注意要把程式放到</html>之后哦。

作者:  来源:CSDN

posted @ 2005-12-20 10:24 船夫 阅读(664) | 评论 (0)编辑 收藏

气死老师的试卷答案


1.地理
地理教过,中国产煤最多的地方是辽宁省抚顺,产铁最多是辽宁省鞍山, 所以抚顺被称为中国的“煤都”,鞍山称为“铁都”。某次考试,试卷上:中国的煤都是(黑的),中国的铁都是(硬的)。考完还说:老师怎么出那么简单的题目?

2、 语文考试

一次语文考试的附加题,问普罗米修斯是什么文学作品里面的人物,一个同学填:哈里-波特。还有一次,问左忠毅公叫什么名字,一个同学写:左冷禅。

3、泰坦尼克号


一次政治时政题:我国的( )号考察船去北极考察。我的答案:泰坦尼克号。

4 . 解释“逝世”一词


语文考试。解释“逝世”一词。我答:“去死”(本来想写“死去”)老师大怒……

5 .一行白鹭上西天


小学,一同学背诗,前面3句背得那么费劲。最后一句:“一行白鹭上西天。”全班晕!

6、 高一语文摸底考试

高一语文摸底考试,“何当共剪西窗烛”,填下句。我答:“夫妻对坐到天明”。正确答案:“却话巴山夜雨时”。

7.诗句填空

一次语文考试,诗句填空是白居易的《题大林寺桃花》中的一句“( ),不知转入此中 来”,正解应是“常恨春归无觅处”,我前排一个同学愣是填了“常恨村姑无觅处”。

8、 生物考试

生物考试一填图题,问一个细胞图是什么生物的,正解是“母果蝇”,我班一人答:“女果蝇”。生物组老师开会研究N久,决定给0分。

9、填诗词下句

高中时候也是填诗词下句。上句是:“洛阳亲友如相问”;我一个同学填:“就说我在岳阳楼

10、 一动也不动

高中一次语文考试,也是填下一句:“蚍蜉撼大树,( )”。我有一同学填:一动也不动。很符合事实。

11、鸡型!

高中时,生物考试,问:鸡的消化类型是什么型?我不会,答:鸡型!结果老师在全班点名批评!

12、对子

上句是:“西塞山前白鹭飞”,同学憋半天憋不出,于是瞎写:“东村河边黑龟爬”!

13、古诗下句

高中语文考试,写古诗下句。上句是:“待到山花烂漫时”,我们班一人居然填了:我便奋力把花采。

14、初中时考语文

初中时考语文,题目问老舍先生的著名作品的名字。一同学想不起,我告诉他:茶馆。结果那位听成:茶壶盖。被老师痛骂!

15、拿出芭蕉

以前同学读课文,其中有一句:拿出芭蕉扇扇扇。本来停顿应该是拿出芭蕉扇,扇扇。那同学直接读成:拿出芭蕉,扇扇扇!

16、“卖”娥冤

初中的时候一次上课把窦娥冤的窦读成“卖”娥冤。全班爆笑我还不知道为什么

17、 数学考试

还有一次是数学考试,最后一道大题是两个解法判断哪个正确。我想了半天没想出来,顺便提了几个词:公说公有理!婆说婆有理!看看都没理!想想全有理……结果数学老师把我的解法整个年级她教的四个班都读一遍以后,我就闻名了!

18、《咏梅》

高中语文课正上毛泽东的《咏梅》,早自习要求背诵。老师点人回答:“——她在丛中笑下面,XX回答!” XX正在吃东西,半天说不出话来,憋出一句“笑也不出声!”全班爆笑!


19.天才学生

考试写:“天生我才必有用”的下句。有位天才学生答:“老鼠儿子会打洞”。我们整办公室的语文老师集体毫无形象的狂笑!


20.英语考试

英语考试: HOW ARE YOU?这么翻译?答案——怎么是你? HOW OLD ARE YOU?怎么翻译?答案——怎么老是你?

21.中国学生在美国

试题:如果一位中国学生在美国加州目睹了一起交通事故,警察来了以后问你知不知道事情的经过,应该怎么对他说?一个人回答:one car come one car go,two car peng peng,one car die。

22.名字太短

A君在做语文试卷时,被一道填空题“《这里的黎明静悄悄》的作者是谁”难住。苦思良久,A君毅然在空栏上写着“霍利菲尔德”。
一旁的监考老师笑问:“怎么不写泰森呢?”
A君道:“他的名字太短了,不像!”

23.一副跳棋

B君在作文中要描述一个人的外貌,遇一字不会,遂悄声问同桌:“一副眼镜的‘副’字怎么写?”
同桌告诉他:“就是一副跳棋的‘副’嘛。”
后老师批阅B君的作文,见上面写道:“他高高的鼻梁上架着一副跳棋。”(

24.一代更比一代浪


题目:长江后浪推前浪__________________

有位学生答:一代更比一代浪

posted @ 2005-12-15 11:18 船夫 阅读(379) | 评论 (0)编辑 收藏

Velocity 简介

1.Velocity 的使用

Velocity是一个开放源吗的模版引擎,由apache.org小组负责开发,现在最新的版本是Velocity1.3.1,http://jakarta.apache.org/velocity/index.html 可以了解Velocity的最新信息。
Velocity允许我们在模版中设定变量,然后在运行时,动态的将数据插入到模版中,替换这些变量。
例如:
<html>
<body>HELLO $CUSTOMERNAME</body>
</html>
我们可以在运行时得到客户的名字,然后把它插入到这个模版中替换变量$CUSTOMERNAME,整个替换过程是由Velocity进行控制的,而且java的调用代码也非常简单,如我们可以在java代码中这样调用
/***********************************************************/
//这个文件中设定了Velocity使用的log4j的配置和Velocity的模版文件所在的目录
Velocity.init("D:\\Template\\resource\\jt.properties");
//模版文件名,模版文件所在的路径在上一条语句中已经设置了
Template template = Velocity.getTemplate("hello.vm", "gb2312");
//实例化一个Context
VelocityContext context = new VelocityContext();
//把模版变量的值设置到context中
context.put("CUSTOMERNAME", "My First Template Engine ---- Velocity.");
//开始模版的替换
template.merge(context, writer);
//写到文件中
PrintWriter filewriter = new PrintWriter(new FileOutputStream(outpath),true);
filewriter.println(writer.toString());
filewriter.close();
/***********************************************************/

这就是整个java的代码,非常的简单。如果我们有多个模版变量,我们仅需要把这些模版变量的值设置到context中。
下面我们简单的分析一下,Velocity引擎读取模板文件时,它直接输出文件中所有的文本,但以$字符开头的除外,$符号标识着一个模版变量位置,
context.put("CUSTOMERNAME", "My First Template Engine ---- Velocity.");
当 Velocity 模板引擎解析并输出模板的结果时,模板中所有出现$CUSTOMERNAME的地方都将插入客户的名字,即被加入到VelocityContext的对象的toString()方法返回值将替代Velocity变量(模板中以$开头的变量)。
模板引擎中最强大、使用最频繁的功能之一是它通过内建的映像(Reflection)引擎查找对象信息的能力。这个映像引擎允许用一种方便的Java“.”类似的操作符,提取任意加入到VelocityContext的对象的任何公用方法的值,或对象的任意数据成员。
映像引擎还带来了另外一个改进:快速引用JavaBean的属性。使用JavaBean属性的时候,我们可以忽略get方法和括号。请看下面这个模板的例子。
<html>
<body>
Name:$Customer.Name()
Address:$Customer.Address()
Age:$Customer.Age()
</body>
</html>

java的代码:
/***********************************************************/
//设置客户信息
Customer mycustomer = new Customer();
mycustomer.setName("Velocity");
mycustomer.setAddress("jakarta.apache.org/velocity/index.html");
mycustomer.setAge(2);
//这个文件中设定了 Velocity 使用的 Log4j 的配置和Velocity的模版文件所在的目录Velocity.init("D:\\Template\\resource\\jt.properties");
//模版文件名,模版文件所在的路径在上一条语句中已经设置了
Template template = Velocity.getTemplate("hello.vm", "gb2312");
//实例化一个Context
VelocityContext context = new VelocityContext();
//把模版变量的值设置到context中
context.put("Customer", mycustomer);
//开始模版的替换
template.merge(context, writer);
//写到文件中
PrintWriter filewriter = new PrintWriter(new FileOutputStream(outpath),true);
filewriter.println(writer.toString());
filewriter.close();
输出结果:
<html>
<body>
Name:Velocity
Address:jakarta.apache.org/velocity/index.html
Age:2
</body>
</html>
除了替换变量之外,象Velocity高级引擎还能做其他许多事情,它们有用来比较和迭代的内建指令,通过这些指令我们可以完成程序语言中的条件判断语句和循环语句等。
例如,我们想要输出年龄等于2的所有客户的信息,我们可以这样定义我们的模版
模版:
<html>
<body>
<table>
<tr>
<td>名称</td>
<td>地址</td>
<td>年龄</td>
</tr>
#foreach ($Customer in $allCustomer)
#if($Customer.Age()=="2")
<tr>
<td>$Customer.Name()</td>
<td>$Customer.Address()</td>
<td>$Customer.Age()</td>
</tr>
#end
#end
</table>
</body>
</html>

java的代码:
/******************************************************/
//设置客户信息
ArrayList allMyCustomer = new ArrayList();
//客户1
Customer mycustomer1 = new Customer();
mycustomer1.setName("Velocity");
mycustomer1.setAddress("jakarta.apache.org/velocity/index.html");
mycustomer1.setAge(2);
//客户2
Customer mycustomer2 = new Customer();
mycustomer2.setName("Tomcat");
mycustomer2.setAddress("jakarta.apache.org/tomcat/index.html");
mycustomer2.setAge(3);
//客户3
Customer mycustomer3 = new Customer();
mycustomer3.setName("Log4J");
mycustomer3.setAddress("jakarta.apache.org/log4j/docs/index.html");
mycustomer3.setAge(2);
//添加到allMyCustomer(ArrayList)中.
allMyCustomer.add(mycustomer1);
allMyCustomer.add(mycustomer2);
allMyCustomer.add(mycustomer3);
//这个文件中设定了Velocity使用的log4j的配置和Velocity的模版文件所在的目
Velocity.init("D:\\Template\\resource\\jt.properties");
//模版文件名,模版文件所在的路径在上一条语句中已经设置了
Template template =Velocity.getTemplate("hello.vm", "gb2312");
//实例化一个Context
VelocityContext context = new VelocityContext();
/** 注意这里我们仅仅需要给一个模版变量负值 */
context.put("allCustomer", allMyCustomer);
//开始模版的替换
template.merge(context, writer);
//写到文件中
PrintWriter filewriter = new PrintWriter(new FileOutputStream(outpath),true);
filewriter.println(writer.toString());
filewriter.close();
/******************************************************/
结果:
<html>
<body>
<table>
<tr>
<td>名称</td>
<td>地址</td>
<td>年龄</td>
</tr>
<tr>
<td>Velocity</td>
<td>jakarta.apache.org/velocity/index.html</td>
<td>2</td>
</tr>
<tr>
<td>Log4J</td>
<td>jakarta.apache.org/log4j/docs/index.html</td>
<td>2</td>
</tr>
</table>
</body>
</html>

#if 语句完成逻辑判断,这个我想不用多说了。
allCustomer对象包含零个或者多个Customer对象。由于ArrayList (List, HashMap, HashTable, Iterator, Vector等)属于Java Collections Framework的一部分,我们可以用#foreach指令迭代其内容。我们不用担心如何定型对象的类型——映像引擎会为我们完成这个任务。#foreach指令的一般格式是“#foreach in ”。#foreach指令迭代list,把list中的每个元素放入item参数,然后解析#foreach块内的内容。对于list内的每个元素,#foreach块的内容都会重复解析一次。从效果上看,它相当于告诉模板引擎说:“把list中的每一个元素依次放入item变量,每次放入一个元素,输出一次#foreach块的内容”。

2.MVC设计模型

使用模板引擎最大的好处在于,它分离了代码(或程序逻辑)和表现(输出)。由于这种分离,你可以修改程序逻辑而不必担心邮件消息本身;类似地,你(或公关部门的职员)可以在不重新编译程序的情况下,重新编写客户列表。实际上,我们分离了系统的数据模式(Data Model,即提供数据的类)、控制器(Controller,即客户列表程序)以及视图(View,即模板)。这种三层体系称为Model-View-Controller模型(MVC)。
如果遵从MVC模型,代码分成三个截然不同的层,简化了软件开发过程中所有相关人员的工作。
结合模板引擎使用的数据模式可以是任何Java对象,最好是使用Java Collection Framework的对象。控制器只要了解模板的环境(如VelocityContext),一般这种环境都很容易使用。
一些关系数据库的“对象-关系”映射工具能够和模板引擎很好地协同,简化JDBC操作;对于EJB,情形也类似。 模板引擎与MVC中视图这一部分的关系更为密切。模板语言的功能很丰富、强大,足以处理所有必需的视图功能,同时它往往很简单,不熟悉编程的人也可以使用它。模板语言不仅使得设计者从过于复杂的编程环境中解脱出来,而且它保护了系统,避免了有意或无意带来危险的代码。例如,模板的编写者不可能编写出导致无限循环的代码,或侵占大量内存的代码。不要轻估这些安全机制的价值;大多数模板编写者不懂得编程,从长远来看,避免他们接触复杂的编程环境相当于节省了你自己的时间。 许多模板引擎的用户相信,在采用模板引擎的方案中,控制器部分和视图部分的明确分离,再加上模板引擎固有的安全机制,使得模板引擎足以成为其他内容发布系统(比如JSP)的替代方案。因此,Java模板引擎最常见的用途是替代JSP也就不足为奇了。

3.HTML处理

由于人们总是看重模板引擎用来替换JSP的作用,有时他们会忘记模板还有更广泛的用途。到目前为止,模板引擎最常见的用途是处理HTML Web内容。但我还用模板引擎生成过SQL、email、XML甚至Java源代码。

posted @ 2005-12-01 08:36 船夫 阅读(513) | 评论 (0)编辑 收藏

一篇关于web.xml配置的详细说明

1 定义头和根元素

部署描述符文件就像所有XML文件一样,必须以一个XML头开始。这个头声明可以使用的XML版本并给出文件的字符编码。
DOCYTPE声明必须立即出现在此头之后。这个声明告诉服务器适用的servlet规范的版本(如2.2或2.3)并指定管理此文件其余部分内容的语法的DTD(Document Type Definition,文档类型定义)。
所有部署描述符文件的顶层(根)元素为web-app。请注意,XML元素不像HTML,他们是大小写敏感的。因此,web-App和WEB-APP都是不合法的,web-app必须用小写。

2 部署描述符文件内的元素次序

XML 元素不仅是大小写敏感的,而且它们还对出现在其他元素中的次序敏感。例如,XML头必须是文件中的第一项,DOCTYPE声明必须是第二项,而web- app元素必须是第三项。在web-app元素内,元素的次序也很重要。服务器不一定强制要求这种次序,但它们允许(实际上有些服务器就是这样做的)完全拒绝执行含有次序不正确的元素的Web应用。这表示使用非标准元素次序的web.xml文件是不可移植的。
下面的列表给出了所有可直接出现在web-app元素内的合法元素所必需的次序。例如,此列表说明servlet元素必须出现在所有servlet-mapping元素之前。请注意,所有这些元素都是可选的。因此,可以省略掉某一元素,但不能把它放于不正确的位置。
l icon icon元素指出IDE和GUI工具用来表示Web应用的一个和两个图像文件的位置。
l display-name display-name元素提供GUI工具可能会用来标记这个特定的Web应用的一个名称。
l description description元素给出与此有关的说明性文本。
l context-param context-param元素声明应用范围内的初始化参数。
l filter 过滤器元素将一个名字与一个实现javax.servlet.Filter接口的类相关联。
l filter-mapping 一旦命名了一个过滤器,就要利用filter-mapping元素把它与一个或多个servlet或JSP页面相关联。
l listener servlet API的版本2.3增加了对事件监听程序的支持,事件监听程序在建立、修改和删除会话或servlet环境时得到通知。Listener元素指出事件监听程序类。
l servlet 在向servlet或JSP页面制定初始化参数或定制URL时,必须首先命名servlet或JSP页面。Servlet元素就是用来完成此项任务的。
l servlet-mapping 服务器一般为servlet提供一个缺省的URL:
http://host/webAppPrefix/servlet/ServletName。但是,常常会更改这个URL,以便servlet可以访问初始化参数或更容易地处理相对URL。在更改缺省URL时,使用servlet-mapping元素。
l session-config 如果某个会话在一定时间内未被访问,服务器可以抛弃它以节省内存。可通过使用HttpSession的setMaxInactiveInterval方法明确设置单个会话对象的超时值,或者可利用session-config元素制定缺省超时值。
l mime-mapping 如果Web应用具有想到特殊的文件,希望能保证给他们分配特定的MIME类型,则mime-mapping元素提供这种保证。
l welcom-file-list welcome-file-list元素指示服务器在收到引用一个目录名而不是文件名的URL时,使用哪个文件。
l error-page error-page元素使得在返回特定HTTP状态代码时,或者特定类型的异常被抛出时,能够制定将要显示的页面。
l taglib taglib元素对标记库描述符文件(Tag Libraryu Descriptor file)指定别名。此功能使你能够更改TLD文件的位置,而不用编辑使用这些文件的JSP页面。
l resource-env-ref resource-env-ref元素声明与资源相关的一个管理对象。
l resource-ref resource-ref元素声明一个资源工厂使用的外部资源。
l security-constraint security-constraint元素制定应该保护的URL。它与login-config元素联合使用
l login-config 用login-config元素来指定服务器应该怎样给试图访问受保护页面的用户授权。它与sercurity-constraint元素联合使用。
l security-role security-role元素给出安全角色的一个列表,这些角色将出现在servlet元素内的security-role-ref元素的role-name子元素中。分别地声明角色可使高级IDE处理安全信息更为容易。
l env-entry env-entry元素声明Web应用的环境项。
l ejb-ref ejb-ref元素声明一个EJB的主目录的引用。
l ejb-local-ref ejb-local-ref元素声明一个EJB的本地主目录的应用。

3 分配名称和定制的UL

在web.xml中完成的一个最常见的任务是对servlet或JSP页面给出名称和定制的URL。用servlet元素分配名称,使用servlet-mapping元素将定制的URL与刚分配的名称相关联。
3.1 分配名称
为了提供初始化参数,对servlet或JSP页面定义一个定制URL或分配一个安全角色,必须首先给servlet或JSP页面一个名称。可通过 servlet元素分配一个名称。最常见的格式包括servlet-name和servlet-class子元素(在web-app元素内),如下所示:
<servlet>
<servlet-name>Test</servlet-name>
<servlet-class>moreservlets.TestServlet</servlet-class>
</servlet>
这表示位于WEB-INF/classes/moreservlets/TestServlet的servlet已经得到了注册名Test。给 servlet一个名称具有两个主要的含义。首先,初始化参数、定制的URL模式以及其他定制通过此注册名而不是类名引用此servlet。其次,可在 URL而不是类名中使用此名称。因此,利用刚才给出的定义,URL
http://host/webAppPrefix/servlet/Test 可用于 http://host/webAppPrefix/servlet/moreservlets.TestServlet 的场所。
请记住:XML元素不仅是大小写敏感的,而且定义它们的次序也很重要。例如,web-app元素内所有servlet元素必须位于所有servlet- mapping元素(下一小节介绍)之前,而且还要位于5.6节和5.11节讨论的与过滤器或文档相关的元素(如果有的话)之前。类似地,servlet 的servlet-name子元素也必须出现在servlet-class之前。5.2节"部署描述符文件内的元素次序"将详细介绍这种必需的次序。
例如,程序清单5-1给出了一个名为TestServlet的简单servlet,它驻留在moreservlets程序包中。因为此servlet是扎根在一个名为deployDemo的目录中的Web应用的组成部分,所以TestServlet.class放在deployDemo/WEB- INF/classes/moreservlets中。程序清单5-2给出将放置在deployDemo/WEB-INF/内的web.xml文件的一部分。此web.xml文件使用servlet-name和servlet-class元素将名称Test与TestServlet.class相关联。图 5-1和图5-2分别显示利用缺省URL和注册名调用TestServlet时的结果。

程序清单5-1 TestServlet.java
package moreservlets;

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

/** Simple servlet used to illustrate servlet naming
* and custom URLs.
* <P>
* Taken from More Servlets and JavaServer Pages
* from Prentice Hall and Sun Microsystems Press,
*
http://www.moreservlets.com/.
* © 2002 Marty Hall; may be freely used or adapted.
*/

public class TestServlet extends HttpServlet {
public void doGet(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html");
PrintWriter out = response.getWriter();
String uri = request.getRequestURI();
out.println(ServletUtilities.headWithTitle("Test Servlet") +
"<BODY BGCOLOR=\"#FDF5E6\">\n" +
"<H2>URI: " + uri + "</H2>\n" +
"</BODY></HTML>");
}
}


程序清单5-2 web.xml(说明servlet名称的摘录)
<?xml version="1.0" encoding="ISO-8859-1"?>
<!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>Test</servlet-name>
<servlet-class>moreservlets.TestServlet</servlet-class>
</servlet>
<!-- … -->
</web-app>

3.2 定义定制的URL
大多数服务器具有一个缺省的serlvet URL:
http://host/webAppPrefix/servlet/packageName.ServletName。虽然在开发中使用这个URL很方便,但是我们常常会希望另一个URL用于部署。例如,可能会需要一个出现在Web应用顶层的URL(如,http: //host/webAppPrefix/Anyname),并且在此URL中没有servlet项。位于顶层的URL简化了相对URL的使用。此外,对许多开发人员来说,顶层URL看上去比更长更麻烦的缺省URL更简短。
事实上,有时需要使用定制的URL。比如,你可能想关闭缺省URL映射,以便更好地强制实施安全限制或防止用户意外地访问无初始化参数的servlet。如果你禁止了缺省的URL,那么你怎样访问servlet呢?这时只有使用定制的URL了。
为了分配一个定制的URL,可使用servlet-mapping元素及其servlet-name和url-pattern子元素。Servlet- name元素提供了一个任意名称,可利用此名称引用相应的servlet;url-pattern描述了相对于Web应用的根目录的URL。url- pattern元素的值必须以斜杠(/)起始。
下面给出一个简单的web.xml摘录,它允许使用URL
http://host/webAppPrefix/UrlTest而不是http://host/webAppPrefix/servlet/Test
http: //host/webAppPrefix/servlet/moreservlets.TestServlet。请注意,仍然需要XML头、 DOCTYPE声明以及web-app封闭元素。此外,可回忆一下,XML元素出现地次序不是随意的。特别是,需要把所有servlet元素放在所有 servlet-mapping元素之前。
<servlet>
<servlet-name>Test</servlet-name>
<servlet-class>moreservlets.TestServlet</servlet-class>
</servlet>
<!-- ... -->
<servlet-mapping>
<servlet-name>Test</servlet-name>
<url-pattern>/UrlTest</url-pattern>
</servlet-mapping>
URL模式还可以包含通配符。例如,下面的小程序指示服务器发送所有以Web应用的URL前缀开始,以..asp结束的请求到名为BashMS的servlet。
<servlet>
<servlet-name>BashMS</servlet-name>
<servlet-class>msUtils.ASPTranslator</servlet-class>
</servlet>
<!-- ... -->
<servlet-mapping>
<servlet-name>BashMS</servlet-name>
<url-pattern>/*.asp</url-pattern>
</servlet-mapping>
3.3 命名JSP页面
因为JSP页面要转换成sevlet,自然希望就像命名servlet一样命名JSP页面。毕竟,JSP页面可能会从初始化参数、安全设置或定制的URL中受益,正如普通的serlvet那样。虽然JSP页面的后台实际上是servlet这句话是正确的,但存在一个关键的猜疑:即,你不知道JSP页面的实际类名(因为系统自己挑选这个名字)。因此,为了命名JSP页面,可将jsp-file元素替换为servlet-calss元素,如下所示:
<servlet>
<servlet-name>Test</servlet-name>
<jsp-file>/TestPage.jsp</jsp-file>
</servlet>
命名JSP页面的原因与命名servlet的原因完全相同:即为了提供一个与定制设置(如,初始化参数和安全设置)一起使用的名称,并且,以便能更改激活 JSP页面的URL(比方说,以便多个URL通过相同页面得以处理,或者从URL中去掉.jsp扩展名)。但是,在设置初始化参数时,应该注意,JSP页面是利用jspInit方法,而不是init方法读取初始化参数的。
例如,程序清单5-3给出一个名为TestPage.jsp的简单JSP页面,它的工作只是打印出用来激活它的URL的本地部分。TestPage.jsp放置在deployDemo应用的顶层。程序清单5-4给出了用来分配一个注册名PageName,然后将此注册名与
http://host/webAppPrefix/UrlTest2/anything 形式的URL相关联的web.xml文件(即,deployDemo/WEB-INF/web.xml)的一部分。

程序清单5-3 TestPage.jsp
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML>
<HEAD>
<TITLE>
JSP Test Page
</TITLE>
</HEAD>
<BODY BGCOLOR="#FDF5E6">
<H2>URI: <%= request.getRequestURI() %></H2>
</BODY>
</HTML>


程序清单5-4 web.xml(说明JSP页命名的摘录)
<?xml version="1.0" encoding="ISO-8859-1"?>
<!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>PageName</servlet-name>
<jsp-file>/TestPage.jsp</jsp-file>
</servlet>
<!-- ... -->
<servlet-mapping>
<servlet-name> PageName </servlet-name>
<url-pattern>/UrlTest2/*</url-pattern>
</servlet-mapping>
<!-- ... -->
</web-app>


4 禁止激活器servlet

对servlet或JSP页面建立定制URL的一个原因是,这样做可以注册从 init(servlet)或jspInit(JSP页面)方法中读取得初始化参数。但是,初始化参数只在是利用定制URL模式或注册名访问 servlet或JSP页面时可以使用,用缺省URL
http://host/webAppPrefix/servlet/ServletName 访问时不能使用。因此,你可能会希望关闭缺省URL,这样就不会有人意外地调用初始化servlet了。这个过程有时称为禁止激活器servlet,因为多数服务器具有一个用缺省的servlet URL注册的标准servlet,并激活缺省的URL应用的实际servlet。
有两种禁止此缺省URL的主要方法:
l 在每个Web应用中重新映射/servlet/模式。
l 全局关闭激活器servlet。
重要的是应该注意到,虽然重新映射每个Web应用中的/servlet/模式比彻底禁止激活servlet所做的工作更多,但重新映射可以用一种完全可移植的方式来完成。相反,全局禁止激活器servlet完全是针对具体机器的,事实上有的服务器(如ServletExec)没有这样的选择。下面的讨论对每个Web应用重新映射/servlet/ URL模式的策略。后面提供在Tomcat中全局禁止激活器servlet的详细内容。
4.1 重新映射/servlet/URL模式
在一个特定的Web应用中禁止以
http://host/webAppPrefix/servlet/ 开始的URL的处理非常简单。所需做的事情就是建立一个错误消息servlet,并使用前一节讨论的url-pattern元素将所有匹配请求转向该 servlet。只要简单地使用:
<url-pattern>/servlet/*</url-pattern>
作为servlet-mapping元素中的模式即可。
例如,程序清单5-5给出了将SorryServlet servlet(程序清单5-6)与所有以
http://host/webAppPrefix/servlet/ 开头的URL相关联的部署描述符文件的一部分。

程序清单5-5 web.xml(说明JSP页命名的摘录)
<?xml version="1.0" encoding="ISO-8859-1"?>
<!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>Sorry</servlet-name>
<servlet-class>moreservlets.SorryServlet</servlet-class>
</servlet>
<!-- ... -->
<servlet-mapping>
<servlet-name> Sorry </servlet-name>
<url-pattern>/servlet/*</url-pattern>
</servlet-mapping>
<!-- ... -->
</web-app>


程序清单5-6 SorryServlet.java
package moreservlets;

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

/** Simple servlet used to give error messages to
* users who try to access default servlet URLs
* (i.e.,
http://host/webAppPrefix/servlet/ServletName)
* in Web applications that have disabled this
* behavior.
* <P>
* Taken from More Servlets and JavaServer Pages
* from Prentice Hall and Sun Microsystems Press,
*
http://www.moreservlets.com/.
* © 2002 Marty Hall; may be freely used or adapted.
*/

public class SorryServlet extends HttpServlet {
public void doGet(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html");
PrintWriter out = response.getWriter();
String title = "Invoker Servlet Disabled.";
out.println(ServletUtilities.headWithTitle(title) +
"<BODY BGCOLOR=\"#FDF5E6\">\n" +
"<H2>" + title + "</H2>\n" +
"Sorry, access to servlets by means of\n" +
"URLs that begin with\n" +
"
http://host/webAppPrefix/servlet/\n" +
"has been disabled.\n" +
"</BODY></HTML>");
}

public void doPost(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}


4.2 全局禁止激活器:Tomcat
Tomcat 4中用来关闭缺省URL的方法与Tomcat 3中所用的很不相同。下面介绍这两种方法:
1.禁止激活器: Tomcat 4
Tomcat 4用与前面相同的方法关闭激活器servlet,即利用web.xml中的url-mapping元素进行关闭。不同之处在于Tomcat使用了放在 install_dir/conf中的一个服务器专用的全局web.xml文件,而前面使用的是存放在每个Web应用的WEB-INF目录中的标准 web.xml文件。
因此,为了在Tomcat 4中关闭激活器servlet,只需在install_dir/conf/web.xml中简单地注释出/servlet/* URL映射项即可,如下所示:
<!--
<servlet-mapping>
<servlet-name>invoker</servlet-name>
<url-pattern>/servlet/*</url-pattern>
</servlet-mapping>
-->
再次提醒,应该注意这个项是位于存放在install_dir/conf的Tomcat专用的web.xml文件中的,此文件不是存放在每个Web应用的WEB-INF目录中的标准web.xml。
2.禁止激活器:Tomcat3
在Apache Tomcat的版本3中,通过在install_dir/conf/server.xml中注释出InvokerInterceptor项全局禁止缺省 servlet URL。例如,下面是禁止使用缺省servlet URL的server.xml文件的一部分。
<!--
<RequsetInterceptor
className="org.apache.tomcat.request.InvokerInterceptor"
debug="0" prefix="/servlet/" />
-->

5 初始化和预装载servlet与JSP页面

这里讨论控制servlet和JSP页面的启动行为的方法。特别是,说明了怎样分配初始化参数以及怎样更改服务器生存期中装载servlet和JSP页面的时刻。
5.1 分配servlet初始化参数
利用init-param元素向servlet提供初始化参数,init-param元素具有param-name和param-value子元素。例如,在下面的例子中,如果initServlet servlet是利用它的注册名(InitTest)访问的,它将能够从其方法中调用getServletConfig(). getInitParameter("param1")获得"Value 1",调用getServletConfig().getInitParameter("param2")获得"2"。
<servlet>
<servlet-name>InitTest</servlet-name>
<servlet-class>moreservlets.InitServlet</servlet-class>
<init-param>
<param-name>param1</param-name>
<param-value>value1</param-value>
</init-param>
<init-param>
<param-name>param2</param-name>
<param-value>2</param-value>
</init-param>
</servlet>
在涉及初始化参数时,有几点需要注意:
l 返回值。GetInitParameter的返回值总是一个String。因此,在前一个例子中,可对param2使用Integer.parseInt获得一个int。
l JSP中的初始化。JSP页面使用jspInit而不是init。JSP页面还需要使用jsp-file元素代替servlet-class。
l 缺省URL。初始化参数只在通过它们的注册名或与它们注册名相关的定制URL模式访问Servlet时可以使用。因此,在这个例子中,param1和 param2初始化参数将能够在使用URL
http://host/webAppPrefix/servlet/InitTest 时可用,但在使用URL http://host/webAppPrefix/servlet/myPackage.InitServlet 时不能使用。
例如,程序清单5-7给出一个名为InitServlet的简单servlet,它使用init方法设置firstName和emailAddress字段。程序清单5-8给出分配名称InitTest给servlet的web.xml文件。
程序清单5-7 InitServlet.java
package moreservlets;

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

/** Simple servlet used to illustrate servlet
* initialization parameters.
* <P>
* Taken from More Servlets and JavaServer Pages
* from Prentice Hall and Sun Microsystems Press,
*
http://www.moreservlets.com/.
* © 2002 Marty Hall; may be freely used or adapted.
*/

public class InitServlet extends HttpServlet {
private String firstName, emailAddress;

public void init() {
ServletConfig config = getServletConfig();
firstName = config.getInitParameter("firstName");
emailAddress = config.getInitParameter("emailAddress");
}

public void doGet(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html");
PrintWriter out = response.getWriter();
String uri = request.getRequestURI();
out.println(ServletUtilities.headWithTitle("Init Servlet") +
"<BODY BGCOLOR=\"#FDF5E6\">\n" +
"<H2>Init Parameters:</H2>\n" +
"<UL>\n" +
"<LI>First name: " + firstName + "\n" +
"<LI>Email address: " + emailAddress + "\n" +
"</UL>\n" +
"</BODY></HTML>");
}
}


程序清单5-8 web.xml(说明初始化参数的摘录)
<?xml version="1.0" encoding="ISO-8859-1"?>
<!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>InitTest</servlet-name>
<servlet-class>moreservlets.InitServlet</servlet-class>
<init-param>
<param-name>firstName</param-name>
<param-value>Larry</param-value>
</init-param>
<init-param>
<param-name>emailAddress</param-name>
<param-value>
Ellison@Microsoft.com</param-value>
</init-param>
</servlet>
<!-- ... -->
</web-app>

5.2 分配JSP初始化参数
给JSP页面提供初始化参数在三个方面不同于给servlet提供初始化参数。
1)使用jsp-file而不是servlet-class。因此,WEB-INF/web.xml文件的servlet元素如下所示:
<servlet>
<servlet-name>PageName</servlet-name>
<jsp-file>/RealPage.jsp</jsp-file>
<init-param>
<param-name>...</param-name>
<param-value>...</param-value>
</init-param>
...
</servlet>
2) 几乎总是分配一个明确的URL模式。对servlet,一般相应地使用以
http://host/webAppPrefix/servlet/ 开始的缺省URL。只需记住,使用注册名而不是原名称即可。这对于JSP页面在技术上也是合法的。例如,在上面给出的例子中,可用URL http://host/webAppPrefix/servlet/PageName 访问RealPage.jsp的对初始化参数具有访问权的版本。但在用于JSP页面时,许多用户似乎不喜欢应用常规的servlet的URL。此外,如果 JSP页面位于服务器为其提供了目录清单的目录中(如,一个既没有index.html也没有index.jsp文件的目录),则用户可能会连接到此 JSP页面,单击它,从而意外地激活未初始化的页面。因此,好的办法是使用url-pattern(5.3节)将JSP页面的原URL与注册的 servlet名相关联。这样,客户机可使用JSP页面的普通名称,但仍然激活定制的版本。例如,给定来自项目1的servlet定义,可使用下面的 servlet-mapping定义:
<servlet-mapping>
<servlet-name>PageName</servlet-name>
<url-pattern>/RealPage.jsp</url-pattern>
</servlet-mapping>
3)JSP页使用jspInit而不是init。自动从JSP页面建立的servlet或许已经使用了inti方法。因此,使用JSP声明提供一个init方法是不合法的,必须制定jspInit方法。
为了说明初始化JSP页面的过程,程序清单5-9给出了一个名为InitPage.jsp的JSP页面,它包含一个jspInit方法且放置于 deployDemo Web应用层次结构的顶层。一般,
http://host/deployDemo/InitPage.jsp 形式的URL将激活此页面的不具有初始化参数访问权的版本,从而将对firstName和emailAddress变量显示null。但是, web.xml文件(程序清单5-10)分配了一个注册名,然后将该注册名与URL模式/InitPage.jsp相关联。

程序清单5-9 InitPage.jsp
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML>
<HEAD><TITLE>JSP Init Test</TITLE></HEAD>
<BODY BGCOLOR="#FDF5E6">
<H2>Init Parameters:</H2>
<UL>
<LI>First name: <%= firstName %>
<LI>Email address: <%= emailAddress %>
</UL>
</BODY></HTML>
<%!
private String firstName, emailAddress;

public void jspInit() {
ServletConfig config = getServletConfig();
firstName = config.getInitParameter("firstName");
emailAddress = config.getInitParameter("emailAddress");
}
%>


程序清单5-10 web.xml(说明JSP页面的init参数的摘录)
<?xml version="1.0" encoding="ISO-8859-1"?>
<!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>InitPage</servlet-name>
<jsp-file>/InitPage.jsp</jsp-file>
<init-param>
<param-name>firstName</param-name>
<param-value>Bill</param-value>
</init-param>
<init-param>
<param-name>emailAddress</param-name>
<param-value>
gates@oracle.com</param-value>
</init-param>
</servlet>
<!-- ... -->
<servlet-mapping>
<servlet-name> InitPage</servlet-name>
<url-pattern>/InitPage.jsp</url-pattern>
</servlet-mapping>
<!-- ... -->
</web-app>


5.3 提供应用范围内的初始化参数
一般,对单个地servlet或JSP页面分配初始化参数。指定的servlet或JSP页面利用ServletConfig的getInitParameter方法读取这些参数。但是,在某些情形下,希望提供可由任意servlet或JSP页面借助ServletContext的getInitParameter方法读取的系统范围内的初始化参数。
可利用context-param元素声明这些系统范围内的初始化值。context-param元素应该包含param-name、param-value以及可选的description子元素,如下所示:
<context-param>
<param-name>support-email</param-name>
<param-value>
blackhole@mycompany.com</param-value>
</context-param>
可回忆一下,为了保证可移植性,web.xml内的元素必须以正确的次序声明。但这里应该注意,context-param元素必须出现任意与文档有关的元素(icon、display-name或description)之后及filter、filter-mapping、listener或 servlet元素之前。
5.4 在服务器启动时装载servlet
假如servlet或JSP页面有一个要花很长时间执行的init (servlet)或jspInit(JSP)方法。例如,假如init或jspInit方法从某个数据库或ResourceBundle查找产量。这种情况下,在第一个客户机请求时装载servlet的缺省行为将对第一个客户机产生较长时间的延迟。因此,可利用servlet的load-on- startup元素规定服务器在第一次启动时装载servlet。下面是一个例子。
<servlet>
<servlet-name> … </servlet-name>
<servlet-class> … </servlet-class> <!-- Or jsp-file -->
<load-on-startup/>
</servlet>
可以为此元素体提供一个整数而不是使用一个空的load-on-startup。想法是服务器应该在装载较大数目的servlet或JSP页面之前装载较少数目的servlet或JSP页面。例如,下面的servlet项(放置在Web应用的WEB-INF目录下的web.xml文件中的web-app元素内)将指示服务器首先装载和初始化SearchServlet,然后装载和初始化由位于Web应用的result目录中的index.jsp文件产生的 servlet。
<servlet>
<servlet-name>Search</servlet-name>
<servlet-class>myPackage.SearchServlet</servlet-class> <!-- Or jsp-file -->
<load-on-startup>1</load-on-startup>
</servlet>
<servlet>
<servlet-name>Results</servlet-name>
<servlet-class>/results/index.jsp</servlet-class> <!-- Or jsp-file -->
<load-on-startup>2</load-on-startup>
</servlet>

6 声明过滤器

servlet版本2.3引入了过滤器的概念。虽然所有支持servlet API版本2.3的服务器都支持过滤器,但为了使用与过滤器有关的元素,必须在web.xml中使用版本2.3的DTD。
过滤器可截取和修改进入一个servlet或JSP页面的请求或从一个servlet或JSP页面发出的相应。在执行一个servlet或JSP页面之前,必须执行第一个相关的过滤器的doFilter方法。在该过滤器对其FilterChain对象调用doFilter时,执行链中的下一个过滤器。如果没有其他过滤器,servlet或JSP页面被执行。过滤器具有对到来的ServletRequest对象的全部访问权,因此,它们可以查看客户机名、查找到来的cookie等。为了访问servlet或JSP页面的输出,过滤器可将响应对象包裹在一个替身对象(stand-in object)中,比方说把输出累加到一个缓冲区。在调用FilterChain对象的doFilter方法之后,过滤器可检查缓冲区,如有必要,就对它进行修改,然后传送到客户机。
例如,程序清单5-11帝国难以了一个简单的过滤器,只要访问相关的servlet或JSP页面,它就截取请求并在标准输出上打印一个报告(开发过程中在桌面系统上运行时,大多数服务器都可以使用这个过滤器)。

程序清单5-11 ReportFilter.java
package moreservlets;

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

/** Simple filter that prints a report on the standard output
* whenever the associated servlet or JSP page is accessed.
* <P>
* Taken from More Servlets and JavaServer Pages
* from Prentice Hall and Sun Microsystems Press,
*
http://www.moreservlets.com/.
* © 2002 Marty Hall; may be freely used or adapted.
*/

public class ReportFilter implements Filter {
public void doFilter(ServletRequest request,
ServletResponse response,
FilterChain chain)
throws ServletException, IOException {
HttpServletRequest req = (HttpServletRequest)request;
System.out.println(req.getRemoteHost() +
" tried to access " +
req.getRequestURL() +
" on " + new Date() + ".");
chain.doFilter(request,response);
}

public void init(FilterConfig config)
throws ServletException {
}

public void destroy() {}
}

一旦建立了一个过滤器,可以在web.xml中利用filter元素以及filter-name(任意名称)、file-class(完全限定的类名)和(可选的)init-params子元素声明它。请注意,元素在web.xml的web-app元素中出现的次序不是任意的;允许服务器(但不是必需的)强制所需的次序,并且实际中有些服务器也是这样做的。但这里要注意,所有filter元素必须出现在任意filter-mapping元素之前, filter-mapping元素又必须出现在所有servlet或servlet-mapping元素之前。
例如,给定上述的ReportFilter类,可在web.xml中作出下面的filter声明。它把名称Reporter与实际的类ReportFilter(位于moreservlets程序包中)相关联。
<filter>
<filter-name>Reporter</filter-name>
<filter-class>moresevlets.ReportFilter</filter-class>
</filter>
一旦命名了一个过滤器,可利用filter-mapping元素把它与一个或多个servlet或JSP页面相关联。关于此项工作有两种选择。
首先,可使用filter-name和servlet-name子元素把此过滤器与一个特定的servlet名(此servlet名必须稍后在相同的 web.xml文件中使用servlet元素声明)关联。例如,下面的程序片断指示系统只要利用一个定制的URL访问名为SomeServletName 的servlet或JSP页面,就运行名为Reporter的过滤器。
<filter-mapping>
<filter-name>Reporter</filter-name>
<servlet-name>SomeServletName</servlet-name>
</filter-mapping>
其次,可利用filter-name和url-pattern子元素将过滤器与一组servlet、JSP页面或静态内容相关联。例如,相面的程序片段指示系统只要访问Web应用中的任意URL,就运行名为Reporter的过滤器。
<filter-mapping>
<filter-name>Reporter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
例如,程序清单5-12给出了将ReportFilter过滤器与名为PageName的servlet相关联的web.xml文件的一部分。名字 PageName依次又与一个名为TestPage.jsp的JSP页面以及以模式http: //host/webAppPrefix/UrlTest2/ 开头的URL相关联。TestPage.jsp的源代码已经JSP页面命名的谈论在前面的3节"分配名称和定制的URL"中给出。事实上,程序清单5- 12中的servlet和servlet-name项从该节原封不动地拿过来的。给定这些web.xml项,可看到下面的标准输出形式的调试报告(换行是为了容易阅读)。
audit.irs.gov tried to access
http://mycompany.com/deployDemo/UrlTest2/business/tax-plan.html
on Tue Dec 25 13:12:29 EDT 2001.

程序清单5-12 Web.xml(说明filter用法的摘录)
<?xml version="1.0" encoding="ISO-8859-1"?>
<!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>
<filter>
<filter-name>Reporter</filter-name>
<filter-class>moresevlets.ReportFilter</filter-class>
</filter>
<!-- ... -->
<filter-mapping>
<filter-name>Reporter</filter-name>
<servlet-name>PageName</servlet-name>
</filter-mapping>
<!-- ... -->
<servlet>
<servlet-name>PageName</servlet-name>
<jsp-file>/RealPage.jsp</jsp-file>
</servlet>
<!-- ... -->
<servlet-mapping>
<servlet-name> PageName </servlet-name>
<url-pattern>/UrlTest2/*</url-pattern>
</servlet-mapping>
<!-- ... -->
</web-app>


7 指定欢迎页

假如用户提供了一个像http: //host/webAppPrefix/directoryName/ 这样的包含一个目录名但没有包含文件名的URL,会发生什么事情呢?用户能得到一个目录表?一个错误?还是标准文件的内容?如果得到标准文件内容,是 index.html、index.jsp、default.html、default.htm或别的什么东西呢?
Welcome-file-list 元素及其辅助的welcome-file元素解决了这个模糊的问题。例如,下面的web.xml项指出,如果一个URL给出一个目录名但未给出文件名,服务器应该首先试用index.jsp,然后再试用index.html。如果两者都没有找到,则结果有赖于所用的服务器(如一个目录列表)。
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
<welcome-file>index.html</welcome-file>
</welcome-file-list>
虽然许多服务器缺省遵循这种行为,但不一定必须这样。因此,明确地使用welcom-file-list保证可移植性是一种良好的习惯。

8 指定处理错误的页面

现在我了解到,你在开发servlet和JSP页面时从不会犯错误,而且你的所有页面是那样的清晰,一般的程序员都不会被它们的搞糊涂。但是,是人总会犯错误的,用户可能会提供不合规定的参数,使用不正确的URL或者不能提供必需的表单字段值。除此之外,其它开发人员可能不那么细心,他们应该有些工具来克服自己的不足。
error-page元素就是用来克服这些问题的。它有两个可能的子元素,分别是:error-code和exception- type。第一个子元素error-code指出在给定的HTTP错误代码出现时使用的URL。第二个子元素excpetion-type指出在出现某个给定的Java异常但未捕捉到时使用的URL。error-code和exception-type都利用location元素指出相应的URL。此 URL必须以/开始。location所指出的位置处的页面可通过查找HttpServletRequest对象的两个专门的属性来访问关于错误的信息,这两个属性分别是:javax.servlet.error.status_code和javax.servlet.error.message。
可回忆一下,在web.xml内以正确的次序声明web-app的子元素很重要。这里只要记住,error-page出现在web.xml文件的末尾附近,servlet、servlet-name和welcome-file-list之后即可。

8.1 error-code元素
为了更好地了解error-code元素的值,可考虑一下如果不正确地输入文件名,大多数站点会作出什么反映。这样做一般会出现一个404错误信息,它表示不能找到该文件,但几乎没提供更多有用的信息。另一方面,可以试一下在
www.microsoft.comwww.ibm.com 处或者特别是在www.bea.com 处输出未知的文件名。这是会得出有用的消息,这些消息提供可选择的位置,以便查找感兴趣的页面。提供这样有用的错误页面对于Web应用来说是很有价值得。事实上rm-error-page子元素)。由form-login-page给出的HTML表单必须具有一个j_security_check的 ACTION属性、一个名为j_username的用户名文本字段以及一个名为j_password的口令字段。
例如,程序清单5-19指示服务器使用基于表单的验证。Web应用的顶层目录中的一个名为login.jsp的页面将收集用户名和口令,并且失败的登陆将由相同目录中名为login-error.jsp的页面报告。

程序清单5-19 web.xml(说明login-config的摘录)
<?xml version="1.0" encoding="ISO-8859-1"?>
<!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>
<!-- ... -->
<security-constraint> ... </security-constraint>
<login-config>
<auth-method> FORM </auth-method>
<form-login-config>
<form-login-page>/login.jsp</form-login-page>
<form-error-page>/login-error.jsp</form-error-page>
</form-login-config>
</login-config>
<!-- ... -->
</web-app>


9.2 限制对Web资源的访问
现在,可以指示服务器使用何种验证方法了。"了不起,"你说道,"除非我能指定一个来收到保护的 URL,否则没有多大用处。"没错。指出这些URL并说明他们应该得到何种保护正是security-constriaint元素的用途。此元素在 web.xml中应该出现在login-config的紧前面。它包含是个可能的子元素,分别是:web-resource-collection、 auth-constraint、user-data-constraint和display-name。下面各小节对它们进行介绍。
l web-resource-collection
此元素确定应该保护的资源。所有security-constraint元素都必须包含至少一个web-resource-collection项。此元素由一个给出任意标识名称的web-resource-name元素、一个确定应该保护的URL的url-pattern元素、一个指出此保护所适用的 HTTP命令(GET、POST等,缺省为所有方法)的http-method元素和一个提供资料的可选description元素组成。例如,下面的 Web-resource-collection项(在security-constratint元素内)指出Web应用的proprietary目录中所有文档应该受到保护。
<security-constraint>
<web-resource-coolection>
<web-resource-name>Proprietary</web-resource-name>
<url-pattern>/propritary/*</url-pattern>
</web-resource-coolection>
<!-- ... -->
</security-constraint>
重要的是应该注意到,url-pattern仅适用于直接访问这些资源的客户机。特别是,它不适合于通过MVC体系结构利用 RequestDispatcher来访问的页面,或者不适合于利用类似jsp:forward的手段来访问的页面。这种不匀称如果利用得当的话很有好处。例如,servlet可利用MVC体系结构查找数据,把它放到bean中,发送请求到从bean中提取数据的JSP页面并显示它。我们希望保证决不直接访问受保护的JSP页面,而只是通过建立该页面将使用的bean的servlet来访问它。url-pattern和auth-contraint元素可通过声明不允许任何用户直接访问JSP页面来提供这种保证。但是,这种不匀称的行为可能让开发人员放松警惕,使他们偶然对应受保护的资源提供不受限制的访问。
l auth-constraint
尽管web-resource-collention元素质出了哪些URL应该受到保护,但是auth-constraint元素却指出哪些用户应该具有受保护资源的访问权。此元素应该包含一个或多个标识具有访问权限的用户类别role- name元素,以及包含(可选)一个描述角色的description元素。例如,下面web.xml中的security-constraint元素部门规定只有指定为Administrator或Big Kahuna(或两者)的用户具有指定资源的访问权。
<security-constraint>
<web-resource-coolection> ... </web-resource-coolection>
<auth-constraint>
<role-name>administrator</role-name>
<role-name>kahuna</role-name>
</auth-constraint>
</security-constraint>
重要的是认识到,到此为止,这个过程的可移植部分结束了。服务器怎样确定哪些用户处于任何角色以及它怎样存放用户的口令,完全有赖于具体的系统。
例如,Tomcat使用install_dir/conf/tomcat-users.xml将用户名与角色名和口令相关联,正如下面例子中所示,它指出用户joe(口令bigshot)和jane(口令enaj)属于administrator和kahuna角色。
<tomcat-users>
<user name="joe" password="bigshot" roles="administrator,kahuna" />
<user name="jane" password="enaj" roles="kahuna" />
</tomcat-users>
l user-data-constraint
这个可选的元素指出在访问相关资源时使用任何传输层保护。它必须包含一个transport-guarantee子元素(合法值为NONE、 INTEGRAL或CONFIDENTIAL),并且可选地包含一个description元素。transport-guarantee为NONE值将对所用的通讯协议不加限制。INTEGRAL值表示数据必须以一种防止截取它的人阅读它的方式传送。虽然原理上(并且在未来的HTTP版本中),在 INTEGRAL和CONFIDENTIAL之间可能会有差别,但在当前实践中,他们都只是简单地要求用SSL。例如,下面指示服务器只允许对相关资源做 HTTPS连接:
<security-constraint>
<!-- ... -->
<user-data-constraint>
<transport-guarantee>CONFIDENTIAL</transport-guarantee>
</user-data-constraint>
</security-constraint>
l display-name
security-constraint的这个很少使用的子元素给予可能由GUI工具使用的安全约束项一个名称。
9.3 分配角色名
迄今为止,讨论已经集中到完全由容器(服务器)处理的安全问题之上了。但servlet以及JSP页面也能够处理它们自己的安全问题。
例如,容器可能允许用户从bigwig或bigcheese角色访问一个显示主管人员额外紧贴的页面,但只允许bigwig用户修改此页面的参数。完成这种更细致的控制的一种常见方法是调用HttpServletRequset的isUserInRole方法,并据此修改访问。
Servlet的 security-role-ref子元素提供出现在服务器专用口令文件中的安全角色名的一个别名。例如,假如编写了一个调用 request.isUserInRole("boss")的servlet,但后来该servlet被用在了一个其口令文件调用角色manager而不是boss的服务器中。下面的程序段使该servlet能够使用这两个名称中的任何一个。
<servlet>
<!-- ... -->
<security-role-ref>
<role-name>boss</role-name> <!-- New alias -->
<role-link>manager</role-link> <!-- Real name -->
</security-role-ref>
</servlet>
也可以在web-app内利用security-role元素提供将出现在role-name元素中的所有安全角色的一个全局列表。分别地生命角色使高级IDE容易处理安全信息。

10 控制会话超时

如果某个会话在一定的时间内未被访问,服务器可把它扔掉以节约内存。可利用HttpSession的setMaxInactiveInterval方法直接设置个别会话对象的超时值。如果不采用这种方法,则缺省的超时值由具体的服务器决定。但可利用session-config和session- timeout元素来给出一个适用于所有服务器的明确的超时值。超时值的单位为分钟,因此,下面的例子设置缺省会话超时值为三个小时(180分钟)。
<session-config>
<session-timeout>180</session-timeout>
</session-config>

11 Web应用的文档化

越来越多的开发环境开始提供servlet和JSP的直接支持。例子有Borland Jbuilder Enterprise Edition、Macromedia UltraDev、Allaire JRun Studio(写此文时,已被Macromedia收购)以及IBM VisuaAge for Java等。
大量的web.xml元素不仅是为服务器设计的,而且还是为可视开发环境设计的。它们包括icon、display-name和discription等。
可回忆一下,在web.xml内以适当地次序声明web-app子元素很重要。不过,这里只要记住icon、display-name和description是web.xml的web-app元素内的前三个合法元素即可。
l icon
icon元素指出GUI工具可用来代表Web应用的一个和两个图像文件。可利用small-icon元素指定一幅16 x 16的GIF或JPEG图像,用large-icon元素指定一幅32 x 32的图像。下面举一个例子:
<icon>
<small-icon>/images/small-book.gif</small-icon>
<large-icon>/images/tome.jpg</large-icon>
</icon>
l display-name
display-name元素提供GUI工具可能会用来标记此Web应用的一个名称。下面是个例子。
<display-name>Rare Books</display-name>
l description
description元素提供解释性文本,如下所示:
<description>
This Web application represents the store developed for
rare-books.com, an online bookstore specializing in rare
and limited-edition books.
</description>

12 关联文件与MIME类型

服务器一般都具有一种让Web站点管理员将文件扩展名与媒体相关联的方法。例如,将会自动给予名为mom.jpg的文件一个image/jpeg的MIME 类型。但是,假如你的Web应用具有几个不寻常的文件,你希望保证它们在发送到客户机时分配为某种MIME类型。mime-mapping元素(具有 extension和mime-type子元素)可提供这种保证。例如,下面的代码指示服务器将application/x-fubar的MIME类型分配给所有以.foo结尾的文件。
<mime-mapping>
<extension>foo</extension>
<mime-type>application/x-fubar</mime-type>
</mime-mapping>
或许,你的Web应用希望重载(override)标准的映射。例如,下面的代码将告诉服务器在发送到客户机时指定.ps文件作为纯文本(text/plain)而不是作为PostScript(application/postscript)。
<mime-mapping>
<extension>ps</extension>
<mime-type>application/postscript</mime-type>
</mime-mapping>


13 定位TLD

JSP taglib元素具有一个必要的uri属性,它给出一个TLD(Tag Library Descriptor)文件相对于Web应用的根的位置。TLD文件的实际名称在发布新的标签库版本时可能会改变,但我们希望避免更改所有现有JSP页面。此外,可能还希望使用保持taglib元素的简练性的一个简短的uri。这就是部署描述符文件的taglib元素派用场的所在了。Taglib包含两个子元素:taglib-uri和taglib-location。taglib-uri元素应该与用于JSP taglib元素的uri属性的东西相匹配。Taglib-location元素给出TLD文件的实际位置。例如,假如你将文件chart-tags- 1.3beta.tld放在WebApp/WEB-INF/tlds中。现在,假如web.xml在web-app元素内包含下列内容。
<taglib>
<taglib-uri>/charts.tld</taglib-uri>
<taglib-location>
/WEB-INF/tlds/chart-tags-1.3beta.tld
</taglib-location>
</taglib>
给出这个说明后,JSP页面可通过下面的简化形式使用标签库。
<%@ taglib uri="/charts.tld" prefix="somePrefix" %>

14 指定应用事件监听程序

应用事件监听器程序是建立或修改servlet环境或会话对象时通知的类。它们是servlet规范的版本2.3中的新内容。这里只简单地说明用来向Web应用注册一个监听程序的web.xml的用法。
注册一个监听程序涉及在web.xml的web-app元素内放置一个listener元素。在listener元素内,listener-class元素列出监听程序的完整的限定类名,如下所示:
<listener>
<listener-class>package.ListenerClass</listener-class>
</listener>
虽然listener元素的结构很简单,但请不要忘记,必须正确地给出web-app元素内的子元素的次序。listener元素位于所有的servlet 元素之前以及所有filter-mapping元素之后。此外,因为应用生存期监听程序是serlvet规范的2.3版本中的新内容,所以必须使用 web.xml DTD的2.3版本,而不是2.2版本。
例如,程序清单5-20给出一个名为ContextReporter的简单的监听程序,只要Web应用的Servlet-Context建立(如装载Web应用)或消除(如服务器关闭)时,它就在标准输出上显示一条消息。程序清单5-21给出此监听程序注册所需要的web.xml文件的一部分。

程序清单5-20 ContextReporterjava
package moreservlets;

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

/** Simple listener that prints a report on the standard output
* when the ServletContext is created or destroyed.
* <P>
* Taken from More Servlets and JavaServer Pages
* from Prentice Hall and Sun Microsystems Press,
*
http://www.moreservlets.com/.
* © 2002 Marty Hall; may be freely used or adapted.
*/

public class ContextReporter implements ServletContextListener {
public void contextInitialized(ServletContextEvent event) {
System.out.println("Context created on " +
new Date() + ".");
}

public void contextDestroyed(ServletContextEvent event) {
System.out.println("Context destroyed on " +
new Date() + ".");
}
}


程序清单5-21 web.xml(声明一个监听程序的摘录)
<?xml version="1.0" encoding="ISO-8859-1"?>
<!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>
<!-- ... -->
<filter-mapping> … </filter-mapping>
<listener>
<listener-class>package.ListenerClass</listener-class>
</listener>
<servlet> ... </servlet>
<!-- ... -->
</web-app>


15 J2EE元素

本节描述用作J2EE环境组成部分的Web应用的web.xml元素。这里将提供一个简明的介绍,详细内容可以参阅
http://java.sun.com/j2ee/j2ee-1_3-fr-spec.pdf的Java 2 Plantform Enterprise Edition版本1.3规范的第5章。
l distributable
distributable 元素指出,Web应用是以这样的方式编程的:即,支持集群的服务器可安全地在多个服务器上分布Web应用。例如,一个可分布的应用必须只使用 Serializable对象作为其HttpSession对象的属性,而且必须避免用实例变量(字段)来实现持续性。distributable元素直接出现在discription元素之后,并且不包含子元素或数据,它只是一个如下的标志。
<distributable />
l resource-env-ref
resource -env-ref元素声明一个与某个资源有关的管理对象。此元素由一个可选的description元素、一个resource-env-ref- name元素(一个相对于java:comp/env环境的JNDI名)以及一个resource-env-type元素(指定资源类型的完全限定的类),如下所示:
<resource-env-ref>
<resource-env-ref-name>
jms/StockQueue
</resource-env-ref-name>
<resource-env-ref-type>
javax.jms.Queue
</resource-env-ref-type>
</resource-env-ref>
l env-entry
env -entry元素声明Web应用的环境项。它由一个可选的description元素、一个env-entry-name元素(一个相对于java: comp/env环境JNDI名)、一个env-entry-value元素(项值)以及一个env-entry-type元素(java.lang程序包中一个类型的完全限定类名,java.lang.Boolean、java.lang.String等)组成。下面是一个例子:
<env-entry>
<env-entry-name>minAmout</env-entry-name>
<env-entry-value>100.00</env-entry-value>
<env-entry-type>minAmout</env-entry-type>
</env-entry>
l ejb-ref
ejb -ref元素声明对一个EJB的主目录的应用。它由一个可选的description元素、一个ejb-ref-name元素(相对于java: comp/env的EJB应用)、一个ejb-ref-type元素(bean的类型,Entity或Session)、一个home元素(bean的主目录接口的完全限定名)、一个remote元素(bean的远程接口的完全限定名)以及一个可选的ejb-link元素(当前bean链接的另一个 bean的名称)组成。
l ejb-local-ref
ejb-local-ref元素声明一个EJB的本地主目录的引用。除了用local-home代替home外,此元素具有与ejb-ref元素相同的属性并以相同的方式使用。

posted @ 2005-11-29 17:38 船夫 阅读(371) | 评论 (0)编辑 收藏

↑→40种网页常用小技巧(javascript)←↓------[不时之需](转自CJSDN)


1. oncontextmenu="window.event.returnValue=false" 将彻底屏蔽鼠标右键
<table border oncontextmenu=return(false)><td>no</table> 可用于Table

2. <body onselectstart="return false"> 取消选取、防止复制

3. onpaste="return false" 不准粘贴

4. oncopy="return false;" oncut="return false;" 防止复制

5. <link rel="Shortcut Icon" href="favicon.ico"> IE地址栏前换成自己的图标

6. <link rel="Bookmark" href="favicon.ico"> 可以在收藏夹中显示出你的图标

7. <input style="ime-mode:disabled"> 关闭输入法

8. 永远都会带着框架
<script language="JavaScript"><!--
if (window == top)top.location.href = "frames.htm"; //frames.htm为框架网页
// --></script>

9. 防止被人frame
<SCRIPT LANGUAGE=JAVASCRIPT><!--
if (top.location != self.location)top.location=self.location;
// --></SCRIPT>

10. 网页将不能被另存为
<noscript><iframe src=*.html></iframe></noscript>

11. <input type=button value=查看网页源代码
onclick="window.location = "view-source:"+ "http://www.pconline.com.cn"">

12.删除时确认
<a href="javascript:if(confirm("确实要删除吗?"))location="boos.asp?&areyou=删除&page=1"">删除</a>

13. 取得控件的绝对位置
//Javascript
<script language="Javascript">
function getIE(e){
var t=e.offsetTop;
var l=e.offsetLeft;
while(e=e.offsetParent){
t+=e.offsetTop;
l+=e.offsetLeft;
}
alert("top="+t+"/nleft="+l);
}
</script>

//VBScript
<script language="VBScript"><!--
function getIE()
dim t,l,a,b
set a=document.all.img1
t=document.all.img1.offsetTop
l=document.all.img1.offsetLeft
while a.tagName<>"BODY"
set a = a.offsetParent
t=t+a.offsetTop
l=l+a.offsetLeft
wend
msgbox "top="&t&chr(13)&"left="&l,64,"得到控件的位置"
end function
--></script>

14. 光标是停在文本框文字的最后
<script language="javascript">
function cc()
{
var e = event.srcElement;
var r =e.createTextRange();
r.moveStart("character",e.value.length);
r.collapse(true);
r.select();
}
</script>
<input type=text name=text1 value="123" onfocus="cc()">

15. 判断上一页的来源
javascript:
document.referrer

16. 最小化、最大化、关闭窗口
<object id=hh1 classid="clsid:ADB880A6-D8FF-11CF-9377-00AA003B7A11">
<param name="Command" value="Minimize"></object>
<object id=hh2 classid="clsid:ADB880A6-D8FF-11CF-9377-00AA003B7A11">
<param name="Command" value="Maximize"></object>
<OBJECT id=hh3 classid="clsid:adb880a6-d8ff-11cf-9377-00aa003b7a11">
<PARAM NAME="Command" VALUE="Close"></OBJECT>
<input type=button value=最小化 onclick=hh1.Click()>
<input type=button value=最大化 onclick=hh2.Click()>
<input type=button value=关闭 onclick=hh3.Click()>
本例适用于IE

17.屏蔽功能键Shift,Alt,Ctrl
<script>
function look(){
if(event.shiftKey)
alert("禁止按Shift键!"); //可以换成ALT CTRL
}
document.onkeydown=look;
</script>

18. 网页不会被缓存
<META HTTP-EQUIV="pragma" CONTENT="no-cache">
<META HTTP-EQUIV="Cache-Control" CONTENT="no-cache, must-revalidate">
<META HTTP-EQUIV="expires" CONTENT="Wed, 26 Feb 1997 08:21:57 GMT">
或者<META HTTP-EQUIV="expires" CONTENT="0">

19.怎样让表单没有凹凸感?
<input type=text style="border:1 solid #000000">

<input type=text style="border-left:none; border-right:none; border-top:none; border-bottom:

1 solid #000000"></textarea>

20.<div><span>&<layer>的区别?
<div>(division)用来定义大段的页面元素,会产生转行
<span>用来定义同一行内的元素,跟<div>的唯一区别是不产生转行
<layer>是ns的标记,ie不支持,相当于<div>

21.让弹出窗口总是在最上面:
<body onblur="this.focus();">

22.不要滚动条?
让竖条没有:
<body style="overflow:scroll;overflow-y:hidden">
</body>
让横条没有:
<body style="overflow:scroll;overflow-x:hidden">
</body>
两个都去掉?更简单了
<body scroll="no">
</body>

23.怎样去掉图片链接点击后,图片周围的虚线?
<a href="#" onFocus="this.blur()"><img src="logo.jpg" border=0></a>

24.电子邮件处理提交表单
<form name="form1" method="post" action="mailto:****@***.com" enctype="text/plain">
<input type=submit>
</form>

25.在打开的子窗口刷新父窗口的代码里如何写?
window.opener.location.reload()

26.如何设定打开页面的大小
<body onload="top.resizeTo(300,200);">
打开页面的位置<body onload="top.moveBy(300,200);">

27.在页面中如何加入不是满铺的背景图片,拉动页面时背景图不动
<STYLE>
body
{background-image:url(logo.gif); background-repeat:no-repeat;
background-position:center;background-attachment: fixed}
</STYLE>

28. 检查一段字符串是否全由数字组成
<script language="Javascript"><!--
function checkNum(str){return str.match(//D/)==null}
alert(checkNum("1232142141"))
alert(checkNum("123214214a1"))
// --></script>

29. 获得一个窗口的大小
document.body.clientWidth; document.body.clientHeight

30. 怎么判断是否是字符
if (/[^/x00-/xff]/g.test(s)) alert("含有汉字");
else alert("全是字符");

31.TEXTAREA自适应文字行数的多少
<textarea rows=1 name=s1 cols=27 onpropertychange="this.style.posHeight=this.scrollHeight">
</textarea>

32. 日期减去天数等于第二个日期
<script language=Javascript>
function cc(dd,dadd)
{
//可以加上错误处理
var a = new Date(dd)
a = a.valueOf()
a = a - dadd * 24 * 60 * 60 * 1000
a = new Date(a)
alert(a.getFullYear() + "年" + (a.getMonth() + 1) + "月" + a.getDate() + "日")
}
cc("12/23/2002",2)
</script>

33. 选择了哪一个Radio
<HTML><script language="vbscript">
function checkme()
for each ob in radio1
if ob.checked then window.alert ob.value
next
end function
</script><BODY>
<INPUT name="radio1" type="radio" value="style" checked>Style
<INPUT name="radio1" type="radio" value="barcode">Barcode
<INPUT type="button" value="check" onclick="checkme()">
</BODY></HTML>

34.脚本永不出错
<SCRIPT LANGUAGE="JavaScript">
<!-- Hide
function killErrors() {
return true;
}
window.onerror = killErrors;
// -->
</SCRIPT>

35.ENTER键可以让光标移到下一个输入框
<input onkeydown="if(event.keyCode==13)event.keyCode=9">

36. 检测某个网站的链接速度:
把如下代码加入<body>区域中:
<script language=Javascript>
tim=1
setInterval("tim++",100)
b=1
var autourl=new Array()
autourl[1]="www.njcatv.net"
autourl[2]="javacool.3322.net"
autourl[3]="www.sina.com.cn"
autourl[4]="www.nuaa.edu.cn"
autourl[5]="www.cctv.com"
function butt(){
document.write("<form name=autof>")
for(var i=1;i<autourl.length;i++)
document.write("<input type=text name=txt"+i+" size=10 value=测试中……> =》<input type=text
name=url"+i+" size=40> =》<input type=button value=GO

onclick=window.open(this.form.url"+i+".value)><br>")
document.write("<input type=submit value=刷新></form>")
}
butt()
function auto(url){
document.forms[0]["url"+b].value=url
if(tim>200)
{document.forms[0]["txt"+b].value="链接超时"}
else
{document.forms[0]["txt"+b].value="时间"+tim/10+"秒"}
b++
}
function run(){for(var i=1;i<autourl.length;i++)document.write("<img src=http://"+autourl+"/"+Math.random()+"

width=1 height=1

onerror=auto("http://"+autourl+"")>")}
run()</script>

37. 各种样式的光标
auto :标准光标
default :标准箭头
hand :手形光标
wait :等待光标
text :I形光标
vertical-text :水平I形光标
no-drop :不可拖动光标
not-allowed :无效光标
help :?帮助光标
all-scroll :三角方向标
move :移动标
crosshair :十字标
e-resize
n-resize
nw-resize
w-resize
s-resize
se-resize
sw-resize

38.页面进入和退出的特效
进入页面<meta http-equiv="Page-Enter" content="revealTrans(duration=x, transition=y)">
推出页面<meta http-equiv="Page-Exit" content="revealTrans(duration=x, transition=y)">
这个是页面被载入和调出时的一些特效。duration表示特效的持续时间,以秒为单位。transition表示使用哪种特效,取值为

1-23:
  0 矩形缩小
  1 矩形扩大
  2 圆形缩小
  3 圆形扩大
  4 下到上刷新
  5 上到下刷新
  6 左到右刷新
  7 右到左刷新
  8 竖百叶窗
  9 横百叶窗
  10 错位横百叶窗
  11 错位竖百叶窗
  12 点扩散
  13 左右到中间刷新
  14 中间到左右刷新
  15 中间到上下
  16 上下到中间
  17 右下到左上
  18 右上到左下
  19 左上到右下
  20 左下到右上
  21 横条
  22 竖条
  23 以上22种随机选择一种

39.在规定时间内跳转
<META http-equiv=V="REFRESH" content="5;URL=http://www.51js.com">

40.网页是否被检索
<meta name="ROBOTS" content="属性值">
  其中属性值有以下一些:
  属性值为"all": 文件将被检索,且页上链接可被查询;
  属性值为"none": 文件不被检索,而且不查询页上的链接;
  属性值为"index": 文件将被检索;
  属性值为"follow": 查询页上的链接;
  属性值为"noindex": 文件不检索,但可被查询链接;
  属性值为"nofollow": 文件不被检索,但可查询页上的链接。

posted @ 2005-11-29 09:27 船夫 阅读(222) | 评论 (0)编辑 收藏

无法刷新include的jsp的问题

      这几天在写web表现层的东西,由于对jsp不是很熟悉,在使用include的时候就遇到了问题。
      可能是用OOP久了,写什么都想封装起来,写jsp的时候就想使用include。我在一个parent.jsp中使用
<%@include file="sub.jsp"%>
include了一个sub.jsp,之后就发现我在刷新parent.jsp的时候不能同时刷新sub.jsp,百思不得其解,听高手说把IE的Cache禁用了就行了,但使用
<META HTTP-EQUIV="Cache-Control" CONTENT="no-cache">
这个禁了之后还是不行,最后到论坛上逛了一圈儿才发现原来是我的标签使用错了,应该使用jsp:include标签,@include file主要用于静态的内容引用,就相当于把被引用的文件代码(sub.jsp)直接copy到主页面(parent.jsp)中。而jsp:include可以随时更新sub.jsp的内容,只要把属性flush设为true。
要详细了解的可以看看以下两篇文章:
http://www-900.ibm.com/developerWorks/cn/java/j-jsp04153/
http://www-900.ibm.com/developerWorks/cn/java/j-jsp04293/

posted @ 2005-11-23 15:26 船夫 阅读(1610) | 评论 (1)编辑 收藏