michaelwang1978

BlogJava 首页 新随笔 联系 聚合 管理
  10 Posts :: 0 Stories :: 0 Comments :: 0 Trackbacks

2005年10月21日 #

其实,这个应用是个简单得不能再简单的JavaScript应用,只不过被冠以了AJAX这个今年2月份才诞生的名词以后忽然热了起来。AJAX这一个单词,居然可以把一堆98年就开始用的技术推到前台来,成为当今在特定的圈子里最热的词汇,倒是一个典型的tipping point(临界点)的案例。就像99年Netcenter用的RSS终于在2002年开始被从blogger捡起来,并在2005年焕发了青春。

这些用Javascript+XMLHTTPRequest的做法给我们提供了一个很广阔的空间,可以有很多的想象。比如,在任何静态的页面里面,只要加入这段代码也就可以拥有这个功能了。

<script language=Javascript src="http://home.wangjianshuo.com/scripts/php/markit.php">
</script>

把鼠标放在上面还可以知道是从哪个IP在什么时间批注的。值得注意的是,这只是一个最简单的SAJAX应用,如果把它应用于地图,以及应用于多个网站之间的联合,会有更让人惊讶的结果出来。估计,以后客齐集的后台的管理系统将会是最早使用这些简单但是有效的思想的地方。

注:那些红线,只是在Word里面随手画的。
注二:没有经过测试,FireFox下面什么样子不晓得,放在其他页面怎么样也不晓得。。

posted @ 2005-10-21 23:05 Michael 阅读(170) | 评论 (0)编辑 收藏

2005年10月11日 #

我们期待自己成为一个优秀的软件模型设计者,但是,要怎样做,又从哪里开始呢? 

  将下列原则应用到你的软件工程中,你会获得立杆见影的成果。 

  1. 人远比技术重要 

  你开发软件是为了供别人使用,没有人使用的软件只是没有意义的数据的集合而已。许多在软件方面很有成就的行家在他们事业的初期却表现平平,因为他们那时侯将主要精力都集中在技术上。显然,构件(components),EJB(Enterprise Java Beans)和代理(agent)是很有趣的东西。但是对于用户来说,如果你设计的软件很难使用或者不能满足他们的需求,后台用再好的技术也于事无补。多花点时间到软件需求和设计一个使用户能很容易理解的界面上。 
 
  2. 理解你要实现的东西 

  好的软件设计人员把大多数时间花费在建立系统模型上,偶尔写一些源代码,但那只不过是为了验证设计过程中所遇到的问题。这将使他们的设计方案更加可行。 

  3. 谦虚是必须的品格 

  你不可能知道一切,你甚至要很努力才能获得足够用的知识。软件开发是一项复杂而艰巨的工作,因为软件开发所用到的工具和技术是在不断更新的。而且,一个人也不可能了解软件开发的所有过程。在日常生活中你每天接触到的新鲜事物可能不会太多。但是对于从事软件开发的人来说,每天可以学习很多新东西(如果愿意的话)。 

  4. 需求就是需求 

  如果你没有任何需求,你就不要动手开发任何软件。成功的软件取决于时间(在用户要求的时间内完成)、预算和是否满足用户的需求。如果你不能确切知道用户需要的是什么,或者软件的需求定义,那么你的工程注定会失败。 

  5. 需求其实很少改变,改变的是你对需求的理解 

  Object ToolSmiths公司(www.objecttoolsmiths.com)的Doug Smith常喜欢说:“分析是一门科学,设计是一门艺术”。他的意思是说在众多的“正确”分析模型中只存在一个最“正确”分析模型可以完全满足解决某个具体问题的需要(我理解的意思是需求分析需要一丝不苟、精确的完成,而设计的时候反而可以发挥创造力和想象力 - 译者注)。 

  如果需求经常改动,很可能是你没有作好需求分析,并不是需求真的改变了。 

  你可以抱怨用户不能告诉你他们想得到什么,但是不要忘记,收集需求信息是你工作。 

  你可以说是新来的开发人员把事情搞得一团糟,但是,你应该确定在工程的第一天就告诉他们应该做什么和怎样去做。 

  如果你觉得公司不让你与用户充分接触,那只能说明公司的管理层并不是真正支持你的项目。 

  你可以抱怨公司有关软件工程的管理制度不合理,但你必须了解大多同行公司是怎么做的。 

  你可以借口说你们的竞争对手的成功是因为他们有了一个新的理念,但是为什么你没先想到呢? 

  需求真正改变的情况很少,但是没有做好需求分析工作的理由却很多。 

  6. 经常阅读 

  在这个每日都在发生变化的产业中,你不可能在已取得的成就上陶醉太久。 

  每个月至少读2、3本专业杂志或者1本专业书籍。保持不落伍需要付出很多的时间和金钱,但会使你成为一个很有实力的竞争者。 

  7. 降低软件模块间的耦合度 

  高耦合度的系统是很难维护的。一处的修改引起另一处甚至更多处的变动。 

  你可以通过以下方法降低程序的耦合度:隐藏实现细节,强制构件接口定义,不使用公用数据结构,不让应用程序直接操作数据库(我的经验法则是:当应用程序员在写SQL代码的时候,你的程序的耦合度就已经很高了)。 

  耦合度低的软件可以很容易被重用、维护和扩充。 

  8. 提高软件的内聚性 

  如果一个软件的模块只实现一个功能,那么该模块具有高内聚性。高内聚性的软件更容易维护和改进。 

  判断一个模块是否有高的内聚性,看一看你是否能够用一个简单的句子描述它的功能就行了。如果你用了一段话或者你需要使用类似“和”、“或”等连词,则说明你需要将该模块细化。 

  只有高内聚性的模块才可能被重用。 

  9. 考虑软件的移植性 

  移植是软件开发中一项具体而又实际的工作,不要相信某些软件工具的广告宣传(比如java 的宣传口号write once run many ? 译者注)。 

  即使仅仅对软件进行常规升级,也要把这看得和向另一个操作系统或数据库移植一样重要。 

  记得从16位Windows移植到32位windows的“乐趣”吗 ?当你使用了某个操作系统的特性,如它的进程间通信(IPC)策略,或用某数据库专有语言写了存储过程。你的软件和那个特定的产品结合度就已经很高了。 

  好的软件设计者把那些特有的实现细节打包隐藏起来,所以,当那些特性该变的时候,你的仅仅需要更新那个包就可以了。 

  10. 接受变化 

  这是一句老话了:唯一不变的只有变化。 

  你应该将所有系统将可能发生的变化以及潜在需求记录下来,以便将来能够实现(参见“Architecting for Change”,Thinking Objectively, May 1999) 

  通过在建模期间考虑这些假设的情况,你就有可能开发出足够强壮且容易维护的软件。设计强壮的软件是你最基本的目标。 

  11. 不要低估对软件规模的需求 

  Internet 带给我们的最大的教训是你必须在软件开发的最初阶段就考虑软件规模的可扩充性。 

  今天只有100人的部门使用的应用程序,明天可能会被有好几万人的组织使用,下月,通过因特网可能会有几百万人使用它。 

  在软件设计的初期,根据在用例模型中定义的必须支持的基本事务处理,确定软件的基本功能。然后,在建造系统的时候再逐步加入比较常用的功能。 

  在设计的开始考虑软件的规模需求,避免在用户群突然增大的情况下,重写软件。 

  12. 性能仅仅是很多设计因素之一 

  关注软件设计中的一个重要因素--性能,这好象也是用户最关心的事情。一个性能不佳的软件将不可避免被重写。 

  但是你的设计还必须具有可靠性,可用性,便携性和可扩展性。你应该在工程开始就应该定义并区分好这些因素,以便在工作中恰当使用。性能可以是,也可以不是优先级最高的因素,我的观点是,给每个设计因素应有的考虑。 

  13. 管理接口 

  “UML User Guide”(Grady Booch,Ivar Jacobson和Jim Rumbaugh ,Addison Wesley, 1999)中指出,你应该在开发阶段的早期就定义软件模块之间的接口。 

  这有助于你的开发人员全面理解软件的设计结构并取得一致意见,让各模块开发小组相对独立的工作。一旦模块的接口确定之后,模块怎样实现就不是很重要了。 

  从根本上说,如果你不能够定义你的模块“从外部看上去会是什么样子”,你肯定也不清楚模块内要实现什么。 

  14. 走近路需要更长的时间 

  在软件开发中没有捷径可以走。 

  缩短你的在需求分析上花的时间,结果只能是开发出来的软件不能满足用户的需求,必须被重写。 

  在软件建模上每节省一周,在将来的编码阶段可能会多花几周时间,因为你在全面思考之前就动手写程序。 

  你为了节省一天的测试时间而漏掉了一个bug,在将来的维护阶段,可能需要花几周甚至几个月的时间去修复。与其如此,还不如重新安排一下项目计划。 

  避免走捷径,只做一次但要做对(do it once by doing it right)。 

  15. 别信赖任何人 

  产品和服务销售公司不是你的朋友,你的大部分员工和高层管理人员也不是。 

  大部分产品供应商希望把你牢牢绑在他们的产品上,可能是操作系统,数据库或者某个开发工具。 

  大部分的顾问和承包商只关心你的钱并不是你的工程(停止向他们付款,看一看他们会在周围呆多长时间)。 

  大部分程序员认为他们自己比其他人更优秀,他们可能抛弃你设计的模型而用自己认为更好的。 

  只有良好的沟通才能解决这些问题。 

  要明确的是,不要只依靠一家产品或服务提供商,即使你的公司(或组织)已经在建模、文档和过程等方面向那个公司投入了很多钱。 

  16. 证明你的设计在实践中可行 

  在设计的时候应当先建立一个技术原型, 或者称为“端到端”原型。以证明你的设计是能够工作的。 

  你应该在开发工作的早期做这些事情,因为,如果软件的设计方案是不可行的,在编码实现阶段无论采取什么措施都于事无补。技术原型将证明你的设计的可行性,从而,你的设计将更容易获得支持。 

  17. 应用已知的模式 

  目前,我们有大量现成的分析和设计模式以及问题的解决方案可以使用。 

  一般来说,好的模型设计和开发人员,都会避免重新设计已经成熟的并被广泛应用的东西。 
