首页 新闻 论坛 群组 Blog 文档 下载 读书 Tag 网摘 搜索 .NET Java 游戏 视频 人才 外包 数据库 第二书店 程序员

wukele/ 


共39个网摘 [ 1  2 ]  下一页  |  访问wukele的个人空间

Java EE系统 中文问题终极解决方案_小罗的空间

wukele收录,使用标签:java,时间:2008-4-9 15:12:09 | 相关网摘我也收藏

第一原则:所有编码的地方,统一设为UTF-8,这样繁体,简体,日文,韩文。。。通吃了)一、下载中文文件名文件问题
a)Tomcat:修改Tomcat安装目录下conf/server.xml文件,加上URIEncoding="UTF-8"/


b)JBOSS :安装目录下 server/default/deploy/jbossweb-tomcat55.sar/server.xml


二、表单get/post传递中文乱码我们用一个过滤器,将所有编码转换为UTF-8找到Tomcat安装目录下\webapps\jsp-examples\WEB-INF\classes\filters下RequestDumperFilter.java,SetCharacterEncodingFilter.java两个文件。加入到你的项目,修改包路径.在web.xml文件中部署这个过滤器

  Set Character Encoding
  SetCharacterEncodingFilter.java 的类路径
  
    encoding
    UTF-8
  


  Set Character Encoding
  /*



三、jsp页面模版所有jsp页面使用如下模版
<%@ page language="java" pageEncoding="UTF-8"%>











四、数据库以Unicode编码存储数据MySQL数据库设置
a)windows系统: windows下安装mysql时,编码选择utf-8,查看mysql安装目录下my,ini文件,在[mysqld]段下面加入default-character-set=utf8
b)linux系统:/etc/mysql/下my.cnf文件,在[mysqld]段下面加入default-character-set=utf8

五、JDBC连接参数注意:xml文件中,"&"是不能直接使用的, & 代替 &Mysql数据库jdbc 连接参数jdbc:mysql://localhost/kms?useUnicode=true&characterEncoding=utf-8sql server数据库jdbc连接参数(强烈建议使用JTDS驱动,比微软官方驱动更好)jdbc:jtds:sqlserver://localhost:1433/kms;TDS=8.0;charset=utf-8;SendStringParameterAsUnicode=true


如何管理复杂软件的源代码-Zeven - 新浪BLOG

wukele收录,使用标签:java,时间:2008-2-25 13:42:17 | 相关网摘我也收藏

如何管理复杂软件的源代码
介绍:
软件项目经常被视为是一个实体。所有的代码位于同一个树中。随着代码增长以及更多方面内容的加入,源代码变得越来越不可管理。代码维护起来也很麻烦。一种降低复杂性的方法是将源代码分割成许多独立的源代码树,而不是放在一个源代码树里面。工具能够辅助管理这些分割的组件,把这些依赖的部分囊括进来。开源项目如Tomcat 和 Apache 就采用的这种类似的处理方法,结果,它的许多小的工程在原父项目之外还具有生命。
在这篇文章中,我将讨论组件设计的重要性以及用于组件管理的工具。文章的内容对于任何想对软件项目的代码结构进行调优的人应该都有是有帮助的。

复杂性:
做为一个咨询顾问,我不得不经常处理新的技术、不同的商业领域以及在业务之间处理同一件事情的不同方法,这些大大降低了我的工作效率。即便是我在同一个复杂的项目上工作很长时间,要记住也项目中错综复杂的某一部分,也不是很容易的,我不得不每几个月花上2-3天来整理。
假如工作被划分为较小的项目,整理起来是不是就会容易些呢?这样每个小的项目都带有自己的单元测试、文档、以及ANT/MAVEN 脚本。
让我们来感受一下这种处理方式的好处吧。

给新开发者一个清晰的模型:
基于组件的解决方案更易于理解,特别是对于新的开发人员。因为每一个模块都有它自己的服务文档来突出说明该模块与众不同的方面。测试类通过模块来组织,因此很容易找到而且很规范统一。而且,对于工具性质的模块都有单元测试而业务处理性质模块都有函数测试。

为每个模块安排负责人:
在管理方面,我们可以遵循一个好的实践经验,那就是为每一块软件代码安排一个开发负责人。这个负责人主要对模块的测试和错误记录负责。该负责人的另外一个重要责任就是确保模块中的公共API的一致。为每个独立的模块安排负责人的做法比通过唯一的源代码树完成同样的工作要直截了当得多。

外部依赖:
从流通方面将,对一个系统较高的要求是比较有效的。产生或者创建依赖图形是表达的第一步,而且,也间接地描述组件的设计和功能。一个简单的 Microsoft Visio 图将会起到很大的作用。再就是对组件按照层次或者子系统进行分组,能够帮助开发者记住组件的外部依赖情况。采用Eclipse,你可以加强层次和依赖性的管理。

编译的策略:
在日常的编译中,编译时会发生故障,产生编译中断。编译中止往往是因为开发人员不了解类之间的依赖情况。在组件基础上做开发人人员,如果没有对公用的API做修改,应该能保证项目能正常编译。因为组件有很多考虑周密的接口,它的接口应该是很稳定的。因此,即便是一个模块中断了编译过程,作为临是的解决方法,采用这个模块的前一个版本应该能使编译完成。
同样的概念能应用的产品中,当需要打补丁的时候,为了安全起见,一般都倾向于重新发布所有的代码。从另一方面来说,如果补丁只是覆盖了某个组件的内部代码,仅仅发布该组件的一个新的版本也是安全的。

更多的开发选择:
在开发方面,如果运行在某些部署场合,如PDA中,使用小的组件会使得移除不必要的代码变得容易。而且用户通过模块管理时很容易转换为一种模型。然而,用户会因为有太多的jar文件感到困惑,那么有一个解决方法是对jar文件打包。下面的例子显示了将jar文件打包是很容易的事情。ANT 打包之后的压缩文件能起效是因为jar文件是一系列被压缩的文件。




这例子将 htdocs/manual 目录下面的所有文件打包到归档路径的 docs/user-guide 目录,而且包含当前目录下面的所有符合examples*.jar 条件的文件,例如所有在 examples1.jar 或者 examples2.jar中的文件。

软件可复用意识:
在源代码结构树上,采用组件而不是采用独立的类的一个重要原因是组件更加突出。开发者要添加一个新功能的时候,他首先想到的应该是采用已经存在的代码而不是拷贝/粘贴代码。

开源:
在商业方面,开源是一个团体共同分担维护成本的方法。并不是所有的组件都适合开源。开源的组件应该对于一个很大的群体有用。框架组件和UI组件往往适合开源,例如在HTML中产生通用的日历和表格的组件。
开源组件提供了免费的代码查看、错误报告和错误修复,所以开源组件质量好、灵活性强、价格便宜。我所谓的开源是组件的源代码免费可用。所以开源社团的贡献应该是在源代码级别的贡献。常用的开源许可证包括不允许软件产品的商业用途到有权修改代码并用于商业用途而不用开放修改内容。
开源站点,像 http://www.apache.org/ 和 http://sourceforge.net/,它们提供了许多被很多软件公司使用的工具。从这些站点上,你可以学到许多管理自己组件的方法。

更多的组件并不意味着更多的脚本代码:
在代码方面,更多的组件似乎要求更多的代码。然而,在代码中使用类的继承和复用能够减少代码副本。事实上,更多的使用组件会使得每个组件更加简短。因此结构更容易理解。

JAR文件配合不恰当:
在版本方面,当只有一个项目使用那些组件的时候,同时发布所有组件,同时把它们作为同一个版本来解决是比较容易的。当两个项目共享组件的时候,你会遇到项目1的代码已经固定而项目2仍然处于开发状态。在这种情况下,为了减少共享组件产生分歧,独立的发布共享组件是比较好的方法。Maven提供了一个可以选择特定的版本或者是最新版本的灵活的方法。

组件依赖管理:
在IDE开发工具方面,在Eclipse 中,每个组件都有自己的一个项目。在Eclipse中可以申明一个项目依赖于哪个项目(组件)。在Eclipse中,依赖对象可以设置为“外部对象”。举一个外部依赖的例子:如果组件1直接依赖组件2和组件3,而组件4有依赖于组件1,那么组件4也间接的依赖于组件2和组件3。

快速编译:
在重复方面,如果你不使用EJB,java中的编译非常快。然而,测试时要求经常性的编译,所以你必须尽可能的优化编译的内容。只有组件需要更新的时候才编译脚本,因而组件一般是不编译的。你可以在脚本中使用正则表达式设置过滤,指定必须包括或者不包括的组件。

可重复使用的依赖性申明:
许多项目采用IDE工具开发,而使用脚本语言如ANT自动编译和发布。不幸的是,这些工作需要多次重复的指定组件的位置和依赖性。这个应该是要避免的。NetBeans 将ANT作为一个底部基础项目,Eclipse却不是这样。然而,Eclipse的项目文件很简洁。因此,有一个方法是可行的,那就是从Eclipse项目中提取依赖性的定义供再ANT使用,或者是从ANT或者外部的XML文件产生Eclipse项目配置信息。

下面的例子显示了Eclipse的项目定义是很简洁的:
一个Eclipse项目定义总是由两个文件组成:.project文件和 .classpath文件。.classpath文件内容类似如下:







Eclipse 使用原始路径(kind="src")来指定当前项目所依赖的项目。[/AnotherComponent] 以斜杠打头表明它是一个被依赖的项目。
就如你上面看到的,产生和理解Eclipse项目中的依赖性是很简单的。

总结:
总之,我讲解了通过将代码模块化为一个外在的组件来阻止项目复杂性增长的方法。我们已经看到,通过基于组件的开发,能够帮助管理软件开发中如何提高软件复用意识、如何开源、如何较好的传播流通等各个方面。让我们尽力保持软件的简约(简约而不简单)。


Eclipse代码自动提示 - wheio8619的专栏 - CSDNBlog

wukele收录,使用标签:java,时间:2008-2-24 22:29:55 | 相关网摘我也收藏

【推荐】让Eclipse 支持 javascript 的代码提示^^
2007-01-25 11:57
使用一个插件,被Adobe 并构的 JSEclipse ^^

下载的时候需要注册一个用户。

将 JSEclipse_1.5.3.zip 解压的 plugins 和 features 目录复制到 eclipse 安装目录下覆盖同名文件夹(实际上原文件夹只是添加

了新文件而已,原内部文件和文件夹不会发生变化),然后删除 eclipse 的 configuration 目录下的 org.eclipse.update 文件夹

,重新启动 eclipse 让其重新读取新的配置。打开你的web项目中的 jsp 文件,在





区域里右键选中 JSEclispe 选项,就可以在有提示的环境下编辑 javascript 了。

编辑完毕之后记得保存哦^^。

运行 eclipse -clean 也可以让 eclipse 重新读取新配置







默认的是alt+/;
你也可以自己设置喜欢的快捷键
windows-->preference-->workbench-->keys-->下有个command
在第一列表框选择edit
在第二个列表框选择Content Assist
这个就是代码提示功能,
你可以设置为你喜欢的快捷键,如:ctrl+j;


一篇关于web.xml配置的详细说明 - surfer1212的专栏 - CSDNBlog

wukele收录,使用标签:java,时间:2008-2-21 22:14:35 | 相关网摘我也收藏


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

用web.xml控制Web应用的行为



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元素内),如下所示:

Test
moreservlets.TestServlet

这 表示位于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.
*
* 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") +
"\n" +
"URI: " + uri + "\n" +
"");
}
}


程序清单5-2 web.xml(说明servlet名称的摘录)

PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd">




Test
moreservlets.TestServlet




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元素之前。

Test
moreservlets.TestServlet



Test
/UrlTest

URL模式还可以包含通配符。例如,下面的小程序指示服务器发送所有以Web应用的URL前缀开始,以..asp结束的请求到名为BashMS的servlet。

BashMS
msUtils.ASPTranslator



BashMS
/*.asp

3.3 命名JSP页面
因 为JSP页面要转换成sevlet,自然希望就像命名servlet一样命名JSP页面。毕竟,JSP页面可能会从初始化参数、安全设置或定制的URL中 受益,正如普通的serlvet那样。虽然JSP页面的后台实际上是servlet这句话是正确的,但存在一个关键的猜疑:即,你不知道JSP页面的实际 类名(因为系统自己挑选这个名字)。因此,为了命名JSP页面,可将jsp-file元素替换为servlet-calss元素,如下所示:

Test
/TestPage.jsp

命 名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




JSP Test Page



URI: <%= request.getRequestURI() %>




程序清单5-4 web.xml(说明JSP页命名的摘录)

PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd">




PageName
/TestPage.jsp



PageName
/UrlTest2/*





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。只要简单地使用:
/servlet/*
作为servlet-mapping元素中的模式即可。
例如,程序清单5-5给出了将SorryServlet servlet(程序清单5-6)与所有以http://host/webAppPrefix/servlet/ 开头的URL相关联的部署描述符文件的一部分。

程序清单5-5 web.xml(说明JSP页命名的摘录)

PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd">




Sorry
moreservlets.SorryServlet



Sorry
/servlet/*





程序清单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.
*
* 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) +
"\n" +
"" + title + "\n" +
"Sorry, access to servlets by means of\n" +
"URLs that begin with\n" +
"http://host/webAppPrefix/servlet/\n" +
"has been disabled.\n" +
"");
}

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映射项即可,如下所示:

再次提醒,应该注意这个项是位于存放在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文件的一部分。


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"。

InitTest
moreservlets.InitServlet

param1
value1


param2
2


在涉及初始化参数时,有几点需要注意:
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.
*
* 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") +
"\n" +
"Init Parameters:\n" +
"\n" +
"First name: " + firstName + "\n" +
"Email address: " + emailAddress + "\n" +
"\n" +
"");
}
}


程序清单5-8 web.xml(说明初始化参数的摘录)

PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd">




InitTest
moreservlets.InitServlet

firstName
Larry


emailAddress
Ellison@Microsoft.com





5.2 分配JSP初始化参数
给JSP页面提供初始化参数在三个方面不同于给servlet提供初始化参数。
1)使用jsp-file而不是servlet-class。因此,WEB-INF/web.xml文件的servlet元素如下所示:

PageName
/RealPage.jsp

...
...

...

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定义:

PageName
/RealPage.jsp

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


JSP Init Test

Init Parameters:

First name: <%= firstName %>
Email address: <%= emailAddress %>


<%!
private String firstName, emailAddress;

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


程序清单5-10 web.xml(说明JSP页面的init参数的摘录)

PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd">




InitPage
/InitPage.jsp

firstName
Bill


emailAddress
gates@oracle.com




InitPage
/InitPage.jsp





5.3 提供应用范围内的初始化参数
一 般,对单个地servlet或JSP页面分配初始化参数。指定的servlet或JSP页面利用ServletConfig的 getInitParameter方法读取这些参数。但是,在某些情形下,希望提供可由任意servlet或JSP页面借助ServletContext 的getInitParameter方法读取的系统范围内的初始化参数。
可利用context-param元素声明这些系统范围内的初始化值。context-param元素应该包含param-name、param-value以及可选的description子元素,如下所示:

support-email
blackhole@mycompany.com

可 回忆一下,为了保证可移植性,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。下面是一个例子。





可 以为此元素体提供一个整数而不是使用一个空的load-on-startup。想法是服务器应该在装载较大数目的servlet或JSP页面之前装载较少 数目的servlet或JSP页面。例如,下面的servlet项(放置在Web应用的WEB-INF目录下的web.xml文件中的web-app元素 内)将指示服务器首先装载和初始化SearchServlet,然后装载和初始化由位于Web应用的result目录中的index.jsp文件产生的 servlet。

Search
myPackage.SearchServlet
1


Results
/results/index.jsp
2


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.
*
* 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程序包中)相关联。

Reporter
moresevlets.ReportFilter

一旦命名了一个过滤器,可利用filter-mapping元素把它与一个或多个servlet或JSP页面相关联。关于此项工作有两种选择。
首 先,可使用filter-name和servlet-name子元素把此过滤器与一个特定的servlet名(此servlet名必须稍后在相同的 web.xml文件中使用servlet元素声明)关联。例如,下面的程序片断指示系统只要利用一个定制的URL访问名为SomeServletName 的servlet或JSP页面,就运行名为Reporter的过滤器。

Reporter
SomeServletName

其次,可利用filter-name和url-pattern子元素将过滤器与一组servlet、JSP页面或静态内容相关联。例如,相面的程序片段指示系统只要访问Web应用中的任意URL,就运行名为Reporter的过滤器。

Reporter
/*

例 如,程序清单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用法的摘录)

PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd">



Reporter
moresevlets.ReportFilter



Reporter
PageName



PageName
/RealPage.jsp



PageName
/UrlTest2/*





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。如果两者都没有找到,则结果有赖于所用的服务器(如一个目录列表)。

index.jsp
index.html

虽然许多服务器缺省遵循这种行为,但不一定必须这样。因此,明确地使用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.com、www.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的摘录)

PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd">



...

FORM

/login.jsp
/login-error.jsp






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目录中 所有文档应该受到保护。


Proprietary
/propritary/*



重 要的是应该注意到,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(或两者)的用户具有指定资源的访问权。

...

administrator
kahuna


重要的是认识到,到此为止,这个过程的可移植部分结束了。服务器怎样确定哪些用户处于任何角色以及它怎样存放用户的口令,完全有赖于具体的系统。
例如,Tomcat使用install_dir/conf/tomcat-users.xml将用户名与角色名和口令相关联,正如下面例子中所示,它指出用户joe(口令bigshot)和jane(口令enaj)属于administrator和kahuna角色。




l user-data-constraint
这 个可选的元素指出在访问相关资源时使用任何传输层保护。它必须包含一个transport-guarantee子元素(合法值为NONE、 INTEGRAL或CONFIDENTIAL),并且可选地包含一个description元素。transport-guarantee为NONE值将 对所用的通讯协议不加限制。INTEGRAL值表示数据必须以一种防止截取它的人阅读它的方式传送。虽然原理上(并且在未来的HTTP版本中),在 INTEGRAL和CONFIDENTIAL之间可能会有差别,但在当前实践中,他们都只是简单地要求用SSL。例如,下面指示服务器只允许对相关资源做 HTTPS连接:



CONFIDENTIAL


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能够使用这两个名称中的任何一个。



boss
manager


也可以在web-app内利用security-role元素提供将出现在role-name元素中的所有安全角色的一个全局列表。分别地生命角色使高级IDE容易处理安全信息。

10 控制会话超时

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

180


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的图像。下面举一个例子:

/images/small-book.gif
/images/tome.jpg

l display-name
display-name元素提供GUI工具可能会用来标记此Web应用的一个名称。下面是个例子。
Rare Books
l description
description元素提供解释性文本,如下所示:

This Web application represents the store developed for
rare-books.com, an online bookstore specializing in rare
and limited-edition books.


12 关联文件与MIME类型

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

foo
application/x-fubar

或许,你的Web应用希望重载(override)标准的映射。例如,下面的代码将告诉服务器在发送到客户机时指定.ps文件作为纯文本(text/plain)而不是作为PostScript(application/postscript)。

ps
application/postscript



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元素内包含下列内容。

/charts.tld

/WEB-INF/tlds/chart-tags-1.3beta.tld


给出这个说明后,JSP页面可通过下面的简化形式使用标签库。
<%@ taglib uri="/charts.tld" prefix="somePrefix" %>

14 指定应用事件监听程序

应用事件监听器程序是建立或修改servlet环境或会话对象时通知的类。它们是servlet规范的版本2.3中的新内容。这里只简单地说明用来向Web应用注册一个监听程序的web.xml的用法。
注册一个监听程序涉及在web.xml的web-app元素内放置一个listener元素。在listener元素内,listener-class元素列出监听程序的完整的限定类名,如下所示:

package.ListenerClass

虽 然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.
*
* 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(声明一个监听程序的摘录)

PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd">





package.ListenerClass

...




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元素之后,并且不包含子元素或数据,它只是一个如下的标志。

l resource-env-ref
resource -env-ref元素声明一个与某个资源有关的管理对象。此元素由一个可选的description元素、一个resource-env-ref- name元素(一个相对于java:comp/env环境的JNDI名)以及一个resource-env-type元素(指定资源类型的完全限定的 类),如下所示:


jms/StockQueue


javax.jms.Queue


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等)组成。下面是一个例子:

minAmout
100.00
minAmout

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元素相同的属性并以相同的方式使用。


IdeaGrace博客 � Blog Archive � Struts2 入门实例代码

wukele收录,使用标签:java,时间:2008-2-21 15:42:19 | 相关网摘我也收藏

Struts2 入门实例代码
September 14, 2007 – 5:47 pm struts2

Struts.xml 文件

代码

"-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
"http://struts.apache.org/dtds/struts-2.0.dtd">






HelloWorld.xml

代码

"-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
"http://struts.apache.org/dtds/struts-2.0.dtd">












/WEB-INF/jsp/Logon.jsp



Main
/WEB-INF/jsp/Logon.jsp


/WEB-INF/jsp/userList.jsp crud!list
/WEB-INF/jsp/userForm.jsp


/WEB-INF/jsp/{1}.jsp




LogonInterceptor.java

代码
package com.jamesby.struts2;
import java.util.Map;
import com.jamesby.struts2.persist.User;
import com.opensymphony.xwork2.Action;
import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.interceptor.AbstractInterceptor;
public class LogonInterceptor extends AbstractInterceptor{
@Override
public String intercept(ActionInvocation ai) throws Exception {
Map session = ai.getInvocationContext().getSession();
User user = (User) session.get("user");
if (null != user) {
return ai.invoke();
} else {
return Action.LOGIN;
}
}
}

Logon.java

代码
package com.jamesby.struts2;
import java.util.Map;
import org.apache.struts2.interceptor.SessionAware;
import org.apache.struts2.interceptor.validation.SkipValidation;
import com.jamesby.struts2.persist.DataBaseMock;
import com.jamesby.struts2.persist.User;
import com.opensymphony.xwork2.ActionSupport;
public class Logon extends ActionSupport implements SessionAware {
private Map session;
public void setSession(Map session) {
this.session = session;
}
@SkipValidation
public String doInput() throws Exception {
return INPUT;
}
public String doLogon() throws Exception {
User user = DataBaseMock.selectUserByUsernameAndPassword(getUsername(),
getPassword());
if (null == user)
return INPUT;
session.put("user", user);
return SUCCESS;
}
private String username;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
private String password;
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}

UserAction.java

代码
package com.jamesby.struts2;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import org.apache.struts2.interceptor.validation.SkipValidation;
import com.jamesby.struts2.persist.DataBaseMock;
import com.jamesby.struts2.persist.User;
import com.opensymphony.xwork2.ActionSupport;
public class UserAction extends ActionSupport {
private User user=new User();
private List userList;
public List getSexArray() {
List sexArray = new ArrayList();
HashMap male = new HashMap();
male.put("key",new Integer(1));
male.put("value","男");
HashMap female = new HashMap();
female.put("key",new Integer(2));
female.put("value","女");
sexArray.add(male);
sexArray.add(female);
return sexArray;
}
public List getFromArray() {
List fromArray = new ArrayList();
HashMap bj = new HashMap();
bj.put("id",new Integer(1));
bj.put("name","北京");
HashMap sh = new HashMap();
sh.put("id",new Integer(2));
sh.put("name","上海");
HashMap tj = new HashMap();
tj.put("id",new Integer(3));
tj.put("name","天津");
fromArray.add(bj);
fromArray.add(sh);
fromArray.add(tj);
return fromArray;
}
@SkipValidation
public String doList() throws Exception {
userList = DataBaseMock.selectAllUser();
return "list";
}
@SkipValidation
public String doInput() {
return INPUT;
}
public String doSave() {
if (null == user.getUserid()) {
user.setUserid(new Integer(DataBaseMock.getNewUserId()));
DataBaseMock.saveUser(user);
}else
{
DataBaseMock.updateUser(user);
}
return SUCCESS;
}
@SkipValidation
public String doRead()
{
user = DataBaseMock.getUser(user.getUserid());
return INPUT;
}
@SkipValidation
public String doDelete() {
DataBaseMock.deleteUser(user);
return SUCCESS;
}
public List getUserList() {
return userList;
}
public void setUserList(List userList) {
this.userList = userList;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
}

ExampleSupport.java

代码
package com.jamesby.struts2;
import com.opensymphony.xwork2.ActionSupport;
public class ExampleSupport extends ActionSupport {
}

User.java

代码
package com.jamesby.struts2.persist;
public class User {
private Integer userid;
private String username;
private String password;
private int sex;
private int age;
private int from;
public int getFrom() {
return from;
}
public void setFrom(int from) {
this.from = from;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public int getSex() {
return sex;
}
public void setSex(int sex) {
this.sex = sex;
}
public Integer getUserid() {
return userid;
}
public void setUserid(Integer userid) {
this.userid = userid;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}

DataBaseMock.java

代码
package com.jamesby.struts2.persist;
import java.util.ArrayList;
import java.util.List;
public class DataBaseMock {
private static List _cache = new ArrayList();
private static int userid = 0;
static {
User user = new User();
user.setUserid(new Integer(0));
user.setUsername("admin");
user.setPassword("12345688");
user.setFrom(1);// 北京
user.setSex(1);// 男
user.setAge(18);
_cache.add(user);
}
public static User selectUserByUsernameAndPassword(String username,String password)
{
for (User u : _cache) {
if (u.getUsername().equals(username)&&u.getPassword().equals(password)) {
return u;
}
}
return null;
}
public static List selectAllUser()
{
return _cache;
}
public static int getNewUserId() {
return ++userid;
}
public static void saveUser(User user) {
_cache.add(user);
}
public static void updateUser(User user) {
deleteUser(user);
saveUser(user);
}
public static void deleteUser(User user) {
for (User u : _cache) {
if (u.getUserid().intValue() == user.getUserid().intValue()) {
_cache.remove(u);
break;
}
}
}
public static User getUser(Integer userid) {
return _cache.get(userid);
}
}

Logon-validation.xml

代码
"-//OpenSymphony Group//XWork Validator 1.0.2//EN"
"http://www.opensymphony.com/xwork/xwork-validator-1.0.2.dtd">













UserAction-validation.xml

代码
"-//OpenSymphony Group//XWork Validator 1.0.2//EN"
"http://www.opensymphony.com/xwork/xwork-validator-1.0.2.dtd">





















18
65










package.properties

代码
requiredstring = $\{getText(fieldName)} is required.
password = Password
username = User Name
main.message = This is main page……………….
label.userList= All User List

user.username=Username
user.password=Password
user.sex=Sex
user.age=Age
user.from=From

errors.required.username=Username is required
errors.required.password=Password is required
errors.required.sex=Sex is Required
errors.required.from=From is Required
errors.required.age.limit=Age between 18 and 65
errors.required.age.limit=Age between 18 and 65

Logon.jsp

代码
<%@ taglib prefix="s" uri="/struts-tags" %>


Logon










userList.jsp

代码
<%@ page contentType="text/html;charset=GBK"%>
<%@taglib prefix="s" uri="/struts-tags" %>






Add New User



用户ID
用户名
性别
年龄
来自
修改
删除











北京
上海
天津


修改


删除





userForm.jsp

代码
<%@ page contentType="text/html;charset=GBK"%>
<%@taglib prefix="s" uri="/struts-tags" %>
User Form











应用程序目录结构

代码
WEB-INF
│ web.xml

├─classes
│ │ commons-logging.properties
│ │ helloworld.xml
│ │ log4j.properties
│ │ struts.properties
│ │ struts.xml
│ │
│ └─com
│ └─jamesby
│ └─struts2
│ │ ExampleSupport.class
│ │ Logon-validation.xml
│ │ Logon.class
│ │ LogonInterceptor.class
│ │ package.properties
│ │ UserAction-validation.xml
│ │ UserAction.class
│ │
│ └─persist
│ DataBaseMock.class
│ User.class

├─jsp
│ Logon.jsp
│ Main.jsp
│ userForm.jsp
│ userList.jsp

├─lib
commons-collections-3.1.jar
commons-logging-1.0.4.jar
freemarker-2.3.8.jar
log4j-1.2.9.jar
ognl-2.6.11.jar
struts2-core-2.0.6.jar
xwork-2.0.1.jar



J2EE电子政务门户设计规划 Java电子政务

wukele收录,使用标签:java,时间:2008-2-21 14:17:51 | 相关网摘我也收藏

J2EE电子政务门户系统


敏捷项目实践步骤 - rocket - BlogJava

wukele收录,使用标签:java,时间:2008-2-21 14:09:56 | 相关网摘我也收藏

一、根据发布目标分析需求,把需求分析成独立的故事,初步的分析可以是粗略的,随着需求的不断深入刻意对故事进行整合或者切割。

要注意的是分析出来的需求尽量在发布目标的范围之内,超出发布目标的需求应该尽量避免过深分析。

所谓的发布目标是确定了这个版本可以让用户满意的条件。

故事模式:做为(用户角色),我可以(做什么),以便(业务价值)。后面的业务价值在比较简单或者大家都比较明确的时候刻意不需要注明。

当前团队实践推行方法:

第一阶段,这个分析工作开始由PM进行收集,整理和分析。

第二阶段,当大家都为用户故事的方式接受以后,采用需求讨论的方式来明确和分析用户故事。



二、对分析的故事进行相对估计,估计出来的故事点是对用户故事和复杂度的无单位估计值,使用的数值大小本身没有绝对意义,只有相对于其他故事规模的相对意义。

比如,用户登录这个用户故事的估计值是2,那么做为同等开发规模的用户推出,这个用户故事的估计只也因该是2。

当前团队实践推行方法:

第一阶段,这个估计的工作暂时由pm来负责完成,但是由于一个人的估计肯定会有偏差,所以在估计完成之后需要进行调查来进行修正

第二阶段,用估计扑克会议来统一的对用户故事进行估计,当主持人拿出一个新的用户故事之后,大家给出自己对这个故事使用扑克打分,然后取出平均值,对差异较大的估计值要给出解释,来消除对用户故事的错误理解。估计扑克会议的实践不超过1个小时。



三、准备产品调查,对用户故事进行功能存在,和功能缺失性的产品调查,然后根据调查结果对用户故事进行划分,划分成3类,基本需求,线性需求,线性需求。

此外还有反对的需求,存在疑问的需求,无所谓的需求3种类型的需求,这些需求将根据进一步的发展进行确认。

当前团队的实践推行办法:

第一阶段,由pm发出调查问卷在参与到项目的开发团队,测试团队,技术支持团队来进行调查,然后汇总答案根据存在问题和缺失问题的答案,对用户故事进行定性

第二阶段,由pm发出调查问卷扩展到相关的用户群体中进行调查,然后汇总答案根据存在问题和缺失问题的答案,对用户故事进行定性



四、确定发布规划,首先要确定的是迭代周期的长度,以周为单位,然后估计出每个迭代周期团队的速度。然后可以从用户故事池中选择出合适的用户故事来填充到第一次和第二次的迭代周期中。其余的暂时可以先不用填充,随着每次迭代周期的完成来对发布计划进行更新。最后根据估计的速度和需要开发的故事来确定需要几个迭代周期,并最终有几个迭代周期来确定需要开发的时间周期。发布计划可以以功能来驱动进行,也可以以日期来驱动进行。

发布规划的特点,以月做为时间范围,规划对象是用户故事,估计的单位是故事点

当前团队的实践推行办法:

第一阶段,使用1周做为迭代周期,开始时团队速度使用估计的方式做出简单估计,根据每个周期结束后的团队速度再进行发布计划的调成。迭代周期内用户故事的完成暂时以开发完成做为标准。

第二阶段,使用2周做为迭代周期,可以使用原有的历史速度做为团队速度,多出的一周时间做为测试修复时间,迭代周期内用户故事的完成以测试完成,完整的功能提交做为标准,并在开发过程中熟练使用单元测试来进行确保功能的完整完成。



五、确定迭代规划,根据填充到迭代周期内的用户故事来分解成工作任务,工作任务包括设计工作,不同层次的开发工作,调试工作和测试工作等等具体的任务,然后对任务进行估计,这时候估计的单位以理想工作小时做为单位。比如,设计需要两个人小时,开发持久层需要1个人小时,调试持久层需要半个人小时,开发业务层需要2个人小时,调试中间层需要1个小时等等。。。

然后根据每个故事的人小时和这个迭代周期内参与的人数,以及每个人所能参与的实际有效时间(注意有效时间约为每天6小时,需要考虑到会议,讨论,头脑休息等非理想工作时间)来判断这个迭代周期的填充是否足够,如果不够则再加入一个用户故事,如果超出则移出一个用户故事到下一个迭代周期中。

迭代规划的特点,以周做为时间范围,规划对象是工作任务,估计的单位是理想小时

当前团队的实践推行办法:

第一阶段,使用速度驱动的方法来进行迭代规划,即确定了本次迭代的速度,然后选择用户故事扩展成任务,对任务进行估计。

第二阶段,使用承诺驱动的方法来进行迭代规划,即提出一个故事,把故事扩展成任务,对任务进行估计,让小组承诺是否可以完成这个故事,如果可以在迭代周期内完成则加入这个故事,如果不能完成则推迟到下一个迭代走起。



六、迭代开始,在迭代开始时召开迭代启动会,分配迭代周期内的用户故事和工作任务到个人,每个工作任务必须精确到个人,同一个用户故事的不同工作任务可以根据情况适当分配给不同的人来完成。

当前团队的实践推行办法:

第一阶段,任务分配给个人,通常一个故事的任务分配给同一个人。

第二阶段,任务分配给结对,通常一个故事的任务分配给同一个结对。



七、迭代进行,每日早对昨日完成的工作任务和问题进行汇报,并且同时计划今天需要完成的工作任务,对于迭代过程中的进度和问题进行及时的观察和调整,要求每个人完成某个任务之后要及时的告知整个小组知道(qq群的方式最为快捷)。

当前团队的实践推行办法:

第一阶段,由pm及时地对当日工作进行询问。并负责把遇到的问题跑出来进行解决。

第二阶段,小组成员主动地对已经完成的任务进行汇报,并及时把自己遇到的问题抛出来。



八、迭代结束,确认本次迭代完成的用户故事,对于完成一部分的用户故事计算到下一次迭代中。并对本次迭代的过程资产进行总结,形成FAQ方式的文档进行规整。

同时根据新的需求情况,资源情况,已完成功能的回馈,以及开发中遭遇的不确定性问题,对发布规划和迭代规划作出调整。

当前团队的实践推行办法:

第一阶段,使用学习网站,或者博客等方式对经验进行记录。

第二阶段,使用完善的skills对经验进行记录,可以方便的组织成培训文档,并方便的进行搜索,查找。



九、迭代测试,为了保证用户功能完整的提交,每个用户故事开发完成之后都要对该用户故事进行测试,然后在针对开发中出现的问题进行修复,以便完整的完成一个用户故事。



第一阶段:测试迭代周期和开发迭代周期分开。

每次迭代开始阶段由pm告知开发组需要开发的和修复的的用户故事,同时告知测试组本次迭代需要测试的故事,需要准备的故事,需要复测的故事。

并在分配任务时,把修复故事的工作规划到本次迭代中来。

每次开发完成的用户故事点算作本次迭代的速度


迭代1
迭代2
迭代3
迭代4
迭代5

测试
准备故事1,2
测试故事1,2

准备故事3,4
测试故事3,4

准备故事5,6
复测故事1,2

测试故事5,6

准备故事7,8
复测故事3,4

测试故事7,8

准备故事9,10

开发
开发故事1,2
开发故事3,4
修复故事1,2

开发故事5,6
修复故事3,4

开发故事7,8
修复故事5,6

开发故事9,10




第二阶段:测试迭代周期和开发迭代周期合并。

每次迭代开始阶段由pm告知开发组需要开发的故事,同时这些故事也是测试组需要准备测试的故事。要求这些故事分解的工作任务中要包括测试工作和修复工作。

每次测试完成的用户故事点算作本次迭代的速度


迭代X

测试
准备故事1,2,3,4
测试故事1,2,3,4
复测故事1,2,3,4

开发
开发故事1,2,3,4
修复故事1,2,3,4
完成故事1,2,3,4




十、发布结束,对本次发布中完成的用户故事进行会议总结:

1确定最终完成的用户故事,以及花费的迭代周期

2通过计算得到一个团队的人平均速度,这个速度做为下次发布规划的参考

3分析哪些用户故事的估计出现了失误,以及出现失误的原因是什么。

4最初的发布版本在市场上有了初步反馈信息之后,可以延长1个迭代周期用来做为发布版本的反馈收尾。


Hibernate(以前写的给公司的培训资料) - fanscial - BlogJava

wukele收录,使用标签:java,时间:2007-12-11 13:03:52 | 相关网摘我也收藏



1. Hibernate简介

Hibernate是非常流行的对象-关系映射工具。

2. 什么是ORM映射



ORM(Object Relational Mapping)简单的说,就是对象与关系的映射,对于实际应用来讲,对象一般指面向对象中的对象,关系指关系型数据库,对于我们具体的项目来说,就是将java中的对象与关系型数据库(oracle,mysql)中的表联系起来 。Hibernate是很强大的工具,当我们将建立联系的工作交给它后,就可以专注于与java中的对象打交道,而不需要知道它代表的是哪些表。

3. POJO(用来映射数据库中的表,构建我们的持久化层)

一个典型的POJO

public class Person{

private long id;

private String name;

public void setId(BigDecimal value) {

this.id = value;

}

public BigDecimal getId() {

return this.id;

}

public void setName(String value) {

this.name = value;

}

public String getName() {

return this.name;

}

}

表面上看来,一个POJO与一个普通的JavaBean没有什么区别,我们需要了解的是如何让POJO和一个表建立联系。

4. 建立联系的桥梁,映射文件XML。

一个典型的映射文件Person.hbm.xml(注意他的命名方式,一般是类名+hbm+xml)

























注意红线部分代表了Pojo对应的是那张表。

一般来说映射文件放在和Pojo同一个包

5. 和数据库的连接

Hibernate配置文件,可以采用xml或者property文件。

一个典型的配置文件




"-//Hibernate/Hibernate Configuration DTD 3.0//EN"

"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">





toposs

toposs



org.hibernate.dialect.Oracle9Dialect





jdbc:oracle:thin:@172.16.1.3:1521:orcl





oracle.jdbc.driver.OracleDriver







6. Hibernate在Eclipse中快速应用

6.1 新建一个工程,将Hibernate3.jar和你需要的数据库驱动添加到工程path中

6.2 在数据库中新建一个名为person的表。




6.3 在工程的默认package下建立一个POJO,Person类与表person对应。

public class Person{



private long id;



private String name;





public void setId(long value) {

this.id = value;

}





public long getId() {

return this.id;

}





public void setName(String value) {

this.name = value;

}





public String getName() {

return this.name;

}

}

6.4 现在我们来建立一个xml的映射文件(Person.hbm.xml)

























6.5 建立hibernate.cfg.xml




"-//Hibernate/Hibernate Configuration DTD 3.0//EN"

"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">





scott

tiger

org.hibernate.dialect.Oracle9Dialect

jdbc:oracle:thin:@172.16.1.2:1521:rsora

oracle.jdbc.driver.OracleDriver

true







注意红线的部分将mapping文件写到resource中,如果有多个文件,要写多个文件,文件的路径是对于根目录的绝对路径

6.6 项目结构图



6.7 所有准备工作都已经做好了,下面在Person中建立一个main方法,我们做一个简单的插入数据库的工作

6.7.1 Main函数的代码

Public static main(String[] args){

Configuration config=new Configuration().configure();

SessionFactory factory=config.buildSessionFactory();

Session session=factory.openSession();

Transaction tran=session.beginTransaction();

Person p=new Person();

p.setName("test");

session.save(p);



tran.commit();

session.close();

}

6.7.2 点击Run As Java Application,运行这个main函数

6.7.3 然后查看数据库



我们发现数据库已经新增加了一条记录



7. 最常见的关联关系,一对多关联。

7.1 用父子关系说明一对多(多对一关联)

在实际应用中,很少有一个表是独立的,大部分情况是表和表之间是有关联关系的,其中最常见的是一对多(多对一关联)。

父亲和儿子是典型的一对多关系,一个父亲有多个儿子,儿子只有一个父亲。在这个关系中,父亲是一方,儿子是多方。

7.2 在数据库中建立父子关系。

建表的sql语句:

CREATE TABLE father (

Father_id INTEGER NOT NULL,

name VARCHAR(10) NULL,

PRIMARY KEY (father_id) );

CREATE TABLE son (

Son_id INTEGER NOT NULL,

Son_name VARCHAR(10) NULL,

Father_ID INTEGER NULL

PRIMARY KEY (son_id),

FOREIGN KEY (father_id)

REFERENCES father

);

7.3 建立的表的结构

儿子的表




父亲的表




7.4 建立POJO

同样在我们的工程的defalt package下面新建类Father和Son。

7.4.1 Father类

public class Father {



private long fid;



private String name;



private Set sons = new HashSet();



public long getFid() {



return fid;

}



public void setFid(long fid) {



this.fid = fid;

}



public String getName() {



return name;

}



public void setName(String name) {



this.name = name;

}



public Set getSons() {



return sons;

}



public void setSons(Set sons) {



this.sons = sons;

}

}

7.4.2 Son类

public class Son {



private long sid;



private String name;



private Father father;



public Father getFather() {



return father;

}



public void setFather(Father father) {



this.father = father;

}



public String getName() {



return name;

}



public void setName(String name) {



this.name = name;

}



public long getSid() {



return sid;

}



public void setSid(long sid) {



this.sid = sid;

}

}

7.5 注意到什么不同了吗,在Father类里多了个Set,Son类中多了个Father成员变量。

这里我们做的是双向关系,也可以做单向关系只在一方做关联。

7.6 映射文件的写法

7.6.1 Father.hbm.xml



































7.6.2 Son.hbm.xml





























7.6.3 看到红线的部分是对应的关联关系的写法,其中没项具体的含义我们留到后面解释

7.7 不要忘了在配置文件中添加我们的映射文件。




"-//Hibernate/Hibernate Configuration DTD 3.0//EN"

"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">





scott

tiger



org.hibernate.dialect.Oracle9Dialect





jdbc:oracle:thin:@172.16.1.2:1521:rsora





oracle.jdbc.driver.OracleDriver



true











7.8 所有准备工作做好了,下面在原来的Main函数中添加代码

public static void main(String[] args) {



Configuration config=new Configuration().configure();

SessionFactory factory=config.buildSessionFactory();

Session session=factory.openSession();

Transaction tran=session.beginTransaction();

Father father=new Father();

father.setName("fanta");

Son son1=new Son();

Son son2=new Son();

son1.setName("son1");

son2.setName("son2");

father.getSons().add(son1);

father.getSons().add(son2);

session.save(father);



tran.commit();

session.close();



}

7.9 点击Run As Java Application,运行这个main函数,看看数据库发生了什么







7.10 Father表插入了1条记录,son表插入了2条记录,然后回头看看我们的代码做了些什么

……

Father father=new Father();

father.setName("fanta");

Son son1=new Son();

Son son2=new Son();

son1.setName("son1");

son2.setName("son2");

father.getSons().add(son1);

father.getSons().add(son2);

session.save(father);

……

我们看到显式的调用存储就只有红线的这句话,只存了father,并没有存son,那为什么数据库会有son的记录呢,这就是Hibernate帮我们做的事情,回忆一下Father的POJO里有个Set吗

public class Father {



private long fid;



private String name;



private Set sons = new HashSet();



……

因为我们将Set中添加了东西(增加了2个儿子),所以Hibernate在存储Father的时候 “顺便”(J)将他的2个儿子也插入到数据库中了。



8. 常用的一对多和多对一映射选项

8.1 多对一设置



(1) name: 属性名。

(2) column (可选): 外间字段名。它也可以通过嵌套的 元素指定。

(3) class (可选 - 默认是通过反射得到属性类型): 关联的类的名字。

(4) cascade(级联) (可选): 指明哪些操作会从父对象级联到关联的对象。

(5) unique (可选): 使用DDL为外键字段生成一个唯一约束。此外, 这也可以用作property-ref的目标属性。这使关联同时具有 一对一的效果。

(6) not-null (可选): 使用DDL为外键字段生成一个非空约束。

(7) lazy (可选 - 默认为 proxy): 默认情况下,单点关联是经过代理的。lazy="true"指定此属性应该在实例变量第一次被访问时应该延迟抓取(fetche lazily)(需要运行时字节码的增强)。 lazy="false"指定此关联总是被预先抓取。



8.2 一对多配置









(1) name 集合属性的名称

(2) table (可选——默认为属性的名称)这个集合表的名称(不能在一对多的关联关系 中使用)

(3) lazy (可选--默认为true) 可以用来关闭延迟加载,指定一直使用预先抓取(对数组 不适用)

(4) inverse (可选——默认为false) 标记这个集合作为双向关联关系中的方向一端。

(5) cascade (可选——默认为none) 让操作级联到子实体

(6) order-by (可选) 指定表的字段(一个或几个)再加上asc或者desc(可选), 定义Set的迭代顺序


Struts struts-config.xml 配置详解 赛迪网技术社�?u=http://bbs.tech.ccidnet.com/read.php?tid=557960

wukele收录,使用标签:java,时间:2007-12-11 12:27:22 | 相关网摘我也收藏

:m8YB/[xE
"-//Apache Software Foundation//DTD Struts Configuration 1.1//EN" DWBk 9RW
"http://jakarta.apache.org/struts/dtds/struts-config.dtd"> z_;``v<
PSr)v
d'_F(C@G
),#/@;
BiMItG4
Q%&e-7
{ tNx2{
7A%f)f31
*0'C] dc
sjbTa"|7I
ccwbiA
c@TLJ
9xqS4aXT
26lf#f.@@
[C[seUqw
 1hYb8@-
aFoSpD[]
+383 e,k+k
;WuILv8
r1;+9nN
^'ilmP
"$GwlYe%5y
YB()g.d
c.eEo'd
*dx=-[|1'8
tr0*
v *]D\-
ZX} XY7-k
vF70ng"2k/
] Dfx2t
l2&
type="addressbook.actions.SearchAction"  Egux@a
name="searchForm" M3eh 
scope="request" B 6S_c2@p
validate="true" CeF)Fei
input="/search.jsp"> XuZc4t_-t
Af XV/%wE<
2pah/1IU
r7$f=#EN
~QHPone
2JVq=cDm!3
,mM, {6V
^sZ:NNOD
?(y_Gl+n)9
G7z}Sc8T
ymgir+a[=
/9}If8
hOx3-0vZ
TpE#Z=+
t^/!ypt
JhP1:93H
/K$z&E8
I`0j=LQ


Java编程 - 迎风 - 51CTO技术博客-领先的IT技术博客

wukele收录,使用标签:java,时间:2007-12-9 9:58:51 | 相关网摘我也收藏

keytool的几个常用命令
1.4和1.5
使用keytool -genkey来产生一对密钥

a、长命令,将所有的参数写在一行

keytool -genkey -dname "cn=Mark Jones, ou=JavaSoft, o=Sun, c=US" -alias business -keypass kpi135 -keystore f:\certJava\myKeystore -storepass ab987c -validity 180 -keyalg RSA -keysize 576 -v

这条命令在sun提供的reference中可以找到,各参数解释如下(它们之间顺序任意):

dname:cn=Mark Jones, ou=JavaSoft, o=Sun, c=US

alias:别名business

keystore:keystore的位置

storepass:打开keystore所需要?.


extremeComponents使用AJAX 指南_笑指南山--java框架、开源搜索引擎研究

wukele收录,使用标签:java,时间:2007-12-6 21:08:15 | 相关网摘我也收藏

AJAX 指南
进行中...

在eXtremeTable中使用AJAX非常简单,对现有功能的扩展也非常方便。 AJAX整合一个最强大的地方是它不需要整合。你可以自由地使用任何你想要使用的AJAX工具包。所有你要做的就是:当表的action被调用时,告诉 eXtremeTable使用什么javascript。表的actions包括:过滤、排序、分页、显示的行数和导出。

在我自己的示例中我将使用非常酷的DWR工具包。DWR 需要的粘合代码非常少,这样我们只需要关注如何构建表。你可以通过本站示例看到效果!

[edit]Assembler Example
本示例中将需要安装DWR工具包,创建POJO来构造表并创建包含eXtremeTable的JSP页面。

[edit]安装DWR
首先要做的就是下载DWR工具包。你应该浏览网站的使用说明,不过下面是我让它符合我的需要来工作所进行的操作:

将dwr-1.1.jar拷贝到WEB-INF/lib目录
在WEB-INF目录下创建一个dwr.xml文件

简而言之(In a nutshell)创建(create)标签允许当方法被调用时,参照构建表需要的POJO。签名(signature)标签声明了被调用方法使用的实际类型。 本示例的Assembler类的getTable方法将通过传入一个Map(包含form参数)和HttpServletRequest。

在WEB-INF/web.xml中对DWR servlet进行声明
dwr-invoker DWR Servlet uk.ltd.getahead.dwr.DWRServlet debug true dwr-invoker /dwr/*
以上就完成了DWR servlet的设置,它被用来调用你的POJO。除了设置它,你不需要对这个servlet有更多的了解。

[edit]创建POJO
DWR使用(works with)POJOs。这个非常符合我们的需要,因为eXtremeTable有足够的API使用Jsp标签来构造表。实际上,JSP标签只不过是eXtremeTable Java API的前端。首先,我将展示构造表的方法:

public class Assembler { private Object build(TableModel model, Collection presidents) throws Exception { Table table = model.getTableInstance(); table.setTableId("assembler"); table.setItems(presidents); table.setAction(model.getContext().getContextPath() + "/assembler.run"); table.setTitle("Presidents"); table.setOnInvokeAction("buildTable('assembler')"); model.addTable(table); Export export = model.getExportInstance(); export.setView(TableConstants.VIEW_XLS); export.setViewResolver(TableConstants.VIEW_XLS); export.setImageName(TableConstants.VIEW_XLS); export.setText(TableConstants.VIEW_XLS); export.setFileName("output.xls"); model.addExport(export); Row row = model.getRowInstance(); row.setHighlightRow(Boolean.FALSE); model.addRow(row); Column columnName = model.getColumnInstance(); columnName.setProperty("fullName"); columnName.setIntercept((AssemblerIntercept.class).getName()); model.addColumn(columnName); Column columnNickName = model.getColumnInstance(); columnNickName.setProperty("nickName"); model.addColumn(columnNickName); Column columnTerm = model.getColumnInstance(); columnTerm.setProperty("term"); model.addColumn(columnTerm); Column columnBorn = model.getColumnInstance(); columnBorn.setProperty("born"); columnBorn.setCell(TableConstants.DATE); model.addColumn(columnBorn); Column columnDied = model.getColumnInstance(); columnDied.setProperty("died"); columnDied.setCell(TableConstants.DATE); model.addColumn(columnDied); Column columnCareer = model.getColumnInstance(); columnCareer.setProperty("career"); model.addColumn(columnCareer); return model.assemble(); }}
上面的大部分代码是自解释性的,你将在下面看到如何构造一个TableModel,但是首先你应该注意到TableModel是构造表时需要交互的唯一对象。构造表的第一步就是使用TableModel来创建Table、Row、Column和Export。一旦你创建了一个model对象,你只需要将它添加到model中。除非你将它添加到TableModel,否则的话model将不会是用它。所有东西已经构建好后,你只需要调用model.assemble()方法来构造表了。

可能table.setOnInvokeAction("buildTable('assembler')");是最有趣的调用。当你使用表的actions(翻页、过滤、排序......),这个javascript方法将被调用。如果表的onInvokeAction空白,则默认的javascript方法将被提交(submit) ,正如你所期望的那样。

Assembler类的另一个方法---getTable():

public class Assembler { public String getTable(Map parameterMap, HttpServletRequest request) { WebApplicationContext webApplicationContext = WebApplicationContextUtils.getWebApplicationContext(request.getSession().getServletContext()); PresidentsDao presidentsDao = (PresidentsDao) webApplicationContext.getBean("presidentsDao"); Collection presidents = presidentsDao.getPresidents(); Context context = null; if (parameterMap == null) { context = new HttpServletRequestContext(request); } else { context = new HttpServletRequestContext(request, parameterMap); } TableModel model = new TableModelImpl(context); try { return build(model, presidents).toString(); } catch (Exception e) { e.printStackTrace(); } return ""; }}
这个方法调用比较频繁,它执