J2EE的异步消息机制(下)

三.消息驱动豆简介   异步消息也可以由消息驱动豆来实现。在EJB 1.1规范中,定义了两种类型的EJB。分别是实体豆(Entity Bean)和会话豆(Session Bean)。客户端通常是以同步的,阻塞方式来调用豆的方法。消息驱动豆将EJB和JMS的功能结合在一起。   正如前述,会话豆通常实现商务逻辑,客户端不能共享一个会话豆。实体豆通常和一些在永久存储中的一些实体条目相对应的。这两种豆通常都有REMOTE和HOME接口,用来与客户端交互。并且,这些交互都是同步的,阻塞方式进行的。比如,一个请求发送给一个豆,通过阻塞式方法调用,服务器返回一个相应。调用者在收到返回后,才能进行下一步处理。消息驱动豆通常配置成是一个特别的主题(topic)或队列的客户端,作为消息的使用者。但消息驱动豆没有HOME和REMOTE接口。一个消息产生者将消息写入TOPIC或队列时,并不知道使用者是一个消息驱动豆。这就允许集成一个分布式的计算系统时,有很大的灵活性。消息驱动豆没有会话性质的状态,所有的实例在不处理请求时是相同的,这与无状态会话豆是类似的。将豆的实例放在缓冲池里,也是高效处理消息驱动豆的一种方法。一个消息驱动豆必须间接或直接地从javax.ejb.MessageDrivenBean接口继承而来。这个接口是由javax.jms.MessageListener继承而来。这个方法的一个参数是javax.jms.Message。可以是任何有效的JMS消息类型。方法的申明中并不包含一个thrown语句。因此在消息处理中,不会仍出应用程序异常。当容器接收到消息时,它首先是从一个缓冲池里得到现成的一个消息驱动豆,然后,如果配置文件需要的,容器还要设置一个和事务处理上下文的一个联系。当这些管理任务完成时,接收到的消息传递给onMessage()方法。一旦方法完成,事务确认或返回,豆又被重新放回到缓冲池。   ejbRemove()在把消息驱动豆从任何存储上删除时调用。并进行清楚操作和垃圾收集。必须在ejbRemove()方法中释放所有豆的实例用到的资源。   setMessageDrivenConnection()方法只有一个参数-javax.ejb.MessageDrivenContext的实例。MessageDrivenContext类与在实体和会话豆中的上下文类似。当一个豆的实例创建时,容器传入豆用的上下文。上下文中得到环境信息的方法,以及JTA UserTranscation类,用于豆管理事务处理的场合。   另外,豆提供者必须提供一个ejbCreate()方法(无参数),用于在EJB服务器对豆进行设置。豆实例可以在ejbCreate()方法中取得任何需要的资源。   消息驱动豆大大地简化了创建一个JMS使用者,创建和配置一个JMS消息使用者这些功能都交由EJB容器来做了。开发人员只需简单地实现消息驱动豆的接口,配置给EJB服务器,用来创建一个接收消息的商业逻辑部件。   四.一个实例   本文为了说明上面的概念,编写了一个消息驱动豆,一个Publisher和一个Subscriber的代码。   下面讲一下怎样运行实例。这里假设读者已经从SUN主页上下载了J2EE SDK 1.3 Bate,并已经安装好了。   1.创建一个WeatherReport   主题(Topic):   j2eeadmin -addJmsDestination WeatherReport topic   可以用下面命令看一下是否正确创建:   D:\j2sdkee1.3\bin>j2eeadmin -listJmsDestination JmsDestination   一般显示结果如下:   < JMS Destination : jms/Topic , javax.jms.Topic >   < JMS Destination : jms/Queue , javax.jms.Queue >   < JMS Destination : WeatherReport , javax.jms.Topic >   2.运行Subscriber:   D:\mysourcecode\testjms>java -Djms.properties=%J2EE_HOME%\config\jms_client.properties jmssub   一般显示结果如下:   Topic name is WeatherReport   Java(TM) Message Service 1.0.2 Reference Implementation (build b10)   To end program, enter Q or q, then   Reading message: A sunny day.   3.运行Publisher:   打开另一个命令行窗口,输入下面命令:   set classpath=%J2EE_HOME%\lib\j2ee.jar;.   java -Djms.properties=%J2EE_HOME%\config\jms_client.properties jmspub   一般显示结果如下:   Topic name is WeatherReport   Java(TM) Message Service 1.0.2 Reference Implementation (build b10)   Publishing message: A sunny day.   4.删除一个话题   D:\j2sdkee1.3\bin>j2eeadmin -removeJmsDestination MyTopic   5.使用消息驱动豆   下面是用消息驱动豆实现接受消息。使用deploytool将附录中的Bean部署好,可以看到下面的信息:   Deploying message driven bean MsgBean, consuming from WeatherReport   Application testjms deployed.   然后再次运行Publisher。可以看到消息驱动豆输出下面的结果:   MESSAGE BEAN: Message received: A sunny day. <淘宝热门商品:
 

268.00元  

Shanghai 秀卡蒂 女性健康購物中心 瘦身減肥

 

205.00 元  

东菱小熊贝尔莱德艾美特(面包机酸奶机挂烫机电暖器礼品小家电)

双皇冠,产地代理『艾美特暖风机HP2009』2000W功率,浴居两用


来源:程序员网

小小豆叮

用Java的加密机制来保护你的数据

Java开发工具包 (JDK)对加密和安全性有很好的支持。其中一个优势就是其内置的对Socket通信的支持。因此,很容易做到在服务器和客户之间建立安全的数据流。 流 Java streams 是一个强大的编程工具。java.io包提供了很多标准的流类型,并能很容易的建立自己的流类型。流的一个有用的特点是和链表一样的简单处理过程。表 A是一个用链表读取文本的例子。这段代码将 FileReader和 BufferedReader链接起来。我们在用客户机/服务器应用程序的时候也会用到类似的概念。 关键字 对于验证来说,关键字很重要,表 B (KeyGen.java)提供了一个称为 getSecretKey的标准方法。通过运行KeyGen来产生一个关键字。因为我们采用同步方法,所以客户机和服务器必须用相同的关键字。 安全socket 我们从一个简单的类开始,它提供我们在普通socket对象之上的加密。表 C (SecretSocket.java) 包含了两段代码-Socket和Key对象。我们的构造器创建了变量并初始化了密码: outCipher = Cipher.getInstance(algorithm); outCipher.init(Cipher.ENCRYPT_MODE, key); inCipher = Cipher.getInstance(algorithm); inCipher.init(Cipher.DECRYPT_MODE, key); 因为socket是双向的通信,所以我们采用两个密码。加密输出的数据并解密输入的数据。我们使用getInputStream()和 getOutputStream(),这两种方法来加密合解密通用的输入和输出的经过包装的数据流。见 表 D 。 在JCE的javax.crypto包中包含CipherInputStream和 CipherOutputStream这两种流类型。他们接收输入输出的流对象和密码对象。 Socket 服务器 开始写我们的socket服务器类吧。 表 E (SecretSocketServer.java)是一个完整的列表。SecretSocketServer在一个端口打开ServerSocket,当接收到连接时,使用SocketHandler产生一个线程来操作连接。 Socket 句柄 表 F (SocketHandler.java) 确定一个socket对象,通过KeyGen来定位关键字,并建立一个 SecretSocket 对象。. Key key = KeyGen.getSecretKey(); this.ss = new SecretSocket(s, key); 注意表F中的 ss对SocketHandler来说是一个实变量。所有的socket 处理都是通过SecretSocket而不是Socket对象。然后我们使用下面的代码: in = ss.getInputStream(); 记住,在SecretSocket中,getInputStream是和CipherInputStream以及 InputStream相结合的。因为SocketHandler 是一个可执行的界面,我们为它生成一个 run()方法。这个方法只是在等待socket的数据: boolean bool = true; while (bool) { bool = listen(); } listen方法用来监听socket 。 int aByte; while ((aByte = in.read()) >= 0) { system.out.println((char)aByte); } Socket 客户 现在我们来看看客户端。见 表 G 。客户端的工作和服务器端很相似,只是反过来了。首先,我们创立一个套接字连接到服务器。使用KeyGen 找到关键字,创立一个安全套接字(SecretSocket)。然后我们利用它的OutputStream给服务器发送数据: Key key = KeyGen.getSecretKey(); Socket s = new Socket("localhost", 4444); SecretSocket ss = new SecretSocket(s, key); OutputStream os = ss.getOutputStream(); os.write("Hello World!".getBytes()); os.flush(); os.close(); s.close(); 总结 通过JCE中的java流和链表,我们可以轻松的加密基于socket的网络通信。 下载文章中的代码 KeyGen.java SecretSocket.java SecretSocketServer.java SocketHandler.java SecretSocketClient.java <淘宝热门商品:
 

50.00 元 

黑头粉刺净 扫光黑头粉刺顽痘 卖疯了

 

110.00元  

动感娱乐中心(修身堂 减肥咖啡 瘦身咖啡 神奇咖啡)


来源:程序员网

小小豆叮

J2EE的异步消息机制(上)

在分布式企业级应用程序中,异步消息机制用于有效地协调各个部分的工作。   J2EE为我们提供了JMS和消息驱动豆(Message-Driven Bean),用来实现应用程序各个部件之间的异步消息传递。   一.什么是消息系统?   通常一个消息系统允许分开的未耦合的应用程序之间可靠地异步通信。在企业应用时,需要一种异步的,非阻塞的消息传递。比如,一个客户端可能希望给一个服务器发送一个请求后,不在乎是否马上能得到回应。这样,客户端没有理由必须等待服务器处理请求。客户端应用程序在递交一个请求之后,只需确保请求到达服务器端后,就可以处理其他任务。通常,这是很高效的。消息系统提供了许多其他分布式对象计算模型没有的优点。它鼓励在消息产生者和使用者之间的"松耦合",在它们之间有很高程度的事务处理。对于使用者,它不在乎谁产生了消息,产生者是否仍在网络上以及消息是什么时候产生的。这就允许建立动态的,可靠的和灵活的系统。整个的子系统能被修改而不会影响系统的其他部分。   另外的优点包括:系统的高度可扩展性,容易与其他系统进行集成,以及高度的可靠性。由于可靠性和可扩展性,使得它们用于解决许多商业和科学计算问题。比如,消息系统是许多应用程序的基础,这些应用程序可以是工作流,网络管理,通信服务或供应链管理程序。在JAVA技术中,处理异步消息的能力是通过JMS来实现的。JMS最初设计是为了给传统的消息对象中间件提供一个标准的JAVA接口。而这些产品是在一个企业级应用程序中必须的。现在出现了许多支持JMS的纯JAVA的产品。   消息系统类型   通常有两种消息类型。   1.发布/订阅(publish/subscribe)   发布/订阅消息系统支持一个事件驱动模型,消息产生者和使用者都参与消息的传递。产生者发布事件,而使用者订阅感兴趣的事件,并使用事件。产生者将消息和一个特定的主题(Topic)连在一起,消息系统根据使用者注册的兴趣,将消息传给使用者。   2.点对点(Peer to peer)   在点对点的消息系统中,消息分发给一个单独的使用者。它维持一个"进入"消息队列。消息应用程序发送消息到一个特定的队列,而客户端从一个队列中得到消息。   二.JMS简介   JMS的目的是提供给消息系统客户一个固定的接口,而且与底层的消息提供者无关。这样,客户端的应用程序可以在不同的机器和操作系统中移植,而且能在不同的消息系统产品之间转移。JMS客户端都是建立在JAVA技术上的,从而也能使用其他JAVAAPI,如JDBC数据库连接,使用JAVABEAN组件模型,JDNI名字服务,JTA客户端事务处理控制以及J2SE和J2EE API来实现企业级应用服务程序。   1.JMS对象模型 图1显示了JMS对象,用于提供JMS客户端与JMS服务提供者相连的对象。   ConnectionFactory是一个客户端用来创建一个Connection的管理对象。由于在Connection创建时有授权和通信建立过程,因此这个对象是比较大的。   Destination对象将一个消息的目的和服务提供者有关的地址及配置信息包装起来。   Session是JMS实体,用来支持事务处理和异步消息消费。JMS并不需要客户端的代码用于异步消息消费或能处理多个并发消息。通常,事务的复杂性都由一个Session来封装。   一个Session是一个原子单位的工作,与数据库的事务一样,要实现多线程事务比较困难。Session提供了在一个线程编程模式下的并发的优点。   MessageProducer和MessageConsumer对象由Session对象创建。用于发送和接受消息。为了确保消息的传递,JMS服务提供者处理的消息都要处于PERSISTENT模式。PERSISTENT模式使得JMS提供者出问题后,也能让消息保存下来。   Session,MessageProducer和MessageConsumer都不支持并发,而ConnectionFactory,Destination和Connection都支持并发。   2.JMS应用程序开发   JMS中的消息   在消息系统中,应用程序之间通信的关键是消息。因此使用JMS必须要先理解消息。   在JMS中,消息由三部分组成:   MESSAGE HEADER用于识别消息,比如用于判断一个给定的消息是否是一个"订阅者"   PROPERITIES用于与应用程序相关的,提供者相关的和可选项的信息   BODY是消息的内容,支持几种格式,包括TextMessage(对String一个简单的封装)和ObjectMessage(对任意对象的封装,但必须支持序列化),也支持其他格式。   TextMessage   一个TextMessage是一个String对象的封装。在只有文本对象传递时,是很有用的。它假设许多消息系统是建立在XML上的。从而TextMessage就可以成为包装它们的容器。   创建一个TextMessage对象很简单,如下面的代码:   TextMessage message=session.createMessage();   message.setText("Hello, world!");   ObjectMessage   如名字所示,它是对一个JAVA对象的封装的消息。任何可序列化的JAVA对象都能用于ObjectMessage,如果必须将多个对象封装在一个消息里传递,可以使用Collection对象,来包括多个序列化对象。   下面是创建一个ObjectMessage   ObjectMessage message=session.createObjectMessage();   message.setObject(myObject);   创建一个JMS客户端程序   一个典型的JMS客户端由下面的几个基本步骤来创建:   创建一个到消息系统提供者的连接(Connection)   创建一个Session,用于接收和发送消息   创建MessageProducer和MessageConsumer来创建和接收消息   当完成了上述步骤后,一个消息产生者客户端将创建并发布消息到一个主题,而消息使用者客户端会接收与一个主题相关的消息。   1.创建一个Connection   一个Connection提供客户端对底层的消息系统的访问。并实现资源的分配和管理。通过使用一个ConnectionFactory来创建一个Connection,通常用JDNI来指定:

Connection message=new initialContext();
TopicConnectionFactory topicConnectionFactory=(TopicConnectionFactory);
topic = (Topic) jndiContext.lookup(topicName);
topicConnection =topicConnectionFactory.createTopicConnection();
2.创建一个Session   Session是一个比较大的JMS对象,他提供了生产和消费消息的手段。用于创建消息使用者和消息产生者。   topicSession = topicConnection.createTopicSession(false,Session.AUTO_ACKNOWLEDGE);   两个参数用于控制事务和消息确认。   3.定位一个Topic   用JDNI来定位一个Topic,Topic用于识别发送或接收的消息,在发布/订阅系统中。订阅者订阅一个给定的Topic,而发布者将它发布的消息与一个Topic相连。   下面是创建一个Topic "WeatherReport"   Topic weatherTopic=messaging.lookup("WeatherReport");   4.启动Connection   在上面的初始化步骤之后,消息流是禁止的,用于防止在初始化时发生不可预料的行为。一旦初始化结束,必须让Connection启动消息系统。   topicConnection.start();   5.创建一个消息产生者   在发布/订阅里,一个产生者发布消息到一个指定的Topic。下面的代码显示创建一个产生者,以及后续的建立和发布一个简单文本消息。   TopicPublisher publisher=session.createPublisher(weatherTopic);   TexeMessage message=session.createMessage();   message.setText("ssss");   publisher.publish(message);   下面是一个消息使用者的代码

topicConnection =topicConnectionFactory.createTopicConnection();
topicSession = topicConnection.createTopicSession(false, Session.AUTO_ACKNOWLEDGE);
topicSubscriber = topicSession.createSubscriber(topic);
topicListener = new MsgListener();
topicSubscriber.setMessageListener(topicListener);
topicConnection.start();
<淘宝热门商品:
 