http://www.ambysoft.com/processPatternsPage.html 收藏了许多开发模式的信息。 

  18. 研究每个模型的长处和弱点 

  目前有很多种类的模型可以使用,如下图所示。用例捕获的是系统行为需求,数据模型则描述支持一个系统运行所需要的数据构成。你可能会试图在用例中加入实际数据描述,但是,这对开发者不是非常有用。同样,数据模型对描述软件需求来说是无用的。每个模型在你建模过程中有其相应的位置,但是,你需要明白在什么地方,什么时候使用它们。 

  19. 在现有任务中应用多个模型 

  当你收集需求的时候,考虑使用用例模型,用户界面模型和领域级的类模型。 

  当你设计软件的时候,应该考虑制作类模型,顺序图、状态图、协作图和最终的软件实际物理模型。 

  程序设计人员应该慢慢意识到,仅仅使用一个模型而实现的软件要么不能够很好地满足用户的需求,要么很难扩展。 

  20. 教育你的听众 

  你花了很大力气建立一个很成熟的系统模型,而你的听众却不能理解它们,甚至更糟-连为什么要先建立模型都不知道。那么你的工作是毫无意义的。 

  教给你开发人员基本的建模知识;否则,他们会只看看你画的漂亮图表,然后继续编写不规范的程序。 

  另外, 你还需要告诉你的用户一些需求建模的基础知识。给他们解释你的用例(uses case)和用户界面模型,以使他们能够明白你要表达地东西。当每个人都能使用一个通用的设计语言的时候(比如UML-译者注),你的团队才能实现真正的合作。 

  21. 带工具的傻瓜还是傻瓜 

  你给我CAD/CAM工具,请我设计一座桥。但是,如果那座桥建成的话,我肯定不想当第一个从桥上过的人,因为我对建筑一窍不通。 

  使用一个很优秀的CASE工具并不能使你成为一个建模专家,只能使你成为一个优秀CASE工具的使用者。成为一个优秀的建模专家需要多年的积累,不会是一周针对某个价值几千美元工具的培训。一个优秀的CASE工具是很重要,但你必须学习使用它,并能够使用它设计它支持的模型。 

  22. 理解完整的过程 

  好的设计人员应该理解整个软件过程,尽管他们可能不是精通全部实现细节。 

  软件开发是一个很复杂的过程,还记得《object-oriented software process》第36页的内容吗?除了编程、建模、测试等你擅长工作外,还有很多工作要做。 

  好的设计者需要考虑全局。必须从长远考虑如何使软件满足用户需要,如何提供维护和技术支持等。 

  23. 常做测试,早做测试 

  如果测试对你的软件来说是无所谓的,那么你的软件多半也没什么必要被开发出来。 

  建立一个技术原型供技术评审使用,以检验你的软件模型。 

  在软件生命周期中,越晚发现的错误越难修改,修改成本越昂贵。尽可能早的做测试是很值得的。 

  24. 把你的工作归档 

  不值得归档的工作往往也不值得做。归档你的设想,以及根据设想做出的决定;归档软件模型中很重要但不很明显的部分。 给每个模型一些概要描述以使别人很快明白模型所表达的内容。 

  25. 技术会变,基本原理不会 

  如果有人说“使用某种开发语言、某个工具或某某技术,我们就不需要再做需求分析,建模,编码或测试”。不要相信,这只说明他还缺乏经验。抛开技术和人的因素,实际上软件开发的基本原理自20世纪70年代以来就没有改变过。你必须还定义需求,建模,编码,测试,配置,面对风险,发布产品,管理工作人员等等。 

  软件建模技术是需要多年的实际工作才能完全掌握的。好在你可以从我的建议开始,完善你们自己的软件开发经验。 

  以鸡汤开始,加入自己的蔬菜。然后,开始享受你自己的丰盛晚餐吧
posted @ 2005-10-11 09:26 Michael 阅读(140) | 评论 (0)编辑 收藏

现在到eclipse网站可以下到中文包了!
    有两个,分别是:NLpack1-eclipse-SDK-3.1.1a-win32.zip和NLpack1_FeatureOverlay-eclipse-SDK-3.1.1.zip。
    后者是前者的补充。
   
    在我的机子上,这两个中文包只适合eclipse3.1.1版本,3.1版本都不适合,但网上有人说可以用,就不得而知了。eclipse3.1.1版本已经出了一段时日了,但一直都没有使用过,今天是试用了一下,Lomboz还可以用,但de.strutsbox_20050804就不能用了。
    不过,装上lomboz,NLpack1_FeatureOverlay-eclipse-SDK-3.1.1.zip就不怎么起作用了。

    myeclipseME-4.0GA_E3.1ManualInstall版在这个版本下面也不能使用。

    eclipse3.1.1在功能上与3.1版没什么区别,但对插件兼容就不敢恭维了。

    eclipse3.1.1.jpg
