Java国际化标准

<淘宝热门商品:
 

68.00元  

海洋新奇特购物天堂

 

¥:7.00 

极限特攻-新奇产品仓库    金秋时节好礼送不停 

创意小猪/手摇式LED手电/手动手电/LED手电


来源:程序员网

小小豆叮

J2ee学习笔记.doc

<淘宝热门商品:
 

 

大芬村油画网上订购【画师联盟】纯手绘油画无框画装饰画四钻信誉

 

3.80 元  

幸福生活 联盟津沽 种子蔬菜种子、花卉种子、园艺用品

【天津商盟】【皇冠信誉】食用草莓种子-观赏草莓种子-花种


来源:程序员网

小小豆叮

学习GoF设计模式的重要性

GoF的《设计模式》也许你没有听说过,但是《Thingking in Java》(Java编程思想)你应该知道甚至读过吧! 在浏览《Thingking in Java》(第一版)时,你是不是觉得好象这还是一本Java基础语言书籍?但又不纯粹是,因为这本书的作者将面向对象的思想巧妙的融合在Java的具体技术上,潜移默化的让你感觉到了一种新的语言和新的思想方式的诞生。 但是读完这本书,你对书中这些蕴含的思想也许需要一种更明晰更系统更透彻的了解和掌握,那么你就需要研读GoF的《设计模式》了。 《Thingking in Java》(第一版中文)是这样描述设计模式的:他在由Gamma, Helm和Johnson Vlissides简称Gang of Four(四人帮),缩写GoF编著的《Design Patterns》一书中被定义成一个“里程碑”。事实上,那本书现在已成为几乎所有OOP(面向对象程序设计)程序员都必备的参考书。(在国外是如此)。 GoF的《设计模式》是所有面向对象语言(C++ Java C#)的基础,只不过不同的语言将之实现得更方便地使用。 GOF的设计模式是一座"桥" 就Java语言体系来说,GOF的设计模式是Java基础知识和J2EE框架知识之间一座隐性的"桥"。 会Java的人越来越多,但是一直徘徊在语言层次的程序员不在少数,真正掌握Java中接口或抽象类的应用不是很多,大家经常以那些技术只适合大型项目为由,避开或忽略它们,实际中,Java的接口或抽象类是真正体现Java思想的核心所在,这些你都将在GoF的设计模式里领略到它们变幻无穷的魔力。 GoF的设计模式表面上好象也是一种具体的"技术",而且新的设计模式不断在出现,设计模式自有其自己的发展轨道,而这些好象和J2EE .Net等技术也无关! 实际上,GoF的设计模式并不是一种具体"技术",它讲述的是思想,它不仅仅展示了接口或抽象类在实际案例中的灵活应用和智慧,让你能够真正掌握接口或抽象类的应用,从而在原来的Java语言基础上跃进一步,更重要的是,GoF的设计模式反复向你强调一个宗旨:要让你的程序尽可能的可重用。 这其实在向一个极限挑战:软件需求变幻无穷,计划没有变化快,但是我们还是要寻找出不变的东西,并将它和变化的东西分离开来,这需要非常的智慧和经验。 而GoF的设计模式是在这方面开始探索的一块里程碑。 J2EE等属于一种框架软件,什么是框架软件?它不同于我们以前接触的Java API等,那些属于Toolkist(工具箱),它不再被动的被使用,被调用,而是深刻的介入到一个领域中去,J2EE等框架软件设计的目的是将一个领域中不变的东西先定义好,比如整体结构和一些主要职责(如数据库操作 事务跟踪 安全等),剩余的就是变化的东西,针对这个领域中具体应用产生的具体不同的变化需求,而这些变化东西就是J2EE程序员所要做的。 由此可见,设计模式和J2EE在思想和动机上是一脉相承,只不过 1.设计模式更抽象,J2EE是具体的产品代码,我们可以接触到,而设计模式在对每个应用时才会产生具体代码。 2.设计模式是比J2EE等框架软件更小的体系结构,J2EE中许多具体程序都是应用设计模式来完成的,当你深入到J2EE的内部代码研究时,这点尤其明显,因此,如果你不具备设计模式的基础知识(GoF的设计模式),你很难快速的理解J2EE。不能理解J2EE,如何能灵活应用? 3.J2EE只是适合企业计算应用的框架软件,但是GoF的设计模式几乎可以用于任何应用!因此GoF的设计模式应该是J2EE的重要理论基础之一。 所以说,GoF的设计模式是Java基础知识和J2EE框架知识之间一座隐性的"桥"。为什么说隐性的? GOF的设计模式是一座隐性的"桥" 因为很多人没有注意到这点,学完Java基础语言就直接去学J2EE,有的甚至鸭子赶架,直接使用起Weblogic等具体J2EE软件,一段时间下来,发现不过如此,挺简单好用,但是你真正理解J2EE了吗?你在具体案例中的应用是否也是在延伸J2EE的思想? 如果你不能很好的延伸J2EE的思想,那你岂非是大炮轰蚊子,认识到J2EE不是适合所有场合的人至少是明智的,但我们更需要将J2EE用对地方,那么只有理解J2EE此类框架软件的精髓,那么你才能真正灵活应用Java解决你的问题,甚至构架出你自己企业的框架来。(我们不能总是使用别人设定好的框架,为什么不能有我们自己的框架?) 因此,首先你必须掌握GoF的设计模式。虽然它是隐性,但不是可以越过的。 在著名的EJB领域顶尖的专家Richard Monson-Haefel的个人网站:www.EJBNow.com中Richard极力推荐的几本书中就有GoF的《设计模式》,原文如下: Design Patterns Most developers claim to experience an epiphany reading this book. If you've never read the Design Patterns book then you have suffered a very serious gap in your programming education that should be remedied immediately. 翻译: 很多程序员在读完这本书,宣布自己相当于经历了一次"主显节"(纪念那稣降生和受洗的双重节日),如果你从来没有读过这本书,你会在你的程序教育生涯里存在一个严重裂沟,所以你应该立即挽救弥补! <淘宝热门商品:
 

18.00 元 

最新版 2面圆领打底衫 精品莱卡棉

 

12.00 元  

最新奇的负离子手表,减压手表


来源:程序员网

小小豆叮

建筑和软件中模式之异同

CSDN的透明特别推崇《建筑的永恒之道》,认为从中探寻到软件的永恒之道,并就"设计模式"写了专门文章《探寻软件的永恒之道 》,其中很多观点我看了很受启发,以前我也将"设计模式" 看成一个简单的解决方案,没有从一种高度来看待"设计模式"在软件中地位,下面是我自己的一些想法: 建筑和软件某些地方是可以来比喻的 特别是中国传统建筑,那是很讲模式的,这些都是传统文化使然,比如京剧 一招一式都有套路;中国画,也有套路,树应该怎么画法?有几种画法?艺术大家通常是创造出自己的套路,比如明末清初,水墨画法开始成熟,这时画树就不用勾勒这个模式了,而是一笔下去,浓淡几个叶子,待毛笔的水墨要干枯时,画一下树干,这样,一个活生写意的树就画出来. 我上面这些描述其实都是一种模式,创建模式的人是大师,但是拘泥于模式的人永远是工匠. 再回到传统建筑中,中国的传统建筑是过分注重模式了,所以建筑风格发展不大,基本分南北两派,大家有个感觉,旅游时,到南方,你发现古代名居建筑都差不多;北方由于受满人等少数民族的影响,在建筑色彩上有些与南方迥异,但是很多细节地方都差不多.这些都是模式的体现. 由于建筑受材料和功用以及费用的影响,所用模式种类不多,这点是和软件很大的不同. 正因为这点不同,导致建筑的管理模式和软件的管理模式就有很多不同, 有些人认识不到这点,就产生了可以大量使用"软件蓝领"的想法,因为他羡慕建筑中"民工"的低成本. 要知道软件还有一个与建筑截然相反的责任和用途,那就是:现代社会中,计划感不上变化,竞争激烈,所有一切变幻莫测,要应付所有这些变化,首推信息技术中的软件,只有软件能够帮助人类去应付各种变化.而这点正好与建筑想反,建筑是不能帮助人类去应付变化的,(它自己反而要求稳固,老老实实帮助人遮风避雨,总不能叫人类在露天或树叶下打开电脑编软件吧). 软件要帮助人类去应付变化,这是软件的首要责任,所以,软件中模式产生的目的就和建筑不一样了,建筑中的模式产生可以因为很多原因:建筑大师的创意;材料的革新等;建筑中这些模式一旦产生,容易发生另外一个缺点,就是有时会阻碍建筑本身的发展,因为很多人会不思创造,反复使用老的模式进行设计,阻碍建筑的发展. 但是在软件中,这点正好相反,软件模式的产生是因为变化的东西太多,为减轻人类的负担,将一些不变的东西先用模式固化,这样让人类可以更加集中精力对付变化的东西,所以在软件中大量反复使用模式(我个人认为这样的软件就叫框架软件了,比如J2EE),不但没阻碍软件的发展,反而是推动了软件的发展.因为其他使用这套软件的人就可以将更多精力集中在对付那些无法用模式的应用上来. 可以关于建筑和软件中的模式作用可以总结如下: 在软件中,模式是帮助人类向"变化"战斗,但是在软件中还需要和'变化'直接面对面战斗的武器:人的思维,特别是创造 分析思维等等,这些是软件真正的灵魂,这种思维可以说只要有实践需求(如有新项目)就要求发生,发生频度高,人类的创造或分析思维决定了软件的质量和特点。 而在建筑中,模式可以构成建筑全部知识,当有新的需求(如有新项目),一般使用旧的模式都可以完成,因此对人类的创造以及分析思维不是每个项目都必须的,也不是非常重要的,对创造性的思维的需求只是属于锦上添花(除非人类以后离开地球居住了〕。 <淘宝热门商品:
 

¥:27.00 

◆男童装女童装◆6-15元◆

0货号559◆女童装 纯棉线线衣(1-5岁)

 

:鲜花速递/蛋糕配送/园艺花艺 

缤纷园艺淘宝店--苗圃直销各类花卉苗木 购买送惊喜


来源:程序员网

小小豆叮

Servlet传送对象给Applet使用



 前日,一位朋友与我谈论Servlet与Applet共享Java对象的问题,现发表出来与大家分享,文中瑕癖
之处甚多,望各位指教.
 朋友谈论的需求是这样的:他想通过页面上一个Applet呼叫一个服务器Servlet,而从Servlet产生
一个Java对象再传给另外一个Applet,怎么样让Servlet实时地把对象传给Applet这是一个问题,有一个方
案是采用JMS(JavaMessageService),在我以后的文章中会有叙述的.这里我给大家展示一个简单的实现,那
就是让Applet主动访问Servlet,让Servlet返回Java对象.下面给出全部代码和配置,其中Applet部分涵盖
了Javascript与Applet的互相调用,对于该部分不感兴趣的朋友可以复略.


第一步,编写需要传递的对象类
/**
 * Class Person just a demo for translate this class to client
 * @author:  rookie
 * @datetime: 2002-7-26
 */
package exapplet;
import java.io.*;

public class Person implements Serializable {//必须实现Serializable接口才能序列化
 private String m_Name;
 private int  m_Age;

 public Person() {
  this("",0);
 }
 public Person(String name,int age) {
  this.m_Name = name;
  this.m_Age = age;
 }
 public String getName() {
  return m_Name;
 }
 public int getAge() {
  return m_Age;
 }

 //Serializable接口中声明的方法
 private void writeObject(java.io.ObjectOutputStream out)
     throws IOException {
  out.defaultWriteObject();
 }

 //Serializable接口中声明的方法 
 private void readObject(java.io.ObjectInputStream in)
     throws IOException, ClassNotFoundException {
  in.defaultReadObject();
 }

 public static void main(String[] args) {
  try {
   Person p = new Person("Liaoyuan",25);
   ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(new File("test.obj")));
   oos.writeObject(p);
   oos.close();
   ObjectInputStream ois = new ObjectInputStream (new FileInputStream(new File("test.obj")));
   Person q = (Person)ois.readObject();
   ois.close();
   System.out.println(q.getName());
   System.out.println(q.getAge());
  } catch(Exception exp) {
   exp.printStackTrace();
  }
 }
}


第二步,实现Servlet
package exapplet;
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;

public class MyServlet extends HttpServlet
{
 public void doGet(HttpServletRequest req,HttpServletResponse res)
  throws ServletException,IOException
 {
  String fPath = "H:\\XSchool\\WorkingRoom\\exapplet\\src\\java.obj";
  
  String act = req.getParameter("Action");
  if ( act.equals("UpdateObject") ) {
   //创建更新JavaObject
   Person p = new Person("Liaoyuan",26);
   ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(new File(fPath)));
   oos.writeObject(p);
   oos.close();
   DataOutputStream dos = new DataOutputStream(res.getOutputStream());
   dos.writeBytes("Server Java Object Updated OK!");
   dos.close();
  } else if ( act.equals("GetObject") ) {
   //传回对象给Applet
   res.setContentType("application/octet-stream");
   Person p;
   ObjectInputStream ois = new ObjectInputStream(new FileInputStream(new File(fPath)));
   try {
    p    = (Person)ois.readObject();
   } catch (ClassNotFoundException e) {
    p = new Person();
   }
   ois.close();
   
   ObjectOutputStream oos = new ObjectOutputStream(res.getOutputStream());
   oos.writeObject(p);
   oos.close();
  }
 }
 public String getServletInfo()
 {
  return "A simple Servlet!";
 }
}


第三步,实现呼叫Servlet更新对象的Applet
package exapplet;
import java.awt.*;
import java.applet.*;
import java.io.*;
import java.net.*;
import netscape.javascript.*;

public class MyApplet extends java.applet.Applet
{
 public void init()
 {
 }
 public void paint(Graphics g)
 {}

 //This method will be call in html
 public void invoke() {
  try {
   URL url = new URL("http://rookie:8080/workingroom/exapplet/PostToApplet?Action=UpdateObject");
   URLConnection urlcon = url.openConnection();
   urlcon.connect();
   
   DataInputStream dis=new DataInputStream(urlcon.getInputStream());
   String txt = dis.readLine();
   dis.close();
   
   String[] info = new String[]{txt};
   JSObject.getWindow(this).call("alert",info);
  } catch (Exception e) {
  }
 }
}