35.00 元 

【天使名妆】100%纯棉休闲瑜珈裤

 

55.00 元 

您试试一箱油能否多跑100公里(5次用)


来源:程序员网

小小豆叮

Java中的cookie管理方案(3)-与J2ME结合

jCookie结构 下面我将描述层及他们使用的不同的类。 层1 那些开发者多数都想进行透明cookie操作,这通常是使用层1的情形。在这个级别,你用Client类操作cookies。它有两个主要的方法: · public CookieJar getCookies(URLConnection urlConn): 这个方法从给出的URLConnection中析取cookies,将它们解析到Cookie对象,并作为一个CookieJar返回。 · public CookieJar setCookies(URLConnection urlConn, CookieJar cj): 这个方法从CookieJar中提取合适的Cookie对象并设置URLConnection的报头。 层0 这些开发者没有在使用层0的代码中深入就无法呼吸(包括我)。在这里,你可以通过使用cookie操作代码改变解析逻辑和安全规则。要这样做,首先实现CookieParser接口,它有以下四个方法: · public Header getCookieHeaders(CookieJar cj): 在CookieJar中转换Cookies为一报头以适合与一个HTTP请求一起发送。 · public boolean allowedCookie(Cookie c, URL url): 检查是否一个给出URL的请求能返回指定的Cookie。 · public CookieJar parseCookies(Header h, URL url): 在一个HTTP响应中将报头转换到一个Cookie对象的CookieJar中。 · public boolean sendCookieWithURL(Cookie c, URL url, boolean bRespectExpires): 检查是否给出的Cookie能被与给出URL的一个请求一起发送。 你能使用Client类的setCookieParser(CookieParser cp)方法去设置CookieParser实现。被库缺省使用的CookieParser是一个RFC 2965 cookie规范中的实现。 在层1,jCookie作为一个库;在层0,它成为一个API的基础。 jCookie用法 Client类在两个层都调用cookie操作逻辑。它提供了应用程序开发者的库架构。要使用jCookie库,按照下面这些步骤: · 从响应到请求检索cookies: 创建一个URLConnection对象并初始化。 连接URLConnection。 创建一个Client对象并设定一个定制的CookieParser。 通过调用Client实例的getCookies()方法得到一个Cookies的CookieJar,作为在URLConnection中的一个参数。 与HTTP响应一起作一些事情。 · 和一个请求(假定一个CookieJar已被检索)一起发送cookies: 创建一个URLConnection对象并初始化。 创建一个Client对象并设定一个定制的CookieParser。 通过调用Client实例的setCookies()方法设置cookie报头,作为URLConnection and CookieJar 中的参数。 连接URLConnection。 与HTTP响应一起作一些事情。 下面的摘录显示了普通jCookie的用法。这个jCookie代码十分突出:

import com.sonalb.net.http.cookie.*; 
import java.net.*; 
import java.io.*; 
... 
public class Example 
{ 
... 
public void someMethod() 
{ 
... 
URL url = new URL("http://www.site.com/"); 
HttpURLConnection huc = (HttpURLConnection) url.openConnection(); 
//在这里初始化HttpURLConnection. 
... 
huc.connect(); 
InputStream is = huc.getInputStream(); 
Client client = new Client(); 
CookieJar cj = client.getCookies(huc); 
//进行一些处理 
... 
huc.disconnect(); 
// 执行另一请求 
url = new URL("http://www.site.com/"); 
huc = (HttpURLConnection) url.openConnection(); 
client.setCookies(huc, cj); 
huc.connect(); 
... 
// 进行一些处理 
} 
} 

上面的代码描述了jCookie API的两个方面: · 本地java.net对象的使用(HttpURLConnection)。 · 轻易地回收和发送cookies(单个方法调用)。 在实践中,上述代码已经能成功地维护两个请求间的会话。现在我们转换层的基本结构,让我们将jCookie与一些真实代码连接。 Hotmail新邮件检测器 为了阐明jCookie库的使用方便,我将在一个显示一个Hotmail账号新消息的发件人、主题及日期字段的应用程序中使用它。为了简单起见,应用程序在控制台显示这些信息。为了在Hotmail收件箱接收新消息,应用程序需要完成以下步骤: · 在登录表单中执行一个HTTP POST操作登录Hotmail。 · 为了到达主页,操作重定向及cookies。 · 检索收件箱的HTML页。 · 提取新消息的相关字段。 多数站点要求用户第一次通过一个表单执行一个HTTP POST 操作以完成登录过程。为了成功鉴定身份,POST的响应通常是一个带一些cookie报头的HTTP重定向。当重定向页被请求时cookies返回给服务器。 jCookie库包括一个很有用的类叫HTTPRedirectHandler,它管理当完成客户端cookie操作时操作重定向的普通任务。要使用这个类,首先要在一个未连接的HttpURLConnection中创建一个HTTPRedirectHandler实例,然后调用HTTPRedirectHandler实例的connect()方法去操作重定向及cookie。句柄从HTTP响应代码中确定是否运行成功。一旦进程完成,调用的类就检索表明最后一次请求的HttpURLConnection对象。CookieJar包含所有在能被检索的重定向过程中接收的cookies。Cookie操作逻辑存在于HTTPRedirectHandler的connect()方法中。让我们来看一看这个方法的代码。Cookie操作部份进行了注释:

package com.sonalb.net.http; 
import com.sonalb.net.http.cookie.*; 
import java.net.*; 
import java.io.*; 
public class HTTPRedirectHandler 
{ 
... 
public HTTPRedirectHandler(HttpURLConnection huc) 
{ 
... 
} 
public void connect() throws IOException 
{ 
if(bConnected) 
{ 
throw new IllegalStateException("No can do. Already connected."); 
} 
int code; 
URL url; 
huc.setFollowRedirects(false); 
// 设置在Cookies中的检验 
if(!cj.isEmpty()) 
{ 
client.setCookies(huc,cj); 
} 
is = huc.getInputStream(); 
// 从HttpURLConnection中提取Cookies并加到CookieJar中去 
cj.addAll(Client.getCookies(huc)); 
while((code = huc.getResponseCode()) != successCode && maxRedirects > 0) 
{ 
if(code != 302) 
{ 
throw new IOException("Can't deal with this code (" + code + ")."); 
} 
is.close(); 
is = null; 
url = new URL(huc.getHeaderField("location")); 
huc.disconnect(); 
huc = null; 
huc = (HttpURLConnection) url.openConnection(); 
//和HTTP请求一起发送Cookies 
Client.setCookies(huc, cj); 
huc.setFollowRedirects(false); 
huc.connect(); 
is = huc.getInputStream(); 
//从响应中提取Cookies并加进jar中去 
cj.addAll(Client.getCookies(huc)); 
maxRedirects--; 
} 
if(maxRedirects <= 0 && code != successCode) 
{ 
throw new IOException("Max redirects exhausted."); 
} 
bConnected = true; 
} 
//其他方法在这里出现 
public void handleCookies(boolean b) 
{ 
... 
} 
public void setSuccessCode(int i) 
{ 
... 
} 
public void setCookieJar(CookieJar cj) 
{ 
... 
} 
public void addCookies(CookieJar cj) 
{ 
... 
} 
public CookieJar getCookieJar() 
{ 
... 
} 
public HttpURLConnection getConnection() 
{ 
... 
} 
public void setMaxRedirects(int i) 
{ 
... 
}  
} 

HotmailChecker应用程序使用HTTPRedirectHandler进行登录操作。应用程序从使用带有并发请求的HTTPRedirectHandler中检索CookieJar。HotmailChecker的相关部份显示如下。Hotmail细节和jCookie关联注释被突出显示:

public boolean doLogin() throws Exception 
{ 
//对于HTTPS初始化JSSE 
System.getProperties().put("java.protocol.handler.pkgs","com.sun.net.ssl.internal.www.protocol"); 
java.security.Security.addProvider(new com.sun.net.ssl.internal.ssl.Provider()); 
//创建HttpURLConnection并初始化 
URL url = new URL("https://lc2.law13.hotmail.passport.com/cgi-bin/dologin"); 
HttpURLConnection huc = (HttpURLConnection) url.openConnection(); 
huc.setDoOutput(true); 
huc.setRequestMethod("POST"); 
huc.setRequestProperty("User-Agent","Mozilla/4.7 [en] (Win98; I)"); 
//发送登录表单字段 
StringBuffer sb = new StringBuffer(); 
sb.append("login="); sb.append(URLEncoder.encode(user)); 
... 
OutputStream os = huc.getOutputStream(); 
os.write(sb.toString().getBytes("US-ASCII")); 
os.close(); 
//创建句柄并进行处理 
HTTPRedirectHandler hrh = new HTTPRedirectHandler(huc); 
hrh.connect(); 
huc = hrh.getConnection(); 
//Microsoft有一个中间过渡页使用了一个刷新元标签以便于在HTTPS和HTTP间转换,这将防止安全 
//警告弹出 
//我们需要通过读取响应和解析URL手动取出URL 
BufferedReader br = new BufferedReader(new InputStreamReader(huc.getInputStream())); 
... 
//一旦我们有了主页的URL,我们就又使用HTTPRedirectHandler重定向并处理响应以校验正确的注 
//册 
url = new URL(homeUrl); 
huc = (HttpURLConnection) url.openConnection(); 
huc.setRequestProperty("User-Agent","Mozilla/4.7 [en] (Win98; I)"); 
hrh = new HTTPRedirectHandler(huc); 
hrh.setCookieJar(cj); 
hrh.connect(); 
... 
//保存Cookies用于以后的请求 
cj.addAll(hrh.getCookieJar()); 
... 
return(bLoggedIn); 
} 

现在我们已经登录到Hotmail,我们请求收件箱页,在登录过程中已检索的Cookies中通过。一旦我们拥有了收件箱页,我们必须因为与新消息有关的信息而解析这个HTML。代替使用暴力的StringTokenizer检索这个信息,我们将用一个稍微文雅(既复杂的)方法调控XML。这种方法包括: · 将成形不好的HTML转换为well-formed HTML。 · 用DOM(文档对象模型)通过well-formed HTML去得到新消息的信息。 假如DOM、XML和well-formed 对你来说一窍不通,只要说我们把收件箱HTML转换成一个树状结构的对象并得到想要的信息就足够了。 要将成形不好的HTML转换成well-formed HTML,我们用一个可自由下载的组件JTidy工具和一个通用的处理器。ConvertBadHTMLToGood帮助类将成形不好的Hotmail HTML转换成well-formed HTML。相关代码显示如下:

import java.io.*; 
import org.w3c.tidy.*; 
public class ConvertBadHTMLToGood 
{ 
... 
public ConvertBadHTMLToGood(Reader r) 
{ 
if(r == null) 
{ 
throw new IllegalArgumentException(); 
} 
inReader = r; 
} 
public Reader doConvert() throws IOException 
{ 
//初始化JTidy对象 
Tidy tidy = new Tidy(); 
tidy.setXmlOut(true); 
tidy.setErrout(new PrintWriter(new StringWriter())); 
//JTidy解析器要求一个InputStream,对于我的知识来说这里没有直接的办法将一个Reader转换 
//成一个InputStream。这个工作区代码没有字符编码安全,但还可以混过。 
BufferedReader br = new BufferedReader(inReader); 
StringBuffer sb = new StringBuffer(); 
String line; 
while((line = br.readLine()) != null) 
{ 
sb.append(line); 
sb.append("\n"); 
} 
ByteArrayInputStream bais = new ByteArrayInputStream(sb.toString().getBytes("US-ASCII")); 
ByteArrayOutputStream baos = new ByteArrayOutputStream(); 
//作一个将HTML转换well-formed HTML 的预备。 
tidy.parse(bais, baos); 
//整理一些遗漏的JTidy得到能被“true-blue”XML解析器解析的输出。 
FixEntities fe = new FixEntities(baos.toString()); 
return(fe.getFixedReader()); 
} 

一旦我们拥有了well-formed HTML,我们就用XML解析的Java API(JAXP)去转换well-formed HTML 成一个DOM树并通过树得到新消息的表单、主题及日期字段。我将忽略一些代码而向你展示如何使用HotmailChecker:

import com.sonalb.net.http.cookie.*; 
... 
public class HotmailChecker 
{ 
public static void main(String args[]) throws Exception 
{ 
if(args.length != 2) 
{ 
usage(); 
System.exit(0); 
} 
String uname = args[0]; 
String pass = args[1]; 
HotmailChecker hmc = new HotmailChecker(uname,pass); 
if(!hmc.doLogin()) 
{ 
System.out.println("Could not login to Hotmail."); 
System.exit(0); 
} 
Vector newMessages = hmc.getNewMessages(); 
if(newMessages == null) 
{ 
System.out.println("No NEW Messages."); 
return; 
} 
System.out.println("You have " + newMessages.size() + " NEW Messages"); 
System.out.println("---------------------------------------------"); 
Iterator iter = newMessages.iterator(); 
//HMMessage封装了一个Hotmail消息 
HMMessage hm; 
while(iter.hasNext()) 
{ 
hm = (HMMessage) iter.next(); 
System.out.println(" From: " + hm.getFrom()); 
System.out.println(" Subject: " + hm.getSubject()); 
System.out.println("Sent Date: " + hm.getSentDate()); 
System.out.println("---------------------------------------------"); 
} 
} 
static void usage() 
{ 
System.out.println("\nUsage: java HotmailChecker  "); 
} 
//实例变量和方法从这里开始 
... 
public HotmailChecker(String username, String password) 
{ 
... 
} 
public boolean doLogin() throws Exception 
{ 
... 
} 
public Vector getNewMessages() throws Exception 
{ 
... 
} 
... 
} 

你可以从Resources下载完全功能的HotmailChecker及相关类。 Java中的cookie管理方案(1)-与J2ME结合 Java中的cookie管理方案(2)-与J2ME结合 Java中的cookie管理方案(3)-与J2ME结合 Java中的cookie管理方案(4)-与J2ME结合 <淘宝热门商品:
 

3.20 元  

Lily's 园艺-万元赠品大派送!种球“买就送”!朱顶红已到货!

Lily's-现货!PT-01葡萄风信子album-荷兰进口种球/球根-皇冠

 

228.00 元 

【专柜正品 超值之选】 JACK JONES/杰


来源:程序员网

小小豆叮

用JavaCard实现特定需求

JavaCard是能够运行Java程序的IC卡。与传统的IC卡相比,JavaCard有高度安全、对多应用的良好支持以及极大的可扩充性等特点,因此在美国IC卡多应用市场,JavaCard已经成为领导的标准,约占了市场的96% 一、满足客户特定需求 在开发项目时,曾遇到过一个特定需求,客户要求建立如下二级系统: 一级机构将充值母卡下发给二级机构,二级机构使用充值母卡对用户卡进行充值。问题在于:一级机构如何控制二级机构对用户卡充值的总次数和金额? 客户要求在卡片COS级实现这一功能,因为一级无法有效地固定二级对卡片进行外部程序开发,所以如果这一功能在卡片外部实现,难以真正有效地达到控制目的。已有的母卡不能满足这种功能需求,但可采用JavaCard。JavaCard的特性使之在发行后可以支持额外的附加服务与应用程序,开发方可将自己设计的Applet注入JavaCard之内,使其成为卡片COS的一部分。通过这样的定制扩充,我们做了以下设计: 1.在充值母卡中建立一个专门的文件,用于记录给用户卡充值的总次数和金额。 2.给充值母卡设计一条专用指令,用于对用户卡的圈存充值。接收到此指令时,除完成对用户卡圈存功能外,还相应减去文件中记录的次数和金额。 3.当文件中记录次数和金额减少到限定值后,母卡不能继续对用户卡充值,必须到一级机构通过配额母卡对其进行配额(重新设定充值母卡文件中的记录次数和金额)后,才能再次投入使用。 除了完成这一特定的功能外,这张JavaCard充值母卡也具备一般母卡的功能,可以完成母卡所需的其他操作。实际上JavaCard既可以作为母卡,也可以作为PSAM卡或用户卡,只要开发方对其做相应的定制即可。 二.JavaCard的应用前景 目前JavaCard在欧美市场上被广泛应用,在国内由于其成本偏高,还没有形成规模,但发展和推广JavaCard是趋势。一方面国内市场的消费水平在提高,另一方面在形成规模后成本会降低,更重要的是JavaCard可以使许多以前由于卡片COS限制无法实现的想法得以实现。即便由于成本因素使用JavaCard作为用户卡还有难度,但用它代替同样高成本的母卡和PSAM卡是可行的。 <淘宝热门商品:
 

 

[玉缘阁精品和田玉]和田美玉 送物传情 13779692122翡翠

 

52.00 元  

【卡盟在线】

皇冠在线充|QQ黑钻腾讯黑钻地下城与勇士(DNF)黑钻3月


来源:程序员网

小小豆叮

手机上做动画!日本公司免费发布Java工具

据日经BP社报道,一家日本公司,Plazmic公司于2002年6月13日开始免费发布该公司开发的手机内容制作工具。其中包括3种工具:可轻松制作动画等内容的多媒体创作工具环境“Beatware e-Picture Plazmic Edition”和“Plazmic Workshop Start”、可在手机上运行的内容执行引擎“Plazmic Media Engine”。 该3种工具均可登录该公司的Web站点免费下载。上述工具支持的手机为NTT DoCoMo的503i系列以后的产品,运行的OS为Windows 2000/XP。 该公司网站的网址为:http://www.plazmic.com/ 该工具的特点为使用遵照XML的2维向量型图像描述语言“SVG(Scalable Vector Graphics)”。由Beatware e-Picture Plazmic Edition和Plazmic Workshop Start制作的内容能够以SVG文件的格式输出。 Plazmic Media Engine具有播放SVG文件及声音的功能,是一种可以下载到手机上使用的Java软件。用户可以使用该工具制作动画等内容,使用个人电脑的手机模拟器确认运行状况,进行内容发行等。 <淘宝热门商品:
 

 

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

 

86.00 元  

艾尔微品牌店//九阳豆浆机//女士精品-三钻100%真人拍摄

Disney Mickey 迪斯尼米奇多色手动机芯机械中性手表


来源:程序员网

小小豆叮

Java中的cookie管理方案(1)-与J2ME结合

摘要 客户端HTTP状态管理对于创建需要与象基于网络浏览器的email或在线银行服务网络程序交互作用的Java应用程序是十分重要的。本文介绍了在Java中一个强大易用的客户端HTTP状态管理cookie库,这个库在固有的java.net工具箱中很少见。其中存在几种客户端HTTP状态管理APIs,它们提供了难于学习并没必要重新开发设计的函数方法。这篇文章中Cookie管理库尽量使用核心Java API类。 当在开发一个针对所有主要的internet邮件服务器(基于Web或其他类型)提供单点访问的通用邮件客户端时,我发现我的应用程序经常不得不作为一个小的网络浏览器与提供邮件服务的网站交互。 当开发XML网络服务以便于机器更容易访问网站时我总在需要网站交互时遇到困难。这些网站经常使用cookies进行状态管理及维护用户会话数据,在这两种情况,我意识到多数网站交互都涉及cookie操作。我也注意到虽然两种情况下的应用程序都执行cookie操作,但其逻辑处理较困难及不具有互换性。针对此限制,我从开发一个小型普通用途库出发致力于cookie操作。在这篇文章中我将与你分享这个库。 为了在运行中图解说明库,我建议使用基于Hotmail邮件检测器的控制台。此外,我从在J2ME平台上使用MIDP的移动设备观点探究了客户端状态管理。 Cookie基础 让我们从回答一些问题开始: 什么是状态管理,为什么我们需要它? 什么是cookies,它们怎样适应图片? 要回答第一个问题,我们必须更精密地检测一下HTTP。HTTP是无国界协议,因为从网络服务器观点看所有HTTP请求都独立于先前请求。就是说每一个HTTP响应完全依赖于相应请求中包含的信息。当这种行为使网络服务执行更简单有效时,用它作为复杂网络应用的基础将更为合适。 状态管理机制克服了HTTP的一些限制并允许网络客户端及服务器端维护请求间的关系。在这种关系维持的期间叫做会话(session)。多数要求你登录的网络应用程序使用了会话及状态管理。购物推车应用程序使用状态管理控制所有标记为已购买项目的列表。状态管理能够使个别用户参数的入口及搜索引擎个性化定制。网络应用程序甚至能使用状态管理根据用户爱好兴趣定制网站内容。 Cookies影响着状态管理。Cookies是服务器在本地机器上存储的小段文本并随每一个请求发送至同一个服务器。 IETF RFC 2965 HTTP State Management Mechanism 是通用cookie规范。网络服务器用HTTP头向客户端发送cookies,在客户终端,浏览器解析这些cookies并将它们保存为一个本地文件,它会自动将到同一服务器的任何请求缚上这些cookies。在这篇文章后面,我同义性地使用了cookie操作和状态管理术语。 如果你要找出你访问的哪个网站使用了cookies,可以试试这个简单的试验: 注意: 只有当你觉得改变你的浏览器设置没什么问题并知道方法时才执行这个练习。 ● 打开你常用的浏览器,我假设你使用的是Internet Explorer (IE) 5+或Netscape Navigator 4+。 ● 使自动cookie操作无效: 在IE浏览器的“工具”菜单中选择“Internet选项”,再选择“安全”标签,单击“自定义级别”然后向下拉动滚条直到你看见“允许使用存储在你计算机上的cookies”并选中“提示”选项,同时也选中“允许使用每个对话cookies(未存储)”的“提示”选项,单击“确定”按钮回到主窗口。 在Netscape Navigator的“编辑”菜单中选择“参数选择”中的“高级”,选中“接收cookie时警告”,单击“确定”按钮回到主窗口。 ● 现在浏览你“收藏”中的站点,特别是当你检查你的网络邮件或进入在线电子商店时,要求你允许接收cookies的对话框会不断地向你轰来。 将上面的步骤恢复到你以前的初始设置,你也能看见哪些cookies被保存到了你的本地机器上(在警告应用之前): ● 对于IE:使用“Windows资源管理器”或“我的电脑”浏览C:\Windows\Cookies文件夹,在这个文件夹中的所有文本文件都包含cookies。 ● 对于Netscape Navigator: 在Windows系统中,使用“Windows资源管理器”或“我的电脑”浏览C:\Program Files\Netscape\Users文件夹,找到一个名叫“cookies.txt”的文件或“cookies”子目录。 在Unix类似系统中,在“.netscape”目录中找到一个名叫“cookies”的文件。 注意: 根据你安装的系统不同,使自动cookie操作无效及查看保存的cookies的步骤也可能不同。 现在你已经知道了一些基本知识,接下来我将阐述怎样将这些与Java联系起来。 Java中的cookie管理方案(1)-与J2ME结合 Java中的cookie管理方案(2)-与J2ME结合 Java中的cookie管理方案(3)-与J2ME结合 Java中的cookie管理方案(4)-与J2ME结合 <淘宝热门商品:
 

3.80 元  

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

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

 

225.00 元  

上海商盟】易淘视听商城

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


来源:程序员网

小小豆叮

Java中的cookie管理方案(2)-与J2ME结合

在Java中的状态管理 Java应用程序在以下几种情况要求cookie操作: ● 网站交互:为了与网站交互,基于Internet的客户端应用程序经常扮演小型网络浏览器的角色。这些站点使用cookies进行状态管理以维护用户的会话数据。 ● 网络服务实现:网络服务承诺使网络成为电脑机器的友好地方。一个都希望的允许机器-网站进行交互的方法就是在网站前面有一个网络服务。因此,网络服务将目标网站的视窗十分友好地呈现在机器面前。这种网络服务的实现将需要cookie操作以达到真正的网站交互。 ● 网络浏览:基于网络浏览的Java将需要cookie操作模块以支持状态管理。 为了执行客户端cookie操作,先看下面几个步骤: ● 检索cookies: 1. 从收到的HTTP头提取cookies。 2. 分别解析cookies的组成部分(名称,值,路径等等)。 3. 判定主机是否允许设置这些cookies。 ● 发送cookies: 1. 判定哪些cookies能被发送给主机。 2. 对于多个cookies,判定必须发送的cookies的顺序。 3. 与外发的HTTP头一起格式并发送cookies。 一个客户端Java应用程序须遵循上面的所有步骤,但是用RFC2965列出的规范执行上述步骤将消耗大量的时间并分散开发者在核心程序上的注意力。结果,开发者经常选择向规范妥协而用很容易就被破坏的随意编写的cookie操作代码结束。 例如,假设你想要写一个与网络商店应用程序的servlet交互的Java客户应用程序,在服务器端,当servlet第一次通过调用request.getSession()为一个会话询问servlet容器时,容器创建一个新的会话并且服务器用一个会话ID在并发请求时检索会话对象,服务器自动将这个会话ID作为一个HTTP cookie发送到客户端。在并发请求时,客户端与请求一起回送同一个会话ID。服务器用ID区别正确的会话对象以便servlet处理请求。典型的客户端代码如下:

/* 取得cookie.*/ 
... 
HttpURLConnection huc= (HttpURLConnection) url.openConnection(); 
... 
InputStream is = huc.getInputStream(); 
// 从响应中检索会话ID. 
String cookieVal = hc.getHeaderField("Set-Cookie"); 
String sessionId; 
if(cookieVal != null) 
{ 
sessionId = cookieVal.substring(0, cookieVal.indexOf(";")); 
} 
... 
/* 发送cookie. */ 
HttpURLConnection huc= (HttpURLConnection) url.openConnection(); 
if(sessionId != null) 
{ 
huc.setRequestProperty("Cookie", sessionId); 
} 
InputStream is = huc.getInputStream(); 
... 

cookie规范RFC2965为cookies版本1定义了一个新报头,Set-Cookie2。假如我们用新报头升级服务器,上面的代码将不能履行。上述代码也不能处理多重cookies。另外,版本1的cookie值可以是一个加引号的字符串,假如会话cookie的值是一个包含分号的加引号字符串,这也将引起上述代码不能履行。简而言之,上面的代码片断不是与cookie的版本使用孤立开来的。 上述代码对于只和一个特别的主机及路径影射交互的简单程序是适合的,但对于一个更庞大的应用程序,当涉及多重主机及路径时cookie管理将变得更复杂。开发者实现cookie规范中的所有算法、安全检查及平衡将证明是痛苦和徒然的。 进入jCookie 为了减轻这种情形,我开发了一个普通用途cookie库,命名为jCookie,用来实现cookie规范。这个库使客户端cookie操作所必需的额外代码和努力最小化并让开发者的精力集中在核心应用程序上。其他APIs库也有(例如,Apache的HTTPClient),但是他们使用了从内建本地的java.net APIs移出的结构,因此需要一个新的学习过程。我的API是一个调用已存在的java.net对象的简单方法。 你也能使用现在发展的jCookie延伸版本,叫jCookieMicro,在J2ME移动设备上创建一套令人激动的能与网络服务应用程序交互的客户系统。 现在我介绍jCookie API的主要行为,先从两个主要数据结构开始: 1. Cookie类:此类的一个实例表明一个独立的cookie。它封装了RFC 2965定义的所有cookie属性并提供用getters和setters访问这些属性。 2. CookieJar类:此类的一个实例被作为一个Cookie对象集的容器。它符合集合结构并提供操作cookie集合的方法。 API提供两个视野以同时满足开发者对于cookie透明操作的要求及开发者对于高级特性的要求。下面的图形说明了这些视野或层。 jCookie库的分层视图<淘宝热门商品:
 

68.00 元 

超人气神奇魔水 柔嫩细滑肌肤一喷即成

 

99.00 元  

DOROTHY去印平坑明星!第二代积雪草细胞再生霜-填平坑


来源:程序员网

小小豆叮

JSP Standard Tag Libraries 实践理解

在本篇文章中,我们将会深入了解在不同的Tag Library描述符(Tag Library Descriptors:TLDs)中使用各种不同的tag的情况.我们将会依次研究 条件、循环、URL、U18N、XML等tag的用法。以此来提高你对JSTL的认识和应用能力,在阅读本文前,你应该对 JSP Tag Lib有所了解,并清楚有关JSTL(JSP Standard Tag Libraries)的基本知识 ,可参看 《JSP Standard Tag Library (JSTL)介绍》一文 JSP Standard Tag Libraries 实践理解 在本篇文章中,我们将会深入了解在不同的Tag Library描述符(Tag Library Descriptors:TLDs)中使用各种不同的tag的情况.我们将会依次研究 条件、循环、URL、U18N、XML等tag的用法。以此来提高你对JSTL的认识和应用能力,在阅读本文前,你应该对 JSP Tag Lib有所了解,并清楚有关JSTL(JSP Standard Tag Libraries)的基本知识 ,可参看 《JSP Standard Tag Library (JSTL)介绍》一文 JSTL是一组标准的已定制好的操作,它们应用于各种功能领域。在JSR-52(Java Specification Request)中的定义中,JSTL包含了 expression language(EL)、流程控制 和Tag Library较验器。有关最终版本,你可以产看 http://www.jcp.org/jsr/detail/52.jsp 上的最终草案 JSTL需要运行在JSP 1.2的容器下,它是用来简化JSP的开发,提供更加的方式处理和访问应用数据. JSTL包含了多中Tag Library的描述定义(TLDs),这些描述位于一个JAR文件中.这些TLDs涵盖了大多数的功能操作,下面我们会逐一列举,不过在此之前,我们会重点讨论expression language,它可能算是JSTL中最重要的特征了. expression language (EL)其实是由制定JSR-152(Java Server Pages 1.3 Specification)的专家组制定的,事实上很可能EL就将会是JSP 1.3的重要组成部分.EL(目前还是叫SPEL:Simplest Possible Expression Language )提供了一些简单的语法来直接访问应用数据,支持操作符、Bean、集合,还有类型自动转换、属性的默认值定义等等。 EL的用法: EL总处在在${...}中(就象JSP 在<%...%>中那样)。在属性中只允许出现一个表达式,例如: <c:if test="${product.price >= customer.limit}"> ... </c:if> 在上面的例子中,我们使用EL进行比较操作,它还可以和静态文本混合使用,可以看看下面这个例子: <c:forEach var="current"> <c:out value="Product-${current}"/> </c:forEach> 在这个例子中我们循环遍历一个集合,把current值按一定的文本形式显示出来,结果如下: Product-1 Product-2 Product-3... 从这个例子你也能看出,使用EL比以前的编码简单了很多。在出现JSTL之前,你需要通过先定义对象、了解对象类型、使用相应的脚本来完成一个很简单的操作。 现在有了JSTL,可以使用更加简单的语法进行操作,你看这个例子: <jsp:useBean id="customer" type="sample.Customer" scope="request"/> ... Customer Name: <%=customer.getName()%> ... <% if (customer.getState().equals("CO")){ %> ... <%}%> 现在可以使用EL写成: Customer Name: ${ customer. name} <c:if test="${customer. state == param. state}"> ... </c:if> EL支持直接访问所有的JSP数据域(JSP scopes)的变量,比如我们使用${foo}来代替pageContext.findAttributes("foo")的写法,EL是使用"."号来使用bean的属性,比如: ${user.address.city} ${products.[product.id]} ${products.["Part-010"]} EL包含了多种操作符:==, !=, <,>, <=, and >=, &&, ||, ! .为了避免和XML冲突,还有一些如lt, gt, le, ge, eq, 和 ne的操作符,以及+、-、/、*、%等算数运算符,还有Boolean运算符and, or, not, 和 empty.EL的另一个特征就是自动类型转换,比如:int value = "${request.myValue}",不会报错,EL会把string 转化成int 另外EL还为变量提供默认的值.这样会避免出现"对空数据操作"的异常.如下的例子显示了如何给变量设置默认值 <c:set var="city" value="${user.address.city}" default="N/A" /> 现在我们来了解一下EL所支持的操作: 核心操作 EL处在核心tag库中,使用<c:out>tag来表示把EL表达式输出到当前的JspWriter中,它很像JSP的<%= scripting exp %> 表达式。比如下面这个例子: <c:out value="${customer.name}" default="N/A" /> EL还可以设置和删除某个值域中的变量,默认的值域是Page值域(JSP所支持的值域包括application \session\page 等值域),例如我们使用<c:set var="customer" value=${customer}" />来设置一个Page值域的变量,然后可以使用<c:remove var="customer" />来删除它 我们还可以使用JSTL的tag来catch ava.lang.Throwable,比如:<c:catch var="myError" />,该tag用于统一page中的异常处理。它并意味着完全代替了JSP的出错机制,只是使用这样的tag可以更富条例的控制异常;不需要把作有的错误都导入出错页面,有些错误不需要这样处理,使用<c:catch> tag可以设计更友好的用户交互 条件操作 相比JSP代码,EL在条件控制上也很强大,使用<c:if>tag就可以构造一个条件表达式,看这个例子: <c:if test="${user.visitCount == 1}"> Welcome back! </c:if> 你可以看到这是一个 if 语句,当然还有其他的条件控制符,<c:choose>, <c:when>,和 <c:otherwise>tag也可以表达出 "if/then/else"的功能 让我们来看这样一个例子,如果我们需要处理一些结果,可以使用这些tag来为相应的情况显示相应消息: <c:choose> <c:when test="${count == 0}"> No records matched your selection. </c:when> <c:otherwise> <c:out value="${count}"/> records matched your selection. </c:otherwise> </c:choose> 循环操作 JSTL中最有用的特性就是循环操作了,JSTL中支持循环操作的tag是 <c:forEach>, <c:forToken>, 和 <x:forEach>,还有一些模仿了核心tag用于XML操作的tags,我们稍后介绍,先来看看这些核心tag中的循环操作. 这些操作支持所有的标准的J2SE的集合类型,包括 List, LinkedList, ArrayList, Vector, Stack, 和 Set。还包括java.util.Map类的对象比如HashMap, Hashtable, Properties, Provider, 和 Attributes。当然还可以循环遍历对象或基本类型的数组。当使用基本类型时注意,在数组中的项目是它们相应的包装类,比如一个int数组中的元素是Integer,每次循环输入两个对象:当前的元素和循环状态,让我们来看看下面这个例子: <table> <c:forEach var="product" items="${products}" varStatus="status"> <tr> <td><c:out value="${status.count}"/></td> <td><c:out value="${product.name}"/></td> </tr> </c:forEach> </table> 从这个例子我们可以看出,EL把products变量作为集合,每一次输出的当前项设为product,当前状态设为status。 URL操作 除了循环操作,核心tag中还包括URL相关的操作。它提供了诸如hyperlinks, resource import, 和 redirect 的功能。使用<c:url>tag可以方便的处理URL的rewriting 和 encoding,让我们来看看下面这个例子: <c:url=http://mysite.com/register var="myUrl"> <c:param name="name" value="${param.name}"/> </c:url> < a href='<c:out value="${myUrl}"/>'>Register< /a> 在JSTL中resource imports也是一项强大的功能,可以方便的指定绝对或相对的路径的外部资源以及FTP资源,我们来看一些例子: Absolute URL: <c:import url="http://sample.com/Welcome.html"/> Relative URL (to the current context): <c:import url="/copyright.html"/> Relative URL with a foreign context: <c:import url="/myLogo.html" context="/common"/> FTP resource: <c:import url="ftp://ftp.sample.com/myFile"/> 从这些例子我们可以看出,<c:import>提供了比<jsp:include>更多的功能,它另外一个优点是可以避免资源内容被多次读入,比如,当你在格式转换(transformation,比如XML通过XSL转换)中使用<jsp:include>来import资源,在include时读入一次,然后所有内容被写入JspWriter,在格式转换中还要被读入一次,使用<c:import>,内容只被读入一次,不写入JspWriter,然后再交由格式转换tag处理 我们还可以把导入的资源作为一个String或Reader对象来使用,使用varReader或var属性来定义对象名。这个对象是可重用的,并自己有自己的缓冲(cache).使用Reader的可以直接读取数据而没任何暂存(buffering),使用声明过的Reader,必须把它嵌入在 <c:import> 和 </c:import>中使用,比如像下面这个例子 <c:import url=http://sample.com/customers varReader="customers"> <mytag:process in="${customers}"/> </c:import> 国际化问题 JSTL中的另一个重要功能是它的国际化格式支持(I18N)。该功能可以对一个特定的语言请求作出相应的响应。它使用了J2SE 的ResourceBundle来保持各种翻译过的语言编码,JSTL会根据不同的地区选择适合的ResourceBundle。<fmt:setLocale>用来设置地区,比如<fmt:setLocale value="es_Es"/>,这等与设定了语言和国家代码。当然还可以指定ResourceBundle,比如:<fmt:bundle basename="ApplicationResource_fr"/> 一旦设定了locale(地区)或ResourceBundle,就可以使用<fmt:message>来把原文进行相应的转化,同时还可以进行参数替换,比如: <fmt:message key="welcome"> <fmt:param value="${visitCount}" /> <fmt:message/> You can also use < fmt:requestEncoding/> to set the request's character encoding. 你还可以使用< fmt:requestEncoding/>来设定请求的字符编码 能正确显示字符,还只是国际化问题的一半.还必须解决数字和时间的格式解析。不同的地区有不同的显示方法。使用<fmt:formatNumber> 或<fmt:parseNumber> 可以按当地的格式显示数字、货币金额、百分比。同时还可以制定模式(pattern)参数,比如<fmt:formatNumber value="12.3" pattern=".00"/>会输出"12.30." 时间和日期使用<fmt:formatDate>, <fmt:timeZone>, <fmt:setTimeZone>, 和 <fmt:parseDate>来处理 SQL操作 SQL操作支持直接访问数据源。在MVC模式中这种做法是会受到警告的,我个人也反对在产品中使用这样的tag,不过对一些快速、小型、简单的开发,他还是会有一些作用,不过不要把它应用到大型应用系统中去。我们来看看SQL操作提供了一些什么功能 可以使用这些tag来设定数据源、查询数据库、很容易的访问查询结果并可以事务性的更新数据。看下面这个例子如何设定数据源: <sql:setDataSource var="datasource" driver="org.gjt.mm.mysql.driver" url="jdbc:mysql://localhost/db" /> <sql:setDataSource>仅仅是封装了JDBC DriverManager的功能。datasource的属性可以是String或JNDI的相对路径或JDBC 参数串.然后在查询中我们可以这样使用datasource:<sql:query datasource="${datasource}" ... /> 我们来看一个综合使用的例子: <sql:query var="customer" datasource="${datasource}" SELECT * FROM customers WHERE state = 'CO' ORDER BY city </sql:query> <table> <c:forEach var="row" items="${customers.row}"> <tr> <td><c:out value="${row.custName}" /></td> <td><c:out value="${row.address}" /></td> </tr> </c:forEach> </table> 使用事务性的更新现在很简单了,比如我们现在定义一个事务,你可以把所有需要的更新操作包括在内: <sql:transaction dataSource="${dataSource}"> <sql:update> UPDATE account SET Balance =Balance -? WHERE accountNo = ? <sql:param value="${transferAmount}"/> <sql:param value="${accountFrom}"/> </sql:update> </sql:transaction> <sql:dateParam> tag 可以设定在 SQL语句中java.util.Date类型的 "?"( parameter markers).在这个例子中没有展示事务级的设定,事务级在java.sql.Connection中设定,如果没有设定事务级,然后在tag中使用它,就会抛出JspTagException. XML操作 最后我们来看看XML操作,XML操作集是在核心、流程控制、转向操作外的一个操作集,它是建立在Xpath上的。使用Xpath表达式。 XML 的核心操作很像JSTL中核心操作,包括<x:out>, <x:set>, 和<x:parse>,不同是这些操作tag支持的是XPath表达式的。<x:parse>用来把XML文档解析成数据,数据由XPath引擎处理,如果我们有一个描述一本书的XML文件,我们可以解析它,并使用XPath表达式显示它 <c:import url="http://oreilly.com/book?id=1234" var="xml"/> <x:parse source="${xml}" var="bookInfo"/> <x:out select="$bookInfo/title"/> <x:out select="$bookInfo/author"/> XML的流程控制也类似于核心集,包括了:if, choose, when, otherwise, 和 forEach tag,不同的是他们使用XPath表达式.结果对象会按XPath的语义定义转化成相应的boolean值,这些语义规定是: 当且仅当一个数是非零正数或非NaN(无穷大)时为true 当且仅当一个节点不为空时,值为true 当且仅当一个字串的长度不为零时该子串为true XML的转换操作是把XML文档用XSL样式文件显示,但不能获得这些结果,把它们存储在某个变量或值域的属性中,这样的操作只是引入XML和 XSL 文件并完成转换 <c:import url="/books" var="xml"/> <c:import url="/WEB-INF/xslt/bookDisplay.xsl" var="xslt"/> <x:transform source="${xml}" xslt="${xslt}"/> 如果要设定一些转换的参数,可以使用<x:param>来指明参数名和值 总结 看过本篇文章后,你可能了解了在JSTL中的一些有用的tag,它可以使你的JSP文件变的简单易用。请关注JSTL的发展,当它的最终草案完成后,我们就可以看到各个厂商针对JSTL对他们的JSP container的调整,如果你现在就想要实践一下,可以下载JSTL目前最新的版本:jakarta 's JSTL. About author Sue Spielman is an associate editor for ONJava.com, covering JSP and Servlets technologies. She is also president - and is one of the many Java expert engineers - for Switchback Software LLC. Switchback Software specializes in consulting on and building Java enterprise business, web, and wireless applications for companies large and small. 英文原文:JSP Standard Tag Libraries, Part 2 <淘宝热门商品:
 

 

新势力品牌旗舰店/LED手表 手机话筒 负离子表 钛项圈大量批发!

大量批发

 

 

泰国佛牌精品店


来源:程序员网

小小豆叮

在无线J2ME设备上实现超文本传输协议

随着越来越多手提电话和个人数字助理开始融入到信息高速公路之上,从移动设备上访问Web站点变得越来越重要。Java开创了消费设备中小型的储存容量的先河,它是用于开发手机、传呼机及其他微型设备应用程序的理想语言。   在本文中,我们将学习如何从一个J2ME客户机上向服务器发送一条HTTP GET请求和一条HTTP POST请求。虽然这只是一篇探讨性质的文章,但是我还是假定读者已经熟悉Java,J2ME,以及Java Midlets(MIDP应用程序)的运作机制。我们将使用J2ME的MIDP简表,并利用SUN的J2ME的无线应用程序开发工具包编译、配置和测试我们的应用程序。对于HTTP服务器,任何WWW地址都可以被访问,但是默认时我们将使用一个简单的Java Servlet来返回我们的HTTP请求的细节。   如何使用J2ME客户机向Web服务器和类似的支持HTTP的服务器发送HTTP请求呢?答案就是使用可在javax.microedition.io程序包中可找到的J2ME的网络类。本文就想具体阐述这个问题。   本文概述∶   使用J2ME设计无线网络应用程序   .发送一条超文本GET请求   .发送一条超文本POST请求   .使用J2ME进行无线网络编程   Java的网络编程能力是相当健壮的。Java 2标准版( J2SE)在java.io和java.net程序包中定义了100多个接口程序,类和异常。通过这些库实现的功能是很强大的,但是这只适用于传统的计算机系统,这些计算机系统有强大的CPU处理能力,快速的内存和持久的数据储存,但是这些在大多数的无线设备上是不现实的。因此,J2ME定义了这些函数的子集,并提供了一套用于网络和文件访问的固定的程序包--- javax.microedition.io程序包。由于可移动设备种类繁多,这个程序包仅仅定义了一套接口,而为每个可移动设备供应厂商留下了实际的应用程序接口实现。这就在可移植性和设备特定特征的应用中找到了一个最佳的平衡点。   定义在javax.microedition.io类中的抽象网络和文件输入输出框架称为通用连接框架(Generic Connection Framework,简称GCF)。GCF定义了一套有关抽象化的内容来描述不同的通信方法。最高级的抽象被称作连接(Connection),还声明了六个接口(四个是直接的,两个是间接的)。这七个接口就构成了J2ME的CLDC的一部分,CLDC是大多数的能使用Java的无线设备使用的配置。设计这个配置的目的就是为所有的CLDC设备(手提电话,双向传呼机,低档的PDA等等)提供公用的网络和文件输入输出能力。虽然GCF的目的是公用网络和文件输入输出框架,但是生产商并不要求实现GCF中声明的所有的接口。有的厂家可以决定只支持socket连接,而其它的厂家可以选择只支持基于数据报的通信。为了促进跨越类似装置的可移植性,MIDP规范要求所有的MIDP设备实现HttpConnection接口。HttpConnection不是GCF的一部分,但是它是从GCF的一个接口ContentConnection衍生出来的。我们将使用HttpConnection接口构造我们样本应用程序。   

发送一个HTTP GET请求