posted @ 2005-10-11 09:15 Michael 阅读(1259) | 评论 (0)编辑 收藏

开放源代码协会通过Linux软件开发公司Ximian开始了一个旨在将微软.Net平台移植到Linux上来的项目。这个叫做Mono工程的项目包括创建一个开发平台允许人们为基于Linux和基于Windows系统的.Net开发应用程序。据Ximian公司的首席技术官员Miguel de Icaza说Mono项目的起因是GNOME社团特别是Ximain公司对于一个改进的开发工具的需要。

但是Mono项目的影响确是更加深远的,因为这些开发工具是基于CLI(通用语言架构)和微软提交给欧洲计算机制造协会(ECMA)的C#实现标准的。如果Mono能够完成基于这些标准创建一套Linux开发工具集的目标的话,开发者将能够编写同时在Windows和Linux上运行的.Net程序,这些程序甚至还可能在其它非Windows的操作系统上运行,比方Unix。

除了实际的开发过程,Mono项目的工具必须在开放源代码社团的内部完成而不能违反微软的知识产权专利--这实际上意味着开发者们必须基于标准重新构造这些工具而不能查看微软的任何源代码。

Mono项目包括三个核心的部分:一个C#语言的编译器,一个CLI和一个类库。 CLI是包含了类加载器的虚拟机,实时的编译器,和一个运行时环境的垃圾收集器。CLI这个组件将允许用C#编写的应用程序能够在象Linux这样的非Windows操作系统上运行。这与Java世界中Java虚拟机能够让一个应用程序在不同的操作系统上运行是类似的。

Mono项目的类库能够让应用程序完成核心的诸如XML处理,文件输入输出,和连接网络之类的任务。它将会和微软的CLI兼容(与微软在.Net framework中发布的东西紧密的配套),还有一点就是将由开放源代码团体编写的额外的类库也将和CLI兼容。

Ximian公司的de Icaza希望在年底到达项目的一个里程碑,这时编译器将能够编译类库了。图形用户界面组件--创建GUI程序所需的类库--将在明年中完成。

“我们在这个方面工作的原因是希望升级我们的开发平台来创建我们的Evolution桌面应用程序,”de Icazo说。Evolution是Ximian公司的电子邮件客户端及个人和工作组信息管理程序。“当我们看见.Net framework的时候,我们觉得这些就是我们将用来开发我们下一代产品要使用的工具,”他说。

Ximian并不将Mono和它自己看作是给Linux开发者一种途径在可用的开发工具方面赶上Windows。其实,Linux开发者将更喜欢用他们目前使用的工具来编写的编译应用程序。Ximian 将另一个开放源代码项目,SharpDevelop看作是用来提供与微软Visual Studio .Net类似的集成开发环境的一种途径。

通过以开放源代码的方式开发Mono,这个项目包含了许多对开发过程拥有广泛兴趣的人们。虽然Ximian可能希望找一些改进的开发工具来加速它的应用程序的开发过程,但其它的开发者可能是希望找到能够让他们在Windows上编写程序然后在Linux系统上运行它们的开发工具。

其中的一个大问题是如何避免微软的知识产权保护。“我们避免知识产权保护的方法是坚持非研究性的主题并使用现有的技术实现其功能,”de Icaza说。例如,Mono JIT编译器没有使用任何先进的JIT编译器技术。相反Mono的版本是基于老的JIT技术的。

De Icaza还声称Mono必须“着眼大处”还不仅仅是去年ECMA规定了些什么。也就是说,Ximian计划参与标准的制定过程并创建类库来提高.Net framework的薄弱之处,比方说电子邮件管理。

据Giga Information Group的副分析师Stacey Quandt称,微软不太可能支持Mono因为其授权是与GNU 通用公众证书为C#的授权和GNU 弱公众证书为类库和运行库的授权联系在一起的。

但即使微软不支持Mono,Mono的存在也证实了微软对于.Net能够移植到其它平台的声明是正确的。

Quandt说面向更广泛的开发团体是Mono面临的另一个挑战。例如IBM和Sun都在Java上花费了巨额的投资,自然也就很难容忍竞争行为。
posted @ 2005-10-11 08:46 Michael 阅读(180) | 评论 (0)编辑 收藏

2005年10月8日 #

结合 JavaBean 和 JDBC,我们可以编写出结构清晰,使用方便的数据库应用程序。

db 类封装了数据库操作,包括建立和关闭连接,以及执行SQL查询操作。
emp类使用db类并针对EMP 表完成了根据工号查询员工资料的功能,并提供了员工姓名的getter方法。

package db;

import java.net.*;
import java.sql.*;
import java.io.*;


public class db {
 Connection conn;
 Statement stmt;
 ResultSet rs;
 
 //数据库连接
 public void getConnection(){
  try{
   Class.forName("com.microsoft.jdbc.sqlserver.SQLServerDriver");
   conn = DriverManager.getConnection("jdbc:microsoft:sqlserver://localhost:1433;DatabaseName=Hotel;User=sa;Password=sa");
  }
  catch (Exception e){
   System.out.println(e.getMessage());
   }
  }
 
 //关闭连接
 public void closeConnection(){
  try{
   if (conn != null){
    conn.close();
   }
  }
  catch(Exception e){
   System.out.println(e.getMessage());
  }
 }
 
 //对数据库进行操作
 public ResultSet executeQuery(String sql){
  rs = null;
  try{
   getConnection();
   if (conn != null){
    stmt = conn.createStatement();
    rs = stmt.executeQuery(sql);
   }
  }
  catch (Exception e){
   System.out.println(e.getMessage());
  }
  return rs;
 }

}

package db;

import java.sql.*;


public class emp extends db {
 private String empno;
 private String ename;
 
 public emp(String em){
  empno = em;
 }
 
 //执行Sql语句 对属性ename赋值
 public void query(){
  try{
   String sSql = "select * from emp where empno =" + empno;
   ResultSet rs = executeQuery(sSql);
   if (rs.next()){
    ename = rs.getString("ename");
   }
   
  }
  catch (Exception e){
   System.out.println(e.getMessage());
  }
 }
 
 //得到ename
 public String getEname(){
  return ename;
 }

}


package db;

import java.io.*;
import java.sql.*;


public class TestBean {
 public static void main(String args[]){
  String empno;
  emp em;
  
  try{
   System.out.println("请输入工号:");
   BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
   empno = br.readLine();
   em = new em(empno);
   em.query();
   System.out.println("工号为" + empno + "的员工姓名是:" + em.getEname());
   em.closeConnection();
   
  }
  catch (Exception e){
   System.out.println(e.getMessage());
  }
  
 }

}


posted @ 2005-10-08 21:28 Michael 阅读(383) | 评论 (0)编辑 收藏