第四步,实现提取对象的Applet
package exapplet;
import java.awt.*;
import java.applet.*;
import java.io.*;
import java.net.*;
import netscape.javascript.*;

public class MyAppletB extends java.applet.Applet
{
 public void init()
 {
 }
 public void paint(Graphics g)
 {}

 //This method will be call in html
 public void invoke() {
  try {
   URL url = new URL("http://rookie:8080/workingroom/exapplet/PostToApplet?Action=GetObject");
   URLConnection urlcon = url.openConnection();
   urlcon.connect();
   ObjectInputStream ois=new ObjectInputStream(urlcon.getInputStream());
   Person p = (Person)ois.readObject();
   ois.close();
   String[] info = new String[]{"Person Info\n\n-Name: "+p.getName()+"\n-Age : "+p.getAge()};
   JSObject.getWindow(this).call("alert",info);
  } catch (Exception e) {
  }
 }
}

第五步,配制WebServer(我用的是Tomcat4.0)
拷贝编译后的MyServlet.class到相应目录下,
编辑对应的web.xml文件,确保下面的内容正确



 
        PostToApplet
        exapplet.MyServlet
   

 
       
            PostToApplet
       

       
            /exapplet/PostToApplet
       

   

第六步,编写html文件
呼叫更新的html


New Document For Using Applet Call Servlet Update Java Object


Hello This is a Test!





提取对象的html


New Document For Using Applet


Hello This is a Test!







中间有错误的地方请指教,zlyperson@163.net


<淘宝热门商品:
 

3C数码配件 

家倍乐床上笔记本电脑桌专利厂家批发零售店

 

保健品/滋补品 

淑芳阁_苗条姿_最有效的减肥瘦身与丰胸专卖店


来源:程序员网

小小豆叮

无线移动如何定位

目前基于无线移动位置服务技术的应用开始兴起,是GIS与主流IT技术、无线通信技术加速融合的结果。随着GIS技术的发展,出现了GIS与主流IT技术、无线通信技术加速融合的趋势。而无线移动位置服务技术的兴起,标志着GIS技术由面向部门级、企业级的应用转向面向大规模社会化服务。随着无线移动位置服务技术的成熟和发展,在不远的将来,人们就可以享受到多种多样的LBS服务。比如,走进商场时,手机就会自动提醒商品的促销信息;路过酒店、饭店、电影院、停车场的时候,手持终端会自动提供其风格、报价、空车位、空房信息;出行在外时,系统会自动告诉你行车最佳路线—综合考虑堵车、单行线、高架桥等各种实时交通因素 目前,基于无线移动位置服务技术的应用在国内刚刚起步,各个厂商都推出自己的解决方案。中国移动也开始在广东、福建、山西等地进行试点工作。方正数码作为国内空间信息技术应用的推动者和移动互联应用解决方案提供商,致力于发展在互联网领域里面空间信息技术和移动互联领域的行业性解决方案技术研究,为客户提供空间信息和地图信息服务,以及电子商务空间信息解决方案。而基于位置相关的信息服务(Location Based Service)结合无线互联网(Wireless Internet)的应用和解决方案也是方正数码空间信息技术业务将主攻的方向之一。经过一年的努力,方正数码在无线移动位置服务技术取得突破性的进展,提出移动定位服务平台解决方案,并在上海APEC会议和山西移动得以成功实践,本文以山西移动定位服务平台为例,对LBS(Location Based Service)技术的应用和特点做了详细介绍,并对关键技术的发展和实现方式进行了探讨。 平台概述 无线定位服务网关是针对中国的现有移动网络状况,结合Nokia移动定位中心mPosiontion 系统,提出移动定位中间件——方正移动定位服务平台解决方案,使SP更容易接入移动定位中心,享受包括定位、地理信息、鉴权、计费等综合性服务。 在图中,定位中间件方正定位服务网关是一个连接SP与定位中心、地图信息;对于SP 而言,定位服务网关提供API定位应用接口(该接口需CMCC发布后,即可成为定位中间件定位服务网关的标准接口),服务提供商只需调用该接口通过XML协议就可以支持终端用户得到定位服务。 关键技术 无线移动定位技术 目前移动定位使用比较广泛的是GSM网络定位法和GPS定位技术。其中,GSM网络定位法不需要对用户终端的升级,适用于面向社会化的服务。GPS定位技术是目前比较常用的技术,但因客户端成本相对较高,一般用于企业级和行业内部的解决方案。 在现有的GSM网络中,由于其它定位技术对现有的网络体系更改大,因此CellId方式以及TA方式在网络定位技术中得到广泛的使用,其当CellId+TA的方式混合使用,能使定位精度达500米以内,具体精度视Cell半径而不同,在城区范围内一般可以达到200米以内。但这一精度基本能满足一般的商业用途。 移动定位服务网关技术 移动定位服务网关是一个承上启下的综合性管理平台。它一方面要为服务提供商提供各种基于XML协议的二次开发接口,提供地理信息服务、定位等功能。另一方面要为移动运营商提供各种运营维护管理功能。如定位、用户鉴权、计费等各种服务。移动定位服务网关系统特性包括:基于WebLogic平台,支持标准的J2EE和EJB;在系统资源和应用资源上有高可扩展性和可用性;支持与多种定位中心连接,支持多种定位方式;提供标准的API接口,以XML、SOAP方式连接;支持与WAP以及SMS的连接,支持GPRS。移动定位服务网关系统容量达1百万用户,为服务提供商提供地理信息位置服务和定位服务。移动定位服务网关可进行综合性计费,能基于应用服务、地图、以及位置的不同给出详细的计费细节,同时还支持被定位用户付费模式。移动定位服务网关能够产生CDR包,ANS.1/BER编码,具有综合性管理平台,可以提供服务提供商管理、信息提供商管理、地理信息管理和终端用户管理。移动定位服务网关系统支持多种形式的鉴权:对申请定位服务的用户以及被定位用户鉴权,保护移动用户的隐私,将移动的身份和位置信息分开;对定位服务提供商、ICP、MAP引擎提供商、地图数据等进行鉴权。移动定位服务网关支持流量控制、负载平衡、以及错误反馈等功能。移动定位服务网关支持与异地定位服务网关连接,实现支持漫游用户定位服务。 <淘宝热门商品:
 

¥:27.00 

◆男童装女童装◆6-15元◆

0货号559◆女童装 纯棉线线衣(1-5岁)

 

185.00 元  

累计销售1000多件 G-STAR 雪纺短款夹克


来源:程序员网

小小豆叮

petstore数据模型分析 pdf

<淘宝热门商品:
 

 

保真无条件包退店【实力派著名书画家在线直销专场】薄金交友

 

109.00 元  

薇薇礼品阁

电视/TV购物热销款平衡左右摇摆踏步机送垫子★健身、瘦身、减肥


来源:程序员网

小小豆叮

XML安全标准一览

如果一个标准象XML一样开放,企业们就不得不对于安全问题加以关注。 控制内容发送和保证信息的完整性的需求导致了很多企业不能够在外部网络上使用它。一些已经发布的标准是针对XML的安全问题的,这些标准还在进一步地发展以便人们能够对XML内容进行颗粒化管理和控制。本文介绍了5种XML安全方面的标准。 XML加密(Xenc)除了在传送XML文件时采用标准进行加密,W3C和IETF还制定了一项标准来对一个XML文档中的数据和部分内容进行加密。这样,如果一个文档只是某些敏感部分需要进行保护,你就可以他们单独进行加密。对于同一个文档中的不同部分用不同的密钥进行加密,你就可以把同一个XML文件发给不同的接受者,而接受者只能看见和他相关的部分。 一旦采用这个这个方法对一个XML文件进行加密,在加密部分的首尾就会出现两个标记,表示该文件是以W3C公布的标准进行加密的。真实的标识名被""和 ""所替代;数据本身显示为一连串的密码。这个标准使XML数据提供者可以根据用户的不同对内容进行颗粒化的控制。而且,由于数据本身而不是整个文件是加密的,整个文件还是可以被XML处理器识别和处理。 XML签名(XML-SIG) XML签名和XML加密紧密相关。和安全认证签名相似,XML也是用于确保XML文件内容没有被篡改的。为了适应各种文件系统和处理器在版式上的不同,XML签名采用了“标准化(canonicalization)”。这就使得XML签名可以适应XML文件可能遇到的各种环境。 当对内容进行签名时,canonicalization使用文件里的数据和标识产生一个独一无二的签名,忽略了一些诸如段落结束或者制表符之类的次要信息。收到一个文件后,客户系统就开始进行“XML签名解密转换”,它通过辨认信息是在标识前还是标识后来区分内容和签名:内容在标识后,而签名在标识前。通过比较运算结果和文件中的签名,可以确认数据的完整性。 XML签名和XML加密结合在一起,可以确保数据发送和接收的一致性。 XML加密管理规范(XKMS) XKMS是W3C制定的一项标准。它定义了分发和注册XML签名规范所使用的公共密钥的方法。XKMS包括了两部分:XML密钥注册服务规范(X-KRSS)和XML密钥信息服务规范(X-KISS)。X-KRSS是用于注册公共密钥的,而X-KISS是用在XML签名提供的密钥方面。 一些诸如VeriSign的供应商对这个规范非常积极支持,他们开发了一些工具包和应用来促进这个规范的实行。 这个规范到目前为止还是比较松散,2002年3月18日发布的最新版本还是局限于现在的需求。 XML访问控制标记语言(XACML) XACML是OASIS制定的一个用以整合各方面(比如IBM和米兰大学)努力成果的一个标准。它和SAML(将在下面提到)共同使用,它提供了一种标准化XML文件接入控制决定的工具。XACML是用来决定是否允许一个请求使用一项资源,比如它是否能使用整个文件,多个文件,还是某个文件的一部分。 XACML收到一个SAML请求后就根据事先制定的规则或策略来判断是否允许请求使用某项资源。和XML加密相反,接入控制信息是物理上独立的,当一个请求生成的时候,该信息被引用。Xpointers和Xpaths是在XML资源中的标识里定义的,它们通知处理器检查XACML策略,以及在哪里可以找到这些策略。 一旦按照策略完成了评估,就会返回一个是真或者是假的逻辑值表示是否允许接入,这个认证决定声明返回后,就会执行相应的操作。你可以访问OASIS XACML Committee了解关于会议时间,学习案例,和2002年3月10日发布的最新版本的工作草稿。 安全声明标记语言(SAML) SAML也是出自OASIS,和XACML相对,它处理证明/授权的请求/响应的交换。一个SAML请求以HTTP方式通过SOAP被发送到一个有相应处理工具的系统去。 一个SAML请求包括诸如用户姓名、密码以及其他一些关于提出请求的人的信息。这些信息被发送到一个处理应用程序那里来决定是否允许使用一项XML资源。 SAML采用了一项由OASIS提出的“声明计划”。有三种声明:认证,授权决定,和属性。这三种声明在一个应用中被用在不同的场合来决定谁是请求者,请求的内容,是否有权提出这项请求。 这个规范最新的版本是2002年5月31日发布的。你可以访问OASIS的网站了解更多:XML-Based Security Services TC (SSTC) page。 XML安全:一个正在推进的进程 这些标准和规范没有一个已经被充分实现并广泛采用了。W3C和OASIS都在为XML提供安全标准而努力工作着。早期的一些解决方案现在已经可以应用了,比如Phaos Technology的Phaos XML和IBM 的alphaWorks。随着XML的应用越来越广泛,对于XML安全性的需求也日益强烈。传统的安全手段妨碍了XML的易用性,不过新的标准应该会很快出现。 <淘宝热门商品:
 

288.00 元 

【19shop 超值正品】英国TOPMAN经典修

 

 

纤体·丽颜New Concept茶坊 纯天然美容瘦身品位花饮


来源:程序员网

小小豆叮

标准建模语言UML及其支持环境

<淘宝热门商品:
 

¥:9.99 

【黑龙江商盟】棋子儿平价美妆店-烟熏彩妆/假睫毛大全/新娘用品

买十送一全网最低价高级无痕透明根部自然浓密凌乱假睫毛仿真毛发

 

保健品/滋补品 

淑芳阁_苗条姿_最有效的减肥瘦身与丰胸专卖店


来源:程序员网

小小豆叮

用连接池提高Servlet访问数据库的效率