  这一节将重点解释程序代码,在下一节中我们将只讲述被用来发送HTTP请求并检索由服务器返回的响应通用连接框架接口和HttpConnection接口。创建MIDP用户界面的程序代码见附录。   我们先要定义一个方法来放用于发送HTTP GET请求的代码。因为这个方法中的有些操作有潜在的抛出IOException的可能,所以我们将把这样的意外(exception)抛给调用方法。 public String sendHttpGet( String url ) throws IOException { HttpConnection hcon = null; DataInputStream dis = null; StringBuffer message = ""; try {   第一步是使用Connector类打开一个到服务器的连接,这是GCF的关键。我们将把这个连接强制转换为需要的类型,在本例中为HttpConnection类型。 hcon = ( HttpConnection ) Connector.open( url );   接下来,我们得到HttpConnection上的一个DataInputStream,允许我们一个字符一个字符的读取服务器的响应数据。 dis = new DataInputStream( hcon.openInputStream() );   使用DataInputStream的read ()方法,服务器响应的每个字符都被集中起来放入StringBuffer对象。 int ch; while ( ( ch = dis.read() ) != -1 ) { message = message.append( ( char ) ch ); }   最后,连接对象被净空以保存资源,而信息从这个方法中返回。 } finally { if ( hcon != null ) hcon.close(); if ( dis != null ) dis.close(); }//结束try/finally代码段 return message.toString(); }//结束 sendGetRequest( String )   

如何发送一个HTTP POST请求

  你可以想象,发送一个HTTP POST请求的处理过程其实与发送一个GET请求非常地类似。我们将修改一个现有命令,添加少量的新的命令,并添加一个来自通用连接框架的附加的对象和一个附加的StringBuffer对象把POST请求体重的内容发送到服务器中。剩下的命令将保持不变。   复制我们刚才创建的sendHttpGet()方法,把它粘贴进同一个类文件,改名为sendHttpPost()。 现在,我们将修改这个新方法来发送一个HTTP POST请求到服务器。 在方法的顶部添加两个新的变量说明。 声明一个类型为DataOutputStream的变量和另一个String类型的变量。 我们将使用DataOutputStream对象把存在于字符串变量中的POST请求体发送到服务器中。 DataOutputStream dos = null; String requestBody = null;   修改connector.open()命令包含另一个参数,指出连接将允许客户端可以通过连接在服务器上读和写。 hcon = ( HttpConnection ) Connector.open( url, Connector.READ_WRITE );   设置HttpConnection对象使用的请求方法为POST(默认的方法是GET)。 hcon.setRequestMethod( HttpConnection.POST );   得到一个用于现有的HTTP连接的DataOutputStream对象。 dos = hc.openDataOutputStream();   声明一个字节数组并通过检索一个来自requestBody字符串的字节数组初始化。 然后把DataOutputStream的缓冲写入字节数组内。 byte[] byteRequest = requestBody.getBytes(); for( int i = 0; i < byteRequest.length; i++ ) { dos.writeByte(byteRequest[i]); }//结束for( int i = 0; i < byteRequest.length; i++ ) dos.flush(); //包含本句,在某些设被上将可能会产生不可预期的结果   调用flush ()方法的意图是发送已经写入的数据到DataOutputStream的服务器的缓冲区中。 在某些电话上,这个操作工作正常,在其他的电话上,它导致HTTP请求的Transfer - Encoding被设置为" chunked ",有一些随机字符被放到请求本身的前面和后面。那又怎样处理这个问题呢?这个方法调用实际上是根本不需要的。在接下来的一行中,服务器连接打开(通过openInputStream ()),将自动输入缓冲区。因此,你最好不要调用缓冲区的flush()方法。这个方法其余的部分保持不变,除了DataOutputStream对象必须在finally{}语句块中关闭。 } finally { if ( hc != null ) hc.close(); if ( dis != null ) dis.close(); if ( dos != null ) dis.close(); }//结束 try/finally   这就是所有的程序代码!并请参见本文后附带的程序代码。   随着可以使用国际互联网络和支持网络的无线设备日益的增多普及,Java和J2ME的重要性也在不断的变大。因为HTTP协议是当前仅有的,被所有的遵从MIDP规范的设备支持的网络协议,它也是用于开发无线网络应用程序的最好的候选者。   在本文中,我们探究了无线网络编程的基本结构和几个核心问题,我们看了如何调用两个最常用的HTTP请求方法:GET和POST。J2ME仍然在它的发展初期,并且无线设备也即将得到大面积的普及。所以,所有有志投身于无线网络编程中的开发者们将得到大展拳脚的好机会。   附录: /* * HttpMidlet.java */ import javax.microedition.midlet.*; import javax.microedition.lcdui.*; import javax.microedition.io.*; import java.io.*; public class HttpMidlet extends MIDlet implements CommandListener { //使用默认的URL。用户可以从图形用户接口改变这个值 private static String defaultURL = "http://localhost:8080/test/servlet/EchoServlet"; // 主MIDP 显示 private Display myDisplay = null; // 输入URL的图形用户接口组件 private Form requestScreen; private TextField requestField; // 用于提交请求的图形用户接口组件 private List list; private String[] menuItems; // 用于显示服务器响应的图形用户接口组件 private Form resultScreen; private StringItem resultField; //用于requestScreen的"send"按钮 Command sendCommand; // 用于requestScreen的"exit"按钮 Command exitCommand; // 用于requestScreen的"back"按钮 Command backCommand; public HttpMidlet(){ // 初始化图形用户接口组件 myDisplay = Display.getDisplay( this ); sendCommand = new Command( "SEND", Command.OK, 1 ); exitCommand = new Command( "EXIT", Command.OK, 1 ); backCommand = new Command( "BACK", Command.OK, 1 ); //显示请求的URL requestScreen = new Form( "Type in a URL:" ); requestField = new TextField( null, defaultURL, 100, TextField.URL ); requestScreen.append( requestField ); requestScreen.addCommand( sendCommand ); requestScreen.addCommand( exitCommand ); requestScreen.setCommandListener( this ); // 选择想要的HTTP请求方法 menuItems = new String[] {"GET Request", "POST Request"}; list = new List( "Select an HTTP method:", List.IMPLICIT, menuItems, null ); list.setCommandListener( this ); // 先是从服务器上收到的信息 resultScreen = new Form( "Server Response:" ); resultScreen.addCommand( backCommand ); resultScreen.setCommandListener( this ); }//结束HttpMidlet() public void startApp() { myDisplay.setCurrent( requestScreen ); }//结束 startApp() public void commandAction( Command com, Displayable disp ) { // 当用户点击"send"按钮 if ( com == sendCommand ) { myDisplay.setCurrent( list ); } else if ( com == backCommand ) { requestField.setString( defaultURL ); myDisplay.setCurrent( requestScreen ); } else if ( com == exitCommand ) { destroyApp( true ); notifyDestroyed(); }//结束 if ( com == sendCommand ) if ( disp == list && com == List.SELECT_COMMAND ) { String result; if ( list.getSelectedIndex() == 0 ) // 发送一个 GET 请求到服务器 result = sendHttpGet( requestField.getString() ); else // 发送一个 POST 请求到服务器 result = sendHttpPost( requestField.getString() ); resultField = new StringItem( null, result ); resultScreen.append( resultField ); myDisplay.setCurrent( resultScreen ); }//结束if ( dis == list && com == List.SELECT_COMMAND ) }//结束 commandAction( Command, Displayable ) private String sendHttpGet( String url ) { HttpConnection hcon = null; DataInputStream dis = null; StringBuffer responseMessage = new StringBuffer(); try { //使用READ权限的标准的 HttpConnection hcon = ( HttpConnection )Connector.open( url ); //从HttpConnection取得一个 DataInputStream dis = new DataInputStream( hcon.openInputStream() ); // 从服务器上取回响应 int ch; while ( ( ch = dis.read() ) != -1 ) { responseMessage.append( (char) ch ); }//结束while ( ( ch = dis.read() ) != -1 ) } catch( Exception e ) { e.printStackTrace(); responseMessage.append( "ERROR" ); } finally { try { if ( hcon != null ) hcon.close(); if ( dis != null ) dis.close(); } catch ( IOException ioe ) { ioe.printStackTrace(); }//结束try/catch }//结束try/catch/finally return responseMessage.toString(); }//结束sendHttpGet( String ) private String sendHttpPost( String url ) { HttpConnection hcon = null; DataInputStream dis = null; DataOutputStream dos = null; StringBuffer responseMessage = new StringBuffer(); // 请求体 String requeststring = "This is a POST."; try { // 使用读写权限的 HttpConnection hcon = ( HttpConnection )Connector.open( url, Connector.READ_WRITE ); //设置请求方法为POST hcon.setRequestMethod( HttpConnection.POST ); // 取得发送请求字符串的DataOutputStream dos = hcon.openDataOutputStream(); byte[] request_body = requeststring.getBytes(); // 发送请求字符串到服务器 for( int i = 0; i < request_body.length; i++ ) { dos.writeByte( request_body[i] ); }//结束 for( int i = 0; i < request_body.length; i++ ) // 取得做为接收服务器响应的DataInputStream dis = new DataInputStream( hcon.openInputStream() ); // 从服务器上取回响应 int ch; while( ( ch = dis.read() ) != -1 ) { responseMessage.append( (char)ch ); }//结束while( ( ch = dis.read() ) != -1 ) { } catch( Exception e ) { e.printStackTrace(); responseMessage.append( "ERROR" ); } finally { // 释放输入输出流和HTTP连接 try { if( hcon != null ) hcon.close(); if( dis != null ) dis.close(); if( dos != null ) dos.close(); } catch ( IOException ioe ) { ioe.printStackTrace(); }//结束try/catch }//结束try/catch/finally return responseMessage.toString(); }//结束sendHttpPost( String ) public void pauseApp() { }//结束pauseApp() public void destroyApp( boolean unconditional ) { myDisplay = null; requestScreen = null; requestField = null; resultScreen = null; resultField = null; }//结束 destroyApp( boolean ) }//结束HttpMidlet <淘宝热门商品:
 

48.00 元  

韩国同步时尚休闲卫衣长款全棉开衫外套

 

1.50元  

星钻喜铺◣皇冠信誉◢{100%满意婚庆一站式店铺}特色婚庆用品大全


来源:程序员网

小小豆叮

基于JDBC的数据库连接池高效管理策略

在基于JDBC的数据库应用开发中,数据库连接的管理是一个难点,因为它是决定该应用性能的一个重要因素。本文在对数据库连接进行透彻分析的基础上,提出并实现了一个高效的连接管理策略,使得开发高性能的数据库应用变得相对容易。特别是,对于连接管理中的两个难点:事务和多线程问题进行了深入的剖析,并给出了一个基于设计模式的解决方案。 介绍 在使用Java语言进行和数据库有关的的应用开发中,一般都使用JDBC来进行和数据库的交互,其中有一个关键的概念就是Connection(连接),它在Java中是一个类,代表了一个通道。通过它,使用数据的应用就可以从数据库访问数据了。 对于一个简单的数据库应用,由于对于数据库的访问不是很频繁。这时可以简单地在需要访问数据库时,就新创建一个连接,用完后就关闭它,这样做也不会带来什么明显的性能上的开销。但是对于一个复杂的数据库应用,情况就完全不同了。频繁的建立、关闭连接,会极大的减低系统的性能,因为对于连接的使用成了系统性能的瓶颈。 本文给出的方法可以有效的解决这个问题。在本方法中提出了一个合理、有效的连接管理策略,避免了对于连接的随意、无规则的使用。该策略的核心思想是:连接复用。通过建立一个数据库连接池以及一套连接使用管理策略,使得一个数据库连接可以得到高效、安全的复用,避免了数据库连接频繁建立、关闭的开销。另外,由于对JDBC中的原始连接进行了封装,从而方便了数据库应用对于连接的使用(特别是对于事务处理),提高了开发效率,也正是因为这个封装层的存在,隔离了应用的本身的处理逻辑和具体数据库访问逻辑,使应用本身的复用成为可能。 问题产生 我参与的项目是开发一个网管系统,不可避免的要和数据库打交道。刚开始时,由于对于数据库的访问不是很频繁,对于数据库连接的使用就是简单的需要时就建立,用完就关闭的策略,这很符合XP(eXtreme Programming)的口号:"Do the Simplest Thing that Could Possibly Work"。确实,开始时工作的很好。随着项目的进展,对于数据库的访问开始变的频繁,问题就暴露出来了,原先的通过简单地获取和关闭数据库连接的方法将很大的影响系统的性能,这种影响是由于数据库资源管理器进程频繁的创建和摧毁那些连接对象而引起的。 此时,就有必要对数据库访问方法进行重构(refactoring),因为我们确实需要进行改进,来提高系统的性能。 解决方案 可以看出,问题的根源就是由于对于连接资源的低效管理造成的。对于共享资源,有一个很著名的设计模式:资源池。该模式正是为了解决资源频繁分配、释放所造成的问题的。把该模式应用到数据库连接管理领域,就是建立一个数据库连接池,提供一套高效的连接分配、使用策略,最终目标是实现连接的高效、安全的复用。 3.1、建立连接池 第一步,就是要建立一个静态的连接池,所谓静态是指,池中的连接是在系统初始化时就分配好的,并且不能够随意关闭的。Java中给我们提供很多容器类可以方便的用来构建连接池,如:Vector、Stack等。在系统初始化时,根据配置创建连接并放置在连接池中,以后所使用的连接都是从该连接池中获取的,这样就可以避免连接随意建立、关闭造成的开销(当然,我们没有办法避免Java的Garbage Collection带来的开销)。 3.2、分配、释放策略 有了这个连接池,下面我们就可以提供一套自定义的分配、释放策略。 当客户请求数据库连接时,首先看连接池中是否有空闲连接,这里的空闲是指,目前没有分配出去的连接。如果存在空闲连接则把连接分配给客户,并作相应处理,具体处理策略,在关键议题中会详述,主要的处理策略就是标记该连接为已分配。若连接池中没有空闲连接,就在已经分配出去的连接中,寻找一个合适的连接给客户(选择策略会在关键议题中详述),此时该连接在多个客户间复用。 当客户释放数据库连接时,可以根据该连接是否被复用,进行不同的处理。如果连接没有使用者,就放入到连接池中,而不是被关闭。 可以看出正是这套策略保证了数据库连接的有效复用。 3.3、配置策略 数据库连接池中到底要放置多少个连接,连接耗尽后该如何处理呢?这时一个配置策略。一般的配置策略是,开始时,根据具体的应用需求,给出一个初始的连接池中连接的数目以及一个连接池可以扩张到的最大连接数目。本方案就是按照这种策略实现的。 关键议题 本节将对上述解决方案中的关键细节进行详述,正是这些关键的策略保证了数据库连接复用的高效和安全。 4.1、引用记数 3.2节中的分配、释放策略对于有效复用连接非常重要,我们采用的方法也是采用了一个很有名的设计模式:Reference Counting(引用记数)。该模式在复用资源方面用的非常广泛,我们把该方法运用到对于连接的分配释放上。每一个数据库连接,保留一个引用记数,用来记录该连接的使用者的个数。具体的实现上,我们采用了两极连接池,空闲池和使用池。空闲池中存放目前还没有分配出去被使用的连接,一旦一个连接被分配出去,那么就会放入到使用池中,并且增加引用记数。 这样做有一个很大的好处,使得我们可以高效的使用连接,因为一旦空闲池中的连接被全部分配出去,我们就可以根据相应的策略从使用池中挑选出一个已经正在使用的连接用来复用,而不是随意拿出一个连接去复用。策略可以根据需要去选择,我们采用的策略比较简单:复用引用记数最小的连接。Java的面向对象特性,使得我们可以灵活的选择不同的策略(提供一个不同策略共用的抽象接口,各个具体的策略都实现这个接口,这样对于策略的处理逻辑就和策略的实现逻辑分离)。 4.2、事务处理 前面谈到的都是关于使用数据库连接进行普通的数据库访问。对于事务处理,情况就变得比较复杂。因为事务本身要求原子性的保证,此时就要求对于数据库的操作符合"All-All-Nothing"原则,即要么全部完成,要么什么都不做。如果简单的采用上述的连接复用的策略,就会发生问题,因为没有办法控制属于同一个事务的多个数据库操作方法的动作,可能这些数据库操作是在多个连接上进行的,并且这些连接可能被其他非事务方法复用。 Connection本身具有提供了对于事务的支持,可以通过设置Connection的AutoCommit属性为false,显式的调用commit或者rollback方法来实现。但是要安全、高效的进行Connection进行复用,就必须提供相应的事务支持机制。我们采用的方法是:采用显式的事务支撑方法,每一个事务独占一个连接。这种方法可以大大降低对于事务处理的复杂性(如果事务不独占一条连接,那么要保证事务的原子性并且又不妨碍复用该连接的其他和该事务无关的操作,基本上不可能,除非Connection类是你开发的),并且又不会妨碍连接的复用,因为隶属于该事务的所有数据库操作都是通过这一个连接完成的,并且事务方法又复用了其他一些数据库方法。 在我们的连接管理服务提供了显式的事务开始、结束(commit或者rollback)声明,以及一个事务注册表,用于登记事务发起者和事务使用的连接的对应关系,通过该表,使用事务的部分和我们的连接管理部分就隔离开,因为该表是在运行时根据实际的调用情况,动态生成的。事务使用的连接在该事务运行中不能被复用。 当使用者需要使用事务方法时,首先调用连接管理服务提供的beginTrans方法,该方法主要处理流程如下(伪码描述): public void beginTrans( ) { … conn = getIdleConnectionFromPoll( ); userId = getUserId( ); registerTrans(userId, conn); … } 在我们的实现中,用户标识是通过使用者所在的线程来标识的。后面的所有对于数据库的访问都是通过查找该注册表,使用已经分配的连接来完成的。当事务结束时,从注册表中删除相应表项。 对于嵌套的事务如何处理呢?我们采用的方法仍为引用记数,不过这里的引用记数是指的"嵌套层次",具体的细节,不再赘述。 4.3、封装 从上面的论述可以看出,普通的数据库方法和事务方法对于连接的使用(分配、释放)是不同的,为了便于使用,对外提供一致的操作接口,我们对连接进行了封装:即普通连接和事务连接。在此,我们利用了Java中的强大的面向对象特性:多态。普通连接和事务连接均实现了一个DbConnection接口,对于接口中定义的方法,分别根据自己的特点作了不同的实现,这样在对于连接的处理上就非常的一致了。 4.4、并发问题 为了是我们的连接管理服务有更大的通用性,就必须要考虑到多线程环境,即并发问题。在一个多线程的环境下,我们必须要保证连接管理自身数据的一致性和连接内部数据是一致性,还好Java提供对这方面的很好的支持(synchronized关键字),这样我们就很容易使连接管理成为线程安全的。 5、结论 本文给出了一个基本的连接管理框架,在其中使用了一些广泛使用的设计模式(资源池,引用记数等),使得高效、安全的复用数据库连接成为可能。当然,还有一些问题没有考虑到,比如:没有实现对不同种类的数据库的联合管理;没有提供定时检测机制,查询连接的状态等。另外在连接管理的使用包装上比起一些商用的系统还显粗糙,但是底层的基理是一致的,所以通过本文相信对于这些商用的产品中的相关功能会有更好的理解。 参考文献 《Thinking in Java》Bruce Eckel 《Real-Time Design Patterns》 Bruce Powel Dougladd <淘宝热门商品:
 

¥:48.00 

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

超级瘦腿!(迷迭香柠檬马鞭草)袋泡瘦腿茶 1月量2盒 包快递哦!

 

运动鞋 

X-2品牌时尚鞋城【郭氏鞋坊旗下】[销售出口多余产品


来源:程序员网

小小豆叮

无线开发者(SUN)

<淘宝热门商品:
 

99.00 元  

DOROTHY去印平坑明星!第二代积雪草细胞再生霜-填平坑

 

278.00 元  

拍趣-拍你喜欢 享受乐趣

3皇冠 大遥控 灿凌RMBOX368(高清DVD/RMVB硬盘播放器) AOK


来源:程序员网

小小豆叮

J2EE design patterns

什么是Design Patten? 简单来说,Design Patten 就是一个常用的方案。 在我们的开发过程中,经常会遇到一些相同或者相近的问题,每次我们都会去寻找一个新的解决方法,为了节省时间提高效率,我们提供一些能够解决这些常见问题的,被证实可行的方案,构成一个统一的资源库。 一个Design Patten描述了一个被证实可行的方案。这些方案非常普通,是有完整定义的最常用的模式。 这些模式可以被重用,有良好的伸缩性,而这些Design Patten的优势将在设计J2EE应用时得到体现。 1. Model-View-Controller a. 问题 如果开发一个企业级应用,只需要一种客户端的话,那么一切都非常容易解决。但真实情况是,我们必须面对运行在各种设备上客户端,象PDA,WAP浏览器以及运行在桌面上的浏览器,我们不得不开发不同的应用程序来处理来自不同客户端的请求。数据访问与现实将混淆在一起,可能会出现重复的数据访问,导致整个开发周期没有必要的延长。 b. 建议的解决方法 Model-View-Controller (MVC) 开发模式被证明是有效的处理方法之一。它可以分离数据访问和数据表现。你可以开发一个有伸缩性的,便于扩展的控制器,来维护整个流程。如图1所示为整个模式的结构。MVC模式可以被映射到多层企业级的J2EE应用上。 § 所有的企业数据以及商业逻辑可以作为模式。 § 视图可以通过模式访问数据,并根据客户端的要求来显示数据。视图必须保证当模式改变的时候,数据显示也必须同时改变。 § 控制器用来结合模式和视图,把客户端来的请求转换成模式能够理解并执行的请求,并且根据请求以及执行结果来决定下一次显示那一个视图。 根据以上的逻辑,你可以象这样建立一个应用: § 应用的商业逻辑由MVC中的模式也就是EJB来表现。模式必须处理由控制器传递过来的对数据的访问请求。 § 多个页面组成了MVC中的视图,这些视图必须随模式一起更新。 § 控制器是一系列接收用户动作的对象,他们把用户的请求转换成模式可理解的请求,并决定显示那一个页面当模式处理完请求后。 图 1(图片来源:java.sun.com) c. 要点 § MVC结构适用于那些多用户的,可扩展的,可维护的,具有很高交互性的系统。 § MVC可以很好的表达用户的交互和系统模式。 § 很方便的用多个视图来显示多套数据,是系统很方便的支持其他新的客户端类型。 § 代码重复达到最低。 § 由于分离了模式中的流控制和数据表现,可以分清开发者的责任,另外,也可以加快产品推向市场的时间。 2. Front Controller a. 问题 MVC给出了一个整个应用的松散的耦合架构。现在来看一下这样一个经常发生的情况。在某一个应用中,用户看到的视图和他所做的操作密切相关。这是一些具有高度交互性的页面,而这些页面之间含有高度的依赖性。在没有任何模式的时候,这个应用只是一个许多独立的页面的集合,维护和扩展变得异常困难。 § 当一个页面移动后,其他含有这个页面链接的文件,都必须修改。 § 当有一系列页面需要口令保护时,许多配置文件需要修改,或者页面需要包含新的标记。 § 当一个页面需要一个新的表示层时,页面中的标记要被重新安排。 当这个系统变得复杂时,这些问题将变得更糟。如果用MVC来解决的话,就变成一个如何管理控制器和视图之间交互的问题。 b. 建议的解决方法 前台控制模式可以解决这个问题。这个模式中,所有的请求都被传送到一个对象中。这个主要的对象将处理所有的请求,决定以后显示那一个视图,以及实现必要的安全需求。对于把视图显示以及其他功能实现集中到一个主要的对象中,将使修改变得很容易,对应用的修改,可以在所有视图中反映出来。 c. 要点 § 这个模式对于需要在多个含有动态数据的页面之间进行复杂导航的系统来说,是很有效的。 § 这个模式对于要在所有页面中都包含模板,转换等的应用来说,也是很有效的。 § 由于视图的选择集中在前端控制器上,因此,视图的导航变得更加容易理解和便于配置。 § 视图重用和变更会更加容易。 § 视图之间的复杂交互,使得控制器变得复杂。从而,当应用发展的时候,控制器将变得难以维护。不过,大部分情况下可以用XML映射来解决。 § 实现应用要求的安全性检验变得很简单。 § 这个模式不适合小型的,只显示静态内容的应用。 d. 样例 § RequestMappings.xml 文件映射了传入的请求,处理器以及下一个页面 com.blah1.blah2.blah3.request1Handler 以上这个文件是控制器的指定配置,控制器的代码如下: § FrontControllerImpl.java 利用上面的XML实现了控制器 // all required imports // exceptions to be caught appropriately wherever applicable public class FrontControllerImpl extends HttpServlet { // all required declarations, definitions private HashMap requestMappings; public void init() { // load the mappings from XML file into the hashmap } public void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { doGet(request, response); } public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { String currentPage= request.getPathInfo(); // get all mapping info for "currentPage" from the hashmap // if "securityCheckRequired = true", do the security check // if "useRequestHandler = true", pass on the incoming request to the specified handler // forward the results to the given "nextScreen" } } 用这种方法实现的控制器将很容易维护,当应用有新的变动的时候,只要修改XML文件就能解决了。前台控制模式将使在视图和控制器之前有复杂交互的J2EE应用变得简单。 3. Session Facade a. 问题 前台控制给出了一个基于MVC的,能有效管理用户与J2EE应用之间进行的复杂交互。这个模式可以使处理页面的现实顺序和用户的并发请求变得简单。并且使增加和改变页面现实变得更加容易。 另外一个常见的问题是,当EJB或者业务逻辑发生变化的时候,应用的客户端也必须随之改变。我们来看一下这个问题。 一般来说,为了表现一个账户中的用户,我们使用一个业务逻辑来表示账户中的信息,象用户名和口令,再用一个EJB来管理用户的个人信息,象爱好,语言等。当要创建一个新的账号或者修改一个已经存在的账号时,必须访问包含账号信息的EJB,读取个人信息,修改并且保存,这样的一个流程。 当然,这只是一个非常简单的例子,实际情况可能比这个复杂的多,象查看用户定制了哪些服务,检验客户信用卡的有效性,存放订单等。在这个案例中,为了实现一个完整的流程,客户端必须访问账户EJB来完成一系列适当的工作。下面的例子显示了一个Servlet客户端如何来控制一个用户订单。 A servlet that does the workflow required for placing an order // all required imports; // exceptions to be caught appropriately wherever applicable; // This servlet assumes that for placing an order the account and // credit status of the customer has to be checked before getting the // approval and committing the order. For simplicity, the EJBs that // represent the business logic of account, credit status etc are // not listed public class OrderHandlingServlet extends HttpServlet { // all required declarations, definitions public void init() { // all inits required done here } public void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { // other logic as required // Get reference to the required EJBs InitialContext ctxt = new InitialContext(); Object obj = ctxt.lookup("java:comp/env/ejb/UserAccount"); UserAccountHome acctHome = (UserAccountHome) PortableRemoteObject.narrow(obj, UserAccountHome.class); UserAccount acct = acctHome.create(); obj = ctxt.lookup("java:comp/env/ejb/CreditCheck"); CreditCheckHome creditCheckHome = (CreditCheckHome) PortableRemoteObject.narrow(obj, CreditCheckHome.class); CreditCheck credit = creditCheckHome.create(); obj = ctxt.lookup("java:comp/env/ejb/Approvals"); ApprovalsHome apprHome = (ApprovalsHome) PortableRemoteObject.narrow(obj, ApprovalsHome.class); Approvals appr = apprHome.create(); obj = ctxt.lookup("java:comp/env/ejb/CommitOrder"); CommitOrderHome orderHome = (CommitOrderHome) PortableRemoteObject.narrow(obj, CommitOrderHome.class); CommitOrder order = orderHome.create(); // Acquire the customer ID and order details; // Now do the required workflow to place the order int result = acct.checkStatus(customerId); if(result != OK) { // stop further steps } result = credit.checkCreditWorth(customerId, currentOrder); if(result != OK) { // stop further steps } result = appr.getApprovals(customerId, currentOrder); if(result != OK) { // stop further steps } // Everything OK; place the order result = order.placeOrder(customerId, currentOrder); // do further processing as required } } 以上的代码显示了一个单个的客户端。如果这个应用支持多种客户端的话,必须为每一个客户端制定一种处理方法来完成工作流程。如果有一个EJB的实现流程需要改变的话,那么所有的参与这个流程的客户端都需要改变。如果不同的EJB之间的交互需要改变的话,所有的客户端都必须知道这一点,如果流程中需要增加一个新的步骤的话,所有的客户端也必须随之修改。 这样一来,EJB和客户端之间的改变变得非常困难。客户端必须对每个EJB分开进行访问,致使网络速度变慢。同样,应用越复杂,麻烦越大。 b. 建议的解决方法 解决这个问题的方法是,把客户端和他们使用的EJB分割开。建议适用Session Fa?ade模式。这个模式通过一个Session Bean,为一系列的EJB提供统一的接口来实现流程。事实上,当客户端只是使用这个接口来触发流程。这样,所有关于EJB实现流程所需要的改变,都和客户端无关。 看下面这个例子。这段代码用来控制与客户相关的订单的处理方法。 // All imports required // Exception handling not shown in the sample code public class OrderSessionFacade implements SessionBean { // all EJB specific methods like ejbCreate defined here // Here is the business method that does the workflow // required when a customer places a new order public int placeOrder(String customerId, Details orderDetails) throws RemoteException { // Get reference to the required EJBs InitialContext ctxt = new InitialContext(); Object obj = ctxt.lookup("java:comp/env/ejb/UserAccount"); UserAccountHome acctHome = (UserAccountHome) PortableRemoteObject.narrow(obj, UserAccountHome.class); UserAccount acct = acctHome.create(); obj = ctxt.lookup("java:comp/env/ejb/CreditCheck"); CreditCheckHome creditCheckHome = (CreditCheckHome) PortableRemoteObject.narrow(obj, CreditCheckHome.class); CreditCheck credit = creditCheckHome.create(); obj = ctxt.lookup("java:comp/env/ejb/Approvals"); ApprovalsHome apprHome = (ApprovalsHome) PortableRemoteObject.narrow(obj, ApprovalsHome.class); Approvals appr = apprHome.create(); obj = ctxt.lookup("java:comp/env/ejb/CommitOrder"); CommitOrderHome orderHome = (CommitOrderHome) PortableRemoteObject.narrow(obj, CommitOrderHome.class); CommitOrder order = orderHome.create(); // Now do the required workflow to place the order int result = acct.checkStatus(customerId); if(result != OK) { // stop further steps } result = credit.checkCreditWorth(customerId, currentOrder); if(result != OK) { // stop further steps } result = appr.getApprovals(customerId, currentOrder); if(result != OK) { // stop further steps } // Everything OK; place the order int orderId = order.placeOrder(customerId, currentOrder); // Do other processing required return(orderId); } // Implement other workflows for other order related functionalities (like // updating an existing order, canceling an existing order etc.) in a // similar way } 在模式允许的情况下,Servlet代码将很容易实现。 // all required imports // exceptions to be caught appropriately wherever applicable public class OrderHandlingServlet extends HttpServlet { // all required declarations, definitions public void init() { // all inits required done here } public void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { // other logic as required // Get reference to the session facade InitialContext ctxt = new InitialContext(); Object obj = ctxt.lookup("java:comp/env/ejb/OrderSessionFacade"); OrderSessionFacadeHome facadeHome = (OrderSessionFacadeHome) PortableRemoteObject.narrow(obj, OrderSessionFacadeHome.class); OrderSessionFacade facade = facadeHome.create(); // trigger the order workflow int orderId = facade.placeOrder(customerId, currentOrder); // do further processing as required } } 就象上面显示的,客户端的逻辑变得非常简单。流程中的任何改变只要修改模式中的一处地方就可以了。客户端可以仍旧使用原来的接口,而不必做任何修改。同样,这个模式可以用来响应其他处理器的流程处理。这让你能用同样的模式来处理不同客户端的不同流程。在这个例子中,模式提供了很好的伸缩性和可维护性。 c. 要点 § 既然这种模式不涉及到数据访问,就应该用Session Bean来实现。 § 对于用简单接口来实现复杂EJB的子系统来说,是一个理想的选择。 § 这个模式不适用于无流程处理的应用。 § 这个模式可以减少客户端于EJB之间的通信和依赖。 § 所有和EJB有关的交互,都有同一个Session Bean来控制,可以减少客户端对EJB的误用。 § 这个模式可以使支持多类型客户端变得更容易。 § 可以减少网络数据传递。 § 所有的服务器端的实现细节都对客户端隐藏,在改变发生后,客户端不用重新发布。 § 这个模式可以同样看成一个集中处理器来处理所有的安全或日志纪录。 4. Data Access Object a. 问题 目前为止,你看到的模型都是用来构建可伸缩的,易于维护的J2EE应用。这些模式尽可能的把应用在多个层上来实现。但是,还有一点必须强调:EJB的数据表现。它们包括象EJB这样的数据库语言。如果数据库有改变的话,相应的SQL也必须改变,而EJB也必须随之更新。 这些常见问题就是:访问数据源的代码与EJB结合在一起,这样致使代码很难维护。看以下的代码。 An EJB that has SQL code embedded in it // all imports required // exceptions not handled in the sample code public class UserAccountEJB implements EntityBean { // All EJB methods like ejbCreate, ejbRemove go here // Business methods start here public UserDetails getUserDetails(String userId) { // A simple query for this example String query = "SELECT id, name, phone FROM userdetails WHERE name = " + userId; InitialContext ic = new InitialContext(); datasource = (DataSource)ic.lookup("java:comp/env/jdbc/DataSource"); Connection dbConnection = datasource.getConnection(); Statement stmt = dbConnection.createStatement(); ResultSet result = stmt.executeQuery(queryStr); // other processing like creation of UserDetails object result.close(); stmt.close(); dbConnection.close(); return(details); } } b. 建议的解决方法 为了解决这个问题,从而让你能很方便的修改你的数据访问。建议使用DAO模式。这个模式把数据访问逻辑从EJB中拿出来放入独立的接口中。结果是EJB保留自己的业务逻辑方法,在需要数据的时候,通过DAO来访问数据库。这样的模式,在要求修改数据访问的时候,只要更新DAO的对象就可以了。看以下的代码。 A Data Access Object that encapsulates all data resource access code // All required imports // Exception handling code not listed below for simplicity public class UserAccountDAO { private transient Connection dbConnection = null; public UserAccountDAO() {} public UserDetails getUserDetails(String userId) { // A simple query for this example String query = "SELECT id, name, phone FROM userdetails WHERE name = " + userId; InitialContext ic = new InitialContext(); datasource = (DataSource)ic.lookup("java:comp/env/jdbc/DataSource"); Connection dbConnection = datasource.getConnection(); Statement stmt = dbConnection.createStatement(); ResultSet result = stmt.executeQuery(queryStr); // other processing like creation of UserDetails object result.close(); stmt.close(); dbConnection.close(); return(details); } // Other data access / modification methods pertaining to the UserAccountEJB } 现在你有了一个DAO对象,利用这个对象你可以访问数据。再看以下的代码。 An EJB that uses a DAO // all imports required // exceptions not handled in the sample code public class UserAccountEJB implements EntityBean { // All EJB methods like ejbCreate, ejbRemove go here // Business methods start here public UserDetails getUserDetails(String userId) { // other processing as required UserAccountDAO dao = new UserAccountDAO(); UserDetails details = dao.getUserDetails(userId); // other processing as required return(details); } } 任何数据源的修改只要更新DAO就可以解决了。另外,为了支持应用能够支持多个不同的数据源类型,你可以开发多个DAO来实现,并在EJB的发布环境中指定这些数据源类型。在一般情况下,EJB可以通过一个Factory对象来得到DAO。用这种方法实现的应用,可以很容易的改变它的数据源类型。 c. 要点 § 这个模式分离了业务逻辑和数据访问逻辑。 § 这种模式特别适用于BMP。过一段时间,这种方式同样可以移植到CMP中。 § DAOs可以在发布的时候选择数据源类型。 § DAOs增强了应用的可伸缩性,因为数据源改变变得很容易。 § DAOs对数据访问没有任何限制,甚至可以访问XML数据。 § 使用这个模式将导致增加一些额外的对象,并在一定程度上增加应用的复杂性。 <淘宝热门商品:
 

¥:4.00 

蓉蓉de美女加工厂 打造淘宝最低价

 

IP卡/网络电话/在线影音充值 

SKYPE官方代理商在线充值


来源:程序员网

小小豆叮

Jcreater+MotoJ2SDK的配置与使用心得

假设安装路径如下: JCreator D:\Program Files\Xinox Software\JCreator LE motoj2sdk D:\Motoj2sdk JDK D:\jdk1.3.1 注意:要先击活模拟环境,运行D:\MotoJ2SDK\generic\scripts\runConstructor.bat 选择手机型号,选择语言,选择normal, 再"创建"。 启动Jcreater之后我的配置如下: 第一步 选择 Configure->Options->JDK Profiles 注意:一定新建 profile and select “D:\jdk1.3.1” 将名字改为“J2ME 388” Add classes path “D:\Motoj2sdk\lib” Add documentation path “D:\Motoj2sdk\docs” 分别将后加的两行移到最上方. 第二步 选择 Configure->Options->JDK Tools 选择Complier 选中 and edit it. 将 parameters 变为 -classpath D:/motoj2sdk/lib $[JavaFiles] 第三步 选择 Configure->Options->Tools 点击“New”选择 DOS command 名字为“Preverifier” 将 arguments 换为 d:\Motoj2sdk\bin\preverifier.exe -classpath "d:\Motoj2sdk\lib" -d . . 将 initial directory 变为 “$[PrjDir]” 第4步 按上面的方法在New一个 DOS command 名字:“Run Emulator” 将 arguments 换成 “java -Djava.library.path=d:/MotoJ2SDK/lib -classpath "d:/MotoJ2SDK/bin/Emulator.jar";"d:/MotoJ2SDK/ConfigTool.jar" com.mot.tools.j2me.emulator.Emulator -classpath$[PrjDir];"d:/MotoJ2SDK/lib" -deviceFile d:/MotoJ2SDK/bin/resources/device.props javax.microedition.midlet.AppManager $[CurClass] -JSA 1 1” 将 initial directory 换成 “d:\Motoj2sdk\bin” ok!编辑工具配置完毕! 新建一个工程——选择Empty Project 再取一个名字 比如:test 则jcreater自动在你的工作目录中生成目录test 再new一个file选择java File 写好你的原代码,保存 如:test.java 在Project中 选add file 然后选中你刚才的test.java 注意:不要有package ; 编译——》tools中的Preverifier进行预先审核——》tools中的Run Emulator进行模拟 test.java 的例子:功能是捕捉键盘输入的ascII吗。 import javax.microedition.lcdui.*; import javax.microedition.midlet.*; public class test extends MIDlet implements CommandListener { /** * The screen for this MIDlet */ private KeyEventsDemoCanvas myCanvas; /** * Reference to current Display */ private Display myDisplay; /** * Command to make sure soft key is not a key event */ private Command okCommand = new Command("OK", Command.OK, 1); test() { myDisplay = Display.getDisplay(this); myCanvas = new KeyEventsDemoCanvas(); myCanvas.addCommand(okCommand); myCanvas.setCommandListener(this); } /** * Do nothing if a command is fired */ public void commandAction(Command c, Displayable s) { } /** * Start the MIDlet */ protected void startApp() throws MIDletStateChangeException { myDisplay.setCurrent(myCanvas); } /** * Pause the MIDlet */ protected void pauseApp() { } /** * Called by the framework before the application is unloaded */ protected void destroyApp(boolean unconditional) { } /** * The screen for this application */ class KeyEventsDemoCanvas extends Canvas { /** * Background color (i.e. the color of the screen) */ public final int BACKGROUND_COLOR = 0xFFFFFF; // white /** * Foreground color (i.e. the color of the rectangles) */ public final int FOREGROUND_COLOR = 0x000000; // black /** * Last key that was pressed */ private int lastKey; /** * Paint the screen */ public void paint(Graphics g) { /* * Clear the screen */ g.setColor(BACKGROUND_COLOR); g.fillRect(0, 0, getWidth(), getHeight()); /* * Paint the message */ g.setColor(FOREGROUND_COLOR); g.drawString("Press a key!", 0, 0, Graphics.TOP | Graphics.LEFT); if (lastKey != 0) { g.drawString("Key Code: " + lastKey, 0, g.getFont().getHeight(), Graphics.TOP | Graphics.LEFT); try { g.drawString("Action: " + getGameAction(lastKey), 0, 2 * g.getFont().getHeight(), Graphics.TOP | Graphics.LEFT); g.drawString("Key Name: " + getKeyName(lastKey), 0, 3 * g.getFont().getHeight(), Graphics.TOP | Graphics.LEFT); } catch (Exception e) { // ignore since alphabet keys will throw this exception } } } /** * Handle key press */ public void keyPressed(int keyCode) { lastKey = keyCode; repaint(); } /** * Demonstrate keyRepeated events */ public void keyRepeated(int keyCode) { System.out.println("Key repeated " + keyCode); } } } <淘宝热门商品:
 

148.00 元  

阳鸟渔具(光威鱼竿 名牌浮漂 品质保证)面向全国团购批发

【25号新到】 Clarks/其乐 超软商务男皮鞋 不平凡AG-801

 

1.50元  

星钻喜铺◣皇冠信誉◢{100%满意婚庆一站式店铺}特色婚庆用品大全


来源:程序员网

小小豆叮

四级灰度的颜色值怎么表示?

private final static int WHITE_COLOR = 0x00FFFFFF; private final static int LIGHT_GRAY = 0x00888888; private final static int DARK_GRAY = 0x00444444; private final static int BLACK_COLOR = 0x00000000; <淘宝热门商品:
 

215.00 元  

08秋冬新款 D&G 优质面料修

 

27.50 元  

兼济天下 公司运营 多家实体店 毛巾 浴巾 美容巾 浴袍 毛巾被

【皇冠信誉 专业做毛巾】外贸原单★素色绣小圆点浴巾◎加厚


来源:程序员网

小小豆叮

仔细研究 J2ME

Java 平台提供了用于小型网络设备的平台

Soma Ghosh (sghosh@entigo.com)
高级应用程序开发员,Entigo

Java 2 平台袖珍版(Java 2 Platform, Micro Edition(J2ME))为开发者提供了伟大的工具,它把 Java 平台的以网络为中心和平台不可知论的特性移植到有限存储器和有限处理器的设备。Soma Ghosh 解释了 J2ME 领域的基础知识,向您展示了该平台的构件并演示了一个样本应用程序。

在我们今天的生活中,个性化的智能信息用品已经是必需品。这些用品包括移动电话、双向寻呼机、智能卡、个人电脑记事本(personal organizer)和掌上电脑(palmtop)。它们的趋势是成为目的特定的、资源有限的网络连接设备,而不是我们迄今已知的通用台式机。为专门满足这一巨大的消费空间,Java 2 平台袖珍版(J2ME)提供了极多的创新 Java 技术。

Java VM 的变迁:从台式机到微型设备
作为 J2ME 目标的微型设备具有 16 位或 32 位处理器和总量不少于大约 128 KB 的存储器。这些设备都符合连接限制设备配置(Connected Limited Device Configuration(CLDC)),同时也保留了 Java 的传统特性,即任何时间、任何地点的代码可移植性、部署灵活性、安全的网络传送以及代码稳定性。J2ME CLDC 的先决条件是一个紧缩的 JVM,称为 K 虚拟机(K Virtual Machine(KVM))。KVM 是为小存储器、资源受限的网络连接设备设计的。

另一个 J2ME 配置是连接设备配置(Connected Device Configuration(CDC))。它的目标是高档的消费类电子产品和嵌入设备,例如智能通信器、高级“智能”寻呼机、智能个人数字助理(PDA)以及交互式数字电视机顶盒。典型地,这些设备运行一个 32 位的微处理器/控制器,而且有总量大于 2 MB 的用于虚拟机和库的存储的存储器。CDC 包含有 C 虚拟机(C Virtual Machine(CVM))。在本篇文章中,我们将把注意力放在 CLDC 和 KVM 体系结构上。关于 CDC 和 CVM 的更多信息,请参阅下面的参考资料部分。

为适应占用资源很小的(small-footprint)设备的特性,KVM 已经按以下方式修改:

  • VM 的大小和类库已减小为 50 到 80 KB 目标代码的标准


  • 存储器占用已经减小为几十千字节的标准


  • 在具有 16 位和 32 位处理器的设备上,性能有效


  • 体系结构是高可移植的,特定于机器和/或平台的代码的总量很少


  • 多线程和垃圾回收是独立于系统的


  • 可以对虚拟机的组件进行配置,以适合于特定设备,从而增强了灵活性

J2ME 体系结构和配置
J2ME 体系结构是基于设备的系列类别的。一个类别定义了一个特定种类的设备:移动电话、简单寻呼机和电脑记事本都是单独的类别。对存储器和处理能力有相近需求的若干类别的设备构成设备的一个系列。移动电话、简单寻呼机和简单个人电脑记事本一起就是占用资源很小的设备的一个系列。

图 1 定义了在 J2ME 上下文环境中设备的系列和类别之间的关系。

图 1. 设备的系列(family)和类别(category)
设备的系列(family)和类别(category)

为了支持资源受限设备系列所要求的那种灵活性和可定制部署,人们将 J2ME 体系结构设计成模块化的和可伸缩的。J2ME 技术在一个完整的应用程序运行时模型中定义了这种模块性和可伸缩性,在该模型中的四个软件层都构建在设备的主机操作系统上。

图 2 显示了 J2ME 体系结构。

图 2. J2ME 体系结构
J2ME 体系结构

  • Java 虚拟机层(Java Virtual Machine Layer):这一层是 Java 虚拟机的一个实现,它是为特定设备的主机操作系统定制的,而且支持一个特定的 J2ME 配置(configuration)。
  • 配置层(Configuration Layer):配置层定义了 Java 虚拟机功能的和特定类别设备上可用的 Java 类库的最小集。从某种程度上说,一个配置定义了 Java 平台功能部件和库的共同性,开发者可以假设这些功能部件和库在属于某一特定类别的所有设备上都是可用的。用户不太会见到这一层,但它对框架(profile)实现者非常重要。
  • 框架层(Profile Layer):框架层定义了特定系列设备上可用的应用程序编程接口(API)的最小集。框架在一个特定的配置上面实现。应用程序是针对特定的框架编写的,因此可以移植到支持该框架的任何设备上。一个设备可以支持多个框架。用户和应用程序供应商看到最多的就是这一层。
  • MIDP 层:移动信息设备框架(Mobile Information Device Profile(MIDP))是一个 Java API 集合,它处理诸如用户界面、持久存储和联网这样的问题。

Java 虚拟机层(Java Virtual Machine Layer)、配置层(Configuration Layer)和框架层(Profile Layer)一起构成了连接限制设备配置(Connected Limited Device Configuration(CLDC))。MID 框架(MID Profile)和 CLDC 提供了一个标准的运行时环境,这个环境允许把新的应用程序和服务动态地部署在终端用户设备上。

用 MIDP API 进行 J2ME 编程:构件
CLDC 和 MIDP 组合起来为创建移动电话和简单双向寻呼机上的应用程序提供了完整的环境。

MID 框架的核心是一个 MIDlet 应用程序。这个应用程序继承了 MIDlet 类,以允许应用程序管理软件对 MIDlet 进行控制、从应用程序描述符检索属性以及对状态变化进行通知和请求。

所有 MIDlet 都继承 MIDlet 类 — 运行时环境(应用程序管理器)和 MIDlet 应用程序代码之间的接口。MIDlet 类提供了用于调用、暂停、重新启动和终止 MIDlet 应用程序的 API。

应用程序管理软件可以在运行时环境内管理多个 MIDlet 的活动。此外,MIDlet 可以自己发起一些状态变化,并把这些变化通知给应用程序管理软件。

MIDP API 类的完整集合可以分为两个类别:

  • 用于用户界面的 MIDP API:设计这些 API 是为了能以一系列屏幕显示为基础与用户进行交互操作,每一屏幕显示把适量的数据显示给用户。命令以每屏幕为基础提供给用户。这些 API 允许应用程序决定下一屏显示什么、执行什么计算和使用网络服务的何种请求。


  • 用于处理数据库的 MIDP API:这些 API 负责组织和操作设备数据库,这个数据库由在 MIDlet 的多个调用之间跨越时保持持久的信息组成。

底层的 CLDC API 用于处理字符串、对象和整数。还提供了 Java 2 API 的一个子集,用于处理 I/O 和网络通信。

图 3 显示了 J2ME 的构件。

图 3. J2ME 的构件
J2ME 的构件

标准(Standard)版和袖珍(Micro)版 Java API 之间的关系如图 4 所示。

图 4. J2ME 和 J2SE API 之间的关系
J2ME 和 J2SE API 之间的关系

J2ME 中的事件处理
J2ME 中的事件处理是以一系列屏幕显示为基础的,这与 Java 平台的台式机版本的事件处理有很大不同。每一屏显示特定的少量数据。

命令以每屏幕为基础提供给用户。Command 对象封装了与动作的语义相关的名称和信息。这个对象主要用于为用户提供动作选择。所产生的命令行为定义在与屏幕显示相关联的 CommandListener 中。

每一个 Command 包含三块信息:一个 label(标号)、一个 type(类型)和一个 priority(优先级)。label 用于命令的可视表示;type 和 priority 由系统使用,系统用它们来决定 Command 如何映射到具体用户界面。

图 5 显示了 J2ME 中的事件处理机制。

图 5. 在 J2ME 中处理用户事件
在 J2ME 中处理用户事件

设计用户界面
MIDP API 尽管维护的是一个受限的框架,但它还是提供了 UI 元素的完整集合。以下是最重要的 UI 元素中的一些:

  • Alert 用于在屏幕上向用户显示关于异常情况或错误的信息。


  • Choice 用于实现从既定数量的选项中进行选择。


  • ChoiceGroup 提供一组相关选项。


  • Form 作为其它 UI 元素的容器。


  • List 提供一个选项列表。


  • StringItem 充当只显(display-only)字符串之用。


  • TextBox 是允许用户输入和编辑文本的屏幕显示。


  • TextField 允许用户输入和编辑文本。多个 TextField 可放到一个 Form 中。


  • DateField 是一个可编辑的组件,用于表示日期和时间信息。DateField 可以放到 Form 中。


  • Ticker 用于文本的可滚动显示。

UI 元素的完整列表可在 MID Profile API 文档中找到,该文档随 J2ME Wireless Toolkit 一起提供(请参阅下面的参考资料获得更多信息)。

管理设备数据库
MIDP 提供了一组用于组织和操作设备数据库的类和接口:RecordStoreRecordComparatorRecordFilterRecordStore 由大量的记录组成,这些记录在 MIDlet 的多个调用之间跨越时保持持久。对 RecordStore 中的记录进行比较,或者从 RecordStore 中抽取若干组记录,都是 RecordComparatorRecordFilter 接口提供的功能。

开发 J2ME 应用程序
前面的部分已经对 J2ME 作了一个概览。在这一部分中,我们将通过开发一个现实的电话界面应用程序来熟悉这个平台的实践细节。

一个样本应用程序:电话日历
J2ME 的著名特色之一是它在受限环境中的日期处理功能。J2ME 提供的 DateField UI 元素是一个可编辑的组件,该组件用于表示日历信息(即日期和时间)。在这一部分中,我们将使用 DateFieldDate 函数来开发一个 J2ME 应用程序,这个应用程序用于在移动电话 UI 上显示一个滚动日历。

一个电话日历应用程序



// Import of API classes
import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;
import java.util.*;

//A first MIDlet with simple text and a few commands.
public class PhoneCalendar extends MIDlet
 implements CommandListener, ItemStateListener {

//The commands
private Command exitCommand;

//The display for this MIDlet
private Display display;

// Display items e.g Form and DateField
Form displayForm;
DateField date;

public PhoneCalendar() {
  display = Display.getDisplay(this);
exitCommand = new Command("Exit", Command.SCREEN, 1);
  date = new DateField("Select to date", DateField.DATE);

}

// Start the MIDlet by creating the Form and 
// associating the exit command and listener.
public void startApp() {
displayForm = new Form("Quick Calendar");
  displayForm.append(date);
  displayForm.addCommand(exitCommand);
displayForm.setCommandListener(this);
displayForm.setItemStateListener(this);
display.setCurrent(displayForm);
}

public  void itemStateChanged(Item item)
{
 // Get the values from changed item
}

// Pause is a no-op when there is no  background
// activities or record stores to be closed.
public void pauseApp() { }

// Destroy must cleanup everything not handled 
// by the garbage collector.
public void destroyApp (boolean unconditional) { }

// Respond to commands. Here we are only implementing
// the exit command. In the exit command, cleanup and
// notify that the MIDlet has been destroyed.
public void commandAction (
Command c, Displayable s) {
if (c == exitCommand) {
destroyApp(false);
  notifyDestroyed();
}
}


}

如上定义的 PhoneCalendar MIDlet 继承了 ItemListenerCommandListener。它使 MIDlet 具备了跟踪屏幕上的条目变化和对用户命令作出响应的功能。由此应用程序创建的用户界面从为电话屏幕定义一个显示并附加上一个 Form 开始。该 Form 充当容器使用,可以保持一些用户界面项。commandAction() 函数在 J2ME 中执行命令处理程序,并且定义某个命令应执行的动作。

部署 J2ME
您可以从 Sun 下载一个仿真器,该仿真器允许您在台式机系统上测试 J2ME 应用程序。如果您宁愿避免所有的图形开销,则您也可以在命令行上部署 J2ME。

在仿真环境中进行部署
在仿真环境中部署和运行 J2ME 应用程序,要涉及到仿真器的安装和配置。J2ME Wireless Toolkit 提供了一个仿真环境,该环境用于在资源受限的设备上对 Java 应用程序进行的开发和部署。这里教您如何自己运行它:

  1. 安装 J2ME Wireless Toolkit(请参阅参考资料)。安装程序中将会用必要的说明指导您进行安装。为运行这些示例,请选择独立(standalone)模式。如果您想将它集成到 IDE,请选择集成(integrated)模式。


  2. 通过 KToolbar 的用户界面创建一个新工程。指定一个类名。


  3. 将第 2 步指定的类名放到 C:\[J2ME Installation directory]\apps\[Project Name]\src 目录。


  4. 编译这个工程。


  5. 从 J2ME Wireless Toolkit -> Default Device Selection 选择 DefaultGrayPhone 作为缺省设备。


  6. 运行这个工程。

该工具箱还提供有一个选项,用于把工程打包成一个 jar 文件和一个 jad 文件。双击 jad 文件将会部署 jar 文件所指定的应用程序。

在命令行上进行部署
这里也有一些可用的命令行选项。

1. 创建类文件:


C:\J2ME\apps\PhoneCalendar>
 javac _ tmpclasses _ootclasspath 
C:\J2ME\lib\midpapi.zip -classpath tmpclasses;
classes src\*.java

2. 创建清单文件 manifest.mf


MIDlet-1: PhoneCalendar,
PhoneCalendar.png,
PhoneCalendar
MIDlet-Name: Phone Calendar
MIDlet-Vendor: Sun Microsystems
MIDlet-Version: 1.0
MicroEdition-Configuration: CLDC-1.0
MicroEdition-Profile: MIDP-1.0

3. 创建 jar 文件:


C:\J2ME\apps\PhoneCalendar>jar cfm .\bin\
PhoneCalendar.jar 
manifest.mf  -C classes . _ res .

4. 创建 jad 文件:


MIDlet-1: PhoneCalendar, 
PhoneCalendar.png, 
PhoneCalendar
MIDlet-Jar-Size: 4490
MIDlet-Jar-URL:
F:\J2ME\apps\PhoneCalendar\bin\
PhoneCalendar.jar
MIDlet-Name: PhoneCalendar
MIDlet-Vendor: Sun Microsystems
MIDlet-Version: 1.0

5. 运行 jad 文件:


C:\J2ME\bin> emulator -Xdescriptor:
C:\J2ME\apps\PhoneCalendar
\bin\PhoneCalendar.jad

结束语
J2ME 是一个重要的用于无线方面的 Java 平台,它从可移植的、以网络为中心的 Java 虚拟机转变而来。J2ME 应用程序的开发和部署的灵活性将有效地满足日益增长的无线领域的需求。敬请继续关注!

参考资料

  • 参加本文的讨论论坛。
  • 访问 developerWorks Wireless 专区,保持对无线(wireless)领域的关注。
  • developerWorks Java 技术专区让您紧跟 Java 领域发生的事件。
  • 这篇文章讨论关联对等网(relating peer-to-peer)以及将所有无线用品融合起来的机制。
  • 到 IBM 的 Pervasive Computing 站点查阅最新进行的开发。
  • 用 IBM 的 VisualAge for Java 编译 Java 应用程序。

Sun 提供的一些文档:

  • 访问 J2ME 的主页,以了解 J2ME 到底是什么。
  • 阅读 J2ME 体系结构和配置的详细信息(PDF 格式)。
  • 参阅关于 J2ME 的更多文档。
  • 阅读 J2ME 平台的 Connected Limited Device Configuration 和 Connected Device Configuration。
  • 访问 MIDP 主页,以了解 MIDP API。
  • 下载 J2ME Wireless Toolkit,以运行和测试您的 J2ME 应用程序。您也可以浏览这个工具箱(toolkit)随带的 MIDP API 文档。
  • 浏览关于“Java 无线倡议”的广泛文章。 关于作者
    Soma Ghosh 是计算机科学与工程学士。在过去六年中,她已经开发了涉及范围颇广的电子商务和网络 Java 应用程序。她相信无线商务是业界近年的前途所在,最近她已从现有的台式机模型中转到了无线倡议中。目前,她是 Entigo 的高级应用程序开发员,也是 B2B 销售和服务器端电子商务产品和解决方案的倡导者。请通过 sghosh@entigo.com 与 Soma 联系。 <淘宝热门商品:
     

    30.00 元 

    实图12色2WAY含羊毛打底毛衣

     

    运动鞋 

    X-2品牌时尚鞋城【郭氏鞋坊旗下】[销售出口多余产品


    来源:程序员网

小小豆叮

配置自已的JAVA环境

JSP是JavaServer Pages的简称,是一种集成HTML及Java程序于一个网页的技术。我觉得使用JSP编写程序比ASP、PHP等语言更具有挑战性,更能学到知识,因为它涉及到面向对象的JAVA语言,要用好JSP,就得对JAVA有一定的了解。除此之外,还要求能熟练使用各种开发工具,像Dreamweaver、Photoshop、JBuilder等。   工欲善其事,必先利其器。在运行JSP程序之前,必须做一些准备工作。首先要有一个WEB伺服器,Apache或IIS都可以;其次要有一个执行JAVA程序的的编译器;再次还要有一个支持JSP的引擎,目前有很多引擎可供选择,例如tomcat、weblogic、resin等。   本问介绍的留言板程序在作者的机器上可以顺利运行,详细资料如下:   操作系统:  Windows 2000 SERVER   JAVA编译器:  JDK1.3   WEB伺服器:  Apache1.13.2 + Tomcat3.1引擎   数据库:  Access 2000   Apache和Tomcat安装后的配置有点挑战性,下面是我的安装过程:   1).安装JDK1.3    a).双击 J2SDK1_3_0-WIN.exe 文件,安装到 C:\jdk1.3 目录下;    b).更新下列环境变量,把     C:\jdk1.3\lib\tools.jar;C:\jdk1.3\lib\dt.jar;C:\myclasses加入到CLASSPATH中。     更新方法:右击 我的电脑-属性-高级-环境变量;    c).重起计算机。   2).安装Apache1.13.2    a).双击 apache_1_3_12_win32.exe 文件,安装到 C:\Apache 目录下;    b).用记事本修改 C:\Apache\conf\httpd.conf:     I).PORT:设置Apache Web Server运行时使用的端口号,我把它改成Port 8080,以后在浏览器上输入http://ip:8080 就可以访问到Apache Web Server服务器;     II).SERVERNAME:我把SERVERNAME设置为202.38.126.134(这是我的机器的IP地址);     III).Apache安装完后在"开始-程序"菜单组中多了Apache Web Server菜单组,运行其中的Install Apache as a service,这样的话在“开始-设置-控制面板-服务”中就多了一个名为Apache的服务,您可以用它来启动或停止Apache服务;     IV).打开“开始-设置-控制面板-服务”,选Apache,按"开始"启动Apache服务。    c).在IE中输入http://ip:8080 (ip是你使用的机器的ip地址),Apache运行否?   3).安装Tomcat3.1    a).用WinZIP把tomcat.zip解压缩到一个目录下,最后弄成C:/tomcat;    b).打开C:\Apache\conf\httpd.conf文件,在该文件最后加上类似这样一句话:      Include C:/tomcat/conf/tomcat.conf;    c).修改Tomcat运行的端口号,注意Tomcat自己有一个独立的HTTP服务器,它必须使用一个还未被使用的端口号,我使用PORT:80,在C:\tomcat\conf\server.xml中修改;    d).将SET TOMCAT_HOME=c:\tomcat      SET JAVA_HOME=c:\jdk1.3 加到 C:\tomcat\bin\tomcat.bat文件中,修改完的文件如下:      ......      rem Guess TOMCAT_HOME if it is not present      SET TOMCAT_HOME=c:\tomcat      SET JAVA_HOME=c:\jdk1.3 if not "%TOMCAT_HOME%" == "" goto gothome      下面还有......    e).双击C:\tomcat\startup.bat启动Tomcat;    f).在浏览器上输入http://ip/,如果能看到Tomcat Version 3.1这一页,就表示Tomcat安装成功了。   到此准备工作也就差不多了,最后在Tomcat目录下创建一个目录,用来存放编写的程序,具体情况如下:    C:\tomcat\fox --存放 .html和 .jsp 文件    C:\tomcat\fox\images --存放图片文件    C:\tomcat\fox\global --存放数据库    C:\tomcat\fox\WEB-INF\classes --存放JAVA类文件   为了使这个目录下的JSP程序能顺利运行,还需要在 C:\tomcat\conf\server.xml文件中加上几行代码:   <Context path="/fox" docBase="fox"     defaultSessionTimeOut="30"isWARExpanded="true"     isWARValidated="false" isInvokerEnabled="true"     isWorkDirPersistent="false"/>   添加完代码后的server.xml文件看起来如下所示:    ......    <Context path="" docBase="webapps/ROOT" debug="0" reloadable="true" >    </Context>    <Context path="/redfox" docBase="redfox" defaultSessionTimeOut="30" isWARExpanded="true" isWARValidated="false" isInvokerEnabled="true" isWorkDirPersistent="false"/>    <Context path="/test" docBase="webapps/test" debug="0" reloadable="true" >    </Context>    下面还有......   现在编写一个名为 test.jsp的程序,存于 C:\tomcat\fox\test.jsp    <html>    <body>     <%java.util.Date date=new java.util.Date(); %>      Hello! the time is now     <%out.println(date);%>    </body>    </html> 在IE中键入 http://ip/fox/test.jsp,如果能看到当前的时间,那么恭喜:可以开始编写留言板程序了。 一.创建数据库   1).打开Access2000,创建一个新的数据库,我将这个数据库命名为 foxdb.mdb,存在C:\tomcat\fox\global\foxdb.mdb。接下来在 eagle.mdb中创建一个表,命名为 foxtable,表中有五个字段,全为文本格式:   其中“URL”用于记录留言者的 IP 。至于各字段的长度,我把“留言”定为200,其它四个各为20。   2).指定ODBC数据源,其名为foxdb ,指向 C:\tomcat\fox\global\foxdb.mdb。   二.编写用户的留言界面 foxnote.html,存于C:\tomcat\fox\foxnote.html:   <html>   <body>    <form method="post" action="foxnoteinsert.jsp">     <br>姓名:     <input name=username size=15 value="">     <br>邮箱:     <input name=email size=15 value="">     <br>留言:     <br>     <textarea name=doc rows="5" cols="40">     </textarea>     <br>     <input type=submit value="递交">     <input type=reset value="重填">    </form>   </bocy>   </html> 三.编写 foxnoteinsert.jsp ,将用户的留言写进数据库表中:   <body bgcolor="#FFFFFF">   <%@ page import="java.sql.*,MyUtil,java.util.*"%>   <%    Connection con=null;    String username=MyUtil.gb2312ToUnicode(request.getParameter("username"));    String email=MyUtil.gb2312ToUnicode(request.getParameter("email"));    String doc=MyUtil.gb2312ToUnicode(request.getParameter("doc"));    String url=request.getRemoteAddr();    try {      Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");                         con=DriverManager.getConnection("jdbc:odbc:foxdb","","");      String str="insert into foxtable values(?,?,?,?);";      PreparedStatement pstmt=con.prepareStatement(str);      pstmt.setString(1,username);      pstmt.setString(2,email);      pstmt.setString(3,doc);      pstmt.setString(4,url);      pstmt.executeUpdate();      pstmt.close();      con.close();     }    catch(Exception e) {      out.println(e.getMessage());     }   %>   这个程序中有一些要说明的地方,就是其中用到了一个 JavaBean :MyUtil.class 。   MyUtil 的作用是字符串之间的转换。必需关注的是JSP的字符串以Unicode码表示,而留言板界面的表单却是以 gb2312 码表示。所以将用户的留言写进数据库还需要码间的转换。如果不转换而把留言直接写到数据库表,则会产生乱码。下面是 MyUtil 的原代码,存于C:\tomcat\fox\WEB-INF\classes\MyUtil.java ,编译后的MyUtil.class文件也存于此。   import java.io.*;   public class MyUtil{   public static String gb2312ToUnicode(String s){    try{      return new String(s.getBytes("ISO8859_1"),"gb2312");     }    catch(UnsupportedEncodingException uee){      return s;     }    }   public static String unicodeTogb2312(String s){    try{     return new String(s.getBytes("gb2312"),"ISO8859_1");    }    catch(UnsupportedEncodingException uee){     return s;     }    }   } 四.编写 foxnoteview.jsp ,用于浏览数据库表中已有的留言,存于C:\tomcat\fox\foxnoteview.jsp ,代码如下:   <html>   <body>   <%@ page contentType="text/html;charset=gb2312" language="java" import="java.sql.*"%>   <%    Connection con=null;    try     {      Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");      con=DriverManager.getConnection("jdbc:odbc:foxdb","","");      Statement statement=con.createStatement();      ResultSet rs=statement.executeQuery("select * from foxtable");    %>   <table border="1" width="100%" cellspacing="0" cellpadding="0" align="center" bordercolorlight="#CCCCFF" bordercolordark="#FFFFFF">   <tr bgcolor="#FFFFFF">   <td width="15%" height="25" align="center"><i>作者</i></td>   <td width="28%" height="25" align="center"><i>发表时间</i></td>   <td width="22%" height="25" align="center"><i>Email</i></td>   <td width="35%" height="25" align="center"><i>留言内容</i></td>   <%    while(rs.next()){     out.println("<TR><td align=center><font size=2 color=#999999>"+rs.getString("作者")+"</TD>");     out.println("<TD><font size=2color=#999999>"+rs.getString("Email")+"</font></TD>");     out.println("<TD><font size=2 color=#999999>"+rs.getString("留言")+"</font></TD>");     out.println("<TD><font size=2 color=#999999>"+rs.getString("URL")+"</font></TD></TR>");    }    rs.close();    con.close();    }    catch(Exception e)    {     out.println(e.getMessage());    }   %>   </table>   </body>   </html>   到此,整个留言板程序就算是完工了。留言板在数据库应用中比较简单,但是加以变化则可以编写出各种各样的应用程序,操作各种各样的数据库^_^ <淘宝热门商品:
 

 

香港恒邦充电电池/充电器专卖店

 

4.60 元  

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

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


来源:程序员网

小小豆叮