Java数据库连接(JDBC)API是一系列能够让Java编程人员访问数据库的接口,各个开发商的接口并不完全相同。在使用多年的Oracle公司的JDBC后,我积累了许多技巧,这些技巧能够使我们更好地发挥系统的性能和实现更多的功能。

  1、在客户端软件开发中使用Thin驱动程序

  在开发Java软件方面,Oracle的数据库提供了四种类型的驱动程序,二种用于应用软件、applets、servlets等客户端软件,另外二种用于数据库中的Java存储过程等服务器端软件。在客户机端软件的开发中,我们可以选择OCI驱动程序或Thin驱动程序。OCI驱动程序利用Java本地化接口(JNI),通过Oracle客户端软件与数据库进行通讯。Thin驱动程序是纯Java驱动程序,它直接与数据库进行通讯。为了获得最高的性能,Oracle建议在客户端软件的开发中使用OCI驱动程序,这似乎是正确的。但我建议使用Thin驱动程序,因为通过多次测试发现,在通常情况下,Thin驱动程序的性能都超过了OCI驱动程序。

  2、关闭自动提交功能,提高系统性能

  在第一次建立与数据库的连接时,在缺省情况下,连接是在自动提交模式下的。为了获得更好的性能,可以通过调用带布尔值false参数的Connection类的setAutoCommit()方法关闭自动提交功能,如下所示:

  conn.setAutoCommit(false);

  值得注意的是,一旦关闭了自动提交功能,我们就需要通过调用Connection类的commit()和rollback()方法来人工的方式对事务进行管理。

  3、在动态SQL或有时间限制的命令中使用Statement对象

  在执行SQL命令时,我们有二种选择:可以使用PreparedStatement对象,也可以使用Statement对象。无论多少次地使用同一个SQL命令,PreparedStatement都只对它解析和编译一次。当使用Statement对象时,每次执行一个SQL命令时,都会对它进行解析和编译。这可能会使你认为,使用PreparedStatement对象比使用Statement对象的速度更快。然而,我进行的测试表明,在客户端软件中,情况并非如此。因此,在有时间限制的SQL操作中,除非成批地处理SQL命令,我们应当考虑使用Statement对象。

  此外,使用Statement对象也使得编写动态SQL命令更加简单,因为我们可以将字符串连接在一起,建立一个有效的SQL命令。因此,我认为,Statement对象可以使动态SQL命令的创建和执行变得更加简单。

  4、利用helper函数对动态SQL命令进行格式化

  在创建使用Statement对象执行的动态SQL命令时,我们需要处理一些格式化方面的问题。例如,如果我们想创建一个将名字O'Reilly插入表中的SQL命令,则必须使用二个相连的“''”号替换O'Reilly中的“'”号。完成这些工作的最好的方法是创建一个完成替换操作的helper方法,然后在连接字符串心服用公式表达一个SQL命令时,使用创建的helper方法。与此类似的是,我们可以让helper方法接受一个Date型的值,然后让它输出基于Oracle的to_date()函数的字符串表达式。

  5、利用PreparedStatement对象提高数据库的总体效率

  在使用PreparedStatement对象执行SQL命令时,命令被数据库进行解析和编译,然后被放到命令缓冲区。然后,每当执行同一个PreparedStatement对象时,它就会被再解析一次,但不会被再次编译。在缓冲区中可以发现预编译的命令,并且可以重新使用。在有大量用户的企业级应用软件中,经常会重复执行相同的SQL命令,使用PreparedStatement对象带来的编译次数的减少能够提高数据库的总体性能。如果不是在客户端创建、预备、执行PreparedStatement任务需要的时间长于Statement任务,我会建议在除动态SQL命令之外的所有情况下使用PreparedStatement对象。

  6、在成批处理重复的插入或更新操作中使用PreparedStatement对象

  如果成批地处理插入和更新操作,就能够显著地减少它们所需要的时间。Oracle提供的Statement和 CallableStatement并不真正地支持批处理,只有PreparedStatement对象才真正地支持批处理。我们可以使用addBatch()和executeBatch()方法选择标准的JDBC批处理,或者通过利用PreparedStatement对象的setExecuteBatch()方法和标准的executeUpdate()方法选择速度更快的Oracle专有的方法。要使用Oracle专有的批处理机制,可以以如下所示的方式调用setExecuteBatch():
PreparedStatement pstmt3D null;
try {
((OraclePreparedStatement)
pstmt).setExecuteBatch(30);
...
pstmt.executeUpdate();
}


  调用setExecuteBatch()时指定的值是一个上限,当达到该值时,就会自动地引发SQL命令执行,标准的executeUpdate()方法就会被作为批处理送到数据库中。我们可以通过调用PreparedStatement类的sendBatch()方法随时传输批处理任务。

  7、使用Oracle locator方法插入、更新大对象(LOB)

  Oracle的PreparedStatement类不完全支持BLOB和CLOB等大对象的处理,尤其是Thin驱动程序不支持利用PreparedStatement对象的setObject()和setBinaryStream()方法设置BLOB的值,也不支持利用setCharacterStream()方法设置CLOB的值。只有locator本身中的方法才能够从数据库中获取LOB类型的值。可以使用PreparedStatement对象插入或更新LOB,但需要使用locator才能获取LOB的值。由于存在这二个问题,因此,我建议使用locator的方法来插入、更新或获取LOB的值。

  8、使用SQL92语法调用存储过程

  在调用存储过程时,我们可以使用SQL92或Oracle PL/SQL,由于使用Oracle PL/SQL并没有什么实际的好处,而且会给以后维护你的应用程序的开发人员带来麻烦,因此,我建议在调用存储过程时使用SQL92。

  9、使用Object SQL将对象模式转移到数据库中

  既然可以将Oracle的数据库作为一种面向对象的数据库来使用,就可以考虑将应用程序中的面向对象模式转到数据库中。目前的方法是创建Java bean作为伪装的数据库对象,将它们的属性映射到关系表中,然后在这些bean中添加方法。尽管这样作在Java中没有什么问题,但由于操作都是在数据库之外进行的,因此其他访问数据库的应用软件无法利用对象模式。如果利用Oracle的面向对象的技术,可以通过创建一个新的数据库对象类型在数据库中模仿其数据和操作,然后使用JPublisher等工具生成自己的Java bean类。如果使用这种方式,不但Java应用程序可以使用应用软件的对象模式,其他需要共享你的应用中的数据和操作的应用软件也可以使用应用软件中的对象模式。

  10、利用SQL完成数据库内的操作

  我要向大家介绍的最重要的经验是充分利用SQL的面向集合的方法来解决数据库处理需求,而不是使用Java等过程化的编程语言。

  如果编程人员要在一个表中查找许多行,结果中的每个行都会查找其他表中的数据,最后,编程人员创建了独立的UPDATE命令来成批地更新第一个表中的数据。与此类似的任务可以通过在set子句中使用多列子查询而在一个UPDATE命令中完成。当能够在单一的SQL命令中完成任务,何必要让数据在网上流来流去的?我建议用户认真学习如何最大限度地发挥SQL的功能。
posted @ 2005-10-08 18:25 Michael 阅读(194) | 评论 (0)编辑 收藏

2005年10月6日 #