用连接池提高Servlet访问数据库的效率 作者:好兵 Java Servlet作为首选的服务器端数据处理技术,正在迅速取代CGI脚本。Servlet超越CGI的优势之一在于,不仅多个请求可以共享公用资源,而且还可以在不同用户请求之间保留持续数据。本文介绍一种充分发挥该特色的实用技术,即数据库连接池。 一、实现连接池的意义 动态Web站点往往用数据库存储的信息生成Web页面,每一个页面请求导致一次数据库访问。连接数据库不仅要开销一定的通讯和内存资源,还必须完成用户验证、安全上下文配置这类任务,因而往往成为最为耗时的操作。当然,实际的连接时间开销千变万化,但1到2秒延迟并非不常见。如果某个基于数据库的Web应用只需建立一次初始连接,不同页面请求能够共享同一连接,就能获得显著的性能改善。 Servlet是一个Java类。Servlet引擎(它可能是Web服务软件的一部分,也可能是一个独立的附加模块)在系统启动或Servlet第一次被请求时将该类装入Java虚拟机并创建它的一个实例。不同用户请求由同一Servlet实例的多个独立线程处理。那些要求在不同请求之间持续有效的数据既可以用Servlet的实例变量来保存,也可以保存在独立的辅助对象中。 用JDBC访问数据库首先要创建与数据库之间的连接,获得一个连接对象(Connection),由连接对象提供执行SQL语句的方法。本文介绍的数据库连接池包括一个管理类DBConnectionManager,负责提供与多个连接池对象(DBConnectionPool类)之间的接口。每一个连接池对象管理一组JDBC连接对象,每一个连接对象可以被任意数量的Servlet共享。 类DBConnectionPool提供以下功能: 1) 从连接池获取(或创建)可用连接。 2) 把连接返回给连接池。 3) 在系统关闭时释放所有资源,关闭所有连接。 此外, DBConnectionPool类还能够处理无效连接(原来登记为可用的连接,由于某种原因不再可用,如超时,通讯问题),并能够限制连接池中的连接总数不超过某个预定值。 管理类DBConnectionManager用于管理多个连接池对象,它提供以下功能: 1) 装载和注册JDBC驱动程序。 2) 根据在属性文件中定义的属性创建连接池对象。 3) 实现连接池名字与其实例之间的映射。 4) 跟踪客户程序对连接池的引用,保证在最后一个客户程序结束时安全地关闭所有连接池。 本文余下部分将详细说明这两个类,最后给出一个示例演示Servlet使用连接池的一般过程。 二、具体实现 DBConnectionManager.java程序清单如下: 001 import java.io.*; 002 import java.sql.*; 003 import java.util.*; 004 import java.util.Date; 005 006 /** 007 * 管理类DBConnectionManager支持对一个或多个由属性文件定义的数据库连接 008 * 池的访问.客户程序可以调用getInstance()方法访问本类的唯一实例. 009 */ 010 public class DBConnectionManager { 011 static private DBConnectionManager instance; // 唯一实例 012 static private int clients; 013 014 private Vector drivers = new Vector(); 015 private PrintWriter log; 016 private Hashtable pools = new Hashtable(); 017 018 /** 019 * 返回唯一实例.如果是第一次调用此方法,则创建实例 020 * 021 * @return DBConnectionManager 唯一实例 022 */ 023 static synchronized public DBConnectionManager getInstance() { 024 if (instance == null) { 025 instance = new DBConnectionManager(); 026 } 027 clients++; 028 return instance; 029 } 030 031 /** 032 * 建构函数私有以防止其它对象创建本类实例 033 */ 034 private DBConnectionManager() { 035 init(); 036 } 037 038 /** 039 * 将连接对象返回给由名字指定的连接池 040 * 041 * @param name 在属性文件中定义的连接池名字 042 * @param con 连接对象 043 */ 044 public void freeConnection(String name, Connection con) { 045 DBConnectionPool pool = (DBConnectionPool) pools.get(name); 046 if (pool != null) { 047 pool.freeConnection(con); 048 } 049 } 050 051 /** 052 * 获得一个可用的(空闲的)连接.如果没有可用连接,且已有连接数小于最大连接数 053 * 限制,则创建并返回新连接 054 * 055 * @param name 在属性文件中定义的连接池名字 056 * @return Connection 可用连接或null 057 */ 058 public Connection getConnection(String name) { 059 DBConnectionPool pool = (DBConnectionPool) pools.get(name); 060 if (pool != null) { 061 return pool.getConnection(); 062 } 063 return null; 064 } 065 066 /** 067 * 获得一个可用连接.若没有可用连接,且已有连接数小于最大连接数限制, 068 * 则创建并返回新连接.否则,在指定的时间内等待其它线程释放连接. 069 * 070 * @param name 连接池名字 071 * @param time 以毫秒计的等待时间 072 * @return Connection 可用连接或null 073 */ 074 public Connection getConnection(String name, long time) { 075 DBConnectionPool pool = (DBConnectionPool) pools.get(name); 076 if (pool != null) { 077 return pool.getConnection(time); 078 } 079 return null; 080 } 081 082 /** 083 * 关闭所有连接,撤销驱动程序的注册 084 */ 085 public synchronized void release() { 086 // 等待直到最后一个客户程序调用 087 if (--clients != 0) { 088 return; 089 } 090 091 Enumeration allPools = pools.elements(); 092 while (allPools.hasMoreElements()) { 093 DBConnectionPool pool = (DBConnectionPool) allPools.nextElement(); 094 pool.release(); 095 } 096 Enumeration allDrivers = drivers.elements(); 097 while (allDrivers.hasMoreElements()) { 098 Driver driver = (Driver) allDrivers.nextElement(); 099 try { 100 DriverManager.deregisterDriver(driver); 101 log("撤销JDBC驱动程序 " + driver.getClass().getName()+"的注册"); 102 } 103 catch (SQLException e) { 104 log(e, "无法撤销下列JDBC驱动程序的注册: " + driver.getClass().getName()); 105 } 106 } 107 } 108 109 /** 110 * 根据指定属性创建连接池实例. 111 * 112 * @param props 连接池属性 113 */ 114 private void createPools(Properties props) { 115 Enumeration propNames = props.propertyNames(); 116 while (propNames.hasMoreElements()) { 117 String name = (String) propNames.nextElement(); 118 if (name.endsWith(".url")) { 119 String poolName = name.substring(0, name.lastIndexOf(".")); 120 String url = props.getProperty(poolName + ".url"); 121 if (url == null) { 122 log("没有为连接池" + poolName + "指定URL"); 123 continue; 124 } 125 String user = props.getProperty(poolName + ".user"); 126 String password = props.getProperty(poolName + ".password"); 127 String maxconn = props.getProperty(poolName + ".maxconn", "0"); 128 int max; 129 try { 130 max = Integer.valueOf(maxconn).intValue(); 131 } 132 catch (NumberFormatException e) { 133 log("错误的最大连接数限制: " + maxconn + " .连接池: " + poolName); 134 max = 0; 135 } 136 DBConnectionPool pool = 137 new DBConnectionPool(poolName, url, user, password, max); 138 pools.put(poolName, pool); 139 log("成功创建连接池" + poolName); 140 } 141 } 142 } 143 144 /** 145 * 读取属性完成初始化 146 */ 147 private void init() { 148 InputStream is = getClass().getResourceAsStream("/db.properties"); 149 Properties dbProps = new Properties(); 150 try { 151 dbProps.load(is); 152 } 153 catch (Exception e) { 154 System.err.println("不能读取属性文件. " + 155 "请确保db.properties在CLASSPATH指定的路径中"); 156 return; 157 } 158 String logFile = dbProps.getProperty("logfile", "DBConnectionManager.log"); 159 try { 160 log = new PrintWriter(new FileWriter(logFile, true), true); 161 } 162 catch (IOException e) { 163 System.err.println("无法打开日志文件: " + logFile); 164 log = new PrintWriter(System.err); 165 } 166 loadDrivers(dbProps); 167 createPools(dbProps); 168 } 169 170 /** 171 * 装载和注册所有JDBC驱动程序 172 * 173 * @param props 属性 174 */ 175 private void loadDrivers(Properties props) { 176 String driverClasses = props.getProperty("drivers"); 177 StringTokenizer st = new StringTokenizer(driverClasses); 178 while (st.hasMoreElements()) { 179 String driverClassName = st.nextToken().trim(); 180 try { 181 Driver driver = (Driver) 182 Class.forName(driverClassName).newInstance(); 183 DriverManager.registerDriver(driver); 184 drivers.addElement(driver); 185 log("成功注册JDBC驱动程序" + driverClassName); 186 } 187 catch (Exception e) { 188 log("无法注册JDBC驱动程序: " + 189 driverClassName + ", 错误: " + e); 190 } 191 } 192 } 193 194 /** 195 * 将文本信息写入日志文件 196 */ 197 private void log(String msg) { 198 log.println(new Date() + ": " + msg); 199 } 200 201 /** 202 * 将文本信息与异常写入日志文件 203 */ 204 private void log(Throwable e, String msg) { 205 log.println(new Date() + ": " + msg); 206 e.printStackTrace(log); 207 } 208 209 /** 210 * 此内部类定义了一个连接池.它能够根据要求创建新连接,直到预定的最 211 * 大连接数为止.在返回连接给客户程序之前,它能够验证连接的有效性. 212 */ 213 class DBConnectionPool { 214 private int checkedOut; 215 private Vector freeConnections = new Vector(); 216 private int maxConn; 217 private String name; 218 private String password; 219 private String URL; 220 private String user; 221 222 /** 223 * 创建新的连接池 224 * 225 * @param name 连接池名字 226 * @param URL 数据库的JDBC URL 227 * @param user 数据库帐号,或 null 228 * @param password 密码,或 null 229 * @param maxConn 此连接池允许建立的最大连接数 230 */ 231 public DBConnectionPool(String name, String URL, String user, String password, 232 int maxConn) { 233 this.name = name; 234 this.URL = URL; 235 this.user = user; 236 this.password = password; 237 this.maxConn = maxConn; 238 } 239 240 /** 241 * 将不再使用的连接返回给连接池 242 * 243 * @param con 客户程序释放的连接 244 */ 245 public synchronized void freeConnection(Connection con) { 246 // 将指定连接加入到向量末尾 247 freeConnections.addElement(con); 248 checkedOut--; 249 notifyAll(); 250 } 251 252 /** 253 * 从连接池获得一个可用连接.如没有空闲的连接且当前连接数小于最大连接 254 * 数限制,则创建新连接.如原来登记为可用的连接不再有效,则从向量删除之, 255 * 然后递归调用自己以尝试新的可用连接. 256 */ 257 public synchronized Connection getConnection() { 258 Connection con = null; 259 if (freeConnections.size() > 0) { 260 // 获取向量中第一个可用连接 261 con = (Connection) freeConnections.firstElement(); 262 freeConnections.removeElementAt(0); 263 try { 264 if (con.isClosed()) { 265 log("从连接池" + name+"删除一个无效连接"); 266 // 递归调用自己,尝试再次获取可用连接 267 con = getConnection(); 268 } 269 } 270 catch (SQLException e) { 271 log("从连接池" + name+"删除一个无效连接"); 272 // 递归调用自己,尝试再次获取可用连接 273 con = getConnection(); 274 } 275 } 276 else if (maxConn == 0 || checkedOut < maxConn) { 277 con = newConnection(); 278 } 279 if (con != null) { 280 checkedOut++; 281 } 282 return con; 283 } 284 285 /** 286 * 从连接池获取可用连接.可以指定客户程序能够等待的最长时间 287 * 参见前一个getConnection()方法. 288 * 289 * @param timeout 以毫秒计的等待时间限制 290 */ 291 public synchronized Connection getConnection(long timeout) { 292 long startTime = new Date().getTime(); 293 Connection con; 294 while ((con = getConnection()) == null) { 295 try { 296 wait(timeout); 297 } 298 catch (InterruptedException e) {} 299 if ((new Date().getTime() - startTime) >= timeout) { 300 // wait()返回的原因是超时 301 return null; 302 } 303 } 304 return con; 305 } 306 307 /** 308 * 关闭所有连接 309 */ 310 public synchronized void release() { 311 Enumeration allConnections = freeConnections.elements(); 312 while (allConnections.hasMoreElements()) { 313 Connection con = (Connection) allConnections.nextElement(); 314 try { 315 con.close(); 316 log("关闭连接池" + name+"中的一个连接"); 317 } 318 catch (SQLException e) { 319 log(e, "无法关闭连接池" + name+"中的连接"); 320 } 321 } 322 freeConnections.removeAllElements(); 323 } 324 325 /** 326 * 创建新的连接 327 */ 328 private Connection newConnection() { 329 Connection con = null; 330 try { 331 if (user == null) { 332 con = DriverManager.getConnection(URL); 333 } 334 else { 335 con = DriverManager.getConnection(URL, user, password); 336 } 337 log("连接池" + name+"创建一个新的连接"); 338 } 339 catch (SQLException e) { 340 log(e, "无法创建下列URL的连接: " + URL); 341 return null; 342 } 343 return con; 344 } 345 } 346 } 三、类DBConnectionPool说明 该类在209至345行实现,它表示指向某个数据库的连接池。数据库由JDBC URL标识。一个JDBC URL由三部分组成:协议标识(总是jdbc),驱动程序标识(如 odbc、idb、oracle等),数据库标识(其格式依赖于驱动程序)。例如,jdbc:odbc:demo,即是一个指向demo数据库的JDBC URL,而且访问该数据库要使用JDBC-ODBC驱动程序。每个连接池都有一个供客户程序使用的名字以及可选的用户帐号、密码、最大连接数限制。如果Web应用程序所支持的某些数据库操作可以被所有用户执行,而其它一些操作应由特别许可的用户执行,则可以为两类操作分别定义连接池,两个连接池使用相同的JDBC URL,但使用不同的帐号和密码。 类DBConnectionPool的建构函数需要上述所有数据作为其参数。如222至238行所示,这些数据被保存为它的实例变量: 如252至283行、285至305行所示, 客户程序可以使用DBConnectionPool类提供的两个方法获取可用连接。两者的共同之处在于:如连接池中存在可用连接,则直接返回,否则创建新的连接并返回。如果没有可用连接且已有连接总数等于最大限制数,第一个方法将直接返回null,而第二个方法将等待直到有可用连接为止。 所有的可用连接对象均登记在名为freeConnections的向量(Vector)中。如果向量中有多于一个的连接,getConnection()总是选取第一个。同时,由于新的可用连接总是从尾部加入向量,从而使得数据库连接由于长时间闲置而被关闭的风险减低到最小程度。 第一个getConnection()在返回可用连接给客户程序之前,调用了isClosed()方法验证连接仍旧有效。如果该连接被关闭或触发异常,getConnection()递归地调用自己以尝试获取另外的可用连接。如果在向量freeConnections中不存在任何可用连接,getConnection()方法检查是否已经指定最大连接数限制。如已经指定,则检查当前连接数是否已经到达极限。此处maxConn为0表示没有限制。如果没有指定最大连接数限制或当前连接数小于该值,该方法尝试创建新的连接。如创建成功,则增加已使用连接的计数并返回,否则返回空值。 如325至345行所示,创建新连接由newConnection()方法实现。创建过程与是否已经指定数据库帐号、密码有关。 JDBC的DriverManager类提供多个getConnection()方法,这些方法要用到JDBC URL与其它一些参数,如用户帐号和密码等。DriverManager将使用指定的JDBC URL确定适合于目标数据库的驱动程序及建立连接。 在285至305行实现的第二个getConnection()方法需要一个以毫秒为单位的时间参数,该参数表示客户程序能够等待的最长时间。建立连接的具体操作仍旧由第一个getConnection()方法实现。 该方法执行时先将startTime初始化为当前时间。在while循环中尝试获得一个连接。如果失败,则以给定的时间值为参数调用wait()。wait()的返回可能是由于其它线程调用notify()或notifyAll(),也可能是由于预定时间已到。为找出wait()返回的真正原因,程序用当前时间减开始时间(startTime),如差值大于预定时间则返回空值,否则再次调用getConnection()。 把空闲的连接登记到连接池由240至250行的freeConnection()方法实现,它的参数为返回给连接池的连接对象。该对象被加入到freeConnections向量的末尾,然后减少已使用连接计数。调用notifyAll()是为了通知其它正在等待可用连接的线程。 许多Servlet引擎为实现安全关闭提供多种方法。数据库连接池需要知道该事件以保证所有连接能够正常关闭。DBConnectionManager类负协调整个关闭过程,但关闭连接池中所有连接的任务则由DBConnectionPool类负责。在307至323行实现的release()方法供DBConnectionManager调用。该方法遍历freeConnections向量并关闭所有连接,然后从向量中删除这些连接。 四、类DBConnectionManager 说明 该类只能创建一个实例,其它对象能够调用其静态方法(也称为类方法)获得该唯一实例的引用。如031至036行所示,DBConnectionManager类的建构函数是私有的,这是为了避免其它对象创建该类的实例。 DBConnectionManager类的客户程序可以调用getInstance()方法获得对该类唯一实例的引用。如018至029行所示,类的唯一实例在getInstance()方法第一次被调用期间创建,此后其引用就一直保存在静态变量instance中。每次调用getInstance()都增加一个DBConnectionManager的客户程序计数。即,该计数代表引用DBConnectionManager唯一实例的客户程序总数,它将被用于控制连接池的关闭操作。 该类实例的初始化工作由146至168行之间的私有方法init()完成。其中 getResourceAsStream()方法用于定位并打开外部文件。外部文件的定位方法依赖于类装载器的实现。标准的本地类装载器查找操作总是开始于类文件所在路径,也能够搜索CLASSPATH中声明的路径。db.properties是一个属性文件,它包含定义连接池的键-值对。可供定义的公用属性如下: drivers 以空格分隔的JDBC驱动程序类列表 logfile 日志文件的绝对路径 其它的属性和特定连接池相关,其属性名字前应加上连接池名字: .url 数据库的 JDBC URL .maxconn 允许建立的最大连接数,0表示没有限制 .user 用于该连接池的数据库帐号 .password 相应的密码 其中url属性是必需的,而其它属性则是可选的。数据库帐号和密码必须合法。用于Windows平台的db.properties文件示例如下: drivers=sun.jdbc.odbc.JdbcOdbcDriver jdbc.idbDriver logfile=D:\\user\\src\\java\\DBConnectionManager\\log.txt idb.url=jdbc:idb:c:\\local\\javawebserver1.1\\db\\db.prp idb.maxconn=2 access.url=jdbc:odbc:demo access.user=demo access.password=demopw 注意在Windows路径中的反斜杠必须输入2个,这是由于属性文件中的反斜杠同时也是一个转义字符。 init()方法在创建属性对象并读取db.properties文件之后,就开始检查logfile属性。如果属性文件中没有指定日志文件,则默认为当前目录下的DBConnectionManager.log文件。如日志文件无法使用,则向System.err输出日志记录。 装载和注册所有在drivers属性中指定的JDBC驱动程序由170至192行之间的loadDrivers()方法实现。该方法先用StringTokenizer将drivers属性值分割为对应于驱动程序名称的字符串,然后依次装载这些类并创建其实例,最后在 DriverManager中注册该实例并把它加入到一个私有的向量drivers。向量drivers将用于关闭服务时从DriverManager取消所有JDBC 驱动程序的注册。 init()方法的最后一个任务是调用私有方法createPools()创建连接池对象。如109至142行所示,createPools()方法先创建所有属性名字的枚举对象(即Enumeration对象,该对象可以想象为一个元素系列,逐次调用其nextElement()方法将顺序返回各元素),然后在其中搜索名字以“.url”结尾的属性。对于每一个符合条件的属性,先提取其连接池名字部分,进而读取所有属于该连接池的属性,最后创建连接池对象并把它保存在实例变量pools中。散列表(Hashtable类 )pools实现连接池名字到连接池对象之间的映射,此处以连接池名字为键,连接池对象为值。 为便于客户程序从指定连接池获得可用连接或将连接返回给连接池,类DBConnectionManager提供了方法getConnection()和freeConnection()。所有这些方法都要求在参数中指定连接池名字,具体的连接获取或返回操作则调用对应的连接池对象完成。它们的实现分别在051至064行、066至080行、038至049行。 如082至107行所示,为实现连接池的安全关闭,DBConnectionManager提供了方法release()。在上面我们已经提到,所有DBConnectionManager的客户程序都应该调用静态方法getInstance()以获得该管理器的引用,此调用将增加客户程序计数。客户程序在关闭时调用release()可以递减该计数。当最后一个客户程序调用release(),递减后的引用计数为0,就可以调用各个连接池的release()方法关闭所有连接了。管理类release()方法最后的任务是撤销所有JDBC驱动程序的注册。 五、Servlet使用连接池示例 Servlet API所定义的Servlet生命周期类如: 1) 创建并初始化Servlet(init()方法)。 2) 响应客户程序的服务请求(service()方法)。 3) Servlet终止运行,释放所有资源(destroy()方法)。 本例演示连接池应用,上述关键步骤中的相关操作为: 1) 在init(),用实例变量connMgr 保存调用DBConnectionManager.getInstance()所返回的引用。 2) 在service(),调用getConnection(),执行数据库操作,用freeConnection()将连接返回给连接池。 3) 在destroy(),调用release()关闭所有连接,释放所有资源。 示例程序清单如下: import java.io.*; import java.sql.*; import javax.servlet.*; import javax.servlet.http.*; public class TestServlet extends HttpServlet { private DBConnectionManager connMgr; public void init(ServletConfig conf) throws ServletException { super.init(conf); connMgr = DBConnectionManager.getInstance(); } public void service(HttpServletRequest req, HttpServletResponse res) throws IOException { res.setContentType("text/html"); PrintWriter out = res.getWriter(); Connection con = connMgr.getConnection("idb"); if (con == null) { out.println("不能获取数据库连接."); return; } ResultSet rs = null; ResultSetMetaData md = null; Statement stmt = null; try { stmt = con.createStatement(); rs = stmt.executeQuery("SELECT * FROM EMPLOYEE"); md = rs.getMetaData(); out.println("职工数据"); while (rs.next()) { out.println(""); for (int i = 1; i < md.getColumnCount(); i++) { out.print(rs.getString(i) + ", "); } } stmt.close(); rs.close(); } catch (SQLException e) { e.printStackTrace(out); } connMgr.freeConnection("idb", con); } public void destroy() { connMgr.release(); super.destroy(); } } <淘宝热门商品:
 

256.0元  

美美减肥瘦身及咨询 能为你服务是我的荣幸!

 

19.00 元  

【广州商盟】靓一族专营匡威运动鞋/秋冬针织帽子

特价19元 09年新款出口韩国时尚个性净版球球针织帽爆款卷边


来源:程序员网

小小豆叮

OO 设计过程

<淘宝热门商品:
 

4.60 元  

旺智通讯手机配件商城-----诚邀各地商家加盟合作(可代发货)

皇冠推荐 特卖 诺基亚原装二手BL-5C电池 型号BL5C

 

1.02 元  

冰之.点卡店

【112热血传奇元宝】1个*游戏交易*


来源:程序员网

小小豆叮

了解JDBC

1. 介绍   许多开发者和用户都在寻找Java程序中访问数据库的便捷方法。由于Java是一个健壮,安全,易于使用的,易于理解且可以从网络中自动download ,所以它成为开发数据库应用的一种良好的语言基础。它提供了C,C++,Smalltalk, BASIC, COBOL, and 4GLs的许多优点。许多公司已经开始在Java与DBMS的连接方面做工作。   许多Java应用开发者都希望能够编写独立于特定DBMS的程序,而我们也相信一个独立于DBMS的接口将使得与各种各样DBMS连接变得最为便捷,开发更加迅速。所以我们认为定义一个通用的SQL数据库存取框架,在各种各样的提供数据库连接模块上提供统一的界面是十分有意义的。这使程序员可以面对单一的数据库界面,使数据库无关的Java工具和产品成为可能,使得数据库连接的开发者可以提供各种各样的连接方案。我们看到我们定义一个通用低层的,支持基本SQL功能的JavaDataBase Connectivity (JDBC)API的紧迫任务。   幸运的是我们不必从头设计一个SQL API。我们可以把我们的工作建立在 X/Open SQL CLI (调用层接口)之上(它也是Microsoft's ODBC 的基础)。   我们主要任务是定义一个自然的Java接口来与X/Open CLI中定义的基本的抽象层和概念连接。   JDBC API得到数据库开发厂商,连接开发厂商,ISV,以及应用开发者的支持是十分重要的。我们相信把我们的工作建立在ODBC抽象层的基础上将JDBC更加容易得到大家的接受。而且从技术上来说,ODBC是我们设计工作的一个良好基础。   因为ODBC是一个C语言接口,所以ODBC在Java中直接使用不适当。从Java中来调用C代码在安全性,健壮性,实现的方便,可移植性等等方面有许多不便。它使得Java在这些方面的许多优点得不到发挥。   我们已经在短期里面实现了一个建立在ODBC上的API。长远来看,我们可以通过其他方式提供实现。 1. 1. 注意   我们非常感谢在数据库,数据库连接和数据库工具领域的许多早期的工作者。他们为JDBC的早期草案提供了很好的意见和建议。他们的工作对本规范起了不可估量的作用。   2. 目标与哲学   这个部分描述了指引这个API开发的目标以及哲学。 2. 1. SQL 级 API   我们的主要目标是为Java定义一个“调用级”(call-level)的SQL接口。着意味着我们主要的注意力集中在执行原原本本的SQL语句并且取回结果。我们预计高层的API也将被定义,这些可能将建立在基层的接口上。   这些高层接口包括象直接地、透明地把表里面的数据影射到Java类里面,用语法树表示更加通用的查询,以及Java内嵌的SQL语法。   我们希望大量的应用开发工具将使用我们的API。然而我们也希望程序员能够使用我们的API,尤其是目前这样在Java里没有任何其他手段(应该是说数据库访问手段)的情况下。 2. 2. 遵循SQL   数据库系统支持各式各样的SQL语法和语义,它们相互之间在比较高级的功能例如外部连接,内嵌过程等方面并不一致,尽管我们能够盼望着随时间的推移这些部分的SQL可以获得标准化。同时我们采取这样的态度与立场:   In fact, an application query need not even be SQL, or it may be a specialized derivative of SQL, e.g. for document or image queries, designed for specific DBMSs.   In order to pass JDBC compliance tests and to be called "JDBC COMPLIANT " we require that a driver support at least ANSI SQL-2 Entry Level. This gives applications that want wide portability a guaranteed least common denominator. We believe ANSI SQL-2 Entry Level is reasonably powerful and is reasonably widely supported today. * JDBC允许查询表达式直接传递到底层的数据驱动,这样一个程序可以获得尽量多的SQL功能,但是可能被DBMS拒绝。事实上,一个程序的查询甚至可以不是SQL的,或者是SQL的一个特殊演化,例如:为专门数据库设计的文本或者图形查询。 * 为了通过JDBC兼容的测试,并且能够被称为JDBC兼容,我们要求一个驱动至少支持ANSI SQL-2的标准。这使得那些需要广泛移植性的程序获得一个最小的分母(这句话的原文是:This gives applications that want wide portability a guaranteed least common denominator.)。我们相信ANSI SQL-2是足够强大的,并且是得到足够支持的。 2. 3. JDBC必须可以建立在现有的数据库接口上   我们必须能够保证 JDBC SQL API 能够建立在普通的SQL API上,尤其是ODBC。这些要求已经对这个规范的一些部分产生了影响,尤其是对传出参数(OUT parameter)和大数据块的处理。 2. 4. 必须保证这个接口与JAVA系统的其他部分保持一致  目前对JAVA的积极回应已经十分热烈。很大程度上是由于这个语言标准以及标准运行时库被认为是一致,简单和强大的。我们将尽我们所能,提供这个Java数据库接口,这个接口将建立在Java内核现有的这种风格,并且将进一步加强它。 2. 5. 保持简单   We would prefer to keep this base API as simple as possible, at least initially. In general we would prefer to provide a single mechanism for performing a particular task, and avoid provid-ing duplicate mechanisms. We will extend the API later if any important functionality is miss-ing.   我们将力争使得基本的API尽量简单,至少开始的时候是这样的。一般来说,我们希望对实现每个特定的任务只提供一种方案,而避免提供多种方案。如果一些重要的功能遗漏了,那么我们在晚些时候将扩充这个API。 2. 6. 尽量保持强的、静态的类型   我们希望这个JDBC API保持尽量强的类型检查,使得尽可能多的类型信息可以静态地表达。着使得尽可能多的错误可以在编译的时候被发现。   由于SQL本身是动态类型的,所以我们可能会在程序运行的时候遇到类型不能匹配的问题。例如:当一个程序员在希望SELECT返回一个整数,但是实际返回的是一个字符串“foo”. 但是我们依然希望程序员把他们所希望的类型在编译的时候就能够表达清楚,这样我们可以做尽可能多的静态检查。我们也希望在必要的时候能够支持动态类型接口(见第四章) 2. 7. 使普通任务简化   我们希望普通的任务能够是简单的,而不一般的工作是可行的。   一个普通任务是指一个程序员执行一个简单的没有参数的SQL语句(例如:SELECT,INSERT,UPDATE,DELETE),然后(例如SELECT)处理返回的具有简单类型的元组。一个具有传入参数(IN parameter)的SQL语句也是普通的。   不那么普通但是也是十分重要的情形是当程序员使用有INOUT,OUT参数的SQL语句。我们也需要支持读写几兆字节对象的SQL语句,更特别一些的情形包括一个语句返回了多个结果集合。   我们希望元数据(Meatdata)的使用很少的,只是那些熟练的程序员以及开发工具才需要处理的问题。元数据存取函数以及动态类型数据存取函数在这个文档末尾,一般的程序员可以不必关心这些章节。 2. 8. 不同的功能让不同的方法(函数)来实现(“方法”的原文是:method,这样翻译是跟VB的)   一种界面设计风格是使用很少的过程,提供许多作为参数传递的控制标志,这样它们可以用来影响很大一个范围内的各种行为。来表达不同的功能。这趋向与使用很多的方法,但是每个方法都比较同意理解。   一般来说,Java内核类使用不同的方法(method)。这个步骤的主要优点是开始学习基本界面的程序员可以不必被那些与复杂功能相关的参数所困扰。我们力图在JDBC接口上也采用相同的策略。一般来说采用不同的方法而不是采用不同的标志和多用途的方法。 3. 接口概貌   接口分为两个层次,一个是面向程序开发人员的JDBC API。另外一个是底层的JDBC Driver API。 3. 1. JDBC API   JDBC API 被描述成为彝族抽象的Java接口,似的应用程序远可以对某个数据库打开连接,执行SQL语句并且处理结果。最重要的接口是: * java.sql.DriverManager 处理驱动的调入并且对产生新的数据库连接提供支持。 * java.sql.Connection 代表对特定数据库的连接。 * java.sql.Statement  代表一个特定的容器,来对一个特定的数据库执行SQL语句。 * java.sql.ResultSet  控制对一个特定语句的行数据的存取。 其中java.sql.Statement又有两个子类型: 1. java.sql.PreparedStatement  用于执行预编译的SQL语句。 2. java.sql.CallableStatement  用于执行对一个数据库内嵌过程的调用。   下面的章节对JDBC是如何运行的提供了更多描述,整个定义见第13章。另外第15章描述了系统如果获取数据库的元数据信息。 3. 2. JDBC Driver API   java.sql.Driver在第9章有完整的定义了.大部分JDBC驱动只需要完成这些JDBC API所定义的抽象类就可以了。特别地,所有的driver必须提供对java.sql.Connection, java.sql. State-ment, java.sql.Prepared-Statement, and java.sql.ResultSet的实现。如果目标DBMS提供有OUT参数的内嵌过程,那么还必须提供java.sql.CallableStatement 接口。 每个database driver必须提供一个类:java.sql.Driver以使得系统可以由 java.sql.DriverManager来管理。   一个显然的driver是在ODBC之上提供对JDBC的实现,从而提供与ODBC接口的JDBC-ODBC 桥,就象前面的图所显示的.由于JDBC放在ODBC之后,所以实现起来简单而且高效。   另外一个有用的驱动直接接触数据库无关的网络协议。发布一个协议允许多个服务器实现的方法,例如在ODBC或者特定的DBMS上(尽管已经有了一些使用固定协议的产品,但是我们不打算对它们实现标准化。),是可取的。   4. JDBC使用场合   Before looking at specifics of the JDBC API, an understanding of typical use scenarios is help-ful. There are two common scenarios that must be treated differently for our purposes: applets and applications.   在看JDBC API之前了解一下典型的使用场合是有帮助的。通常有两种情形必须分别对待:applet和application. 4. 1. Applet   目前Java使用的最多的从网络中下载的applet,它们作为web文件的一个部分。当中有数据库存取applet和能够使用JDBC来接触数据库的applet。例如,一个用户可能下载一个显示股票历史价格图的applet。这个applet通过internet来从关系数据库中获得股票历史价格。   最一般的情况里面,对applet的使用是通过不可靠的边界的。例如从另外一个公司或者Internet上获得这些applet。于是称这个情况为"Internet"场合。然而applet也可能通过局域网下载。在这个情况里面,客户机的安全都还是一个问题。 典型的applet在几个方面与传统的数据库应用程序有所不同: 1). 不可靠的applet被严格地限制在他们被允许执行的的操作上。特别地,不允许他们存取本地的文件,切不允许他们对任意的数据库建立网络连接。 2). 就标识和连接网上数据库来说,Internet环境里面的applet面临新的问题。 3). 当数据库可能与你相隔万里的时候,效率的考虑也有所不同了。与局域网相比,Internet上数据库applet可能会碰到十分不同的反应时间。 4. 2. Application   Java也可以用来建立普通的应用,从而想一般的应用一样在客户机上使用。我们相信随着开发工具越来越多,人们开始认识到提高程序生产效率的必要性,以及Java的其他优点,Java的这种用法将越来越流行。在这种方式里面,Java的代码是可以信赖的,且被允许读写文件打开网络连接等等,就想其他的应用程序代码一样。   也许这些Java应用使用的最多的是在一个公司内部或者在Intranet上,所以不妨成为Intranet场合。例如一个公司希望利用Java及其GUI构件工具来建立他的基于合作数据模式的合作软件。这些应用程序将存取局域网或者广域网的数据。Java应用可以作到这些。   Java应用程序场合和Intranet场合与applet场合有诸多不同。例如标定一个数据库最自然的方式是用一个数据库的名字,就象"Customers" 和"Personnel"这样。然后用户希望系统能够定位具体的机器,DBMS,JDBC driver,和Java应用程序。 4. 3. 其他场合 还有其他一些有趣的场合: 1). 已验证的applet(Trusted applets)是指那些已经被Java虚拟机器认定是可以信赖的applet。他们之所以被认为是可信的是因为他们已经对上了特定的密匙,或者用户认为从特定来源来的applet是可信的。在安全的方面上他们与应用(appliction)相同,但是其他方面(例如定位一个数据库)与则与applet相似。 2). 与直接从Java GUI出发用客户/服务器模式来度曲DBMS服务器不同,三层存取方式可能被使用。在这个场合里面,Java应用程序对中间层的服务发出调用,中间层的服务在网上,它又再去调用数据库。这些调用可能通过RPC (remote procedure call)或者ORB (object request broker )。在这两种场合里面,中间层最好使用一个对象变化。我们希望三层结构会变得越来越普遍,因为对于MIS管理者来说,这可以使得他们有机会在公共数据库上显式地定义合法操作等。同时三层结构可以提供许多效率上的好处。   目前中间层一般用C或者C++这样的语言来完成。通过优化编译器把把Java 字节代码翻译成为高效的机器代码,中间层也可以用Java来实现。Java有许多优良特性(健壮性,安全性,多线程)可以达到中间层需要达到的目的。   5. 安全性考虑   作为网络上的语言JAVA必须十分注安全性的考虑。基于上面的讨论,JDBC的两种主要使用场合里面,我们必须考虑安全性问题: * 在Java applications的场合里面Java代码是本地的,所以也是"trusted" * 没有验证的Java applet代码不可以存取本地的以及其他网络的数据。 5. 1. JDBC 和未验证的applet JDBC首先必须符合JAVA的一般安全规则。另外: * JDBC 必须认为没有验证的applets是不可靠的。 * JDBC 不可以让不可靠的applets存取本地数据库。 * 一个已经向JDBC DriverManager注册的是JDBC Driver只能存取它所来的数据源。 * 一个applet也只能向它所Download来的服务器来存取数据。   如果JDBC驱动层如果完全确信对一个数据库服务器打开连接不会引起认证或者权限问题(可能由网上随机主机上运行的程序引起),那么它就允许applet打开这样的连接。数据库服务器不通过IP地址来限制存取是相当少的,主要是为了举例。(当心,这一段话我可能翻译反了!!!大家看看原文。)这些限制是相当烦琐的。不过他们与对一般applet的限制是一致的我们没有必要放开这些限制。 5. 2. JDBC 和Java应用程序   对于一个普通的Java应用程序(例如全部用Java代码而不是不可靠的applet )JDBC将从本地的类路径里面获得驱动,并且允许应用程序自由存取文件,远程服务器等等。   但是和applet一样,如果由于某些原因一个没有验证的sun.sql.Driver类从远程的来源里面获得,那么这个驱动只能和相同地方来的代码配合。 5. 3. Driver的安全责任   JDBC driver可能在各种情况下使用,所以驱动的编制者遵循一定的简单的安全规则,从而避免applet做非法的数据库连接。   如果所有的驱动都象applet一样从网上下载,那么这些原则将是不必要的,因为普通的安全规则已经对它做了限制。但是驱动的编写者必须记住一旦他们的驱动获得成功,用户将在本地磁盘安装这些驱动,那么驱动将成为Java环境中一个被信任的部分,所以必须确信它不会被来访的applet所滥用。所以我们鼓励所有的驱动编写者必须遵循一定安全原则。   所有这些原则都是在连接打开的时候使用。这正式驱动和虚拟机器检查当前调用者是否真的可以与指定的数据库连接的时刻。一旦连接建立就不必做更多的检查了。 5. 3. 1. 分享TCP/IP连接的时候必须谨慎   如果一个JDBC驱动试图打开一个 TCP 连接,那么这个打开会被Java 安全管理机制自动检查。这个机构会检查当前调用栈里面有没有applet,如果有那么就限定它可以访问的机器集合。所以一般地JDBC驱动可以把TCP建立检查留给Java虚拟机。   但是如果一个JDBC驱动试图在多个数据库连接之间共享一个TCP连接,那么驱动就必须自己负责检查每个调用者是否真的被允许与目标数据库联系。例如如果我们为applet A打开了一个通往机器foobah 的TCP连接,这并不意味着applet B被自动允许来共享这个连接。applet B可能没有任何访问机器foobah的权力。所以在允许某个程序重用一个现成的TCP连接之前,JDBC 驱动必须通过安全机构来检查当前的的调用者是否可以访问这个连接。通过下面的代码可是实现这个功能。 SecurityManager security = System.getSecurityManager(); if (security != null) { security.checkConnect(hostName, portNumber); }   如果连接是不允许的,那么Security.checkConnect方法将产生一个java.lang.SecurityException。 5. 3. 2. 检查所有的本地文件访问   如果一个JDBC取得需要访问本地机器上的数据,那么他必须确信调用者是被允许打开这个文件的。例如: SecurityManager security = System.getSecurityManager(); if (security != null) { security.checkRead(fileName); }   如果对特定文件的访问是不允许的,那么Security.checkRead方法将产生一个java.lang.SecurityException。 5. 3. 3. 作好最坏的准备   一些驱动可能使用本地的方法来桥接底层数据库程序。则这些情况里面判断那些本地文件将被底层函数所访问是困难的。   在这些环境里面用户必须作好最坏的打算,并且否决所有下载applet所发出的数据库存取,除非驱动可能完全确信将要做存取是没有问题的。   例如一个JDBC-ODBC桥接器必须检查ODBC数据源的的名称,确保applet只可以访问它的"生源地"。如果对有的名字中不能判断出数据源的主机名,那么只能否决这个访问。   为了决定一个当前的调用者是可以信赖的应用还是一个applet,JDBC驱动必须能够检查这个调用者是否可以写一个随机的文件: SecurityManager security = System.getSecurityManager(); if (security != null) { security.checkWrite("foobaz"); } <淘宝热门商品:
 

 

【北京商盟】风の轩杂货铺 小美贵族瘦身

 

25.00 元 

重庆女人香专业减肥丰胸网~一品婷/美姿姿/脱脂减肥*批发代理


来源:程序员网

小小豆叮

当前流行的J2EE WEB应用架构分析

龚永生 (gongys@legend.com)
2002 年 7 月

1. 架构概述

J2EE体系包括java server pages(JSP) ,java SERVLET, enterprise bean,WEB service等技术。这些技术的出现给电子商务时代的WEB应用程序的开发提供了一个非常有竞争力的选择。怎样把这些技术组合起来形成一个适应项目需要的稳定架构是项目开发过程中一个非常重要的步骤。完成这个步骤可以形成一个主要里程碑基线。形成这个基线有很多好处:

  1. 各种因数初步确定
    为了形成架构基线,架构设计师要对平台(体系)中的技术进行筛选,各种利弊的权衡。往往架构设计师在这个过程中要阅读大量的技术资料,听取项目组成员的建议,考虑领域专家的需求,考虑赞助商成本(包括开发成本和运行维护成本)限额。一旦架构设计经过评审,这些因数初步地就有了在整个项目过程中的对项目起多大作用的定位。
  2. 定向技术培训
    一旦架构师设计的架构得到了批准形成了基线,项目开发和运行所采用的技术基本确定下来了。众多的项目经理都会对预备项目组成员的技术功底感到担心;他们需要培训部门提供培训,但就架构师面对的技术海洋,项目经理根本就提不出明确的技术培训需求。怎不能够对体系中所有技术都进行培训吧!有了架构里程碑基线,项目经理能确定这个项目开发会采用什么技术,这是提出培训需求应该是最精确的。不过在实际项目开发中,技术培训可以在基线确定之前与架构设计并发进行。
  3. 角色分工
    有了一个好的架构蓝图,我们就能准确划分工作。如网页设计,JSP 标签处理类设计,SERVLET 设计,session bean设计,还有各种实现。这些任务在架构蓝图上都可以清晰地标出位置,使得项目组成员能很好地定位自己的任务。一个好的架构蓝图同时也能规范化任务,能很好地把任务划分为几类,在同一类中的任务的工作量和性质相同或相似。这样工作量估计起来有一个非常好的基础。
  4. 运行维护
    前面说过各个任务在架构图上都有比较好的定位。任何人能借助它很快地熟悉整个项目的运行情况,错误出现时能比较快速地定位错误点。另外,有了清晰的架构图,项目版本管理也有很好的版本树躯干。
  5. 扩展性
    架构犹如一颗参天大树的躯干,只要躯干根系牢,树干粗,长一些旁支,加一些树叶轻而易举无疑。同样,有一个稳定的经得起考验的架构,增加一两个业务组件是非常快速和容易的。

大家都知道这些好处,一心想形成一个这样的J2EE应用程序架构(就像在windows平台中的MFC)。在这个路程中经历了两个大的阶段:

1.1. 模型1

模型1其实不是一个什么稳定架构,甚至谈不上形成了架构。模型1的基础是JSP文件。它从HTTP的请求中提取参数,调用相应的业务逻辑,处理HTTP会话,最后生成HTTP文档。一系列这样的JSP文件形成一个完整的模型1应用,当然可能会有其他辅助类或文件。早期的ASP 和 PHP 技术就属于这个情况。

总的看来,这个模型的好处是简单,但是它把业务逻辑和表现混在一块,对大应用来说,这个缺点是令人容忍不了的。

1.2. 模型2

在经过一番实践,并广泛借鉴和总结经验教训之后,J2EE应用程序终于迎来了MVC(模型-视图-控制)模式。MVC模式并不是J2EE行业人士标新立异的,所以前面我谈到广发借鉴。MVC的核心就是做到三层甚至多层的松散耦合。这对基于组件的,所覆盖的技术不断膨胀的J2EE体系来说真是福音和救星。

它在浏览器(本文对客户代理都称浏览器)和JSP或SERVLET之间插入一个控制组件。这个控制组件集中了处理浏览器发过来的HTTP请求的分发逻辑,也就是说,它会根据HTTP请求的URL,输入参数,和目前应用的内部状态,把请求分发给相应的WEB 层的JSP 或SERVLET。另外它也负责选择下一个视图(在J2EE中,JSP,SERVLET会生成回给浏览器的html从而形成视图)。集中的控制组件也有利于安全验证,日志纪录,有时也封装请求数据给下面的WEB tier层。这一套逻辑的实现形成了一个像MFC的应用框架,位置如图:

1.3. 多层应用

下图为J2EE体系中典型的多层应用模型。

  • Client tier客户层
    一般为浏览器或其他应用。客户层普遍地支持HTTP协议,也称客户代理。
  • WEB tier WEB应用层
    在J2EE中,这一层由WEB 容器运行,它包括JSP, SERVLET等WEB部件。
  • EJB tier 企业组件层
    企业组件层由EJB容器运行,支持EJB, JMS, JTA 等服务和技术。
  • EIS tier 企业信息系统层
    企业信息系统包含企业内传统信息系统如财务,CRM等,特点是有数据库系统的支持。

应用框架目前主要集中在WEB层,旨在规范这一层软件的开发。其实企业组件层也可以实现这个模型,但目前主要以设计模式的形式存在。而且有些框架可以扩充,有了企业组件层组件的参与,框架会显得更紧凑,更自然,效率会更高。

2. 候选方案

目前,实现模型2的框架也在不断的涌现,下面列出比较有名的框架。

2.1. Apache Struts

Struts是一个免费的开源的WEB层的应用框架,apache软件基金致力于struts的开发。Struts具是高可配置的性,和有一个不断增长的特性列表。一个前端控制组件,一系列动作类,动作映射,处理XML的实用工具类,服务器端java bean 的自动填充,支持验证的WEB 表单,国际化支持,生成HTML,实现表现逻辑和模版组成了struts的灵魂。

2.1.1. Struts和MVC

模型2的目的和MVC的目的是一样的,所以模型2基本可以和MVC等同起来。下图体现了Struts的运作机理:

2.1.1.1. 控制

如图所示,它的主要部件是一个通用的控制组件。这个控制组件提供了处理所有发送到Struts 的HTTP请求的入口点。它截取和分发这些请求到相应的动作类(这些动作类都是Action类的子类)。另外控制组件也负责用相应的请求参数填充 From bean,并传给动作类。动作类实现核心商业逻辑,它可以通过访问java bean 或调用EJB。最后动作类把控制权传给后续的JSP 文件,后者生成视图。所有这些控制逻辑利用一个叫struts-config.xml文件来配置。

2.1.1.2. 模型

模型以一个或几个java bean的形式存在。这些bean分为三种:

  • Form beans(表单Beans)
    它保存了HTTP post请求传来的数据,在Struts里,所有的Form beans都是 ActionFrom 类的子类。
  • 业务逻辑beans
    专门用来处理业务逻辑。
  • 系统状态beans
    它保存了跨越多个HTTP 请求的单个客户的会话信息,还有系统状态。

2.1.1.3. 视图

控制组件续传HTTP请求给实现了视图的JSP文件。JSP能访问beans 并生成结果文档反馈到客户。Struts提供JSP 标签库: Html,Bean,Logic,Template等来达到这个目的,并有利于分开表现逻辑和程序逻辑。

2.1.2. Struts的细节分析

2.1.2.1. 视图-控制-模型

用户发出一个*.do的HTTP请求,控制组件接收到这个请求后,查找针对这个请求的动作映射,再检查是否曾创建过相应的动作对象(action实例),如果没有则调用actionmapping生成一个动作对象,控制组件会保存这个动作对象供以后使用。接着调用actionmapping的方法得到actionForm对象。之后把actionForm作为参数传给动作对象的perform方法,这个方法结束之后会返回给控制组件一个 actionforward对象。控制组件接着从这个对象中获取下一个视图的路径和重定向属性。如果为重定向则调用HTTPSERVLETREPONSE的方法来显示下一个视图,否则相继调用requestdispatcher, SERVLETcontext的方法续传HTTP请求到下一个视图。

当动作对象运行perform方法时,可能出现错误信息。动作对象可以保存这些错误信息到一个error对象中,接着调用自身的saveerrors方法把这个错误保存到request对象的属性中。接着动作对象调用actionmapping对象的getInput方法从动作映射中获取input参数,也就是产生输入的视图,并以这个input为参数生成一个actionforward对象返回。这个input参数的JSP中一般有HTTP:errors定制标签读取这些错误信息并显示在页面上。

下面是一个logon.JSP 的代码实例:

<%@ page language="java" %>
<%@ taglib uri="/WEB-INF/struts-bean.tld" prefix="bean" %>
<%@ taglib uri="/WEB-INF/struts-html.tld" prefix="html" %>

<html:html locale="true">
<head>
<title><bean:message key="logon.title"/></title>
<html:base/>
</head>
<body bgcolor="white">

<html:errors/>   <!--  如果出现错误会显示在这里  -->

<html:form action="/logon" focus="username">
<table border="0" width="100%">

  <tr>
    <th align="right">
      <bean:message key="prompt.username"/>
    </th>
    <td align="left">
      <html:text property="username" size="16" maxlength="16"/>
    </td>
  </tr>

  <tr>
    <th align="right">
      <bean:message key="prompt.password"/>
    </th>
    <td align="left">
      <html:password property="password" size="16" maxlength="16"
                    redisplay="false"/>
    </td>
  </tr>

  <tr>
    <td align="right">
      <html:submit property="submit" value="Submit"/>
    </td>
    <td align="left">
      <html:reset/>
    </td>
  </tr>

</table>

2.1.2.2. 模型到视图

模型到视图指视图在显示之前装载系统数据到视图的过程。系统数据一般为模型内java bean的信息。示意图表现了由控制组件forward过来的有html:form定制标签的JSP 的处理逻辑。

html:form定制标签处理对象从application scope(通过查询SERVLETCONTEXT对象的属性来实现)获取先前由控制组件actionSERVLET放在那里的动作映射等对象,由html:form 的action属性查得actionform名字、类型和范围等信息,在相应的范围内查找actionform,如果有则利用它的信息填充html form表单[实际填充动作在嵌套的html:text等定制标签的处理对象中]。否则在相应范围内创建一个actionform 对象。

2.1.3. 优缺点

优点:

  • 一些开发商开始采用并推广这个框架
  • 作为开源项目,有很多先进的实现思想
  • 对大型的应用支持的较好
  • 有集中的网页导航定义

缺点:

  • 不是业届标准
  • 对开发工具的支持不够
  • 复杂的taglib,需要比较长的时间来掌握
  • html form 和 actionform的搭配比较封闭,但这也是它的精华所在。

修改建议
把actionform属性的设置器和访问器修改成读取或生成xml文档的方法,然后 html form和actionform之间用xml文档进行数据交换,使之松散耦合,适应数据结构易变化的应用。

2.2. JATO

JATO应用程序框架是iPlanet 应用程序框架的旧名。它是一个成熟的、强大的,基于J2EE标准的面向于开发WEB应用程序的应用框架。结合了显示字段、应用程序事件、组件层次和以页面为中心的开发方法、以及MVC和服务到工作者service-to-workers的设计模式等概念。JATO可适用于中、大、超大规模的WEB应用。但是它也不是一个企业层的应用框架,也就是说它不会直接提供创建EJB, WEB services等企业层组件的方法,但用它可以构造出访问企业层组件的客户应用。

这个框架功能主要有三部分组成:

  • iPlanet应用框架核心;
  • iPlanet应用框架组件;
  • iPlanet应用框架扩展。

应用框架核心定义了基本接口、对象协议、简单组件,以及iPlanet应用框架程序的最小核心。包括视图简单组件、模型简单组件、请求分发组件和可重用命令对象。iPlanet应用框架组件利用框架核心定义的基本接口、协议和组件向开发者提供高层的重用组件,这些组件既有与特定视觉效果无关的水平组件,同时也有适应特定实用环境、提高可用性而特意提供的垂直型组件。框架扩展实现了用框架相容的方法访问非J2EE环境的方法。通常情况下,扩展被框架应用程序用来无缝访问J2EE容器特定功能。JATO平台栈图很清楚地表达了这个情况。

JATO最大的威力在:对于快速开发用户,你能利用框架组件和扩展提高生产率,对于要求更大灵活性的用户,你能实现框架核心提供的接口来保持应用的框架兼容性。

此图表示实现一个JATO应用程序,可以简单地实现控制组件module1Servlet,视图组件ListCustomersViewBean和模型组件CustomersModuleImpl,以及一个给客户代理显示界面的ListCustomers.jsp文件。并清楚地表明这些组件与JATO框架组件的继承关系。

JATO标签库提供了VIEW对象与JSP文件的接口。库中标签处理程序负责实现VIEW对象和JSP产生地客户端文档的信息同步和交换。这个图清楚地表达了这种对应关系

2.2.1. MVC分析

前端控制组件接收用户发来的任何请求,这个可在WEB.xml中指定 请求分发组件负责视图管理和导航,和前端控制组件封装在ApplicationSERVLETBase一起实现。应用程序开发者需要为每一个子系统(人力资源,财务,CRM等)实现一个此类的继承。

请求分发组件分发请求给工作者,工作者实现了command接口。应用开发者可以实现这个接口。JATO提供了一个缺省实现:DefaultRequestHandingCommand,这个实现会把请求传给视图组件的特定事件。

组合视图是指视图组件在显示给用户时的层次关系:根视图是一个ViewBean类的对象 字段是一个DisplayField类的对象,容器视图是一个ContainerView类的对象。视图组件类的层次关系如下图:

2.2.2. 优缺点分析

优点:

  • 这种框架的适应范围大,即提供了底层接口,也有立即可用的组件
  • 具有与客户端RAD开发工具相似的开发概念如页为中心(等同于VB的FORM),事件处理等.
  • 对大型的应用支持较好

缺点:

  • 不是业届标准
  • 目前还没有开发工具的支持(然JATO已经为工具支持做好了准备)
  • 没有定义网页导航,开发者在视图中自己指定具体的导航URL

修改建议
把众多的VIEW/MODEL对应修改成xml文档传递数据,加上集中的网页导航定义

2.3. JSF(JavaServer Faces)

JSF是一个包括SUN在内的专家组正在定义的开发WEB应用用户界面的框架,JSF 技术包括:

  • 一组API,它实现UI了组件,管理组件的状态,处理事件,输入校验,定义页面导航,支持国际化和访问;
  • 一个JSP定制标签库实现与JSP的接口。

JSF非常简单,是一个定义良好的编程模型。利用这个技术,开发者通过在页面内组合可重用的UI组件,在把这些组件和应用的数据源相连,路由客户产生的事件到服务器端的事件处理器进行编程。JSP处理了所有幕后的复杂工作,使得开发者把关注重点放在应用代码上。

2.3.1. STRUTS、JATO和JSF比较

它们之间有部分重叠,但重点不一样。

  • STRUTS和JATO都提供了一个MVC式的应用模型,而JSF只在用户界面上提供编程接口。这意味着前两者涉及的范围比后者广。JSF可以成为前两者在UI开发的部分。
  • JSF的规范的发布版将在 2002年底发布,实现可能要比这个时间晚些。另外将会有工具支持这个框架的应用开发。

2.4. WAF

WAF是WEB APPLICATION FRAMWORK的简称,是SUN蓝皮书例子程序中提出的应用框架。它实现了 MVC和其他良好的设计模式。

2.4.1. 细节分析


点击这里看大图

2.4.2. 视图-控制-模型

如图所示,开发人员编写的两个xml配置文件定义了WAF的运作参数。Screendefinition.xml定义了一系列的屏幕(screen)。Mapping.xml则定义了某个动作之后应该显示的屏幕,但没有指定屏幕到哪里拿数据。

用户发出一个HTTP请求(*.screen),由TemplateSERVLET屏幕前端控制组件接收,它提取请求信息,设置request对象CurrentScreen属性,再把请求发到模版JSP。模版JSP收到请求后,JSP中的Template标签察看这个当前屏幕,并从屏幕定义文件(Screendefinition.xml)中获取这个屏幕的具体参数,再生成html返回给客户。

假设返回给客户的html中包括了html表单,用户在输入一定数据之后提交,发出一个HTTP请求(*.do)。这个请求被MainSERVLET接收,它提取请求信息,察看动作映射文件(mapping.xml),设置处理这个请求的动作对象(HTTPAction对象),交给requestprosessor对象处理。Requestprosessor对象调用动作对象完成任务,如果需要进一步处理,requestprosessor对象会调用WEBclientcontroler对象的事件处理机制。MainSERVLET在处理完请求之后,从屏幕流管理对象那里得到下一个屏幕,并把请求传给这个屏幕的JSP文件。

值得一提的是WEBclientcontroler事件处理机制最终把HTTP请求的数据传到了EJBAction对象那里处理。这样HTTPAction对象和EJBAction对象形成了两级处理机制,前一级与request对象紧密相关,把数据封装起来形成一个Event对象,再传给了EJBAction对象,后者与Request对象无关。这个方式可以形成一个session级别的数据处理机制。下图显示了这个方法。HTTPAction1对象处理一个请求,并把数据放到一个状态SessionBean内,HTTPAction2也如此,当HTTPAction3接收到HTTP请求之后,把控制传给EJBAction, 后者获取状态SessionBean数据,处理请求,成功后清控状态SessionBean的内容。这个机制非常适应多个输入页面才能满足一个业务的输入数据的情况(比如购物车)。

2.4.3. 优缺点分析

优点

  • 屏幕导航定义明确
  • 为框架的扩展提供了一个空间

缺点

  • 源码比较乱,稳定性和可靠性没人验证。
  • 只是一个框架躯干,没有正式的model层,视图的概念不强
  • 没有模型到视图的定义

修改意见
只有一个框架躯干,正为实现自己的应用框架提供了灵活性。没有僵化的视图概念,提供了在网页输入到模型的扩充接口,比如插入XML数据交换。

关于作者:

龚永生,您可以通过email:gongys@legend.com 与他取得联系。 <淘宝热门商品:
 

¥:9.99 

【黑龙江商盟】棋子儿平价美妆店-烟熏彩妆/假睫毛大全/新娘用品

买十送一全网最低价高级无痕透明根部自然浓密凌乱假睫毛仿真毛发

 

88.00 元 

【魅力先生】推存!Dior韩国立体裁剪修身小直筒


来源:程序员网

小小豆叮

如何在JBOSS Server上发布EJB

-------------------------------------------------------------------------------- 1.准备文件 需要的软件:JDK1.3(for WIN) ,J2EE_1_2_1_SDK,JBoss2.0(www.jboss.org) 需要的文档:J2EE_1_2_1_SDK_DOC,Devguide1_2_1 2.准备环境 安装JDK1.3(支持JBOSS),装完后检查一下环境变量,可以编译运行一个小程序试一下. 安装JBOSS2.0,完成后运行bin\run.bat试一下.JNDI 端口是1099,WEB端口是8080,可以用浏览器试一下,1099端口会返回一段乱码,8080端口返回空. 3.编译和打包 按照JavaTM 2 Enterprise Edition Developer´s Guide (v1.2.1)的Getting Started章中说的编译例子程序 ConverterEJB,然后用Deploy Tool打包生成 ConverterApp.ear. 用jar -xvf ConverterApp.ear 从中抽取 ejb-jar-ic.jar 这是打包好的和Bean有关的三个文件和工具生成meta-info\*.xml文件(所谓的deployment descriptor). 然后运行JBoss的Deploy Tool打开ejb-jar-ic.jar,设置JNDI Name为MyConverter.然后保存.(该工具会自动生成JBoss的Deployment descriptor) 在把ejb-jar-ic.jar拷到jboss\deploy目录下,jboss会自动发布该Bean.. 4.运行客户端程序测试 按照JBoss的教学文档,修改 ConverterClient.java为 import javax.naming.*; import java.util.Hashtable; import javax.rmi.PortableRemoteObject; import java.util.Properties; import java.io.FileInputStream; import javax.rmi.PortableRemoteObject; import Converter; import ConverterHome; public class ConverterClient { public static void main(String[] args) { try { Properties props = new Properties(); Properties sysProps = System.getProperties(); try { props.load (new FileInputStream ("test.properties")); sysProps.putAll(props); } catch (Exception e) { System.err.println ("Can´t read `test.proprties´"); System.exit (-1); } System.setProperties (sysProps); Context initial = new InitialContext(); Object objref = initial.lookup("MyConverter"); ConverterHome home = (ConverterHome)PortableRemoteObject.narrow(objref, ConverterHome.class); Converter currencyConverter = home.create(); double amount = currencyConverter.dollarToYen(200.00); System.out.println(String.valueOf(amount)); amount = currencyConverter.yenToEuro(200.00); System.out.println(String.valueOf(amount)); } catch (Exception ex) { System.err.println("Caught an unexpected exception!"); ex.printStackTrace(); } } } test.properties文件内容如下 java.naming.factory.initial=org.jnp.interfaces.NamingContextFactory java.naming.provider.url=xxx.xxx.xxx.xxx:1099 (写上JBoss所在机器的IP) 然后运行CompileClient.bat和TestClient.bat,就可以享受成功的喜悦了. <淘宝热门商品:
 

 

【上海商盟】高更食品极美滋新奥尔良系列烧烤腌料皇冠旗舰店

 

¥:27.00 

◆男童装女童装◆6-15元◆

0货号559◆女童装 纯棉线线衣(1-5岁)


来源:程序员网

小小豆叮

Java keytool工具的作用及使用方法

Keytool 是安全钥匙与证书的管理工具.它管理一个存储了私有钥匙和验证相应公共钥匙的与它们相关联的X.509 证书链的keystore(相当一个数据库). Keytool 是一个有效的安全钥匙和证书的管理工具. 它能够使用户使用数字签名来管理他们自己的私有/公共钥匙对,管理用来作自我鉴定的相关的证书,管理数据完整性和鉴定服务.它还能使用户在通信时缓存它们的公共钥匙. 一个证书是某一实体(个人,公司等)的数字签名,指出其他实体的公共钥匙(或其他信息)的详细的值.当数据被签名后,这个签名信息被用来检验数据的完整性和真实性.完整性指数据没有被修改和篡改,真实性指数据从任何产生和签名的一方真正的传输到达. Keytool 把钥匙和证书储存到一个keystore.默任的实现keystore的是一个文件.它用一个密码保护钥匙. 而另外的一个工具jarsigner用keystore中的信息产生或检验Java aRchive(jar文件)中的数字签名. Keystore有两个不同的入口: 1.钥匙入口:保存了非常敏感的加密的钥匙信息,并且是用一个保护的格式存储以防止未被授权的访问.以这种形式存储的钥匙是秘密钥匙,或是一个对应证书链中公有钥匙的私有钥匙. 2.信任证书入口:包含一个属于其他部分的单一公共钥匙证书.它之所以被称为"信任证书",是因为keystore信任的证书中的公共钥匙真正属于证书所有者的身份识别. Keystore的别名: 所有的keystore入口(钥匙和信任证书入口)是通过唯一的别名访问.别名是 不区分大小写的.如别名Hugo和hugo指向同一个keystore入口. 可以在加一个入口到keystore的时候使用-genkey参数来产生一个钥匙对(公共钥匙和私有钥匙)时指定别名.也可以用-import参数加一个证书或证书链到信任证书. 如: keytool -genkey -alias duke -keypass dukekeypasswd 其中duke为别名,dukekeypasswd为duke别名的密码.这行命令的作用是产生一个新的公共/私有钥匙对. 假如你想修改密码,可以用: keytool -keypasswd -alias duke -keypass dukekeypasswd -new newpass 将旧密码dukekeypasswd改为newpass. Keystore的产生: 1.当使用-genkey 或-import或-identitydb命令添加数据到一个keystore,而当这个keystore不存在时,产生一个keystore.默认名是.keystore,存放到user-home目录. 2.当用-keystore指定时,将产生指定的keystore. Keystore的实现: Keytool 类位于java.security包下,提供一个非常好的接口去取得和修改一个keystore中的信息. 目前有两个命令行:keytool和jarsinger,一个GUI工具Policy 可以实现keystore.由于keystore是公开的,用户可以用它写一些额外的安全应用程序. Keystore还有一个sun公司提供的內在实现.它把keystore作为一个文件来实现.利用了一个keystore类型(格式)"JKS".它用单独的密码保护每一个私有钥匙.也用可能不同的密码保护整个keystore的完整性. 支持的算法和钥匙大小: keytool允许用户指定钥匙对和注册密码服务供应者所提供的签名算法.缺省的钥匙对产生算法是"DSA".假如私有钥匙是"DSA"类型,缺省签名算法是"SHA1withDSA",假如私有钥匙是"RSA"类型,缺省算法是"MD5withRSA". 当产生一个DSA钥匙对,钥匙必须在512-1024位之间.对任何算法的缺省钥匙大小是1024位. 证书: 一个证书是一个实体的数字签名,指出其他实体的公共钥匙有明确的值. 1.公共钥匙 :是同一个详细的实体的数字关联,并有意让所有想同这个实体发生信任关系的其他实体知道.公共钥匙用来检验签名; 2.数字签名:假如数据已被签名,并用身份存储在一个实体中,一个签名能够证明这个实体知道这个数据.这个数据用实体私有钥匙签名并递交; 3.身份:知道实体的方法.在一些系统中身份是公共钥匙,其他系统中可以是从一个X.509名字的邮件地址的Unix UID来的任何东西; 4.签名:一个签名用用实体私有钥匙来计算某些加密数据; 5.私有钥匙:是一些数字,每一个私有钥匙只能被特定的拥有该私有钥匙的实体知道.私有和公共钥匙存在所有用公共钥匙加密的系统的钥匙对中.一个公共钥匙加密(如DSA),一个私有钥匙与一个正确的公共钥匙通信.私有钥匙用来计算签名. 6.实体:一个实体可以是一个人,一个组织,一个程序,一台计算机,一个商业,一个银行,或其他你想信任的东西. Keytool应用实例: 1.产生一个keystore: keytool -genkey -alias User(keystore的别名) -keyalg RSA -validity 7 -keystore keystore(指定keystore). 运行这个命令,系统提示: Enter keystore password:yourpassword(输入密码) What is your first and last name? [Unknown]: your name(输入你的名字) What is the name of your organizational unit? [Unknown]:your organizational(输入你所在组织单位的名字) What is the name of your organization? [Unknown]:your organization name (输入你所在组织的名字) What is the name of your City or Locality? [Unknown]:your city name(输入所在城市的名字) What is the name of your State or Province? [Unknown]:your provice name(输入所在省份名字) What is the two-letter country code for this unit? [Unknown]:cn(输入国家名字) Is CN=your name, OU=your organizaion, O="your organization name", L=your city name, ST=your province name, C=cn correct? [no]: yes 2.检查一个keystore: keytool -list -v -keystore keystore Enter keystore password:your password(输入密码) 将显示keystore內容如: Keystore type: jks Keystore provider: SUN Your keystore contains 1 entry Alias name: yourname Creation date: Dec 20, 2001 Entry type: keyEntry Certificate chain length: 1 Certificate[1]: Owner: CN=yourname, OU=your organization, O="your organization name", L=your city name, ST=your province name, C=CN Issuer: CN=Duke, OU=Java Software, O="Sun Microsystems, Inc.", L=Palo Alto, ST=CA, C=US Serial number: 3c22adc1 Valid from: Thu Dec 20 19:34:25 PST 2001 until: Thu Dec 27 19:34:25 PST 2001 Certificate fingerprints: MD5: F1:5B:9B:A1:F7:16:CF:25:CF:F4:FF:35:3F:4C:9C:F0 SHA1: B2:00:50:DD:B6:CC:35:66:21:45:0F:96:AA:AF:6A:3D:E4:03:7C:74 3.输出keystore到一个文件:testkey: keytool -export -alias duke -keystore keystore -rfc -file testkey 系统输出: Enter keystore password:your password(输入密码) Certificate stored in file 4.输入证书到一个新的truststore: keytool -import -alias dukecert -file testkey -keystore truststore Enter keystore password:your new password.(输入truststore新密码) 5.检查truststore: keytool -list -v -keystore truststore 系统将显示truststore的信息. 现在可以用适当的keystore运行你的应用程序.如: java -Djavax.net.ssl.keyStore=keystore -Djavax.net.ssl.keyStorePassword=password Server 和: java -Djavax.net.ssl.trustStore=truststore -Djavax.net.ssl.trustStorePassword=trustword Client <淘宝热门商品:
 

25.00 元 

重庆女人香专业减肥丰胸网~一品婷/美姿姿/脱脂减肥*批发代理

 

225.00 元  

上海商盟】易淘视听商城

五钻100%原装松下HTX7耳机经典白色 松下头戴式耳机 东方神起代言


来源:程序员网

小小豆叮

使用FileFilter搜索文件

如何快速的按照特定要求找出所有文件呢?试试java.io.FileFilter 吧。 FileFilter 包含在Java Development Kit (JDK) 1.2 众多的附件中。它的主要作用就是检测文件是否存在。FileFilter 和它的前身FilenameFilter 的唯一不同是FileFilter 提供文件对象的访问方法,而FilenameFilter 是按照目录和文件名的方式来工作的。 例如,FileFilter 是这样的: boolean accept(File file); 而FilenameFilter 却是以下的样子: boolean accept(File directory, String name); 一个简单的例子是搜索特定的文件扩展名,你可以使用FilenameFilter ,但是出来的结果会让你很难判断到底是文件夹还是文件。要解决这个问题,你需要使用文件对象。也就是使用FileFilter吧。 以下是ExtensionFileFilter 的代码: package com.generationjava.io.find; import java.io.File; import java.io.FileFilter; public class ExtensionFileFilter implements FileFilter { private String extension; public ExtensionFileFilter(String extension) { this.extension = extension; } public boolean accept(File file) { if(file.isDirectory( )) { return false; } String name = file.getName( ); // find the last int idx = name.lastIndexOf("."); if(index == -1) { return false; } else if(index == name.length( ) -1) { return false; } else { return this.extension.equals(name.substring(index+1)); } } } 以下的例子中用到了上述的ExtensionFileFilter 代码: ... String dir = "..."; // directory of your choice File file = new File(dir); File[] files = file.listFiles(new ExtensionFileFilter("cfg")); // files variable is now c:\*.cfg if 'dir' is c:\ // that is, all the files in the specified directory ending in *.cfg ... FileFilter 其实是从 javax.swing.filechooser.FileFilter派生出来的,javax.swing.filechooser.FileFilter 是使用JFileChoosers的抽象类。 <淘宝热门商品:
 

 

泰国佛牌精品店

 

 

【上海商盟】高更食品极美滋新奥尔良系列烧烤腌料皇冠旗舰店


来源:程序员网

小小豆叮

The J2EE Tutorial

Mapping Table Relationships for Bean-Managed Persistence In a relational database, tables can be related by common columns. The relationships between the tables affect the design of their corresponding entity beans. The entity beans discussed in this section are backed up by tables with the following types of relationships: One-to-one One-to-many Many-to-many One-to-One Relationships In a one-to-one relationship, each row in a table is related to a single row in another table. For example, in a warehouse application, a storagebin table might have a one-to-one relationship with a widget table. This application would model a physical warehouse in which each storage bin contains one type of widget and each widget resides in one storage bin. Figure 5-1 illustrates the storagebin and widget tables. Because the storagebinid uniquely identifies a row in the storagebin table, it is that table's primary key. The widgetid is the primary key of the widget table. The two tables are related because the widgetid is also a column in the storagebin table. By referring to the primary key of the widget table, the widgetid in the storagebin table identifies which widget resides in a particular storage bin in the warehouse. Because the widgetid of the storagebin table refers to the primary key of another table, it is called a foreign key. (The figures in this chapter denote a primary key with PK and a foreign key with FK.) Figure 5-1 One-to-One Table Relationship A dependent (child) table includes a foreign key that matches the primary key of the referenced (parent) table. The values of the foreign keys in the storagebin (child) table depend on the primary keys in the widget (parent) table. For example, if the storagebin table has a row with a widgetid of 344, then the widget table should also have a row whose widgetid is 344. When designing a database application, you may choose to enforce the dependency between the parent and child tables. There are two ways to enforce such a dependency: by defining a referential constraint in the database or by performing checks in the application code. The storagebin table has a referential constraint named fk_widgetid: CREATE TABLE storagebin (storagebinid VARCHAR(3) CONSTRAINT pk_storagebin PRIMARY KEY, widgetid VARCHAR(3), quantity INTEGER, CONSTRAINT fk_widgetid FOREIGN KEY (widgetid) REFERENCES widget(widgetid)); The source code for the following example is in the j2eetutorial/examples/src/ejb/storagebin directory. To compile the code, go to the j2eetutorial/examples directory and type ant storagebin. A sample StorageBinApp.ear file is in the j2eetutorial/examples/ears directory. The StorageBinBean and WidgetBean classes illustrate the one-to-one relationship of the storagebin and widget tables. The StorageBinBean class contains variables for each column in the storagebin table, including the foreign key, widgetId: private String storageBinId; private String widgetId; private int quantity; The ejbFindByWidgetId method of the StorageBinBean class returns the storageBinId that matches a given widgetId: public String ejbFindByWidgetId(String widgetId) throws FinderException { String storageBinId; try { storageBinId = selectByWidgetId(widgetId); } catch (Exception ex) { throw new EJBException("ejbFindByWidgetId: " + ex.getMessage()); } if (storageBinId == null) { throw new ObjectNotFoundException ("Row for widgetId " + widgetId + " not found."); } else { return storageBinId; } } The ejbFindByWidgetId method locates the widgetId by querying the database in the selectByWidgetId method: private String selectByWidgetId(String widgetId) throws SQLException { String storageBinId; String selectStatement = "select storagebinid " + "from storagebin where widgetid = ? "; PreparedStatement prepStmt = con.prepareStatement(selectStatement); prepStmt.setString(1, widgetId); ResultSet rs = prepStmt.executeQuery(); if (rs.next()) { storageBinId = rs.getString(1); } else { storageBinId = null; } prepStmt.close(); return storageBinId; } To find out in which storage bin a widget resides, the StorageBinClient program calls the findByWidgetId method: String widgetId = "777"; StorageBin storageBin = storageBinHome.findByWidgetId(widgetId); String storageBinId = (String)storageBin.getPrimaryKey(); int quantity = storageBin.getQuantity(); Running the StorageBinEJB Example Create the storagebin database table. Go to the j2eetutorial/examples directory. Type ant create-storagebin-table. Deploy the StorageBinApp.ear file (located in the j2eetutorial/examples/ears directory). Run the client. Go to the j2eetutorial/examples/ears directory. Set the APPCPATH environment variable to StorageBinAppClient.jar. Type the following command on a single line: runclient -client StorageBinApp.ear -name StorageBinClient -textauth At the login prompts, enter guest for the user name and guest123 for the password. One-to-Many Relationships If the primary key in a parent table matches multiple foreign keys in a child table, then the relationship is one-to-many. This relationship is common in database applications. For example, an application for a sports league might access a team table and a player table. Each team has multiple players, and each player belongs to a single team. Every row in the child table (player) has a foreign key identifying the player's team. This foreign key matches the team table's primary key. The sections that follow describe how you might implement one-to-many relationships in entity beans. When designing such entity beans, you must decide whether both tables are represented by entity beans, or just one. A Helper Class for the Child Table Not every database table needs to be mapped to an entity bean. If a database table doesn't represent a business entity, or if it stores information that is contained in another entity, then the table should be represented with a helper class. In an online shopping application, for example, each order submitted by a customer can have multiple line items. The application stores the information in the database tables shown by Figure 5-2. Figure 5-2 One-to-Many Relationship: Order and Line Items Not only does a line item belong to an order, it also does not exist without the order. Therefore, the lineitems table should be represented with a helper class and not with an entity bean. Using a helper class in this case is not required, but doing so might improve performance because a helper class uses fewer system resources than an entity bean. The source code for the following example is in the j2eetutorial/examples/src/ejb/order directory. To compile the code, go to the j2eetutorial/examples directory and type ant order. A sample OrderApp.ear file is in the j2eetutorial/examples/ears directory. The LineItem and OrderBean classes show how to implement a one-to-many relationship with a helper class (LineItem). The instance variables in the LineItem class correspond to the columns in the lineitems table. The itemNo variable matches the primary key for the lineitems table, and the orderId variable represents the table's foreign key. Here is the source code for the LineItem class: public class LineItem implements java.io.Serializable { String productId; int quantity; double unitPrice; int itemNo; String orderId; public LineItem(String productId, int quantity, double unitPrice, int itemNo, String orderId) { this.productId = productId; this.quantity = quantity; this.unitPrice = unitPrice; this.itemNo = itemNo; this.orderId = orderId; } public String getProductId() { return productId; } public int getQuantity() { return quantity; } public double getUnitPrice() { return unitPrice; } public int getItemNo() { return itemNo; } public String getOrderId() { return orderId; } } The OrderBean class contains an ArrayList variable named lineItems. Each element in the lineItems variable is a LineItem object. The lineItems variable is passed to the OrderBean class in the ejbCreate method. For every LineItem object in the lineItems variable, the ejbCreate method inserts a row into the lineitems table. It also inserts a single row into the orders table. The code for the ejbCreate method follows: public String ejbCreate(String orderId, String customerId, String status, double totalPrice, ArrayList lineItems) throws CreateException { try { insertOrder(orderId, customerId, status, totalPrice); for (int i = 0; i < lineItems.size(); i++) { LineItem item = (LineItem)lineItems.get(i); insertItem(item); } } catch (Exception ex) { throw new EJBException("ejbCreate: " + ex.getMessage()); } this.orderId = orderId; this.customerId = customerId; this.status = status; this.totalPrice = totalPrice; this.lineItems = lineItems ; return orderId; } The OrderClient program creates and loads an ArrayList of LineItem objects. The program passes this ArrayList to the entity bean when it invokes the create method: ArrayList lineItems = new ArrayList(); lineItems.add(new LineItem("p23", 13, 12.00, 1, "123")); lineItems.add(new LineItem("p67", 47, 89.00, 2, "123")); lineItems.add(new LineItem("p11", 28, 41.00, 3, "123")); ... Order duke = home.create("123", "c44", "open", totalItems(lineItems), lineItems); Other methods in the OrderBean class also access both database tables. The ejbRemove method, for example, not only deletes a row from the orders table, but also deletes all corresponding rows in the lineitems table. The ejbLoad and ejbStore methods synchronize the state of an OrderEJB instance, including the lineItems ArrayList, with the orders and lineitems tables. The ejbFindByProductId method enables clients to locate all orders that have a particular product. This method queries the lineitems table for all rows with a specific productId. The method returns a Collection of Order objects. The OrderClient program iterates through the Collection and prints the primary key of each order: Collection c = home.findByProductId("p67"); Iterator i=c.iterator(); while (i.hasNext()) { Order order = (Order)i.next(); String id = (String)order.getPrimaryKey(); System.out.println(id); } Running the OrderEJB Example Create the orders database table:. Go to the j2eetutorial/examples directory. Type ant create-order-table. Deploy the OrderApp.ear file (located in the j2eetutorial/examples/ears directory). Run the client. Go to the j2eetutorial/examples/ears directory. Set the APPCPATH environment variable to OrderAppClient.jar. Type the following command on a single line: runclient -client OrderApp.ear -name OrderClient -textauth At the login prompts, enter guest for the user name and guest123 for the password. An Entity Bean for the Child Table You should consider building an entity bean for a child table under the following conditions: The information in the child table is not dependent on the parent table. The business entity of the child table could exist without that of the parent table. The child table might be accessed by another application that does not access the parent table. These conditions exist in the following scenario. Suppose that each sales representative in a company has multiple customers and that each customer has only one sales representative. The company tracks its sales force with a database application. In the database, each row in the salesrep table (parent) matches multiple rows in the customer table (child). Figure 5-3 illustrates this relationship. Figure 5-3 One-to-Many Relationship: Sales Representative and Customers The SalesRepBean and CustomerBean entity bean classes implement the one-to-many relationship of the sales and customer tables. The source code for this example is in the j2eetutorial/examples/src/ejb/salesrep directory. To compile the code, go to the j2eetutorial/examples directory and type ant salesrep. A sample SalesRepApp.ear file is in the j2eetutorial/examples/ears directory. The SalesRepBean class contains a variable named customerIds, which is an ArrayList of String elements. These String elements identify which customers belong to the sales representative. Because the customerIds variable reflects this relationship, the SalesRepBean class must keep the variable up to date. The SalesRepBean class instantiates the customerIds variable in the setEntityContext method, not in ejbCreate. The container invokes setEntityContext just once--when it creates the bean instance--ensuring that customerIds is instantiated just once. Because the same bean instance can assume different identities during its life cycle, instantiating customerIds in ejbCreate might cause multiple and unnecessary instantiations. Therefore, the SalesRepBean class instantiates the customerIds variable in setEntityContext: public void setEntityContext(EntityContext context) { this.context = context; customerIds = new ArrayList(); try { makeConnection(); Context initial = new InitialContext(); Object objref = initial.lookup("java:comp/env/ejb/Customer"); customerHome = (CustomerHome)PortableRemoteObject.narrow(objref, CustomerHome.class); } catch (Exception ex) { throw new EJBException("setEntityContext: " + ex.getMessage()); } } Invoked by the ejbLoad method, loadCustomerIds is a private method that refreshes the customerIds variable. There are two approaches when coding a method such as loadCustomerIds: fetch the identifiers from the customer database table or get them from the CustomerEJB entity bean. Fetching the identifiers from the database might be faster, but exposes the code in the SalesRepBean class to the CustomerEJB bean's underlying database table. In the future, if you were to change the CustomerEJB bean's table (or move the bean to a different J2EE server), you might need to change the SalesRepBean code. But if the SalesRepBean class gets the identifiers from the CustomerEJB entity bean, no coding changes would be required. The two approaches present a trade-off: performance versus flexibility. The SalesRepEJB example opts for flexibility, loading the customerIds variable by calling the findSalesRep and getPrimaryKey methods of CustomerEJB. Here is the code for the loadCustomerIds method: private void loadCustomerIds() { customerIds.clear(); try { Collection c = customerHome.findBySalesRep(salesRepId); Iterator i=c.iterator(); while (i.hasNext()) { Customer customer = (Customer)i.next(); String id = (String)customer.getPrimaryKey(); customerIds.add(id); } } catch (Exception ex) { throw new EJBException("Exception in loadCustomerIds: " + ex.getMessage()); } } If a customer's sales representative changes, the client program updates the database by calling the setSalesRepId method of the CustomerBean class. The next time a business method of the SalesRepBean class is called, the ejbLoad method invokes loadCustomerIds, which refreshes the customerIds variable. (To ensure that ejbLoad is invoked before each business method, set the transaction attributes of the business methods to Required.) For example, the SalesRepClient program changes the salesRepId for a customer named Mary Jackson as follows: Customer mary = customerHome.findByPrimaryKey("987"); mary.setSalesRepId("543"); The salesRepId value 543 identifies a sales representative named Janice Martin. To list all of Janice's customers, the SalesRepClient program invokes the getCustomerIds method, iterates through the ArrayList of identifiers, and locates each CustomerEJB entity bean by calling its findByPrimaryKey method: SalesRep janice = salesHome.findByPrimaryKey("543"); ArrayList a = janice.getCustomerIds(); i = a.iterator(); while (i.hasNext()) { String customerId = (String)i.next(); Customer customer = customerHome.findByPrimaryKey(customerId); String name = customer.getName(); System.out.println(customerId + ": " + name); } Running the SalesRepEJB Example Create the database tables. Go to the j2eetutorial/examples/src directory. Type ant create-salesrep-table. Deploy the SalesRepApp.ear file (located in the j2eetutorial/examples/ears directory). Run the client. Go to the j2eetutorial/examples/ears directory. Set the APPCPATH environment variable to SalesRepAppClient.jar. Type the following command on a single line: runclient -client SalesRepApp.ear -name SalesRepClient -textauth At the login prompts, enter guest for the user name and guest123 for the password. Many-to-Many Relationships In a many-to-many relationship, each entity may be related to multiple occurrences of the other entity. For example, a college course has many students and each student may take several courses. In a database, this relationship is represented by a cross reference table containing the foreign keys. In Figure 5-4, the cross reference table is the enrollment table. These tables are accessed by the StudentBean, CourseBean, and EnrollerBean classes. Figure 5-4 Many-to-Many Relationship: Students and Courses The source code for this example is in the j2eetutorial/examples/src/ejb/enroller directory. To compile the code, go to the j2eetutorial/examples directory and type ant enroller. A sample EnrollerApp.ear file is in the j2eetutorial/examples/ears directory. The StudentBean and CourseBean classes are complementary. Each class contains an ArrayList of foreign keys. The StudentBean class contains an ArrayList named courseIds, which identifies the courses the student is enrolled in. Likewise, the CourseBean class contains an ArrayList named studentIds. The ejbLoad method of the StudentBean class adds elements to the courseIds ArrayList by calling loadCourseIds, a private method. The loadCourseIds method gets the course identifiers from the EnrollerEJB session bean. The source code for the loadCourseIds method follows: private void loadCourseIds() { courseIds.clear(); try { Enroller enroller = enrollerHome.create(); ArrayList a = enroller.getCourseIds(studentId); courseIds.addAll(a); } catch (Exception ex) { throw new EJBException("Exception in loadCourseIds: " + ex.getMessage()); } } Invoked by the loadCourseIds method, the getCourseIds method of the EnrollerBean class queries the enrollment table: select courseid from enrollment where studentid = ? Only the EnrollerBean class accesses the enrollment table. Therefore, the EnrollerBean class manages the student-course relationship represented in the enrollment table. If a student enrolls in a course, for example, the client calls the enroll business method, which inserts a row: insert into enrollment values (studentid, courseid) If a student drops a course, the unEnroll method deletes a row: delete from enrollment where studentid = ? and courseid = ? And if a student leaves the school, the deleteStudent method deletes all rows in the table for that student: delete from enrollment where student = ? The EnrollerBean class does not delete the matching row from the student table. That action is performed by the ejbRemove method of the StudentBean class. To ensure that both deletes are executed as a single operation, they should belong to the same transaction. See Chapter 14 for more information. Running the EnrollerEJB Example Create the database tables. Go to the j2eetutorial/examples directory. Type ant create-enroller-table. Deploy the EnrollerApp.ear file (located in the j2eetutorial/examples/ears directory). Run the client. Go to the j2eetutorial/examples/ears directory. Set the APPCPATH environment variable to EnrollerAppClient.jar. Type the following command on a single line: runclient -client EnrollerApp.ear -name EnrollerClient -textauth At the login prompts, enter guest for the user name and guest123 for the password. <淘宝热门商品:
 

138.00 元  

免邮-七色瘦减肥胶囊-店主亲试劲减30斤前后照片

 

鲜花速递/蛋糕配送/园艺花艺 

瑞锦记锦缎喜糖袋〓婚礼特制●上等材质●流行韩


来源:程序员网

小小豆叮