第一,谈谈final, finally, finalize的区别。

    第二,Anonymous Inner Class (匿名内部类) 是否可以extends(继承)其它类,是否可以implements(实现)interface(接口)?

    第三,Static Nested Class 和 Inner Class的不同,说得越多越好(面试题有的很笼统)。

    第四,&和&&的区别。

    第五,HashMap和Hashtable的区别。

    第六,Collection 和 Collections的区别。

    第七,什么时候用assert.

    第八,GC是什么? 为什么要有GC?

    第九,String s = new String("xyz");创建了几个String Object?

    第十,Math.round(11.5)等於多少? Math.round(-11.5)等於多少?

    第十一,short s1 = 1; s1 = s1 + 1;有什么错? short s1 = 1; s1 += 1;有什么错?

    第十二,sleep() 和 wait() 有什么区别?

    第十三,Java有没有goto?

    第十四,数组有没有length()这个方法? String有没有length()这个方法?

    第十五,Overload和Override的区别。Overloaded的方法是否可以改变返回值的类型?

    第十六,Set里的元素是不能重复的,那么用什么方法来区分重复与否呢? 是用==还是equals()? 它们有何区别?

    第十七,给我一个你最常见到的runtime exception.

    第十八,error和exception有什么区别?

    第十九,List, Set, Map是否继承自Collection接口?

    第二十,abstract class和interface有什么区别?

    第二十一,abstract的method是否可同时是static,是否可同时是native,是否可同时是synchronized?

    第二十二,接口是否可继承接口? 抽象类是否可实现(implements)接口? 抽象类是否可继承实体类(concrete class)?

    第二十三,启动一个线程是用run()还是start()?

    第二十四,构造器Constructor是否可被override?

    第二十五,是否可以继承String类?

    第二十六,当一个线程进入一个对象的一个synchronized方法后,其它线程是否可进入此对象的其它方法?

    第二十七,try {}里有一个return语句,那么紧跟在这个try后的finally {}里的code会不会被执行,什么时候被执行,在return前还是后?

    第二十八,编程题: 用最有效率的方法算出2乘以8等於几?

    第二十九,两个对象值相同(x.equals(y) == true),但却可有不同的hash code,这句话对不对?

    第三十,当一个对象被当作参数传递到一个方法后,此方法可改变这个对象的属性,并可返回变化后的结果,那么这里到底是值传递还是引用传递?

    第三十一,swtich是否能作用在byte上,是否能作用在long上,是否能作用在String上?

    第三十二,编程题: 写一个Singleton出来。


以下是答案

    第一,谈谈final, finally, finalize的区别。

    final?修饰符(关键字)如果一个类被声明为final,意味着它不能再派生出新的子类,不能作为父类被继承。因此一个类不能既被声明为 abstract的,又被声明为final的。将变量或方法声明为final,可以保证它们在使用中不被改变。被声明为final的变量必须在声明时给定初值,而在以后的引用中只能读取,不可修改。被声明为final的方法也同样只能使用,不能重载
finally?再异常处理时提供 finally 块来执行任何清除操作。如果抛出一个异常,那么相匹配的 catch 子句就会执行,然后控制就会进入 finally 块(如果有的话)。

    finalize?方法名。Java 技术允许使用 finalize() 方法在垃圾收集器将对象从内存中清除出去之前做必要的清理工作。这个方法是由垃圾收集器在确定这个对象没有被引用时对这个对象调用的。它是在 Object 类中定义的,因此所有的类都继承了它。子类覆盖 finalize() 方法以整理系统资源或者执行其他清理工作。finalize() 方法是在垃圾收集器删除对象之前对这个对象调用的。

    第二,Anonymous Inner Class (匿名内部类) 是否可以extends(继承)其它类,是否可以implements(实现)interface(接口)?

    匿名的内部类是没有名字的内部类。不能extends(继承) 其它类,但一个内部类可以作为一个接口,由另一个内部类实现。

    第三,Static Nested Class 和 Inner Class的不同,说得越多越好(面试题有的很笼统)。

    Nested Class (一般是C++的说法),Inner Class (一般是JAVA的说法)。Java内部类与C++嵌套类最大的不同就在于是否有指向外部的引用上。具体可见http: //www.frontfree.net/articles/services/view.asp?id=704&page=1

    注: 静态内部类(Inner Class)意味着1创建一个static内部类的对象,不需要一个外部类对象,2不能从一个static内部类的一个对象访问一个外部类对象

    第四,&和&&的区别。

    &是位运算符。&&是布尔逻辑运算符。

    第五,HashMap和Hashtable的区别。

    都属于Map接口的类,实现了将惟一键映射到特定的值上。

    HashMap 类没有分类或者排序。它允许一个 null 键和多个 null 值。

    Hashtable 类似于 HashMap,但是不允许 null 键和 null 值。它也比 HashMap 慢,因为它是同步的。

    第六,Collection 和 Collections的区别。

    Collections是个java.util下的类,它包含有各种有关集合操作的静态方法。

    Collection是个java.util下的接口,它是各种集合结构的父接口。

第七,什么时候用assert。 

  断言是一个包含布尔表达式的语句,在执行这个语句时假定该表达式为 true。如果表达式计算为 false,那么系统会报告一个 AssertionError。它用于调试目的: 

assert(a > 0); // throws an AssertionError if a <= 0 

  断言可以有两种形式: 

  assert Expression1 ; 
  assert Expression1 : Expression2 ; 

  Expression1 应该总是产生一个布尔值。 
  Expression2 可以是得出一个值的任意表达式。这个值用于生成显示更多调试信息的 String 消息。 
断言在默认情况下是禁用的。要在编译时启用断言,需要使用 source 1.4 标记: 

  javac -source 1.4 Test.java 

  要在运行时启用断言,可使用 -enableassertions 或者 -ea 标记。 
  要在运行时选择禁用断言,可使用 -da 或者 -disableassertions 标记。 
  要系统类中启用断言,可使用 -esa 或者 -dsa 标记。还可以在包的基础上启用或者禁用断言。 

  可以在预计正常情况下不会到达的任何位置上放置断言。断言可以用于验证传递给私有方法的参数。不过,断言不应该用于验证传递给公有方法的参数,因为不管是否启用了断言,公有方法都必须检查其参数。不过,既可以在公有方法中,也可以在非公有方法中利用断言测试后置条件。另外,断言不应该以任何方式改变程序的状态。 


  第八,GC是什么? 为什么要有GC? (基础)。 

  GC是垃圾收集器。Java 程序员不用担心内存管理,因为垃圾收集器会自动进行管理。要请求垃圾收集,可以调用下面的方法之一: 

  System.gc() 
  Runtime.getRuntime().gc() 

  第九,String s = new String("xyz");创建了几个String Object? 

  两个对象,一个是“xyx”,一个是指向“xyx”的引用对象s。 

  第十,Math.round(11.5)等於多少? Math.round(-11.5)等於多少? 

  Math.round(11.5)返回(long)12,Math.round(-11.5)返回(long)-11; 

  第十一,short s1 = 1; s1 = s1 + 1;有什么错? short s1 = 1; s1 += 1;有什么错? 

  short s1 = 1; s1 = s1 + 1;有错,s1是short型,s1+1是int型,不能显式转化为short型。可修改为s1 =(short)(s1 + 1) 。short s1 = 1; s1 += 1正确。 

  第十二,sleep() 和 wait() 有什么区别? 搞线程的最爱 

  sleep()方法是使线程停止一段时间的方法。在sleep 时间间隔期满后,线程不一定立即恢复执行。这是因为在那个时刻,其它线程可能正在运行而且没有被调度为放弃执行,除非(a)“醒来”的线程具有更高的优先级,(b)正在运行的线程因为其它原因而阻塞。 

  wait()是线程交互时,如果线程对一个同步对象x 发出一个wait()调用,该线程会暂停执行,被调对象进入等待状态,直到被唤醒或等待时间到。 

  第十三,Java有没有goto? 

  Goto?java中的保留字,现在没有在java中使用。 

  第十四,数组有没有length()这个方法? String有没有length()这个方法? 

  数组没有length()这个方法,有length的属性。 
  String有有length()这个方法。 

  第十五,Overload和Override的区别。Overloaded的方法是否可以改变返回值的类型? 

  方法的重写Overriding和重载Overloading是Java多态性的不同表现。重写Overriding是父类与子类之间多态性的一种表现,重载Overloading是一个类中多态性的一种表现。如果在子类中定义某方法与其父类有相同的名称和参数,我们说该方法被重写 (Overriding)。子类的对象使用这个方法时,将调用子类中的定义,对它而言,父类中的定义如同被“屏蔽”了。如果在一个类中定义了多个同名的方法,它们或有不同的参数个数或有不同的参数类型,则称为方法的重载(Overloading)。Overloaded的方法是可以改变返回值的类型。 

  第十六,Set里的元素是不能重复的,那么用什么方法来区分重复与否呢? 是用==还是equals()? 它们有何区别? 

  Set里的元素是不能重复的,那么用iterator()方法来区分重复与否。equals()是判读两个Set是否相等。 

  equals()和==方法决定引用值是否指向同一对象equals()在类中被覆盖,为的是当两个分离的对象的内容和类型相配的话,返回真值。 

  第十七,给我一个你最常见到的runtime exception。 

  ArithmeticException,
ArrayStoreException,
BufferOverflowException,
BufferUnderflowException, 
CannotRedoException,   
CannotUndoException, 
ClassCastException,
CMMException,  
ConcurrentModificationException,  
DOMException,
EmptyStackException,
IllegalArgumentException, 
IllegalMonitorStateException,  
IllegalPathStateException, 
IllegalStateException,  
ImagingOpException,  
IndexOutOfBoundsException, 
MissingResourceException, 
NegativeArraySizeException, 
NoSuchElementException,  
NullPointerException, 
ProfileDataException,
ProviderException, 
 RasterFormatException, 
SecurityException,
SystemException,
UndeclaredThrowableException,  
UnmodifiableSetException, 
UnsupportedOperationException  

  第十八,error和exception有什么区别? 

  error 表示恢复不是不可能但很困难的情况下的一种严重问题。比如说内存溢出。不可能指望程序能处理这样的情况。

  exception 表示一种设计或实现问题。也就是说,它表示如果程序运行正常,从不会发生的情况。 


  第十九,List, Set, Map是否继承自Collection接口? 

  List,Set是 

  Map不是 

  第二十,abstract class和interface有什么区别? 

  声明方法的存在而不去实现它的类被叫做抽象类(abstract class),它用于要创建一个体现某些基本行为的类,并为该类声明方法,但不能在该类中实现该类的情况。不能创建abstract 类的实例。然而可以创建一个变量,其类型是一个抽象类,并让它指向具体子类的一个实例。不能有抽象构造函数或抽象静态方法。Abstract 类的子类为它们父类中的所有抽象方法提供实现,否则它们也是抽象类为。取而代之,在子类中实现该方法。知道其行为的其它类可以在类中实现这些方法。 

  接口(interface)是抽象类的变体。在接口中,所有方法都是抽象的。多继承性可通过实现这样的接口而获得。接口中的所有方法都是抽象的,没有一个有程序体。接口只可以定义static final成员变量。接口的实现与子类相似,除了该实现类不能从接口定义中继承行为。当类实现特殊接口时,它定义(即将程序体给予)所有这种接口的方法。然后,它可以在实现了该接口的类的任何对象上调用接口的方法。由于有抽象类,它允许使用接口名作为引用变量的类型。通常的动态联编将生效。引用可以转换到接口类型或从接口类型转换,instanceof 运算符可以用来决定某对象的类是否实现了接口。 

  第二十一,abstract的method是否可同时是static,是否可同时是native,是否可同时是synchronized? 

  都不能 

  第二十二,接口是否可继承接口? 抽象类是否可实现(implements)接口? 抽象类是否可继承实体类(concrete class)? 

  接口可以继承接口。抽象类可以实现(implements)接口,抽象类是否可继承实体类,但前提是实体类必须有明确的构造函数。 

  第二十三,启动一个线程是用run()还是start()? 

  启动一个线程是调用start()方法,使线程所代表的虚拟处理机处于可运行状态,这意味着它可以由JVM调度并执行。这并不意味着线程就会立即运行。run()方法可以产生必须退出的标志来停止一个线程。 

 

  第二十四,构造器Constructor是否可被override? 

  构造器Constructor不能被继承,因此不能重写Overriding,但可以被重载Overloading。 

  第二十五,是否可以继承String类? 

  String类是final类故不可以继承。 

  第二十六,当一个线程进入一个对象的一个synchronized方法后,其它线程是否可进入此对象的其它方法? 

  不能,一个对象的一个synchronized方法只能由一个线程访问。 

  第二十七,try {}里有一个return语句,那么紧跟在这个try后的finally {}里的code会不会被执行,什么时候被执行,在return前还是后? 

  会执行,在return前执行。 

  第二十八,编程题: 用最有效率的方法算出2乘以8等於几? 

  有C背景的程序员特别喜欢问这种问题。 

  2 << 3 

  第二十九,两个对象值相同(x.equals(y) == true),但却可有不同的hash code,这句话对不对? 

  不对,有相同的hash code。 

  第三十,当一个对象被当作参数传递到一个方法后,此方法可改变这个对象的属性,并可返回变化后的结果,那么这里到底是值传递还是引用传递? 

  是值传递。Java 编程语言只由值传递参数。当一个对象实例作为一个参数被传递到方法中时,参数的值就是对该对象的引用。对象的内容可以在被调用的方法中改变,但对象的引用是永远不会改变的。 


  第三十一,swtich是否能作用在byte上,是否能作用在long上,是否能作用在String上? 

  switch(expr1)中,expr1是一个整数表达式。因此传递给 switch 和 case 语句的参数应该是 int、 short、 char 或者 byte。long,string 都不能作用于swtich。 

  第三十二,编程题: 写一个Singleton出来。

  Singleton模式主要作用是保证在Java应用程序中,一个类Class只有一个实例存在。 

  一般Singleton模式通常有几种种形式: 

  第一种形式: 定义一个类,它的构造函数为private的,它有一个static的private的该类变量,在类初始化时实例话,通过一个public的getInstance方法获取对它的引用,继而调用其中的方法。 

public class Singleton { 
  private Singleton(){} 
  //在自己内部定义自己一个实例,是不是很奇怪? 
  //注意这是private 只供内部调用 
  private static Singleton instance = new Singleton(); 
  //这里提供了一个供外部访问本class的静态方法,可以直接访问   
  public static Singleton getInstance() { 
    return instance;    
   } 

  第二种形式: 

public class Singleton { 
  private static Singleton instance = null; 
  public static synchronized Singleton getInstance() { 
  //这个方法比上面有所改进,不用每次都进行生成对象,只是第一次      
  //使用时生成实例,提高了效率! 
  if (instance==null) 
    instance=new Singleton(); 
return instance;   } 

  其他形式: 

  定义一个类,它的构造函数为private的,所有方法为static的。 

  一般认为第一种形式要更加安全些 

  第三十三 Hashtable和HashMap 

  Hashtable继承自Dictionary类,而HashMap是Java1.2引进的Map interface的一个实现 

  HashMap允许将null作为一个entry的key或者value,而Hashtable不允许 

  还有就是,HashMap把Hashtable的contains方法去掉了,改成containsvalue和containsKey。因为contains方法容易让人引起误解。 

  最大的不同是,Hashtable的方法是Synchronize的,而HashMap不是,在多个线程访问Hashtable时,不需要自己为它的方法实现同步,而HashMap就必须为之提供外同步。 

  Hashtable和HashMap采用的hash/rehash算法都大概一样,所以性能不会有很大的差异。 

版权声明  本篇文章对您是否有帮助?  投票: 是    否     投票结果:     24       0
 
 
 
作者其它文章:
Java多线程程序设计
前车之覆,后车之鉴 --开源项目经验谈
Resin服务器的使用
用Java的加密机制来保护你的数据
使用XML封装数据库操作语句的实现
作者全部文章     查看作者的Blog 
 
 
  评论人:onefox    参与分: 40162    专家分: 965  发表时间: 2005-03-21 21:21 
很有自信的能回答的,大概就 30%题目。

其他很多涉及的问题平时都用自己的一套过滤掉了。

没有仔细研究过 
 
  评论人:javasleepless    参与分: 312    专家分: 10  发表时间: 2005-03-25 19:27 
8错,可以借此机会弄清那些混淆的概念 
 
  评论人:andersonmao    参与分: 94    专家分: 0  发表时间: 2005-05-12 10:51 
关于26,没有说详细。
=============================================
  第二十六,当一个线程进入一个对象的一个synchronized方法后,其它线程是否可进入此对象的其它方法? 
  不能,一个对象的一个synchronized方法只能由一个线程访问。 
=============================================关于26,没有说详细。
=============================================
    第二十六,当一个线程进入一个对象的一个synchronized方法后,其它线程是否可进入此对象的其它方法? 
    不能,一个对象的一个synchronized方法只能由一个线程访问。 
=============================================
    一个对象的所有synchronized方法在同一个时间只能由一个线程访问。这个对象的其它不是synchronized方法不受这个限制。就是说

当一个线程正在执行这个对象的一个synchronized时。这个对象的所有synchronized方法都不能被其它线程访问,但是这个对象的不是

synchronized的方法可以被其它线程访问。
    例子:
SynObject.java
====
public class SynObject{   
    public synchronized void SynMethod(int index){
        System.out.println("Thread Index="+index+" In SynMethod - Begin");
        try{
            Thread.sleep(100);
        }catch(Exception e){
        }
        System.out.println("Thread Index="+index+" In SynMethod - End");
    }
    public void NoneSynMethod(int index){
        System.out.println("Thread Index="+index+" In NoneSynMethod");
    }
}
====
ThreadTest.java
====
public class ThreadTest extends Thread{
    int threadNo;
    static SynObject obj=new SynObject();
    public void run(){
        System.out.println("Thread No="+threadNo+" Begin run");
        for(int i=0;i<3;i++){
            obj.SynMethod(threadNo);
            obj.NoneSynMethod(threadNo);
        }
    }
    public ThreadTest(int No){
        threadNo=No;
    }
    public static void main(String[] a){
        Thread th1=new ThreadTest(1);
        Thread th2=new ThreadTest(2);
        th1.start();
        th2.start();
    }   
}
====
运行 java ThreadTest
可能的结果为(因为线程相关,结果可能不一样):
Thread No=1 Begin run
Thread Index=1 In SynMethod - Begin
Thread No=2 Begin run
Thread Index=1 In SynMethod - End
Thread Index=2 In SynMethod - Begin
Thread Index=1 In NoneSynMethod            //在Thread 2 执行SynMethod() 过程中,Thread 1 执行了 NoneSynMethod()
Thread Index=2 In SynMethod - End
Thread Index=2 In NoneSynMethod
Thread Index=1 In SynMethod - Begin
Thread Index=1 In SynMethod - End
Thread Index=2 In SynMethod - Begin
Thread Index=1 In NoneSynMethod
Thread Index=2 In SynMethod - End
Thread Index=1 In SynMethod - Begin
Thread Index=2 In NoneSynMethod
Thread Index=1 In SynMethod - End
Thread Index=1 In NoneSynMethod
Thread Index=2 In SynMethod - Begin
Thread Index=2 In SynMethod - End
Thread Index=2 In NoneSynMethod


1. 使类尽可能短小精悍,而且只解决一个特定的问题。下面是对类设计的一些建议:

  一个复杂的开关语句:考虑采用"多形"机制;
  数量众多的方法涉及到类型差别极大的操作:考虑用几个类来分别实现;
  许多成员变量在特征上有很大的差别:考虑使用几个类.


2. 在多线程环境中,隐私是特别重要的一个因素--只有private字段才能在非同步使用的情况下受到保护。

3. 任何时候只要发现类与类之间结合得非常紧密,就需要考虑是否采用内部类,从而改善编码及维护工作(参见第14章14.1.2小节的"用内部类改进代码")。
 
 
 


  

posted @ 2005-10-06 12:05 Michael 阅读(253) | 评论 (0)编辑 收藏

Hibernate 提供了比较好的分页查询api极大地方便了使用者。以下是我在项目中写的一个Hibernate 分页查询的代码:
//根据Message 对象所封装的查询条件分页查询Message对象,S
public List getPageinMessage(Message message,int startRow,int rows) throws DAOException {       
        StringBuffer queryString=new StringBuffer(" from Message as message where ");
        //ActionExceptionHandler actionHandler=new ActionExceptionHandler();
        if(message.getSource()!=null){
            queryString.append("message.source.id="+message.getSource().getId());
            queryString.append(" and senderDelFlag=0");
        }else if(message.getTarget()!=null){
            //if message's target is not null query message base on target's id
            logger.debug("query inbox==================");
            queryString.append("message.target.id="+message.getTarget().getId());
            queryString.append(" and receiverDelFlag=0");
        } else{
            throw new BusinessException("未选定消息发送者或接受者"); 
        }
        queryString.append(" order by message.creatDate DESC");
        Query query=null;
        List messageList=null;
        Session session=this.getSession();       
        try {
            query=session.createQuery(queryString.toString());
            query.setFirstResult(startRow);
            query.setMaxResults(rows);
            logger.debug("first row===="+startRow+"===row amount==="+rows);
            messageList=query.list();
            if(messageList.size()>0){
                Message message2=(Message)messageList.get(0);              
                logger.debug("messageList's length==="+message2);           
                logger.debug("messageList's length==="+messageList.size());
            }
        } catch (HibernateException e) {
            // TODO Auto-generated catch block          
            e.printStackTrace();
            throw new BusinessException("读取页面数据发生错误"); 
        }finally{
            if(session!=null&&session.isOpen()){
                try {
                    session.close();
                } catch (HibernateException e1) {
                    e1.printStackTrace();
                    throw new BusinessException("会话关闭异常");                   
                }
            }
        }          
        return messageList;       
    }
posted @ 2005-10-06 11:05 Michael 阅读(223) | 评论 (0)编辑 收藏

2005年10月5日 #

Java Servlet及其特点

  Servlet是Java技术对CGI编程的回答。Servlet程序在服务器端运行,动态地生成Web页面。与传统的CGI和许多其他类似CGI的技术相比,Java Servlet具有更高的效率,更容易使用,功能更强大,具有更好的可移植性,更节省投资。

      高效

  在传统的CGI中,每个请求都要启动一个新的进程,如果CGI程序本身的执行时间较短,启动进程所需要的开销很可能反而超过实际执行时间。而在Servlet中,每个请求由一个轻量级的Java线程处理(而不是重量级的操作系统进程)。

  在传统CGI中,如果有N个并发的对同一CGI程序的请求,则该CGI程序的代码在内存中重复装载了N次;而对于Servlet,处理请求的是N个线程,只需要一份Servlet类代码。在性能优化方面,Servlet也比CGI有着更多的选择,比如缓冲以前的计算结果,保持数据库连接的活动,等等。

   其实CGI是Common Gateway Interface(公共网关接口)

  方便

  Servlet提供了大量的实用工具例程,例如自动地解析和解码HTML表单数据、读取和设置HTTP头、处理Cookie、跟踪会话状态等。

  功能强大

  在Servlet中,许多使用传统CGI程序很难完成的任务都可以轻松地完成。例如,Servlet能够直接和Web服务器交互,而普通的CGI程序不能。Servlet还能够在各个程序之间共享数据,使得数据库连接池之类的功能很容易实现。

  可移植性好

  Servlet用Java编写,Servlet API具有完善的标准。因此,为I-Planet Enterprise Server写的Servlet无需任何实质上的改动即可移植到Apache、Microsoft IIS或者WebStar。几乎所有的主流服务器都直接或通过插件支持Servlet。

  节省投资

  不仅有许多廉价甚至免费的Web服务器可供个人或小规模网站使用,而且对于现有的服务器,如果它不支持Servlet的话,要加上这部分功能也往往是免费的(或只需要极少的投资)。

 


 JSP及其特点

  JavaServer Pages(JSP)是一种实现普通静态HTML和动态HTML混合编码的技术

许多由CGI程序生成的页面大部分仍旧是静态HTML,动态内容只在页面中有限的几个部分出现。但是包括Servlet在内的大多数CGI技术及其变种,总是通过程序生成整个页面。JSP使得我们可以分别创建这两个部分。例如,下面就是一个简单的JSP页面:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML>
<HEAD><TITLE>欢迎访问网上商店</TITLE></HEAD>
<BODY>
<H1>欢迎</H1>
<SMALL>欢迎,
<!-- 首次访问的用户名字为"New User" -->
<% out.println(Utils.getUserNameFromCookie(request)); %>
要设置帐号信息,请点击
<A HREF="Account-Settings.html">这里</A></SMALL>
<P>
页面的其余内容。.
</BODY></HTML>

  下面是JSP和其他类似或相关技术的一个简单比较:

  JSP和Active Server Pages(ASP)相比

  Microsoft的ASP是一种和JSP类似的技术。JSP和ASP相比具有两方面的优点。首先,动态部分用Java编写,而不是VB Script或其他Microsoft语言,不仅功能更强大而且更易于使用。第二,JSP应用可以移植到其他操作系统和非Microsoft的Web服务器上。

  JSP和纯Servlet相比

  JSP并没有增加任何本质上不能用Servlet实现的功能。但是,在JSP中编写静态HTML更加方便,不必再用 println语句来输出每一行HTML代码。更重要的是,借助内容和外观的分离,页面制作中不同性质的任务可以方便地分开:比如,由页面设计专家进行HTML设计,同时留出供Servlet程序员插入动态内容的空间。

  JSP和服务器端包含(Server-Side Include,SSI)相比

  SSI是一种受到广泛支持的在静态HTML中引入外部代码的技术。JSP在这方面的支持更为完善,因为它可以用Servlet而不是独立的程序来生成动态内容。另外,SSI实际上只用于简单的包含,而不是面向那些能够处理表单数据、访问数据库的“真正的”程序。

  JSP和JavaScript相比

  JavaScript能够在客户端动态地生成HTML。虽然JavaScript很有用,但它只能处理以客户端环境为基础的动态信息。除了Cookie之外,HTTP状态和表单提交数据对JavaScript来说都是不可用的。另外,由于是在客户端运行,JavaScript不能访问服务器端资源,比如数据库、目录信息等等

posted @ 2005-10-05 20:06 Michael 阅读(633) | 评论 (0)编辑 收藏

1 javascript ,设置一个变量,只允许提交一次。 

  <script language="javascript">

   var checkSubmitFlg = false;

   function checkSubmit() {

   if (checkSubmitFlg == true) {

   return false;

   }

   checkSubmitFlg = true;

   return true;

   }

   document.ondblclick = function docondblclick() {

   window.event.returnValue = false;

   }

   document.onclick = function doconclick() {

   if (checkSubmitFlg) {

   window.event.returnValue = false;

   }

   }

  </script>
<html:form action="myAction.do" method="post" onsubmit="return checkSubmit();">
  

  2 还是javascript,将提交按钮或者image置为disable  

   <html:form action="myAction.do" method="post"

   onsubmit="getElById('submitInput').disabled = true; return true;">   

   <html:image styleId="submitInput" src="images/ok_b.gif" border="0" /> 

   </html:form>  

  3 利用struts的同步令牌机制  

  利用同步令牌(Token)机制来解决Web应用中重复提交的问题,Struts也给出了一个参考实现。

  基本原理: 

  服务器端在处理到达的请求之前,会将请求中包含的令牌值与保存在当前用户会话中的令牌值进行比较,看是否匹配。在处理完该请求后,且在答复发送给客户端之前,将会产生一个新的令牌,该令牌除传给客户端以外,也会将用户会话中保存的旧的令牌进行替换。这样如果用户回退到刚才的提交页面并再次提交的话,客户端传过来的令牌就和服务器端的令牌不一致,从而有效地防止了重复提交的发生。 

  if (isTokenValid(request, true)) {

   // your code here

   return mapping.findForward("success");

  } else {

   saveToken(request);

   return mapping.findForward("submitagain");

  } 

  Struts根据用户会话ID和当前系统时间来生成一个唯一(对于每个会话)令牌的,具体实现可以参考TokenProcessor类中的generateToken()方法。  

  1. //验证事务控制令牌,<html:form >会自动根据session中标识生成一个隐含input代表令牌,防止两次提交

  2. 在action中:  

   //<input type="hidden" name="org.apache.struts.taglib.html.TOKEN"

   // value="6aa35341f25184fd996c4c918255c3ae">

   if (!isTokenValid(request)) errors.add(ActionErrors.GLOBAL_ERROR,

   new ActionError("error.transaction.token"));

   resetToken(request); //删除session中的令牌  

  3. action有这样的一个方法生成令牌  

   protected String generateToken(HttpServletRequest request) {  

   HttpSession session = request.getSession();

   try {

   byte id[] = session.getId().getBytes();

   byte now[] =

   new Long(System.currentTimeMillis()).toString().getBytes();

   MessageDigest md = MessageDigest.getInstance("MD5");

   md.update(id);

   md.update(now);

   return (toHex(md.digest()));

   } catch (IllegalStateException e) {

   return (null);

   } catch (NoSuchAlgorithmException e) {

   return (null);

   }

   }

posted @ 2005-10-05 20:04 Michael 阅读(222) | 评论 (0)编辑 收藏

仅列出标题