﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>BlogJava-常言笑的家-随笔分类-JAVA/J2EE</title><link>http://www.blogjava.net/wealupa/category/23606.html</link><description>Spring, Hibernate, Struts, Ajax, RoR</description><language>zh-cn</language><lastBuildDate>Tue, 13 May 2008 02:37:53 GMT</lastBuildDate><pubDate>Tue, 13 May 2008 02:37:53 GMT</pubDate><ttl>60</ttl><item><title>appfuse配置文件解读</title><link>http://www.blogjava.net/wealupa/archive/2008/05/08/199326.html</link><dc:creator>常言笑</dc:creator><author>常言笑</author><pubDate>Thu, 08 May 2008 11:40:00 GMT</pubDate><guid>http://www.blogjava.net/wealupa/archive/2008/05/08/199326.html</guid><wfw:comment>http://www.blogjava.net/wealupa/comments/199326.html</wfw:comment><comments>http://www.blogjava.net/wealupa/archive/2008/05/08/199326.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/wealupa/comments/commentRss/199326.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/wealupa/services/trackbacks/199326.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: &nbsp;● AppFuse的ant构建使用非常复杂，功能也非常强大，怎样能够充分的利用它，为我所用，在今后的开发中大幅度的减轻开发量，顾做此详细研究(其中不包括测试任务)。 build.xml的正常运行依赖以下文件i) propertie..●&nbsp;&nbsp;&nbsp; AppFuse的ant构建使用非常复杂，功能也非常强大， 怎样能够充分的利用它，为我所用，在今后的开发中大...&nbsp;&nbsp;<a href='http://www.blogjava.net/wealupa/archive/2008/05/08/199326.html'>阅读全文</a><img src ="http://www.blogjava.net/wealupa/aggbug/199326.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/wealupa/" target="_blank">常言笑</a> 2008-05-08 19:40 <a href="http://www.blogjava.net/wealupa/archive/2008/05/08/199326.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>java多线程设计模式</title><link>http://www.blogjava.net/wealupa/archive/2007/07/27/132683.html</link><dc:creator>常言笑</dc:creator><author>常言笑</author><pubDate>Fri, 27 Jul 2007 01:17:00 GMT</pubDate><guid>http://www.blogjava.net/wealupa/archive/2007/07/27/132683.html</guid><wfw:comment>http://www.blogjava.net/wealupa/comments/132683.html</wfw:comment><comments>http://www.blogjava.net/wealupa/archive/2007/07/27/132683.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/wealupa/comments/commentRss/132683.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/wealupa/services/trackbacks/132683.html</trackback:ping><description><![CDATA[<h4>java语言已经内置了多线程支持，所有实现Runnable接口的类都可被启动一个新线程，新线程会执行该实例的run()方法，当run()方法执行完毕后，线程就结束了。一旦一个线程执行完毕，这个实例就不能再重新启动，只能重新生成一个新实例，再启动一个新线程。</h4>
<p>Thread类是实现了Runnable接口的一个实例，它代表一个线程的实例，并且，启动线程的唯一方法就是通过Thread类的start()实例方法：
<p>Thread t = new Thread();<br>t.start();
<p>start()方法是一个native方法，它将启动一个新线程，并执行run()方法。Thread类默认的run()方法什么也不做就退出了。注意：直接调用run()方法并不会启动一个新线程，它和调用一个普通的java方法没有什么区别。
<p>因此，有两个方法可以实现自己的线程：
<p>方法1：自己的类extend Thread，并复写run()方法，就可以启动新线程并执行自己定义的run()方法。例如：
<p>public class MyThread extends Thread {<br>&nbsp;&nbsp;&nbsp; public run() {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println("MyThread.run()");<br>&nbsp;&nbsp;&nbsp; }<br>}
<p>在合适的地方启动线程：new MyThread().start();
<p>方法2：如果自己的类已经extends另一个类，就无法直接extends Thread，此时，必须实现一个Runnable接口：
<p>public class MyThread extends OtherClass implements Runnable {<br>&nbsp;&nbsp;&nbsp; public run() {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println("MyThread.run()");<br>&nbsp;&nbsp;&nbsp; }<br>}
<p>为了启动MyThread，需要首先实例化一个Thread，并传入自己的MyThread实例：
<p>MyThread myt = new MyThread();<br>Thread t = new Thread(myt);<br>t.start();
<p>事实上，当传入一个Runnable target参数给Thread后，Thread的run()方法就会调用target.run()，参考JDK源代码：
<p>public void run() {<br>&nbsp;&nbsp;&nbsp; if (target != null) {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; target.run();<br>&nbsp;&nbsp;&nbsp; }<br>}
<p>线程还有一些Name, ThreadGroup, isDaemon等设置，由于和线程设计模式关联很少，这里就不多说了。
<p>由于同一进程内的多个线程共享内存空间，在Java中，就是共享实例，当多个线程试图同时修改某个实例的内容时，就会造成冲突，因此，线程必须实现共享互斥，使多线程同步。
<p>最简单的同步是将一个方法标记为synchronized，对同一个实例来说，任一时刻只能有一个synchronized方法在执行。当一个方法正在执行某个synchronized方法时，其他线程如果想要执行这个实例的任意一个synchronized方法，都必须等待当前执行 synchronized方法的线程退出此方法后，才能依次执行。
<p>但是，非synchronized方法不受影响，不管当前有没有执行synchronized方法，非synchronized方法都可以被多个线程同时执行。
<p>此外，必须注意，只有同一实例的synchronized方法同一时间只能被一个线程执行，不同实例的synchronized方法是可以并发的。例如，class A定义了synchronized方法sync()，则不同实例a1.sync()和a2.sync()可以同时由两个线程来执行。
<p>多线程同步的实现最终依赖锁机制。我们可以想象某一共享资源是一间屋子，每个人都是一个线程。当A希望进入房间时，他必须获得门锁，一旦A获得门锁，他进去后就立刻将门锁上，于是B,C,D...就不得不在门外等待，直到A释放锁出来后，B,C,D...中的某一人抢到了该锁（具体抢法依赖于 JVM的实现，可以先到先得，也可以随机挑选），然后进屋又将门锁上。这样，任一时刻最多有一人在屋内（使用共享资源）。
<p>Java语言规范内置了对多线程的支持。对于Java程序来说，每一个对象实例都有一把&#8220;锁&#8221;，一旦某个线程获得了该锁，别的线程如果希望获得该锁，只能等待这个线程释放锁之后。获得锁的方法只有一个，就是synchronized关键字。例如：
<p>public class SharedResource {<br>&nbsp;&nbsp;&nbsp; private int count = 0;<br>&nbsp;&nbsp;&nbsp; public int getCount() { return count; }<br>&nbsp;&nbsp;&nbsp; public <strong>synchronized</strong> void setCount(int count) { this.count = count; }<br>}
<p>同步方法public synchronized void setCount(int count) { this.count = count; } 事实上相当于：
<p>public&nbsp;void setCount(int count) {<br><strong>synchronized(this) { // 在此获得this锁<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;this.count = count;</strong><br><strong>} // 在此释放this锁<br></strong>}
<p>红色部分表示需要同步的代码段，该区域为&#8220;危险区域&#8221;，如果两个以上的线程同时执行，会引发冲突，因此，要更改SharedResource的内部状态，必须先获得SharedResource实例的锁。
<p>退出synchronized块时，线程拥有的锁自动释放，于是，别的线程又可以获取该锁了。
<p>为了提高性能，不一定要锁定this，例如，SharedResource有两个独立变化的变量：
<p>public class SharedResouce {<br>&nbsp;&nbsp;&nbsp; private int a = 0;<br>&nbsp;&nbsp;&nbsp; private int b = 0;<br>&nbsp;&nbsp;&nbsp; public synchronized void setA(int a) { this.a = a; }<br>&nbsp;&nbsp;&nbsp; public synchronized void setB(int b) { this.b = b; }<br>}
<p>若同步整个方法，则setA()的时候无法setB()，setB()时无法setA()。为了提高性能，可以使用不同对象的锁：
<p>public class SharedResouce {<br>&nbsp;&nbsp;&nbsp; private int a = 0;<br>&nbsp;&nbsp;&nbsp; private int b = 0;<br>&nbsp;&nbsp;&nbsp; private Object sync_a = new Object();<br>&nbsp;&nbsp;&nbsp; private Object sync_b = new Object();<br>&nbsp;&nbsp;&nbsp; public void setA(int a) {<br><strong>synchronized(sync_a) {<br></strong>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this.a = a;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; public synchronized void setB(int b) {<br><strong>synchronized(sync_b) {<br></strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this.b = b;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; }<br>}
<p>通常，多线程之间需要协调工作。例如，浏览器的一个显示图片的线程displayThread想要执行显示图片的任务，必须等待下载线程 downloadThread将该图片下载完毕。如果图片还没有下载完，displayThread可以暂停，当downloadThread完成了任务后，再通知displayThread&#8220;图片准备完毕，可以显示了&#8221;，这时，displayThread继续执行。
<p>以上逻辑简单的说就是：如果条件不满足，则等待。当条件满足时，等待该条件的线程将被唤醒。在Java中，这个机制的实现依赖于wait/notify。等待机制与锁机制是密切关联的。例如：
<p>synchronized(obj) {<br>&nbsp;&nbsp;&nbsp; while(!condition) {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; obj.<strong>wait()</strong>;<br>&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; obj.doSomething();<br>}
<p>当线程A获得了obj锁后，发现条件condition不满足，无法继续下一处理，于是线程A就wait()。
<p>在另一线程B中，如果B更改了某些条件，使得线程A的condition条件满足了，就可以唤醒线程A：
<p>synchronized(obj) {<br>&nbsp;&nbsp;&nbsp; condition = true;<br>&nbsp;&nbsp;&nbsp; obj.notify();<br>}
<p><strong>需要注意的概念是：</strong>
<p># 调用obj的wait(), notify()方法前，必须获得obj锁，也就是必须写在synchronized(obj) {...} 代码段内。
<p># 调用obj.wait()后，线程A就释放了obj的锁，否则线程B无法获得obj锁，也就无法在synchronized(obj) {...} 代码段内唤醒A。
<p># 当obj.wait()方法返回后，线程A需要再次获得obj锁，才能继续执行。
<p># 如果A1,A2,A3都在obj.wait()，则B调用obj.notify()只能唤醒A1,A2,A3中的一个（具体哪一个由JVM决定）。
<p># obj.notifyAll()则能全部唤醒A1,A2,A3，但是要继续执行obj.wait()的下一条语句，必须获得obj锁，因此，A1,A2,A3只有一个有机会获得锁继续执行，例如A1，其余的需要等待A1释放obj锁之后才能继续执行。
<p># 当B调用obj.notify/notifyAll的时候，B正持有obj锁，因此，A1,A2,A3虽被唤醒，但是仍无法获得obj锁。直到B退出synchronized块，释放obj锁后，A1,A2,A3中的一个才有机会获得锁继续执行。
<p>前面讲了wait/notify机制，Thread还有一个sleep()静态方法，它也能使线程暂停一段时间。sleep与wait的不同点是： sleep并不释放锁，并且sleep的暂停和wait暂停是不一样的。obj.wait会使线程进入obj对象的等待集合中并等待唤醒。
<p>但是wait()和sleep()都可以通过interrupt()方法打断线程的暂停状态，从而使线程立刻抛出InterruptedException。
<p>如果线程A希望立即结束线程B，则可以对线程B对应的Thread实例调用interrupt方法。如果此刻线程B正在 wait/sleep/join，则线程B会立刻抛出InterruptedException，在catch() {} 中直接return即可安全地结束线程。
<p>需要注意的是，InterruptedException是线程自己从内部抛出的，并不是interrupt()方法抛出的。对某一线程调用 interrupt()时，如果该线程正在执行普通的代码，那么该线程根本就不会抛出InterruptedException。但是，一旦该线程进入到 wait()/sleep()/join()后，就会立刻抛出InterruptedException。
<p>GuardedSuspention模式主要思想是：
<p>当条件不满足时，线程等待，直到条件满足时，等待该条件的线程被唤醒。
<p>我们设计一个客户端线程和一个服务器线程，客户端线程不断发送请求给服务器线程，服务器线程不断处理请求。当请求队列为空时，服务器线程就必须等待，直到客户端发送了请求。
<p>先定义一个请求队列：Queue
<p>package com.crackj2ee.thread;<br>import java.util.*;<br>public class Queue {<br>&nbsp;&nbsp;&nbsp; private List queue = new LinkedList();<br>&nbsp;&nbsp;&nbsp; public synchronized Request getRequest() {<br><strong>while(queue.size()==0) {<br></strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; try {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this.wait();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; catch(InterruptedException ie) {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return null;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return (Request)queue.remove(0);<br>&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; public synchronized void putRequest(Request request) {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; queue.add(request);<br><strong>this.notifyAll();</strong><br>&nbsp;&nbsp;&nbsp; }<br>}
<p>蓝色部分就是服务器线程的等待条件，而客户端线程在放入了一个request后，就使服务器线程等待条件满足，于是唤醒服务器线程。
<p>客户端线程：ClientThread
<p>package com.crackj2ee.thread;<br>public class ClientThread extends Thread {<br>&nbsp;&nbsp;&nbsp; private Queue queue;<br>&nbsp;&nbsp;&nbsp; private String clientName;<br>&nbsp;&nbsp;&nbsp; public ClientThread(Queue queue, String clientName) {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this.queue = queue;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this.clientName = clientName;<br>&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; public String toString() {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return "[ClientThread-" + clientName + "]";<br>&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; public void run() {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for(int i=0; i&lt;100; i++) {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Request request = new Request("" + (long)(Math.random()*10000));<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println(this + " send request: " + request);<br><strong>queue.putRequest(request);<br></strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; try {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Thread.sleep((long)(Math.random() * 10000 + 1000));<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; catch(InterruptedException ie) {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println(this + " shutdown.");<br>&nbsp;&nbsp;&nbsp; }<br>}
<p>服务器线程：ServerThread
<p>package com.crackj2ee.thread;<br>public class ServerThread extends Thread {<br>&nbsp;&nbsp;&nbsp; private boolean stop = false;<br>&nbsp;&nbsp;&nbsp; private Queue queue;<br>&nbsp;&nbsp;&nbsp; public ServerThread(Queue queue) {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this.queue = queue;<br>&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; public void shutdown() {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; stop = true;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this.interrupt();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; try {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this.join();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; catch(InterruptedException ie) {}<br>&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; public void run() {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; while(!stop) {<br><strong>Request request = queue.getRequest();<br></strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println("[ServerThread] handle request: " + request);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; try {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Thread.sleep(2000);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; catch(InterruptedException ie) {}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println("[ServerThread] shutdown.");<br>&nbsp;&nbsp;&nbsp; }<br>}
<p>服务器线程在红色部分可能会阻塞，也就是说，Queue.getRequest是一个阻塞方法。这和java标准库的许多IO方法类似。
<p>最后，写一个Main来启动他们：
<p>package com.crackj2ee.thread;<br>public class Main {<br>&nbsp;&nbsp;&nbsp; public static void main(String[] args) {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Queue queue = new Queue();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ServerThread server = new ServerThread(queue);<br><strong>server.start();<br></strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ClientThread[] clients = new ClientThread[5];<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for(int i=0; i<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; clients[i] = new ClientThread(queue, ""+i);<br><strong>clients[i].start();<br></strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; try {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Thread.sleep(100000);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; catch(InterruptedException ie) {}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; server.shutdown();<br>&nbsp;&nbsp;&nbsp; }<br>}
<p>我们启动了5个客户端线程和一个服务器线程，运行结果如下：
<p>[ClientThread-0] send request: Request-4984<br>[ServerThread] handle request: Request-4984<br>[ClientThread-1] send request: Request-2020<br>[ClientThread-2] send request: Request-8980<br>[ClientThread-3] send request: Request-5044<br>[ClientThread-4] send request: Request-548<br>[ClientThread-4] send request: Request-6832<br>[ServerThread] handle request: Request-2020<br>[ServerThread] handle request: Request-8980<br>[ServerThread] handle request: Request-5044<br>[ServerThread] handle request: Request-548<br>[ClientThread-4] send request: Request-1681<br>[ClientThread-0] send request: Request-7859<br>[ClientThread-3] send request: Request-3926<br>[ServerThread] handle request: Request-6832<br>[ClientThread-2] send request: Request-9906<br>......
<p>可以观察到ServerThread处理来自不同客户端的请求。
<p><strong>思考</strong>
<p>Q: 服务器线程的wait条件while(queue.size()==0)能否换成if(queue.size()==0)?
<p>A: 在这个例子中可以，因为服务器线程只有一个。但是，如果服务器线程有多个（例如Web应用程序有多个线程处理并发请求，这非常普遍），就会造成严重问题。
<p>Q: 能否用sleep(1000)代替wait()?
<p>A: 绝对不可以。sleep()不会释放锁，因此sleep期间别的线程根本没有办法调用getRequest()和putRequest()，导致所有相关线程都被阻塞。
<p>Q: (Request)queue.remove(0)可以放到synchronized() {}块外面吗？
<p>A: 不可以。因为while()是测试queue，remove()是使用queue，两者是一个原子操作，不能放在synchronized外面。
<p><strong>总结</strong>
<p>多线程设计看似简单，实际上必须非常仔细地考虑各种锁定/同步的条件，稍不小心，就可能出错。并且，当线程较少时，很可能发现不了问题，一旦问题出现又难以调试。
<p>所幸的是，已有一些被验证过的模式可以供我们使用，我们会继续介绍一些常用的多线程设计模式。
<p>前面谈了多线程应用程序能极大地改善用户相应。例如对于一个Web应用程序，每当一个用户请求服务器连接时，服务器就可以启动一个新线程为用户服务。
<p>然而，创建和销毁线程本身就有一定的开销，如果频繁创建和销毁线程，CPU和内存开销就不可忽略，垃圾收集器还必须负担更多的工作。因此，线程池就是为了避免频繁创建和销毁线程。
<p>每当服务器接受了一个新的请求后，服务器就从线程池中挑选一个等待的线程并执行请求处理。处理完毕后，线程并不结束，而是转为阻塞状态再次被放入线程池中。这样就避免了频繁创建和销毁线程。
<p>Worker Pattern实现了类似线程池的功能。首先定义Task接口：
<p>package com.crackj2ee.thread;<br>public interface Task {<br>&nbsp;&nbsp;&nbsp; void <strong>execute</strong>();<br>}
<p>线程将负责执行execute()方法。注意到任务是由子类通过实现execute()方法实现的，线程本身并不知道自己执行的任务。它只负责运行一个耗时的execute()方法。
<p>具体任务由子类实现，我们定义了一个CalculateTask和一个TimerTask：
<p>// CalculateTask.java<br>package com.crackj2ee.thread;<br>public class CalculateTask implements Task {<br>&nbsp;&nbsp;&nbsp; private static int count = 0;<br>&nbsp;&nbsp;&nbsp; private int num = count;<br>&nbsp;&nbsp;&nbsp; public CalculateTask() {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; count++;<br>&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; public void <strong>execute</strong>() {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println("[CalculateTask " + num + "] start...");<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; try {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Thread.sleep(3000);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; catch(InterruptedException ie) {}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println("[CalculateTask " + num + "] done.");<br>&nbsp;&nbsp;&nbsp; }<br>}
<p>// TimerTask.java<br>package com.crackj2ee.thread;<br>public class TimerTask implements Task {<br>&nbsp;&nbsp;&nbsp; private static int count = 0;<br>&nbsp;&nbsp;&nbsp; private int num = count;<br>&nbsp;&nbsp;&nbsp; public TimerTask() {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; count++;<br>&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; public void <strong>execute</strong>() {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println("[TimerTask " + num + "] start...");<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; try {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Thread.sleep(2000);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; catch(InterruptedException ie) {}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println("[TimerTask " + num + "] done.");<br>&nbsp;&nbsp;&nbsp; }<br>}
<p>以上任务均简单的sleep若干秒。
<p>TaskQueue实现了一个队列，客户端可以将请求放入队列，服务器线程可以从队列中取出任务：
<p>package com.crackj2ee.thread;<br>import java.util.*;<br>public class TaskQueue {<br>&nbsp;&nbsp;&nbsp; private List queue = new LinkedList();<br>&nbsp;&nbsp;&nbsp; public synchronized Task <strong>getTask</strong>() {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; while(queue.size()==0) {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; try {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this.wait();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; catch(InterruptedException ie) {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return null;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return (Task)queue.remove(0);<br>&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; public synchronized void <strong>putTask</strong>(Task task) {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; queue.add(task);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this.notifyAll();<br>&nbsp;&nbsp;&nbsp; }<br>}
<p>终于到了真正的WorkerThread，这是真正执行任务的服务器线程：
<p>package com.crackj2ee.thread;<br>public class WorkerThread extends Thread {<br>&nbsp;&nbsp;&nbsp; private static int count = 0;<br>&nbsp;&nbsp;&nbsp; private boolean busy = false;<br>&nbsp;&nbsp;&nbsp; private boolean stop = false;<br>&nbsp;&nbsp;&nbsp; private TaskQueue queue;<br>&nbsp;&nbsp;&nbsp; public WorkerThread(ThreadGroup group, TaskQueue queue) {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; super(group, "worker-" + count);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; count++;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this.queue = queue;<br>&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; public void shutdown() {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; stop = true;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this.interrupt();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; try {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this.join();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; catch(InterruptedException ie) {}<br>&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; public boolean isIdle() {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return !busy;<br>&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; public void run() {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println(getName() + " start.");&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; while(!stop) {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Task task = <strong>queue.getTask();</strong><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(task!=null) {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; busy = true;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; task.execute();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; busy = false;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println(getName() + " end.");<br>&nbsp;&nbsp;&nbsp; }<br>}
<p>前面已经讲过，queue.getTask()是一个阻塞方法，服务器线程可能在此wait()一段时间。此外，WorkerThread还有一个shutdown方法，用于安全结束线程。
<p>最后是ThreadPool，负责管理所有的服务器线程，还可以动态增加和减少线程数：
<p>package com.crackj2ee.thread;<br>import java.util.*;<br>public class ThreadPool extends ThreadGroup {<br>&nbsp;&nbsp;&nbsp; private List threads = new LinkedList();<br>&nbsp;&nbsp;&nbsp; private TaskQueue queue;<br>&nbsp;&nbsp;&nbsp; public ThreadPool(TaskQueue queue) {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; super("Thread-Pool");<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this.queue = queue;<br>&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; public synchronized void addWorkerThread() {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Thread t = new WorkerThread(this, queue);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; threads.add(t);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; t.start();<br>&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; public synchronized void removeWorkerThread() {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(threads.size()&gt;0) {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; WorkerThread t = (WorkerThread)threads.remove(0);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; t.shutdown();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; public synchronized void <strong>currentStatus</strong>() {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println("-----------------------------------------------");<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println("Thread count = " + threads.size());<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Iterator it = threads.iterator();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; while(it.hasNext()) {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; WorkerThread t = (WorkerThread)it.next();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println(t.getName() + ": " + (t.isIdle() ? "idle" : "busy"));<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println("-----------------------------------------------");<br>&nbsp;&nbsp;&nbsp; }<br>}
<p>currentStatus()方法是为了方便调试，打印出所有线程的当前状态。
<p>最后，Main负责完成main()方法：
<p>package com.crackj2ee.thread;<br>public class Main {<br>&nbsp;&nbsp;&nbsp; public static void main(String[] args) {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; TaskQueue queue = new TaskQueue();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ThreadPool pool = new ThreadPool(queue);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for(int i=0; i&lt;10; i++) {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; queue.putTask(new CalculateTask());<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; queue.putTask(new TimerTask());<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pool.addWorkerThread();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pool.addWorkerThread();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; doSleep(8000);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pool.currentStatus();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pool.addWorkerThread();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pool.addWorkerThread();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pool.addWorkerThread();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pool.addWorkerThread();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pool.addWorkerThread();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; doSleep(5000);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pool.currentStatus();<br>&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; private static void doSleep(long ms) {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; try {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Thread.sleep(ms);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; catch(InterruptedException ie) {}<br>&nbsp;&nbsp;&nbsp; }<br>}
<p>main()一开始放入了20个Task，然后动态添加了一些服务线程，并定期打印线程状态，运行结果如下：
<p>worker-0 start.<br>[CalculateTask 0] start...<br>worker-1 start.<br>[TimerTask 0] start...<br>[TimerTask 0] done.<br>[CalculateTask 1] start...<br>[CalculateTask 0] done.<br>[TimerTask 1] start...<br>[CalculateTask 1] done.<br>[CalculateTask 2] start...<br>[TimerTask 1] done.<br>[TimerTask 2] start...<br>[TimerTask 2] done.<br>[CalculateTask 3] start...<br>-----------------------------------------------<br>Thread count = 2<br>worker-0: busy<br>worker-1: busy<br>-----------------------------------------------<br>[CalculateTask 2] done.<br>[TimerTask 3] start...<br>worker-2 start.<br>[CalculateTask 4] start...<br>worker-3 start.<br>[TimerTask 4] start...<br>worker-4 start.<br>[CalculateTask 5] start...<br>worker-5 start.<br>[TimerTask 5] start...<br>worker-6 start.<br>[CalculateTask 6] start...<br>[CalculateTask 3] done.<br>[TimerTask 6] start...<br>[TimerTask 3] done.<br>[CalculateTask 7] start...<br>[TimerTask 4] done.<br>[TimerTask 7] start...<br>[TimerTask 5] done.<br>[CalculateTask 8] start...<br>[CalculateTask 4] done.<br>[TimerTask 8] start...<br>[CalculateTask 5] done.<br>[CalculateTask 9] start...<br>[CalculateTask 6] done.<br>[TimerTask 9] start...<br>[TimerTask 6] done.<br>[TimerTask 7] done.<br>-----------------------------------------------<br>Thread count = 7<br><strong>worker-0: idle<br></strong>worker-1: busy<br>worker-2: busy<br><strong>worker-3: idle</strong><br>worker-4: busy<br>worker-5: busy<br>worker-6: busy<br>-----------------------------------------------<br>[CalculateTask 7] done.<br>[CalculateTask 8] done.<br>[TimerTask 8] done.<br>[TimerTask 9] done.<br>[CalculateTask 9] done.
<p><strong>仔细观察</strong>：一开始只有两个服务器线程，因此线程状态都是忙，后来线程数增多，6个线程中的两个状态变成idle，说明处于wait()状态。
<p><strong>思考</strong>：本例的线程调度算法其实根本没有，因为这个应用是围绕TaskQueue设计的，不是以Thread Pool为中心设计的。因此，Task调度取决于TaskQueue的getTask()方法，你可以改进这个方法，例如使用优先队列，使优先级高的任务先被执行。
<p>如果所有的服务器线程都处于busy状态，则说明任务繁忙，TaskQueue的队列越来越长，最终会导致服务器内存耗尽。因此，可以限制 TaskQueue的等待任务数，超过最大长度就拒绝处理。许多Web服务器在用户请求繁忙时就会拒绝用户：HTTP 503 SERVICE UNAVAILABLE
<p>多线程读写同一个对象的数据是很普遍的，通常，要避免读写冲突，必须保证任何时候仅有一个线程在写入，有线程正在读取的时候，写入操作就必须等待。简单说，就是要避免&#8220;写-写&#8221;冲突和&#8220;读-写&#8221;冲突。但是同时读是允许的，因为&#8220;读-读&#8221;不冲突，而且很安全。
<p>要实现以上的ReadWriteLock，简单的使用synchronized就不行，我们必须自己设计一个ReadWriteLock类，在读之前，必须先获得&#8220;读锁&#8221;，写之前，必须先获得&#8220;写锁&#8221;。举例说明：
<p>DataHandler对象保存了一个可读写的char[]数组：
<p>package com.crackj2ee.thread;<br>public class DataHandler {<br>&nbsp;&nbsp;&nbsp; // store data:<br>&nbsp;&nbsp;&nbsp; private char[] buffer = "AAAAAAAAAA".toCharArray();<br>&nbsp;&nbsp;&nbsp; private char[] doRead() {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; char[] ret = new char[buffer.length];<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for(int i=0; i<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ret[i] = buffer[i];<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sleep(3);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return ret;<br>&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; private void doWrite(char[] data) {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(data!=null) {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; buffer = new char[data.length];<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for(int i=0; i<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; buffer[i] = data[i];<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sleep(10);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; private void sleep(int ms) {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; try {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Thread.sleep(ms);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; catch(InterruptedException ie) {}<br>&nbsp;&nbsp;&nbsp; }<br>}
<p>doRead()和doWrite()方法是非线程安全的读写方法。为了演示，加入了sleep()，并设置读的速度大约是写的3倍，这符合通常的情况。
<p>为了让多线程能安全读写，我们设计了一个ReadWriteLock：
<p>package com.crackj2ee.thread;<br>public class ReadWriteLock {<br>&nbsp;&nbsp;&nbsp; private int readingThreads = 0;<br>&nbsp;&nbsp;&nbsp; private int writingThreads = 0;<br>&nbsp;&nbsp;&nbsp; private int waitingThreads = 0; // waiting for write<br>&nbsp;&nbsp;&nbsp; private boolean preferWrite = true;<br>&nbsp;&nbsp;&nbsp; public synchronized void readLock() throws InterruptedException {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; while(writingThreads&gt;0 || (preferWrite &amp;&amp; waitingThreads&gt;0))<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this.wait();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; readingThreads++;<br>&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; public synchronized void readUnlock() {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; readingThreads--;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; preferWrite = true;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; notifyAll();<br>&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; public synchronized void writeLock() throws InterruptedException {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; waitingThreads++;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; try {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; while(readingThreads&gt;0 || writingThreads&gt;0)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this.wait();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; finally {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; waitingThreads--;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; writingThreads++;<br>&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; public synchronized void writeUnlock() {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; writingThreads--;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; preferWrite = false;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; notifyAll();<br>&nbsp;&nbsp;&nbsp; }<br>}
<p>readLock()用于获得读锁，readUnlock()释放读锁，writeLock()和writeUnlock()一样。由于锁用完必须释放，因此，必须保证lock和unlock匹配。我们修改DataHandler，加入ReadWriteLock：
<p>package com.crackj2ee.thread;<br>public class DataHandler {<br>&nbsp;&nbsp;&nbsp; // store data:<br>&nbsp;&nbsp;&nbsp; private char[] buffer = "AAAAAAAAAA".toCharArray();<br>&nbsp;&nbsp;&nbsp; // lock:<br>&nbsp;&nbsp;&nbsp; private ReadWriteLock lock = new ReadWriteLock();<br>&nbsp;&nbsp;&nbsp; public char[] read(String name) throws InterruptedException {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println(name + " waiting for read...");<br><strong>lock.readLock();</strong><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; try {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; char[] data = doRead();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println(name + " reads data: " + new String(data));<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return data;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; finally {<br><strong>lock.readUnlock();<br></strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; public void write(String name, char[] data) throws InterruptedException {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println(name + " waiting for write...");<br><strong>lock.writeLock();<br></strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; try {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println(name + " wrote data: " + new String(data));<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; doWrite(data);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; finally {<br><strong>lock.writeUnlock();<br></strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; private char[] doRead() {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; char[] ret = new char[buffer.length];<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for(int i=0; i<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ret[i] = buffer[i];<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sleep(3);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return ret;<br>&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; private void doWrite(char[] data) {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(data!=null) {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; buffer = new char[data.length];<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for(int i=0; i<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; buffer[i] = data[i];<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sleep(10);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; private void sleep(int ms) {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; try {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Thread.sleep(ms);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; catch(InterruptedException ie) {}<br>&nbsp;&nbsp;&nbsp; }<br>}
<p>public方法read()和write()完全封装了底层的ReadWriteLock，因此，多线程可以安全地调用这两个方法：
<p>// ReadingThread不断读取数据：<br>package com.crackj2ee.thread;<br>public class ReadingThread extends Thread {<br>&nbsp;&nbsp;&nbsp; private DataHandler handler;<br>&nbsp;&nbsp;&nbsp; public ReadingThread(DataHandler handler) {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this.handler = handler;<br>&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; public void run() {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for(;;) {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; try {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; char[] data = handler.read(getName());<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Thread.sleep((long)(Math.random()*1000+100));<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; catch(InterruptedException ie) {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; break;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; }<br>}
<p>// WritingThread不断写入数据，每次写入的都是10个相同的字符：<br>package com.crackj2ee.thread;<br>public class WritingThread extends Thread {<br>&nbsp;&nbsp;&nbsp; private DataHandler handler;<br>&nbsp;&nbsp;&nbsp; public WritingThread(DataHandler handler) {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this.handler = handler;<br>&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; public void run() {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; char[] data = new char[10];<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for(;;) {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; try {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; fill(data);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; handler.write(getName(), data);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Thread.sleep((long)(Math.random()*1000+100));<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; catch(InterruptedException ie) {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; break;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; //&nbsp;产生一个A-Z随机字符，填入char[10]:<br>&nbsp;&nbsp;&nbsp; private void fill(char[] data) {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; char c = (char)(Math.random()*26+'A');<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for(int i=0; i<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; data[i] = c;<br>&nbsp;&nbsp;&nbsp; }<br>}
<p>最后Main负责启动这些线程：
<p>package com.crackj2ee.thread;<br>public class Main {<br>&nbsp;&nbsp;&nbsp; public static void main(String[] args) {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DataHandler handler = new DataHandler();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Thread[] ts = new Thread[] {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; new ReadingThread(handler),<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; new ReadingThread(handler),<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; new ReadingThread(handler),<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; new ReadingThread(handler),<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; new ReadingThread(handler),<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; new WritingThread(handler),<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; new WritingThread(handler)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; };<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for(int i=0; i<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ts[i].start();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; }<br>}
<p>我们启动了5个读线程和2个写线程，运行结果如下：
<p>Thread-0 waiting for read...<br>Thread-1 waiting for read...<br>Thread-2 waiting for read...<br>Thread-3 waiting for read...<br>Thread-4 waiting for read...<br>Thread-5 waiting for write...<br>Thread-6 waiting for write...<br>Thread-4 reads data: AAAAAAAAAA<br>Thread-3 reads data: AAAAAAAAAA<br>Thread-2 reads data: AAAAAAAAAA<br>Thread-1 reads data: AAAAAAAAAA<br>Thread-0 reads data: AAAAAAAAAA<br>Thread-5 wrote data: EEEEEEEEEE<br>Thread-6 wrote data: MMMMMMMMMM<br>Thread-1 waiting for read...<br>Thread-4 waiting for read...<br>Thread-1 reads data: MMMMMMMMMM<br>Thread-4 reads data: MMMMMMMMMM<br>Thread-2 waiting for read...<br>Thread-2 reads data: MMMMMMMMMM<br>Thread-0 waiting for read...<br>Thread-0 reads data: MMMMMMMMMM<br>Thread-4 waiting for read...<br>Thread-4 reads data: MMMMMMMMMM<br>Thread-2 waiting for read...<br>Thread-5 waiting for write...<br>Thread-2 reads data: MMMMMMMMMM<br>Thread-5 wrote data: GGGGGGGGGG<br>Thread-6 waiting for write...<br>Thread-6 wrote data: AAAAAAAAAA<br>Thread-3 waiting for read...<br>Thread-3 reads data: AAAAAAAAAA<br>......
<p>可以看到，每次读/写都是完整的原子操作，因为我们每次写入的都是10个相同字符。并且，每次读出的都是最近一次写入的内容。
<p>如果去掉ReadWriteLock：
<p>package com.crackj2ee.thread;<br>public class DataHandler {<br>&nbsp;&nbsp;&nbsp; // store data:<br>&nbsp;&nbsp;&nbsp; private char[] buffer = "AAAAAAAAAA".toCharArray();<br>&nbsp;&nbsp;&nbsp; public char[] read(String name) throws InterruptedException {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; char[] data = doRead();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println(name + " reads data: " + new String(data));<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return data;<br>&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; public void write(String name, char[] data) throws InterruptedException {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println(name + " wrote data: " + new String(data));<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; doWrite(data);<br>&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; private char[] doRead() {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; char[] ret = new char[10];<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for(int i=0; i&lt;10; i++) {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ret[i] = buffer[i];<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sleep(3);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return ret;<br>&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; private void doWrite(char[] data) {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for(int i=0; i&lt;10; i++) {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; buffer[i] = data[i];<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sleep(10);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; private void sleep(int ms) {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; try {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Thread.sleep(ms);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; catch(InterruptedException ie) {}<br>&nbsp;&nbsp;&nbsp; }<br>}
<p>运行结果如下：
<p>Thread-5 wrote data: AAAAAAAAAA<br>Thread-6 wrote data: MMMMMMMMMM<br>Thread-0 reads data: AAAAAAAAAA<br>Thread-1 reads data: AAAAAAAAAA<br>Thread-2 reads data: AAAAAAAAAA<br>Thread-3 reads data: AAAAAAAAAA<br>Thread-4 reads data: AAAAAAAAAA<br>Thread-2 reads data: MAAAAAAAAA<br>Thread-3 reads data: MAAAAAAAAA<br>Thread-5 wrote data: CCCCCCCCCC<br>Thread-1 reads data: MAAAAAAAAA<br>Thread-0 reads data: MAAAAAAAAA<br>Thread-4 reads data: MAAAAAAAAA<br><strong>Thread-6 wrote data: EEEEEEEEEE<br>Thread-3 reads data: EEEEECCCCC<br>Thread-4 reads data: EEEEEEEEEC<br>Thread-1 reads data: EEEEEEEEEE</strong>
<p>可以看到在Thread-6写入EEEEEEEEEE的过程中，3个线程读取的内容是不同的。
<p><strong>思考</strong>
<p>java的synchronized提供了最底层的物理锁，要在synchronized的基础上，实现自己的逻辑锁，就必须仔细设计ReadWriteLock。
<p>Q: lock.readLock()为什么不放入try{ }&nbsp;内？<br>A: 因为readLock()会抛出InterruptedException，导致readingThreads++不执行，而readUnlock()在 finally{ } 中，导致readingThreads--执行，从而使readingThread状态出错。writeLock()也是类似的。
<p>Q: preferWrite有用吗？<br>A: 如果去掉preferWrite，线程安全不受影响。但是，如果读取线程很多，上一个线程还没有读取完，下一个线程又开始读了，就导致写入线程长时间无法获得writeLock；如果写入线程等待的很多，一个接一个写，也会导致读取线程长时间无法获得readLock。preferWrite的作用是让读 /写交替执行，避免由于读线程繁忙导致写无法进行和由于写线程繁忙导致读无法进行。
<p>Q: notifyAll()换成notify()行不行？<br>A: 不可以。由于preferWrite的存在，如果一个线程刚读取完毕，此时preferWrite=true，再notify()，若恰好唤醒的是一个读线程，则while(writingThreads&gt;0 || (preferWrite &amp;&amp; waitingThreads&gt;0))可能为true导致该读线程继续等待，而等待写入的线程也处于wait()中，结果所有线程都处于wait ()状态，谁也无法唤醒谁。因此，notifyAll()比notify()要来得安全。程序验证notify()带来的死锁：
<p>Thread-0 waiting for read...<br>Thread-1 waiting for read...<br>Thread-2 waiting for read...<br>Thread-3 waiting for read...<br>Thread-4 waiting for read...<br>Thread-5 waiting for write...<br>Thread-6 waiting for write...<br>Thread-0 reads data: AAAAAAAAAA<br>Thread-4 reads data: AAAAAAAAAA<br>Thread-3 reads data: AAAAAAAAAA<br>Thread-2 reads data: AAAAAAAAAA<br>Thread-1 reads data: AAAAAAAAAA<br>Thread-5 wrote data: CCCCCCCCCC<br>Thread-2 waiting for read...<br>Thread-1 waiting for read...<br>Thread-3 waiting for read...<br>Thread-0 waiting for read...<br>Thread-4 waiting for read...<br>Thread-6 wrote data: LLLLLLLLLL<br>Thread-5 waiting for write...<br>Thread-6 waiting for write...<br>Thread-2 reads data: LLLLLLLLLL<br>Thread-2 waiting for read...<br>（运行到此不动了）
<p>注意到这种死锁是由于所有线程都在等待别的线程唤醒自己，结果都无法醒过来。这和两个线程希望获得对方已有的锁造成死锁不同。因此多线程设计的难度远远高于单线程应用。</p>
<img src ="http://www.blogjava.net/wealupa/aggbug/132683.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/wealupa/" target="_blank">常言笑</a> 2007-07-27 09:17 <a href="http://www.blogjava.net/wealupa/archive/2007/07/27/132683.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>详细讲解Java中集合类的使用</title><link>http://www.blogjava.net/wealupa/archive/2007/07/03/127781.html</link><dc:creator>常言笑</dc:creator><author>常言笑</author><pubDate>Tue, 03 Jul 2007 03:21:00 GMT</pubDate><guid>http://www.blogjava.net/wealupa/archive/2007/07/03/127781.html</guid><wfw:comment>http://www.blogjava.net/wealupa/comments/127781.html</wfw:comment><comments>http://www.blogjava.net/wealupa/archive/2007/07/03/127781.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/wealupa/comments/commentRss/127781.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/wealupa/services/trackbacks/127781.html</trackback:ping><description><![CDATA[<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Enumeration是一个接口，主要提供了枚举集合对象中所有对象的功能。建议使用Iterator接口，它提供了和Enumeration一样的功能，而且还有删除集合元素的方法。hasMoreElements()方法用来判断Enumeration接口中是否还有元素，返回一个boolean值。Enumeration是java &nbsp; 1.1 &nbsp; 的遗留物，请不要继续使用。在java &nbsp; 2中使用Iterator来替代。<br><br><span style="FONT-SIZE: 10pt"><span>Collection<br>├List<br>│├LinkedList<br>│├ArrayList<br>│└Vector<br>│</span>　<span>└Stack<br>└Set<br>Map<br>├Hashtable<br>├HashMap<br>└WeakHashMap<br><br><span style="FONT-SIZE: 10pt">Map</span><span style="FONT-SIZE: 10pt">接口<span><br></span>　　请注意，<span>Map</span>没有继承<span>Collection</span>接口，<span>Map</span>提供<span>key</span>到<span>value</span>的映射。一个<span>Map</span>中不能包含相同的<span>key</span>，每个<span>key</span>只能映射一个<span> value</span>。<span>Map</span>接口提供<span>3</span>种集合的视图，<span>Map</span>的内容可以被当作一组<span>key</span>集合，一组<span>value</span>集合，或者一组<span>key-value</span>映射。<span></span></span></span></span>
<img src ="http://www.blogjava.net/wealupa/aggbug/127781.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/wealupa/" target="_blank">常言笑</a> 2007-07-03 11:21 <a href="http://www.blogjava.net/wealupa/archive/2007/07/03/127781.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>POJO应用架构：Spring与EJB 3.0的对比</title><link>http://www.blogjava.net/wealupa/archive/2007/05/10/116376.html</link><dc:creator>常言笑</dc:creator><author>常言笑</author><pubDate>Thu, 10 May 2007 01:00:00 GMT</pubDate><guid>http://www.blogjava.net/wealupa/archive/2007/05/10/116376.html</guid><wfw:comment>http://www.blogjava.net/wealupa/comments/116376.html</wfw:comment><comments>http://www.blogjava.net/wealupa/archive/2007/05/10/116376.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/wealupa/comments/commentRss/116376.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/wealupa/services/trackbacks/116376.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 爱因斯坦曾经说过："每件事物都应该尽可能简单，而不是更简单"。的确，对科学真理的追求都是为了简化理论的根本假设，这样我们才能处理真正麻烦的问题。企业级软件的开发也是这样的。<br><br>　　简化企业级软件开发的关键是提供一个隐藏了复杂性（例如事务、安全性和永续性）的应用框架。良好设计的框架组件可以提升代码的重复使用（reuse）能力，提高开发效率，从而得到更好的软件质量。但是，目前J2EE 1.4中的EJB 2.1框架组件被人们普遍认为是设计较差的和过于复杂的。Java开发者对EJB 2.1很不满，他们已经试验了多种其它的用于中间件服务传送的方法。最引人注目的，下面两个框架组件已经引起开发者的巨大兴趣和积极的反映。它们很可能成为未来企业级Java应用程序可供选择的框架组件。<br><br>　　&#183; Spring框架组件是一个流行的，但是非标准的开放源代码框架组件。它主要是由Interface21 Inc.公司开发和控制的。Spring框架组件的架构是基于依赖注入（DI）设计模式的。Spring可以单独地或者与现有的应用程序服务器一起工作，它大量地使用XML配置文件。<br><br>　　&#183; EJB 3.0框架组件是一个标准的框架组件，由Java社区组织（JCP）定义，并受到所有主流的J2EE厂商支持。预发布的EJB 3.0规范的开放源代码和商业实现都可以在JBoss和Oracle上看到了。EJB 3.0大量使用Java注释（annotation）。<br><br>　　这两个框架组件的核心设计理念是相同的：两者的目标都是把中间件服务传递给松散耦合的简单旧式Java对象（POJO）。这些框架组件通过在运行时截取执行内容或向POJO注入服务对象，把应用程序服务与POJO捆绑在一起。POJO本身不关心捆绑的过程，并且对框架组件几乎没有依赖。其结果是，开发者可以聚焦于业务逻辑，个人可以在没有框架组件的情况下测试他们的POJO。此外，由于POJO不需要从框架组件中继承或实现框架组件接口，开发者建立继承结构和构建应用程序的时候都有高度的灵活性。<br><br>　　但是，尽管两者的设计理念是相同的，它们传递POJO服务时却采用了完全不同的方法。尽管目前已经出版了大量的图书和文章来把Spring或EJB 3.0与EJB 2.1进行对比，但是它们都没有对Spring与EJB 3.0之间的差异进行认真的研究。在本文中，我将研究Spring和EJB 3.0框架组件之间的关键差异，并讨论它们的优缺点。本文的主题也可以应用在其它一些名气稍小的企业级中间件框架组件上，因为它们都聚焦于"松散耦合的POJO"设计。我希望本文能够帮助你选择符合需求的最佳的框架组件。 <br><br>　　<strong>厂商无关性（Independence）<br></strong><br>　　开发者选择某种Java平台的一个最重要的理由就是该平台的厂商无关性。EJB 3.0是一个开放的、标准的、具有厂商无关性的平台。EJB 3.0规范是由企业级Java团体中所有主流开放源代码和商业厂商开发和支持的。EJB 3.0框架组件把开发人员与应用程序服务器实现（implementation）隔离开来了。例如，尽管JBoss的EJB 3.0实现是基于Hibernate的，而Oracle的EJB 3.0实现是基于TopLink的，但是开发人员并不需要学习Hibernate或TopLink的特殊API，就可以让他们的应用程序在JBoss和Oracle上运行。厂商无关性把EJB 3.0框架组件与其它的POJO中间件框架组件区分开来了。<br><br>　　但是，很多EJB 3.0的批评家迅速指出，在写这篇文章的时候，EJB 3.0规范还没有达到最终发表的版本。在EJB 3.0被所有主流的J2EE厂商采用之前可能还需要一到两年时间。但是，即使你的应用程序服务器还没有自然地（natively）支持EJB 3.0，你还是可以通过下载和安装一个"嵌入式的" EJB 3.0产品，在服务器上运行EJB 3.0应用程序。例如，JBoss嵌入式EJB 3.0产品是开放源代码的，可以在任何与J2SE-5.0兼容的环境中（例如，在Java应用程序服务器中）运行。它现在正在进行beta测试。其它的厂商也可能很快发布他们的嵌入式EJB 3.0产品，特别是用于规范的"数据永续性"部分的产品。<br><br>　　另一方面，Spring一直是非标准的技术，而且在可以预见的未来它仍然是这样的。尽管你可以把Spring框架组件与任何应用程序服务器一起使用，但是Spring应用程序都被"锁定"在Spring自身和你所选择的集成到Spring中的特定服务中了。<br><br>　　&#183; 尽管Spring框架组件是一个开放源代码项目，但是它仍然拥有配置文件的专利XML格式和专利编程接口。当然，这类"锁定"发生在任何非标准的产品上，Spring也不例外。但是它却造成了：你的Spring应用程序的长期生存能力依赖于Spring项目本身（或Interface21 Inc公司，它雇佣了大多数Spring核心开放人员）。此外，如果你使用任何Spring特定的服务，例如Spring事务管理器或Spring MVC，你就被"锁定"在这些API中了。<br><br>　　&#183; Spring应用程序需要知道后台的服务提供者。例如，对于数据持续（data persistence）服务来说，Spring框架组件为JDBC、Hibernate、iBatis和JDO使用了不同的DAO和模板辅助类。因此，如果你希望为Spring应用程序更换持续服务提供者（例如从JDBC切换到Hibernate），你就必须重构自己的应用程序代码，使用新的辅助类。<br><br>　　<strong>服务集成</strong><br><br>　　从较高的层次看，Spring框架组件位于应用程序服务器和服务类库之上。其服务集成代码（例如数据访问模板和辅助类）位于框架组件之中，并暴露给应用程序开发者。与此不同的是，EJB 3.0框架组件被紧密地集成到应用程序服务器中，服务集成代码被封装在标准的接口中。<br><br>　　其结果是，EJB 3.0厂商可以积极地优化总体性能和开发者体验。例如，在JBoss的 EJB 3.0实现中，使用EntityManager保持实体BeanPOJO的时候，下层Hibernate对话事务会自动地与该调用方法的JTA事务联系在一起，当JTA事务提交的时候，它也会提交。如果使用简单的@PersistenceContext注释（本文后面有一个例子），你甚至于可以在有状态的（stateful）对话bean中把EntityManager和它的下层Hibernate事务捆绑到一个应用程序事务上。该应用程序事务在一个对话中跨越了多个线程，它在事务性的Web应用程序（例如多页面购物车）中是非常有效的。由于在JBoss中，EJB 3.0框架组件、Hibernate和Tomcat紧密集成，上述的简单和集成的编程接口才得以实现。Oracle的EJB 3.0框架组件和其下层Toplink持续服务之间的也实现了类似层次的集成。<br><br>　　EJB 3.0中集成服务的另一个例子是群集（clustering）支持。如果你在服务器群集中部署EJB 3.0应用程序，那么所有的失效接续（fail-over）、负载均衡、分布式缓存和状态复制服务都是可以自动地供应用程序使用的。下层群集服务都隐藏在EJB 3.0编程接口后面，它们对于EJB 3.0开发人员来说是完全透明的。<br><br>　　在Spring中，优化框架组件与服务之间的交互操作要困难得多。例如，为了使用Spring的宣告式事务服务来管理Hibernate事务，你必须在XML配置文件中显式地配置Spring TransactionManager和Hibernate SessionFactory对象。Spring应用程序开发者必须显式地管理跨多个HTTP请求的事务。此外，要在Spring应用程序中使用群集服务也没有简单的途径。<br><br>　　<strong>服务集成的灵活性</strong><br><br>　　由于Spring中的服务集成代码是作为编程接口的一部分暴露的，应用程序开发者可以根据需要灵活地集成服务。这个特性允许你集成自己的"轻量级"应用程序服务器。Spring最普遍的使用方式是把Tomcat和Hibernate"粘合"在一起来提供简单的数据库驱动web应用程序。在这种情况下，Spring自身提供事务服务，Hibernate提供持续（persistence）服务--这种组织方式在Spring中建立了一个微型应用程序服务器。<br><br>　　EJB 3.0应用程序服务器没有赋予你挑选服务的灵活性。在大多数情况中，你得到一组事先包装好的特性，而你只需要其中的一部分。但是，如果应用程序服务器由模式化的内部设计主导（类似JBoss），那么你就可能把它分开，去掉一些不必要的特性。在任何情况下，定制成熟的应用程序服务器都不是一个简单的事情。<br><br>　　当然，如果应用程序的范围超越了单节点，那么你可能需要捆绑来自普通应用程序服务器的服务（例如资源缓冲池、消息队列和群集）。在总体的资源消耗方面，Spring解决方案与任何EJB 3.0解决方案一样，都是"重量级"的。<br><br>　　在Spring中，灵活的服务集成使得我们更容易把仿制（mock）对象（而不是实际的服务对象）捆绑到应用程序，用于在容器外部进行单元测试。在EJB 3.0应用程序中，大多数组件都是简单的POJO，我们可以很容易地在容器外部测试这些它们。但是对于测试那些涉及到容器服务的对象（例如持续EntityManager），我们推荐在容器内测试，因为比起仿制对象的方法，它们更简单、更牢固、更精确。 XML与注释的比较<br>从应用程序开发者的角度来看，Spring的编程接口主要是基于XML配置文件的，而EJB 3.0广泛使用了Java注释。XML文件可以表达复杂的关系，但是它们同时也很冗长、牢固程度也较低。注释简单明了，但是在注释中我们却很难表达复杂的或层次的结构。<br><br>　　Spring和EJB 3.0关于XML或注释的选择是依赖于这两个框架组件后面的架构的：由于注释只能保存相当少的配置信息，只有预先集成的框架组件（类似在框架组件中已经完成了大多数预备工作）可以广泛地把注释作为配置选项。我们已经讨论过了，EJB 3.0符合这种需求，而Spring作为一个通用的DI框架组件，不符合这个需求。<br><br>　　当然，EJB 3.0和Spring都在学习对方的最佳特性，它们都在某个程度上支持XML和注释。例如，在EJB 3.0中XML配置文件是一个可选的重载机制，可以用于改变注释的默认行为。注释也可以用于配置某㏒pring服务。<br><br>　　认识XML和注释之间的区别的最好途径是通过示例。在下一部分，我们会看到Spring和EJB 3.0是如何为应用程序提供关键服务的。<br><br><strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 宣告式服务</strong>（Declarative Services）<br><br>　　Spring和EJB 3.0都把运行时服务（例如事务、安全性、日志记录、消息和定制服务）捆绑到应用程序上。由于这些服务都没有直接地与应用程序的业务逻辑相关联，因此它们不由应用程序自身来管理。作为代替，这些服务是在运行时由服务容器（例如Spring或EJB 3.0）透明地应用在程序上的。开发者（或管理员）配置容器并告诉容器如何/什么时候应用服务。<br><br>　　EJB 3.0使用Java注释配置宣告式服务，而Spring使用XML配置文件。在大多数情况下，对于这类服务，EJB 3.0注释方法更加简单，更加优雅。下面是一个在EJB 3.0中给POJO方法应用事务服务的例子。<br><br><code>public class Foo {<br><br>@TransactionAttribute(TransactionAttributeType.REQUIRED)<br>public bar () {<br>// 执行某些操作 ...<br>} <br>}</code><br>　　你也可以在一个代码片断中定义多个属性，应用多个服务。下面是一个在EJB 3.0中同时给POJO应用了事务和安全性服务的例子：<br><br><code>@SecurityDomain("other")<br>public class Foo {<br><br>@RolesAllowed({"managers"})<br>@TransactionAttribute(TransactionAttributeType.REQUIRED)<br>public bar () {<br>// 执行某些操作 ...<br>} <br>}</code><br>　　使用XML指定代码属性和配置宣告式服务可能导致冗长的和不稳定的配置文件。下面是一个在Spring应用程序中利用XML元素给Foo.bar()方法应用一个非常简单的Hibernate事务服务的例子：<br><br><code>＜!-- Setup the transaction interceptor --＞<br>＜bean id="foo" <br>class="org.springframework.transaction<br>.interceptor.TransactionProxyFactoryBean"＞<br><br>＜property name="target"＞<br>＜bean class="Foo"/＞<br>＜/property＞<br><br>＜property name="transactionManager"＞<br>＜ref bean="transactionManager"/＞<br>＜/property＞<br><br>＜property name="transactionAttributeSource"＞<br>＜ref bean="attributeSource"/＞<br>＜/property＞<br>＜/bean＞<br><br>＜!-- Setup the transaction manager for Hibernate --＞<br>＜bean id="transactionManager" <br>class="org.springframework.orm<br>.hibernate.HibernateTransactionManager"＞<br><br>＜property name="sessionFactory"＞<br>＜!-- you need to setup the sessionFactory bean in <br>yet another XML element -- omitted here --＞<br>＜ref bean="sessionFactory"/＞<br>＜/property＞<br>＜/bean＞<br><br>＜!-- Specify which methods to apply transaction --＞<br>＜bean id="transactionAttributeSource"<br>class="org.springframework.transaction<br>.interceptor.NameMatchTransactionAttributeSource"＞<br><br>＜property name="properties"＞<br>＜props＞<br>＜prop key="bar"＞<br>＜/props＞<br>＜/property＞<br>＜/bean＞</code><br>　　如果你给同一个POJO添加多个拦截器（interceptor，例如安全性拦截器），那么XML的复杂程度会呈几何级数增长。Spring意识到了只使用XML配置文件的局限性，它现在支持在Java源代码中使用Apache通用元数据指定事务属性。在最新的Spring 1.2中，还支持JDK-1.5样式的注释。如果你要使用事务元数据，就需要把上面的transactionAttributeSource bean改变成AttributesTransactionAttributeSource示例，并增加与元数据拦截器相关的额外配置。<br><br><code>＜bean id="autoproxy"<br>class="org.springframework.aop.framework.autoproxy<br>.DefaultAdvisorAutoProxyCreator"/＞<br>＜bean id="transactionAttributeSource"<br>class="org.springframework.transaction.interceptor<br>.AttributesTransactionAttributeSource"<br>autowire="constructor"/＞<br>＜bean id="transactionInterceptor"<br>class="org.springframework.transaction.interceptor<br>.TransactionInterceptor"<br>autowire="byType"/＞<br>＜bean id="transactionAdvisor"<br>class="org.springframework.transaction.interceptor<br>.TransactionAttributeSourceAdvisor"<br>autowire="constructor"/＞<br>＜bean id="attributes"<br>class="org.springframework.metadata.commons<br>.CommonsAttributes"/＞</code><br>　　当你拥有很多事务方法的时候，Spring元数据简化了transactionAttributeSource元素。但是它没有解决XML配置文件的基本问题--冗长和脆弱，还是需要使用事务拦截器、transactionManager和transactionAttributeSource。<br><br>　　<strong>依赖注入</strong>（Dependency Injection）<br><br>　　中间件容器的关键优势在于它们允许开发者建立松散耦合的应用程序。服务的客户端只需要知道服务的接口。容器用具体的实现来初始化服务对象，并使客户端能够访问它们。这就允许了容器在不同的服务实现之间进行切换，而不需要改变接口或客户端代码。<br><br>　　依赖注入（DI）模式是实现松散耦合的应用程序的最好的方法之一。它比旧方法（例如通过JNDI的依赖查找或容器回调）更易于使用、更优雅。使用DI的时候，框架组件充当建立服务对象的对象工厂，并根据运行时配置，把这些服务对象注入应用程序POJO中。从应用程序开发者的角度来看，当客户端POJO需要使用某种服务对象的时候，它们会自动地获取该对象。 <br><br>　　Spring和EJB 3.0都给DI模式提供了广泛的支持，但是它们之间有一些深刻的差异。Spring支持普通的、但是复杂的、基于XML配置文件的DI API；EJB 3.0通过简单的注释支持大多数通用服务对象（例如EJB和上下文关系对象）和JNDI对象的注入操作。<br><br>　　EJB 3.0 DI注释非常简洁，易于使用。@Resource标签注入大多数通用服务对象和JNDI对象。下面的例子演示了如何把JNDI中的服务器的默认DataSource对象注入POJO的一个字段变量中。DefaultDS是JNDI用于表示DataSource的名称。在第一次使用myDb变量之前，会把正确的值自动地赋给它。 <br><br><code>public class FooDao {<br><br>@Resource (name="DefaultDS")<br>DataSource myDb;<br><br>// 使用 myDb 获取数据库的JDBC连接<br>}</code><br>　　作为对字段变量直接注入的补充，我们还可以使用EJB 3.0中的@Resource注释，通过设置（setter）方法来注入对象。例如，下面的例子就注入了一个对话上下文关系（context）对象。应用程序一直没有显式调用设置方法--该方法在被其它的任何方法调用之前，会先被容器调用。<br><br><code>@Resource <br>public void setSessionContext (SessionContext ctx) { <br>sessionCtx = ctx; <br>} </code><br>　　对于更加复杂的服务对象，已经定义了一些专用的注入注释。例如，@EJB注释用于注入EJB stub，@PersistenceContext注释用于注入EntityManager对象（它为EJB 3.0实体bean处理数据库访问）。下面的例子演示了如何向一个有状态的对话bean注入EntityManager对象。@PersistenceContext注释的type属性指明被注入的EntityManager拥有扩展的事务上下文关系--它不会自动地与JTA事务管理器一起提交，因此它可以用于那些在一个对话中跨越多个线程的应用程序事务。<br><br><code>@Stateful<br>public class FooBean implements Foo, Serializable {<br><br>@PersistenceContext(<br>type=PersistenceContextType.EXTENDED<br>)<br>protected EntityManager em;<br><br>public Foo getFoo (Integer id) {<br>return (Foo) em.find(Foo.class, id);<br>}<br>}</code><br>　　EJB 3.0规范定义了可以通过注释注入的服务器资源。但是它不支持用户自定义的应用程序POJO的彼此相互注入。<br><br>　　在Spring中，你首先需要为POJO的服务对象定义一个设置方法（或者带参数的构造函数）。下面的例子显示POJO需要一个指向Hibernate对话工厂的指针。<br><br><code>public class FooDao {<br><br>HibernateTemplate hibernateTemplate;<br><br>public void setHibernateTemplate (HibernateTemplate ht) {<br>hibernateTemplate = ht;<br>}<br><br>// 使用 Hibernate 模板访问数据<br>public Foo getFoo (Integer id) {<br>return (Foo) hibernateTemplate.load (Foo.class, id);<br>}<br>}</code><br>　　接下来，你可以指定容器如何在运行时通过XML元素链获取服务对象并把它捆绑到POJO上。下面的例子演示了把数据源捆绑到Hibernate对话工厂，把对话捆绑到Hibernate模板对象，最后把模板对象捆绑到应用程序POJO的XML元素。这段Spring代码如此复杂的部分原因在于我们必须手动地注入下层Hibernate管道对象，而EJB 3.0 EntityManager是由服务器自动地管理和配置的。但是这又让我们回到了Spring没有像EJB 3.0那样与服务紧密集成的讨论中了。<br><br><code>＜bean id="dataSource" <br>class="org.springframework<br>.jndi.JndiObjectFactoryBean"＞<br>＜property name="jndiname"＞<br>＜value＞java:comp/env/jdbc/MyDataSource＜/value＞<br>＜/property＞<br>＜/bean＞<br><br>＜bean id="sessionFactory" <br>class="org.springframework.orm<br>.hibernate.LocalSessionFactoryBean"＞<br>＜property name="dataSource"＞<br>＜ref bean="dataSource"/＞<br>＜/property＞<br>＜/bean＞<br><br>＜bean id="hibernateTemplate" <br>class="org.springframework.orm<br>.hibernate.HibernateTemplate"＞<br>＜property name="sessionFactory"＞<br>＜ref bean="sessionFactory"/＞<br>＜/property＞ <br>＜/bean＞<br><br>＜bean id="fooDao" class="FooDao"＞<br>＜property name="hibernateTemplate"＞<br>＜ref bean="hibernateTemplate"/＞<br>＜/property＞<br>＜/bean＞<br><br>＜!-- The hibernateTemplate can be injected<br>into more DAO objects --＞</code><br>　　尽管在Spring中基于XML的依赖注入语法是复杂的，但是它却很强大。你可以把任何POJO（包括你在应用程序中定义的）注入另一个POJO。如果你真的希望在EJB 3.0应用程序中使用Spring的依赖注入能力，你可以通过JNDI把Spring bean工厂注入EJB中。在某些EJB 3.0应用程序服务器中，厂商可能定义了额外的非标准的API，以注入任意的POJO。其中一个很好的例子是JBoss MicroContainer，它甚至比Spring更普通，因为它处理了面向方面编程（AOP）的依赖性。<br><br>　　<strong>结论</strong><br><br>　　尽管Spring和EJB 3.0的目标都是为松散耦合的POJO提供企业级服务，但是它们是使用截然不同的方法来达到这个目标的。在这两个框架组件中都大量地使用了依赖注入（DI）。<br><br>　　使用EJB 3.0的时候，基于标准的方法、注释的大量使用、以及与应用程序服务器的紧密集成形成了强大的厂商无关性和开发者的高效率。使用Spring的时候，一致地使用依赖注入和集中的XML配置文件，允许开发者构造更加灵活的应用程序，并在同一时刻使用多个应用服务<br>
<img src ="http://www.blogjava.net/wealupa/aggbug/116376.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/wealupa/" target="_blank">常言笑</a> 2007-05-10 09:00 <a href="http://www.blogjava.net/wealupa/archive/2007/05/10/116376.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Ofbiz 介绍</title><link>http://www.blogjava.net/wealupa/archive/2007/04/19/111971.html</link><dc:creator>常言笑</dc:creator><author>常言笑</author><pubDate>Thu, 19 Apr 2007 08:06:00 GMT</pubDate><guid>http://www.blogjava.net/wealupa/archive/2007/04/19/111971.html</guid><wfw:comment>http://www.blogjava.net/wealupa/comments/111971.html</wfw:comment><comments>http://www.blogjava.net/wealupa/archive/2007/04/19/111971.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/wealupa/comments/commentRss/111971.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/wealupa/services/trackbacks/111971.html</trackback:ping><description><![CDATA[<div class="contentdiv pkg">
<h2 class=diaryTitle>&nbsp;</h2>
<p>&nbsp;</p>
<p>1.Ofbiz 介绍：<br><br>Ofbiz(<a href="http://www.ofbiz.org/" target=_blank><!--
***Rojo:Ins:/Tag:CloseOne: A before A
--></a><a href="http://www.ofbiz.org/" target=_blank><u><font color=#800080>http://www.ofbiz.org/</font></u></a>) 是 Open Source 的商务软件系统，充分利用了各优秀的的Open Source 项目，<br>像 Tomcat, Ant, BeanShell, Jboss 等，构建了一个强大的系统平台，Ofbiz 已经完成了大部分商务类软件系统<br>都需要的部件，像用户认证、工作流、商务规则处理等，Ofbiz 的核心技术在于 Entity Engine，其他的组件基本都<br>是基于它的。简单来说 Entity Engine 的主要功能是将数据库表创建、对象与数据表的映射、对象的查询等做了强大<br>封装，你可以在一个简单的 XML 文件中定义数据库表结构，Ofbiz 会自动帮你在数据库建表，并动态生成映射对象，<br>你在程序中可以只考虑对 Object 的处理，Ofbiz 会自动通过事务逻辑更新到数据库中。Ofbiz 宣称的优点之一是用<br>很少的 Code 完成复杂的处理。 <br><br>2.Ofbiz 下载与安装<br><br>首先要安装 J2SDK1.4，到 <a href="http://java.sun.com/" target=_blank><!--
***Rojo:Ins:/Tag:CloseOne: A before A
--></a><a href="http://java.sun.com/" target=_blank><u><font color=#0000ff>http://java.sun.com/</font></u></a> 上下载，安装后设定 JAVA_HOME 环境变量为 J2SDK 的安装目录。<br><br>访问网站 <a href="http://www.ofbiz.org，上面有下载的连接，请选择/" target=_blank><!--
***Rojo:Ins:/Tag:CloseOne: A before A
--></a><a href="http://www.ofbiz.org，上面有下载的连接，请选择/" target=_blank><u><font color=#0000ff>http://www.ofbiz.org，上面有下载的连接，请选择/</font></u></a> Complete 包，因为这个包中已经包含了运行 Ofbiz <br>的所有东西，下载下来解开后就可以运行了。<br><br>解开 Ofbiz 包到一个目录下，假设是 &#8220;C:ofbiz&#8221;，该目录下将会有 catalina 和 ofbiz 两个目录， catalina <br>目录是 Tomcat 的目录，Ofbiz 对其配置做了修改，ofbiz 目录是 Ofbiz 的程序代码目录。在命令行状态下进入 <br>&#8220;c:ofbizcatalinain&#8221; 目录，运行&#8220; ofbiz run&#8221;命令，就可以启动 Ofbiz，启动后你可以用浏览器访问 <br>&#8220;<a href="http://localhost:8080/ecommerce&#8221;，这可以访问" target=_blank><!--
***Rojo:Ins:/Tag:CloseOne: A before A
--></a><a href="http://localhost:8080/ecommerce&#8221;，这可以访问" target=_blank><u><font color=#0000ff>http://localhost:8080/ecommerce&#8221;，这可以访问</font></u></a> Ofbiz 的电子商务模块，通过页面上面的连接你可以访问到<br>其他模块。<br><br><br>3.Ofbiz Schema 的创建 <br><br>Ofbiz 应用入门：<br><br>以一个实例说明，假设我们需要建一个客户资料表，起名为 StudyCustomer，各个段分别如下：<br>StudyCustomer { <br>customerId Integer,<br>customerName String,<br>customerNote String,<br>}<br><br>我们来实现基本的数据操作---增/删/改/查询，具体步骤如下：<br><br><br>1.在 XML 文件中定义数据 Schema：<br>需要用到三个文件，一个是我们要建的项目的 entitymodel_xxx.xml 和 entityengine.xml，还有<br>entitygroup.xml,<br>entitymodel_xxx.xml 是需要我们自己创建的，假设我们起名为 entitymodel_study.xml，放在 <br>&#8220;c:ofbizofbizcommonappentitydef&#8221;目录下，<br>entityengine.xml 是 Ofbiz 已经有的，放在 &#8220;c:ofbizcommonappetc&#8221;目录下，用来包含我们<br>定义的 entitymodel 文件。<br>entitygroup.xml 也是 Ofbiz 已经有的，跟 engityengine.xml 在同一目录下，我们需要把我们的<br>Schema 定义加入到该文件中<br><br>entitymodel_study.xml 文件的定义格式如下：<br>&lt;!--================================================================================--&gt;<br><br>&lt;?xml version="1.0" encoding="UTF-8"?&gt;<br>&lt;!DOCTYPE entitymodel PUBLIC "-//OFBiz//DTD Entity Model//EN" <br><br>"<a href="http://www.ofbiz.org/dtds/entitymodel.dtd"><u><font color=#0000ff>" target="_blank"&gt;<!--
***Rojo:Ins:/Tag:CloseOne: A before A
--></font></u></a><a href='http://www.ofbiz.org/dtds/entitymodel.dtd">' target=_blank href_cetemp='http://www.ofbiz.org/dtds/entitymodel.dtd">'><u><font color=#0000ff>http://www.ofbiz.org/dtds/entitymodel.dtd"&gt;</font></u></a><br><br>&lt;entitymodel&gt;<br>&lt;title&gt;Entity of an Open For Business Project Component&lt;/title&gt;<br>&lt;description&gt;None&lt;/description&gt;<br>&lt;copyright&gt;Copyright (c) 2002 The Open For Business Project - <a href="http://feed.bmforum.com/art/month200611/www.ofbiz.org</copyright>" target=_blank href_cetemp="http://feed.bmforum.com/art/month200611/www.ofbiz.org</copyright>"><u><font color=#0000ff>http://feed.bmforum.com/art/month200611/www.ofbiz.org&lt;/copyright&gt;</font></u></a><br>&lt;author&gt;None&lt;/author&gt;<br>&lt;version&gt;1.0&lt;/version&gt;<br><br>&lt;!-- ========================================================= --&gt;<br>&lt;!-- ======================== Data Model ===================== --&gt;<br>&lt;!-- The modules in this file are as follows: --&gt;<br>&lt;!-- - org.ofbiz.commonapp.study --&gt;<br>&lt;!-- ========================================================= --&gt;<br><br><br>&lt;!-- ========================================================= --&gt;<br>&lt;!-- org.ofbiz.commonapp.study --&gt;<br>&lt;!-- ========================================================= --&gt;<br><br>&lt;entity entity-name="StudyCustomer"<br>package-name="org.ofbiz.commonapp.study"<br>title="Study Customer Entity"&gt;<br>&lt;field name="customerId" type="id-ne"&gt;&lt;/field&gt;<br>&lt;field name="customerName" type="long-varchar"&gt;&lt;/field&gt;<br>&lt;field name="customerNote" type="long-varchar"&gt;&lt;/field&gt;<br>&lt;prim-key field="customerId"/&gt;<br>&lt;/entity&gt;<br>&lt;/entitymodel&gt;<br><br>&lt;!--================================================================================--&gt;<br><br>这个 XML 文件中的 Tag 基本是看得明白的，只是 field 的 type 是 Ofbiz 已经预定义好的，这<br>是为了保证数据库间的迁移。<br><br>在 entityengine.xml 加入我们刚才定义的文件，加入一行在合适的位置：<br>&lt;resource loader="mainfile" location="entitymodel_study.xml"/&gt;<br>具体放的位置我们可以通过查看 entityengine.xml 找到，里面已经有加好的其他文件。<br><br>在 entitygroup.xml 加入我们的 Schema 定义，在后面加入一行<br>&lt;entity-group group="org.ofbiz.commonapp" entity="StudyCustomer" /&gt;<br><br>这样我们就定义好了 Schema，现在把 c:ofbizcommonappetcentityengine.xml 拷贝到<br>c:ofbizcatalinasharedclasses 目录下，这点要切记，我以前就因为没有拷贝，最后 Schema<br>怎么也创建不了。<br><br>重新启动 Ofbiz，访问 URL: <a href="http://localhost:8080/webtools，点击右上方的" target=_blank><!--
***Rojo:Ins:/Tag:CloseOne: A before A
--></a><a href="http://localhost:8080/webtools，点击右上方的" target=_blank><u><font color=#0000ff>http://localhost:8080/webtools，点击右上方的</font></u></a> "Login" 链接，<br>用 admin/ofbiz 登录，登录进入后选择链接&#8220;Check/Update Database&#8221;，这时会出现 Check 的 Form，<br>该表单可以只检验 Schema 是否改变，默认的 GroupName 是&#8220;org.ofbiz.commonapp&#8221;，这个不需要变，<br>点击&#8220;Check Only&#8221;按钮，Ofbiz 会检验变动情况，显示出一个完整的列表，你可以查一下是否有我们刚建的<br>"StudyCustomer"，如果没有，可能是我们前面定义的有些问题，检查一下再重新做。<br><br>在检查到以后，可以再选择&#8220;Check and Add Missing&#8221;，这是 Ofbiz 很强大的一个功能，你在 XML 中新<br>增了表，或在某个表中新增了段，它会自动映射到数据库中，避免我们去直接操作数据库。<br><br>现在已经完成了 StudyCustomer Schema 的创建,如果想检验一下是否有表创建，我们可以用编辑器打开<br>c:ofbizdataofbiz.script ，在里面查询 CREATE TABLE StudyCustomer 的字样，如果前面没有<br>问题，我们可以找到的。<br><br><br><br>4.如何使用已经定义的 Schema<br><br>如何使用已经定义的 Schema<br><br>Ofbiz 遵循 MVC 的设计模式，在 View 端，即 JSP 端主要使用 Ofbiz 定义的 Tag 来显示或<br>提取数据，Control 是一个 Controller Servlet，我们在 Controller Servlet 的 URI mapping<br>配置文件中定义各 URL 应该指向什么程序，这样，通过这个 mapping 配置文件，可以保证我们各个页面<br>及具体处理程序之间的独立性，例我们可以通过修改这个配置文件就可以改变某个 Form 的 Post Action<br>的 URL，而不需要修改实际的 HTML 或 JSP 代码。<br><br>Ofbiz 中定义了 Regions 的概念，即将一个 HTML 页面分成几个区域，像 Top, Left, Right, Main<br>等，通过这些 Regions 我们可以方便的组合 UI 界面，并且可以方便改变各部分所处的位置，如我们可以<br>把菜单很容易的从上方移到下方，只需要改变一个配置文件。Regions 类似于 HTML 中的 Frame，但它是<br>通过一个页面来组合界面，Frame 是通过几个页面显示在不同的帧中，Frame 的控制比较复杂，而且需要<br>改变相关的程序。<br><br>在 Ofbiz 中，我们可以直接在 JSP 中操作 Schema 定义的 Object，即我们刚定义的 StudyCustomer，<br>示例如下：<br><br><br>&lt;% at taglib uri="ofbizTags" prefix="ofbiz" %&gt;<br><br>&lt;%@ page import="java dot util.*" %&gt;<br>&lt;% at page import="org dot ofbiz.core.util.*, org.ofbiz.core.pseudotag.*" %&gt;<br>&lt;% at page import="org dot ofbiz.core.entity.*" %&gt;<br><br>&lt;jsp:useBean id="delegator" type="org.ofbiz.core.entity.GenericDelegator" scope="request" /&gt;<br>&lt;jsp:useBean id="security" type="org.ofbiz.core.security.Security" scope="request" /&gt;<br><br>&lt;%if(security.hasEntityPermission("PARTYMGR", "_VIEW", session)) { %&gt;<br><br>&lt;%<br>try { <br>delegator.create("StudyCustomer",<br>UtilMisc.toMap("customerId","1","customerName","Cust1","customerNote","Customer Note 1"));<br><br>Iterator custs = <br><br>UtilMisc.toIterator(delegator.findAll("StudyCustomer",UtilMisc.toList("customerId","customerName","customerNote")));<br><br>while(custs.hasNext())<br>{ <br>GenericValue cust = (GenericValue)custs.next();<br>out.println(cust.getString("customerId"));<br>out.println(cust.getString("customerName"));<br>out.println(cust.getString("customerNote"));<br>}<br>} catch(Exception e)<br>{ <br>out.println(e.getMessage());<br>}<br>%&gt;<br>&lt;% }else{ %&gt;<br>&lt;h3&gt;You do not have permission to view this page. ("PARTYMGR_VIEW" or "PARTYMGR_ADMIN" needed)&lt;/h3&gt;<br>&lt;% }%&gt;<br><br><br>这段程序挺容易理解，先是通过 delegator 创建一个 Object，该 Object 将会由 Ofbiz 自动同步到<br>数据库中。然后通过 delegator 的 findAll 取到所有已保存的 Object，最后通过一个 Iterator 对象<br>显示出来。<br><br>这个程序起名为 testofbiz.jsp，为简单起见，我们放到 Ofbiz 已有的一个 Webapp 的目录下，放到<br>c:ofbizofbizpartymgrwebappparty 目录下。然后我们需要修改两个配置文件：controller.xml<br>和 regions.xml，这两个文件就是我们上面提到的 mapping 和 regions 配置文件。<br><br>这两个文件都在：c:ofbizofbizpartymgrwebappWEB-INF 下，在 controller.xml 中加入下面<br><br>&lt;request-map uri="testofbiz"&gt;<br>&lt;description&gt;Test Ofbiz&lt;/description&gt;<br>&lt;security https="false" auth="false"/&gt;<br>&lt;response name="success" type="view" value="testofbiz"/&gt;<br>&lt;/request-map&gt;<br>和<br>&lt;view-map name="testofbiz" type="region"/&gt;<br><br>加入位置请参照 controller.xml 中已经有的配置。在 regions.xml 中加入：<br>&lt;define id='testofbiz' region='MAIN_REGION'&gt;<br>&lt;put section='title'&gt;Test Ofbiz&lt;/put&gt;<br>&lt;put section='content' content='/party/testofbiz.jsp'/&gt;<br>&lt;/define&gt;<br>具体加入位置请参考已有的配置。<br><br>配置完后，重新启动 ofbiz，然后访问 URL:<br><a href="http://localhost:8080/partymgr/control/testofbiz" target=_blank><!--
***Rojo:Ins:/Tag:CloseOne: A before A
--></a><a href="http://localhost:8080/partymgr/control/testofbiz" target=_blank><u><font color=#0000ff>http://localhost:8080/partymgr/control/testofbiz</font></u></a><br><br>由于我们在 testofbiz.jsp 程序中使用了 Ofbiz 的安全控制机制，系统会提示现在没有访问<br>权限，需要登录，点击右边的&#8220;Login&#8221; 用 admin/ofbiz 登录后会看到我们程序 testofbiz.jsp<br>的运行结果。如果需要增加新记录，请修改<br><br>UtilMisc.toMap("customerId","1","customerName","Cust1","customerNote","Customer Note 1"));<br><br>中的各个段的值，然后再访问 <a href="http://localhost:8080/partymgr/control/testofbiz，如果不修改" target=_blank><!--
***Rojo:Ins:/Tag:CloseOne: A before A
--></a><a href="http://localhost:8080/partymgr/control/testofbiz，如果不修改" target=_blank><u><font color=#0000ff>http://localhost:8080/partymgr/control/testofbiz，如果不修改</font></u></a><br>而直接访问那个 URL 时，系统会提示 Primary key 冲突。<br><br><br>5.按照显示与逻辑分离的原则使用 Schema:<br><br>上篇讲了如何在 JSP 中使用创建的 Schema 对象，这次我们来讲述一下如何把程序<br>逻辑放到 JavaBeans 中，把显示处理放到 JSP 中，并使用 controller.xml 将两<br>部分整合起来。<br><br>首先我们来创建一个 JavaBeans，来完成Add/Get/Delete/Update Schema 对象<br>的操作，程序文件名为 TestOfbiz.java，放置在 <br>c:ofbizofbiz estOfbizcomgeeyoofbiz 目录下, 具体程序如下：<br><br>&gt;=================================================================<br>package com.geeyo.ofbiz;<br><br>import javax.servlet.*;<br>import javax.servlet.http.*;<br>import java.util.*;<br>import java.net.*;<br>import org.ofbiz.core.util.*;<br>import org.ofbiz.core.entity.*;<br>import org.ofbiz.core.service.*;<br>import org.ofbiz.core.security.*;<br>import org.ofbiz.core.stats.*;<br><br>public class TestOfbiz<br>{ <br>public static void main(String[] args)<br>throws Exception<br>{ <br>GenericDelegator delegator = GenericDelegator.getGenericDelegator("default");<br>delegator.create("StudyCustomer",UtilMisc.toMap("customerId","3","customerName","Kane3","customerNote","This is test customer.3"));<br><br>Iterator custs = UtilMisc.toIterator(delegator.findAll("StudyCustomer",UtilMisc.toList("customerId","customerName","customerNote")));<br><br>while(custs.hasNext())<br>{ <br>GenericValue cust = (GenericValue)custs.next();<br>System.out.println(cust.getString("customerId"));<br>System.out.println(cust.getString("customerName"));<br>System.out.println(cust.getString("customerNote"));<br>}<br>}<br><br>public static String createNewRecord(HttpServletRequest request, HttpServletResponse response)<br>throws Exception<br>{ <br>Map paras = UtilMisc.getParameterMap(request);<br><br>GenericDelegator delegator = GenericDelegator.getGenericDelegator("default");<br>delegator.create("StudyCustomer",paras);<br><br>return "success";<br>}<br><br>public static String lookAllRecords(HttpServletRequest request, HttpServletResponse response)<br>throws Exception<br>{ <br>GenericDelegator delegator = GenericDelegator.getGenericDelegator("default");<br>Iterator custs = UtilMisc.toIterator(delegator.findAll("StudyCustomer",UtilMisc.toList("customerId","customerName","customerNote")));<br><br>Collection col = new ArrayList();<br><br>while(custs.hasNext())<br>{ <br>GenericValue cust = (GenericValue)custs.next();<br>col.add(cust);<br><br>}<br><br>request.getSession().setAttribute("search_results",col);<br><br>return "success";<br>}<br><br>public static String findRecord(HttpServletRequest request, HttpServletResponse response)<br>throws Exception<br>{ <br>String id = (String)request.getParameter("customerId");<br><br>GenericDelegator delegator = GenericDelegator.getGenericDelegator("default");<br><br>try { <br>GenericValue cust = delegator.findByPrimaryKey("StudyCustomer",UtilMisc.toMap("customerId",id));<br><br>request.getSession().setAttribute("edit_cust",cust);<br>} catch (GenericEntityException gee) { <br>Debug.logWarning(gee);<br>}<br><br>return "success";<br>} <br><br>public static String updateRecord(HttpServletRequest request, HttpServletResponse response)<br>throws Exception<br>{ <br>Map paras = UtilMisc.getParameterMap(request);<br><br>GenericDelegator delegator = GenericDelegator.getGenericDelegator("default");<br>GenericValue cust = delegator.findByPrimaryKey("StudyCustomer",UtilMisc.toMap("customerId",paras.get("customerId")));<br>cust.setNonPKFields(paras);<br>cust.store();<br><br>request.getSession().setAttribute("edit_cust",cust);<br><br>return "success";<br>}<br><br>public static String removeRecord(HttpServletRequest request, HttpServletResponse response)<br>throws Exception<br>{ <br>String strId = request.getParameter("id");<br>GenericDelegator delegator = GenericDelegator.getGenericDelegator("default");<br>GenericValue cust = delegator.findByPrimaryKey("StudyCustomer",UtilMisc.toMap("customerId",strId));<br>cust.remove();<br><br>return "success";<br>}<br><br>}<br><br><br>&gt;=================================================================<br><br><br>程序中的处理大部分可以看懂的，其中有个功能，是<br>Map paras = UtilMisc.getParameterMap(request);<br>这是 Ofbiz 的一个有趣但非常有用的功能，它是把 request 中各段的名字和值映射到一个 Map<br>对象中，然后使用<br>cust.setNonPKFields(paras);<br>就可以赋给 Object cust 的各个段，免了我们使用 request.getParameter("name")来取各个<br>值，在值很多的时候这个功能可以大大减少冗余代码量。<br><br>基本程序的逻辑是这样的，<br>1.从 request 读取传来的值<br> 2.使用 delegator 来处理，Add/Update/Delete/Query<br>3.将返回结果放到 Session 中传给 JSP<br><br>我做了个 Ant build.xml 文件可以帮助编译，把这个文件放在:<br>c:ofbizofbiz estOfbiz 目录下，然后在命令行窗口下进入该目录，敲入 ant<br>来编译（需要保证已经安装 Ant），编译后的 .class 会放在<br>c:ofbizofbiz estOfbizcomgeeyoofbiz 下，<br>拷贝 c:ofbizofbiz estofbizcom 目录到 c:ofbizofbizpartymgrwebappWEB-INFclasses<br>目录下。<br><br>build.xml<br>&gt;=============================================================================<br><br>&lt;project name="TestOfbiz" default="dist" basedir="."&gt;<br>&lt;description&gt;<br>Test ofbiz<br>&lt;/description&gt;<br><br>&lt;!--test cvs--&gt;<br>&lt;!-- set global properties for this build --&gt;<br><br>&lt;property name="src" location="."/&gt;<br>&lt;property name="build" location="."/&gt;<br><br>&lt;property name="lib_dir" location="c:/ofbiz/catalina/shared/lib"/&gt;<br>&lt;property name="lib1_dir" location="c:/ofbiz/catalina/common/lib"/&gt;<br><br>&lt;path id="project.class.path"&gt;<br>&lt;fileset dir="${ lib_dir }"&gt;<br>&lt;include name="*.jar"/&gt;<br>&lt;/fileset&gt;<br>&lt;fileset dir="${ lib1_dir }"&gt;<br>&lt;include name="*.jar"/&gt;<br>&lt;/fileset&gt;<br>&lt;/path&gt;<br><br>&lt;target name="init"&gt;<br>&lt;!-- Create the time stamp --&gt;<br>&lt;tstamp/&gt;<br>&lt;!-- Create the build directory structure used by compile --&gt;<br>&lt;mkdir dir="${ build }"/&gt;<br>&lt;/target&gt;<br><br>&lt;target name="compile" depends="init"<br>description="compile the source " &gt;<br>&lt;!-- Compile the java code from ${ src } into ${ build } --&gt;<br>&lt;javac srcdir="${ src }" destdir="${ build }"&gt;<br>&lt;classpath refid="project.class.path"/&gt;<br>&lt;/javac&gt;<br>&lt;/target&gt;<br><br>&lt;target name="dist" depends="compile"<br>description="generate the distribution" &gt;<br>&lt;!-- Create the distribution directory --&gt;<br>&lt;/target&gt;<br><br>&lt;target name="clean"<br>description="clean up" &gt;<br>&lt;!-- Delete the ${ build } and ${ dist } directory trees --&gt;<br>&lt;/target&gt;<br>&lt;/project&gt;<br><br><br>&gt;=============================================================================<br><br>然后我们来创建 JSP 程序，JSP 程序全部放在 <br>c:ofbizofbizpartymgrwebappparty 下面<br><br>1.listofbiz.jsp<br>&gt;=============================================================================<br><br>&lt;% at taglib uri="ofbizTags" prefix="ofbiz" %&gt;<br><br>&lt;%@ page import="java dot util.*, org.ofbiz.core.service.ModelService" %&gt;<br>&lt;% at page import="org dot ofbiz.core.util.*, org.ofbiz.core.pseudotag.*" %&gt;<br>&lt;% at page import="org dot ofbiz.core.entity.*" %&gt;<br>&lt;jsp:useBean id="security" type="org.ofbiz.core.security.Security" scope="request" /&gt;<br>&lt;jsp:useBean id="delegator" type="org.ofbiz.core.entity.GenericDelegator" scope="request" /&gt;<br><br>&lt;script language="JavaScript"&gt;<br>function confirmDelete()<br>{ <br>return confirm("Are your sure to delete?");<br>}<br>&lt;/script&gt;<br><br><br>&lt;%if(security.hasEntityPermission("PARTYMGR", "_VIEW", session)) { %&gt;<br><br>&lt;table width="600" align="center"&gt;<br>&lt;ofbiz:if name="search_results"&gt;<br>&lt;tr&gt;&lt;th&gt;Id&lt;/th&gt;&lt;th&gt;Name&lt;/th&gt;&lt;th&gt;Note&lt;/th&gt;&lt;th&gt;&lt;/th&gt;&lt;/tr&gt;<br>&lt;ofbiz:iterator name="cust" property="search_results"&gt;<br>&lt;tr&gt;<br>&lt;td&gt;&lt;ofbiz:entityfield attribute="cust" field="customerId"/&gt;&lt;/td&gt;<br>&lt;td&gt;&lt;ofbiz:entityfield attribute="cust" field="customerName"/&gt;&lt;/td&gt;<br>&lt;td&gt;&lt;ofbiz:entityfield attribute="cust" field="customerNote"/&gt;&lt;/td&gt;<br>&lt;td&gt;<br>&lt;a href='&lt;ofbiz:url&gt;/showtest?customerId=&lt;ofbiz:entityfield attribute="cust" field="customerId"/&gt;&lt;/ofbiz:url&gt;' class="buttontext"&gt;[Edit]&lt;/a&gt;<br>&lt;a href='&lt;ofbiz:url&gt;/removetest?customerId=&lt;ofbiz:entityfield attribute="cust" field="customerId"/&gt;&lt;/ofbiz:url&gt;' class="buttontext" onclick="return confirmDelete()"&gt;[Remove]&lt;/a&gt;<br>&lt;/td&gt;<br>&lt;/tr&gt;<br>&lt;/ofbiz:iterator&gt;<br>&lt;/ofbiz:if&gt;<br>&lt;/table&gt;<br>&lt;table width="200" align="center"&gt;<br>&lt;tr&gt;<br>&lt;td&gt;&lt;a href='&lt;ofbiz:url&gt;/createTestForm&lt;/ofbiz:url&gt;'&gt;Create customer&lt;/a&gt;&lt;/td&gt;<br>&lt;/tr&gt;<br>&lt;/table&gt;<br><br>&lt;% }else{ %&gt;<br>&lt;h3&gt;You do not have permission to view this page. ("PARTYMGR_VIEW" or "PARTYMGR_ADMIN" needed)&lt;/h3&gt;<br>&lt;% }%&gt;<br><br>&gt;=============================================================================<br><br>上面程序中需要说明的是<br>&lt;ofbiz:if name="search_results"&gt;<br>和<br>&lt;ofbiz:iterator name="cust" property="search_results"&gt;，<br><br>&lt;ofbiz:if name="search_results"&gt; 是用来检验在 session 或 pageContext 对象<br>中是否包含 search_results 对象，该对象是由我们的程序放到 session 中的。<br>&lt;ofbiz:iterator name="cust" property="search_results"&gt; 是用来循环读取对象<br>search_results（是个 Collection 对象）中存储的各对象，并赋给cust，然后在循环体<br>中，我们就可以用 cust 对象来读取各个段的值了。<br><br><br>2.createofbiz.jsp<br>&gt;=============================================================================<br><br>&lt;% at taglib uri="ofbizTags" prefix="ofbiz" %&gt;<br><br>&lt;%@ page import="java dot util.*, org.ofbiz.core.service.ModelService" %&gt;<br>&lt;% at page import="org dot ofbiz.core.util.*, org.ofbiz.core.pseudotag.*" %&gt;<br>&lt;% at page import="org dot ofbiz.core.entity.*" %&gt;<br>&lt;jsp:useBean id="security" type="org.ofbiz.core.security.Security" scope="request" /&gt;<br>&lt;jsp:useBean id="delegator" type="org.ofbiz.core.entity.GenericDelegator" scope="request" /&gt;<br>&lt;%if(security.hasEntityPermission("PARTYMGR", "_VIEW", session)) { %&gt;<br><br>&lt;form method="post" action="&lt;ofbiz:url&gt;/createTest&lt;/ofbiz:url&gt;" name="createofbiz"&gt;<br>&lt;table width="300" align="center"&gt;<br>&lt;tr&gt;<br>&lt;td&gt;Id&lt;/td&gt;&lt;td&gt;&lt;input type="text" name="customerId" size="20"&gt;&lt;/td&gt;<br>&lt;/tr&gt;<br>&lt;tr&gt;<br>&lt;td&gt;Name&lt;/td&gt;&lt;td&gt;&lt;input type="text" name="customerName" size="20"&gt;&lt;/td&gt;<br>&lt;/tr&gt;<br>&lt;tr&gt;<br>&lt;td&gt;Note&lt;/td&gt;&lt;td&gt;&lt;input type="text" name="customerNote" size="30"&gt;&lt;/td&gt;<br>&lt;/tr&gt;<br>&lt;tr&gt;<br>&lt;td&gt;&lt;/td&gt;<br>&lt;td&gt;&lt;input type="submit"&gt;&lt;/td&gt;<br>&lt;/tr&gt;<br>&lt;/table&gt;<br>&lt;/form&gt;<br><br>&lt;% }else{ %&gt;<br>&lt;h3&gt;You do not have permission to view this page. ("PARTYMGR_VIEW" or "PARTYMGR_ADMIN" needed)&lt;/h3&gt;<br>&lt;% }%&gt;<br>&gt;=============================================================================<br><br>这个程序很容易理解，需要注意的是每个文本框的名字，要跟 Schema StudyCustomer 的各<br>个段一致，以使程序中跟容易处理。<br><br>3.showofbiz.jsp<br>&gt;=============================================================================<br><br>&lt;% at taglib uri="ofbizTags" prefix="ofbiz" %&gt;<br><br>&lt;%@ page import="java dot util.*, org.ofbiz.core.service.ModelService" %&gt;<br>&lt;% at page import="org dot ofbiz.core.util.*, org.ofbiz.core.pseudotag.*" %&gt;<br>&lt;% at page import="org dot ofbiz.core.entity.*" %&gt;<br>&lt;jsp:useBean id="security" type="org.ofbiz.core.security.Security" scope="request" /&gt;<br>&lt;jsp:useBean id="delegator" type="org.ofbiz.core.entity.GenericDelegator" scope="request" /&gt;<br>&lt;%if(security.hasEntityPermission("PARTYMGR", "_VIEW", session)) { %&gt;<br><br>&lt;form method="post" action="&lt;ofbiz:url&gt;/updateTest&lt;/ofbiz:url&gt;" name="updateofbiz"&gt;<br>&lt;table width="300" align="center"&gt;<br>&lt;tr&gt;<br>&lt;td&gt;Id&lt;/td&gt;&lt;td&gt;&lt;input type="text" name="customerId" size="20" value="&lt;ofbiz:entityfield attribute="edit_cust" field="customerId"/&gt;"&gt;&lt;/td&gt;<br>&lt;/tr&gt;<br>&lt;tr&gt;<br>&lt;td&gt;Name&lt;/td&gt;&lt;td&gt;&lt;input type="text" name="customerName" size="20" value="&lt;ofbiz:entityfield attribute="edit_cust" field="customerName"/&gt;"&gt;&lt;/td&gt;<br>&lt;/tr&gt;<br>&lt;tr&gt;<br>&lt;td&gt;Note&lt;/td&gt;&lt;td&gt;&lt;input type="text" name="customerNote" size="30" value="&lt;ofbiz:entityfield attribute="edit_cust" field="customerNote"/&gt;"&gt;&lt;/td&gt;<br>&lt;/tr&gt;<br>&lt;tr&gt;<br>&lt;td&gt;&lt;/td&gt;<br>&lt;td&gt;&lt;input type="submit"&gt;&lt;/td&gt;<br>&lt;/tr&gt;<br>&lt;/table&gt;<br>&lt;/form&gt;<br><br>&lt;% }else{ %&gt;<br>&lt;h3&gt;You do not have permission to view this page. ("PARTYMGR_VIEW" or "PARTYMGR_ADMIN" needed)&lt;/h3&gt;<br>&lt;% }%&gt;<br><br>&gt;=============================================================================<br><br>这个程序中，主要是通过<br>&lt;ofbiz:entityfield attribute="edit_cust" field="customerId"/&gt;<br>把取到的对象的段显示出来, 对象 edit_cust 是我们在程序中取到并放到 session 中的。<br><br>下面我们来配置 controller.xml 和 regions.xml, 在 controller.xml 中加入:<br>&gt;=============================================================================<br><br>&lt;request-map uri="createTestForm"&gt;<br>&lt;description&gt;Show the create form&lt;/description&gt;<br>&lt;security https="false" auth="false"/&gt;<br>&lt;response name="success" type="view" value="createTestForm"/&gt;<br>&lt;/request-map&gt;<br><br>&lt;request-map uri="testofbiz"&gt;<br>&lt;description&gt;Test Ofbiz&lt;/description&gt;<br>&lt;security https="false" auth="false"/&gt;<br>&lt;response name="success" type="view" value="testofbiz"/&gt;<br>&lt;/request-map&gt;<br><br>&lt;request-map uri="listtest"&gt;<br>&lt;description&gt;List all records&lt;/description&gt;<br>&lt;security https="false" auth="false"/&gt;<br>&lt;event type="java" path="com.geeyo.ofbiz.TestOfbiz" invoke="lookAllRecords" /&gt;<br>&lt;response name="success" type="view" value="listAllTest"/&gt;<br>&lt;/request-map&gt;<br><br>&lt;request-map uri="showtest"&gt;<br>&lt;description&gt;Show records&lt;/description&gt;<br>&lt;security https="false" auth="false"/&gt;<br>&lt;event type="java" path="com.geeyo.ofbiz.TestOfbiz" invoke="findRecord" /&gt;<br>&lt;response name="success" type="view" value="showTest"/&gt;<br>&lt;/request-map&gt;<br><br>&lt;request-map uri="createTest"&gt;<br>&lt;security https="true" auth="true"/&gt;<br>&lt;event type="java" path="com.geeyo.ofbiz.TestOfbiz" invoke="createNewRecord"/&gt;<br>&lt;response name="success" type="request" value="listtest"/&gt;<br>&lt;response name="error" type="view" value="createTestForm"/&gt;<br>&lt;/request-map&gt;<br><br>&lt;request-map uri="updateTest"&gt;<br>&lt;description&gt;update a record&lt;/description&gt;<br>&lt;security https="false" auth="false"/&gt;<br>&lt;event type="java" path="com.geeyo.ofbiz.TestOfbiz" invoke="updateRecord" /&gt;<br>&lt;response name="success" type="request" value="listtest"/&gt;<br>&lt;/request-map&gt;<br><br>&lt;request-map uri="removetest"&gt;<br>&lt;description&gt;remove a record&lt;/description&gt;<br>&lt;security https="false" auth="false"/&gt;<br>&lt;event type="java" path="com.geeyo.ofbiz.TestOfbiz" invoke="removeRecord" /&gt;<br>&lt;response name="success" type="request" value="listtest"/&gt;<br>&lt;/request-map&gt;<br><br>&lt;view-map name="listAllTest" type="region"/&gt;<br>&lt;view-map name="createTestForm" type="region"/&gt;<br>&lt;view-map name="showTest" type="region"/&gt;<br>&gt;=============================================================================<br><br>在 regions.xml 中加入：<br>&gt;=============================================================================<br>&lt;define id='createTestForm' region='MAIN_REGION'&gt;<br>&lt;put section='title'&gt;Create Ofbiz&lt;/put&gt;<br>&lt;put section='content' content='/party/createofbiz.jsp'/&gt;<br>&lt;/define&gt;<br><br>&lt;define id='listAllTest' region='MAIN_REGION'&gt;<br>&lt;put section='title'&gt;List Ofbiz&lt;/put&gt;<br>&lt;put section='content' content='/party/listofbiz.jsp'/&gt;<br>&lt;/define&gt;<br><br>&lt;define id='showTest' region='MAIN_REGION'&gt;<br>&lt;put section='title'&gt;Show Ofbiz&lt;/put&gt;<br>&lt;put section='content' content='/party/showofbiz.jsp'/&gt;<br>&lt;/define&gt;<br><br>&gt;=============================================================================<br><br>现在就完成了，我们重新启动 Ofbiz，然后用 IE 访问：<br><a href="http://localhost:8080/partymgr/control/listtest，用admin/ofbiz" target=_blank><!--
***Rojo:Ins:/Tag:CloseOne: A before A
--></a><a href="http://localhost:8080/partymgr/control/listtest，用admin/ofbiz" target=_blank><u><font color=#0000ff>http://localhost:8080/partymgr/control/listtest，用admin/ofbiz</font></u></a> 登录后就可以<br>看到我们刚才的工作成果了，你现在可以增加/删除/修改记录。<br><br><br>6.Ofbiz 通过 XML 来完成数据库操作（非常强大的功能）<br><br>这是 Ofbiz 的一个非常强大的功能，可能通过简单的 XML 文件来完成数据增/删/改的处理，<br>这些处理在数据库应用中是非常多的，因为很多需要维护的数据，所以写程序也是最花时间的，<br>Ofbiz 把这些操作通过 XML 来完成，不能不说是一大革命---使我们不用写程序就可以完成大<br>部分处理，这是每个程序员都向往的终极目标。<br><br>我们下面举例来讲述一下，处理的数据还是利用我们前面创建的 StudyCustomer，使用 XML<br>配置文件来完成前面程序 TestOfbiz.java 的大部分操作。<br><br>在 c:ofbizofbiz estOfbizcomgeeyoofbiz 目录下创建文件 TestOfbizServices.xml，<br>该文件的内容如下：<br><br>&gt;=================================================================<br><br>&lt;?xml version="1.0" encoding="UTF-8" ?&gt;<br>&lt;!DOCTYPE simple-methods PUBLIC "-//OFBiz//DTD Simple Methods//EN" "<a href="http://www.ofbiz.org/dtds/simple-methods.dtd"><u><font color=#0000ff>" target="_blank"&gt;<!--
***Rojo:Ins:/Tag:CloseOne: A before A
--></font></u></a><a href='http://www.ofbiz.org/dtds/simple-methods.dtd">' target=_blank href_cetemp='http://www.ofbiz.org/dtds/simple-methods.dtd">'><u><font color=#0000ff>http://www.ofbiz.org/dtds/simple-methods.dtd"&gt;</font></u></a><br><br>&lt;simple-methods&gt;<br><br>&lt;!-- TestOfbiz methods --&gt;<br>&lt;simple-method method-name="createNewRecord" short-description="Create a new record"&gt;<br>&lt;check-permission permission="STUDYCUSTOMER" action="_CREATE"&gt;&lt;fail-message message="Security Error: to run createRecord you must have the STUDYCUSTOMER_CREATE permission"/&gt;&lt;/check-permission&gt; &lt;check-errors/&gt;<br><br>&lt;make-value entity-name="StudyCustomer" value-name="newEntity"/&gt;<br>&lt;set-pk-fields map-name="parameters" value-name="newEntity"/&gt;<br>&lt;set-nonpk-fields map-name="parameters" value-name="newEntity"/&gt;<br><br>&lt;create-value value-name="newEntity"/&gt;<br>&lt;/simple-method&gt;<br>&lt;simple-method method-name="updateRecord" short-description="Update a record"&gt;<br>&lt;check-permission permission="STUDYCUSTOMER" action="_UPDATE"&gt;&lt;fail-message message="Security Error: to run updateRecord you must have the STUDYCUSTOMER_UPDATE permission"/&gt;&lt;/check-permission&gt;<br><br>&lt;check-errors/&gt;<br><br>&lt;make-value entity-name="StudyCustomer" value-name="lookupPKMap"/&gt;<br>&lt;set-pk-fields map-name="parameters" value-name="lookupPKMap"/&gt;<br>&lt;find-by-primary-key entity-name="StudyCustomer" map-name="lookupPKMap" value-name="lookedUpValue"/&gt;<br>&lt;set-nonpk-fields map-name="parameters" value-name="lookedUpValue"/&gt;<br><br>&lt;store-value value-name="lookedUpValue"/&gt;<br>&lt;/simple-method&gt;<br><br>&lt;simple-method method-name="findRecord" short-description="lookup a record"&gt;<br>&lt;check-errors/&gt;<br><br>&lt;make-value entity-name="StudyCustomer" value-name="lookupPKMap"/&gt;<br>&lt;set-pk-fields map-name="parameters" value-name="lookupPKMap"/&gt;<br>&lt;find-by-primary-key entity-name="StudyCustomer" map-name="lookupPKMap" value-name="edit_cust"/&gt;<br>&lt;field-to-session field-name="edit_cust"/&gt;<br>&lt;/simple-method&gt;<br><br>&lt;simple-method method-name="removeRecord" short-description="Delete a record"&gt;<br>&lt;check-permission permission="STUDYCUSTOMER" action="_DELETE"&gt;&lt;fail-message message="Security Error: to run deleteRecord you must have the STUDYCUSTOMER_DELETE permission"/&gt;&lt;/check-permission&gt;<br>&lt;check-errors/&gt;<br><br>&lt;make-value entity-name="StudyCustomer" value-name="lookupPKMap"/&gt;<br>&lt;set-pk-fields map-name="parameters" value-name="lookupPKMap"/&gt;<br>&lt;find-by-primary-key entity-name="StudyCustomer" map-name="lookupPKMap" value-name="lookedUpValue"/&gt;<br>&lt;remove-value value-name="lookedUpValue"/&gt;<br>&lt;/simple-method&gt;<br><br>&lt;simple-method method-name="lookAllRecords" short-description="lookup suitable records"&gt;<br>&lt;check-errors/&gt;<br>&lt;find-by-and entity-name="StudyCustomer" list-name="search_results"/&gt;<br>&lt;field-to-session field-name="search_results"/&gt;<br>&lt;/simple-method&gt;<br><br>&lt;/simple-methods&gt;<br><br><br>&gt;=================================================================<br><br>上面的 XML 基本是不用解释的，定义了<br><br>createNewRecord<br>updateRecord<br>lookAllRecords<br>removeRecord<br>findRecord<br><br>这几个方法，而且都有对用户权限的检查，这几个方法对应于前面 TestOfbiz.java 中的几个方法，<br>这样来做数据库操作显然比用 Java 程序写要简单得多，<br><br>下面还需要在 controller.xml（具体文件得位置请参照前面的教程）更改一下 mapping 的设置，<br>更改如下，以前使用 TestOfbiz.java 时的配置我以注释的方式保留着以做参照：<br><br>&gt;=================================================================<br><br>&lt;request-map uri="createTestForm"&gt;<br>&lt;description&gt;Show the create form&lt;/description&gt;<br>&lt;security https="false" auth="false"/&gt;<br>&lt;response name="success" type="view" value="createTestForm"/&gt;<br>&lt;/request-map&gt;<br><br>&lt;request-map uri="listtest"&gt;<br>&lt;description&gt;List all records&lt;/description&gt;<br>&lt;security https="false" auth="false"/&gt;<br>&lt;event type="simple" path="com/geeyo/ofbiz/TestOfbizServices.xml" invoke="lookAllRecords" /&gt;<br>&lt;response name="success" type="view" value="listAllTest"/&gt;<br>&lt;/request-map&gt;<br><br>&lt;request-map uri="showtest"&gt;<br>&lt;description&gt;Show records&lt;/description&gt;<br>&lt;security https="false" auth="false"/&gt;<br>&lt;event type="simple" path="com/geeyo/ofbiz/TestOfbizServices.xml" invoke="findRecord" /&gt;<br>&lt;response name="success" type="view" value="showTest"/&gt;<br>&lt;/request-map&gt;<br><br>&lt;request-map uri="createTest"&gt;<br>&lt;security https="true" auth="true"/&gt;<br>&lt;event type="simple" path="com/geeyo/ofbiz/TestOfbizServices.xml" invoke="createNewRecord"/&gt;<br>&lt;response name="success" type="request" value="listtest"/&gt;<br>&lt;response name="error" type="view" value="createTestForm"/&gt;<br>&lt;/request-map&gt;<br><br>&lt;request-map uri="updateTest"&gt;<br>&lt;description&gt;update a record&lt;/description&gt;<br>&lt;security https="false" auth="false"/&gt;<br>&lt;event type="simple" path="com/geeyo/ofbiz/TestOfbizServices.xml" invoke="updateRecord" /&gt;<br>&lt;response name="success" type="request" value="listtest"/&gt;<br>&lt;/request-map&gt;<br><br>&lt;request-map uri="removetest"&gt;<br>&lt;description&gt;remove a record&lt;/description&gt;<br>&lt;security https="false" auth="false"/&gt;<br>&lt;event type="simple" path="com/geeyo/ofbiz/TestOfbizServices.xml" invoke="removeRecord" /&gt;<br>&lt;response name="success" type="request" value="listtest"/&gt;<br>&lt;/request-map&gt;<br><br>&lt;view-map name="listAllTest" type="region"/&gt;<br>&lt;view-map name="createTestForm" type="region"/&gt;<br>&lt;view-map name="testofbiz" type="region"/&gt;<br>&lt;view-map name="showTest" type="region"/&gt;<br><br>&gt;=================================================================<br><br>配置该文件的方法请参照前面的教程，regions.xml 不需改动。<br><br>配置完后请用前面讲过的方法访问 URL: <a href="http://localhost:8080/partymgr/control/listtest" target=_blank><!--
***Rojo:Ins:/Tag:CloseOne: A before A
--></a><a href="http://localhost:8080/partymgr/control/listtest" target=_blank><u><font color=#0000ff>http://localhost:8080/partymgr/control/listtest</font></u></a><br><br>现在我们可以看到，Ofbiz 在 MVC 方面做得非常好，我们可以把后端的处理程序从 java 改<br>成用 XMl 控制，而其他部分（像 JSP）不需任何改动，这可以保证我们系统各部分的独立性。<br></p>
<p><a href="http://www.cnpoint.com/mvnforum/mvnforum/viewthread?thread=65"><!--
***Rojo:Ins:/Tag:CloseOne: A before A
--></a><a href="http://www.cnpoint.com/mvnforum/mvnforum/viewthread?thread=65" target=_blank><u><font color=#0000ff>http://www.cnpoint.com/mvnforum/mvnforum/viewthread?thread=65</font></u></a></p>
<br>(<a href="http://www.yulanmail.com/blog/index.php?job=art&amp;articleid=a_20061120_235521" target=_blank><u><font color=#0000ff> 网页浏览 </font></u></a>)&nbsp;&nbsp; <!-- end dd.scoopedby --></div>
<!--
<div style="clear: both; height: 1px; line-height: 1px;">&nbsp;</div>
-->
<img src ="http://www.blogjava.net/wealupa/aggbug/111971.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/wealupa/" target="_blank">常言笑</a> 2007-04-19 16:06 <a href="http://www.blogjava.net/wealupa/archive/2007/04/19/111971.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Ofbiz学习经验谈</title><link>http://www.blogjava.net/wealupa/archive/2007/04/19/111960.html</link><dc:creator>常言笑</dc:creator><author>常言笑</author><pubDate>Thu, 19 Apr 2007 07:49:00 GMT</pubDate><guid>http://www.blogjava.net/wealupa/archive/2007/04/19/111960.html</guid><wfw:comment>http://www.blogjava.net/wealupa/comments/111960.html</wfw:comment><comments>http://www.blogjava.net/wealupa/archive/2007/04/19/111960.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/wealupa/comments/commentRss/111960.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/wealupa/services/trackbacks/111960.html</trackback:ping><description><![CDATA[<p>不可否认，OFBiz这个开源的系统功能是非常强大的，涉及到的东西太多了，其实对我们现在而言，最有用的只有这么几个：实体引擎、服务引擎、WebTools、用户权限管理。<br><br>最先要提醒各位的是，在配置一个OFBiz时，路径中千万不要包含空格，要不然老提示出错，无外乎是scoket write error之类的信息，会让你郁闷得不停^_^<br><br>用户登录鉴权这一块我们完全可以照搬OFBiz现有的东西，其实也就是调用包org.ofbiz.securityext.login.LoginEvents里面的一些方法来进行处理。 <br><br>Component定义：component-load.xml，可根据需要调整需在启动时引入的Component，比如增加一个Study，定义：<br><br>&lt;load-component component-location="${ofbiz.home}/components/study"/&gt;<br><br><br><br>首先需要进行如下几个项目的总体配置：<br><br>1、 entityengine.xml：实体引擎配置，主要是配置该数据的方式，如通过oracle访问，就配置一下localoracle，特别需要注意的是，在dataSource中配置中，一定要配置一个属性 - schema-name="OFBIZ"，这个主要是为了在OFBiz启动时能够正常同数据库的对象进行匹配，如果没有进行配置，每次都会试图重新建立对象，会报对象名已经被占用的情况。<br><br>2、 serviceengine.xml：服务引擎配置，这个基本上不用作太大的修改，如要必要，可在这里边进行一些参数的调优，比如访问线程数配置等。<br><br>之后需要在components目录下新建一个目录study，目录里面的一些文件可直接从模板中拷贝，之后再进行必要的修改，涉及修改内容： <br>1、 entitygroup.xml &amp; entitymodel 实体定义（3.0版本开始,各实体定义可在各自的Component下定义,而不必统一集中在commonapp下）；定义实体及实体的相关属性(其实也就是相当于数据库的各种对象，需要注意的是，后续进行数据提取时，如果需要关联到多张表，也需要在这里面定义一个view-entity);<br><br>2、 services.xml：如果必要的话，可以这里边定义一些服务;<br><br>3、 data：一些初始配置数据，应该是相对固定，不经常变动的才放在这边，可通过Webtool工具导入到数据库中;<br><br>4、 src：如改动了一些Java源文件内容后，需要重新编译该目录的文件，可通过UltraEdit的工具配置来进行ant编译，非常方便，推荐使用，编译后的文件将生成到build目录下，生成的文件有各个class文件，也有一些.jar包（放在lib目录下），这些jar包是我们在Web应用中需要引用到的，当然，引用哪些包也是可配置的，下面会讲到;<br><br>5、 ofbiz-component.xml：主要的配置文件，需要注意的一些东西：<br><br>（1）&lt;classpath type="jar" location="build/lib/*"/&gt; 这是jar引用路径，我在考虑是否可改成直接引用class文件，也就是直接设置class文件所在的目录;<br><br>（2）title="Study" 这个就是我们通过appbar.ftl文件在主界面显示的那一排按钮上显示的内容，可根据需要调整，调整完要重启OFBiz，麻烦，可以考虑通过hot-deploy目录进行发布。<br><br>至于其他一些配置，很简单，看看就晓得。<br><br>下面讲一下Web应用配置，Web应用配置中涉及到的最重要的两个文件是：controller.xml和regions.xml，controller.xml文件主要是配置request-map，也就是请求映射关系，所有的请求映射都需要在这里边进行配置，也就是我们在Web页面上常看到的/login等，如果涉及到view-map类型是region，就需要从region.xml文件中去读取配置，其实也就是配置各个region引用的处理页面（可以是各种开发语言，比如Jsp、ftl等等）。另外，在region.xml配置文件中最重要的一部分就是MAIN_REGION的配置，就是整个网页布局的配置，包括header、appbar、error、content、footer等等，其中appbar就是我们在前面刚刚提到的主界面上那一排按钮的配置了，header、footer和error太简单，不说了，我们主要要修改的东西都是在content这一块上进行展现。 <br>网页中用到的一些样式、公用的定义都是在main_template.jsp中写入的，也需要在MAIN_REGION的属性中配置引用的文件。样式定义文件是引用images这个component，所以这个也是关键，不能缺的。<br><br>最后，讲一讲我对数据库访问的一些简单的了解：对数据库的访问主要是通过GenericDelegator进行控制，包括一些常用的方法，如findAll、remove、store、create等等，具体的用法要去研究一下，其实也不算复杂，先建立一个GenericDelegator，如果是create、store就可以通过makeValue方法将一些字段的值设置到GenericValue，之后再进行store或是create，具体语法要去参考一些文档，还没去看这一块的东西。<br><br>最最需要访问的一些文档：OFBizChina 实体引擎配置指南、OFBizChina 区块（Region）指南、OFBizChina 服务引擎配置指南、OFBizChina JSP标签库指南，当然，研究OFBiz的前提是要首先要理解MVC模式的概念，也就是View-Model-Control，否则一切都是空谈。</p>
<p>补充几点：<br>1、 对于Ofbiz构造动态查询语句<br>(1) 构造查询条件<br>(2) 给每个条件之间加上逻辑关系，用mainCond = new EntityConditionList(andExprs, EntityOperator.AND);<br>(3) 设置要显示的字段列表<br>(4) 设置排序字段列表<br>(5) 设置Distinct列表<br>EntityFindOptions findOpts = new EntityFindOptions(true, EntityFindOptions.TYPE_SCROLL_INSENSITIVE, EntityFindOptions.CONCUR_READ_ONLY, true);<br>(6) 获取实体列表<br>EntityListIterator pli = delegator.findListIteratorByCondition(entityName, mainCond, null, fieldsToSelect, orderBy, findOpts);<br>(7) 一个动态查询语句的具体实例<br>&lt;%<br>String entityName="study";<br>List andExprs = new ArrayList();<br>String number="";<br>String name="";<br>String sex="";<br>String tel="";<br>//GenericDelegator delegator = GenericDelegator.getGenericDelegator("default");<br>EntityConditionList mainCond=null;<br>if (request.getParameter("number")!=null) <br>number=request.getParameter("number").toString();<br>if (request.getParameter("name")!=null) <br>name=request.getParameter("name").toString();<br>if (request.getParameter("sex")!=null) <br>sex=request.getParameter("sex").toString();<br>if (request.getParameter("tel")!=null) <br>tel=request.getParameter("tel").toString();<br>//构造查询条件<br>if (number.compareTo("")!=0)<br>andExprs.add(new EntityExpr("number",EntityOperator.EQUALS,number));<br>if (name.compareTo("")!=0)<br>andExprs.add(new EntityExpr("name1",true,EntityOperator.LIKE,"%"+name+"%",true));<br>if (sex.compareTo("")!=0)<br>andExprs.add(new EntityExpr("sex1",true,EntityOperator.LIKE,"%"+sex+"%",true));<br>if (tel.compareTo("")!=0)<br>andExprs.add(new EntityExpr("tel",true,EntityOperator.LIKE,"%"+tel+"%",true));<br>//每个条件间的逻辑关系<br>if (andExprs.size() &gt; 0) <br>mainCond = new EntityConditionList(andExprs, EntityOperator.AND);<br>//要显示的字段列表<br>List fieldsToSelect = new ArrayList();<br>fieldsToSelect.add("number");<br>fieldsToSelect.add("name1");<br>fieldsToSelect.add("sex1");<br>fieldsToSelect.add("tel");<br>//排序字段列表<br>List orderBy = UtilMisc.toList("number", "name1");<br>//Distinct列表<br>EntityFindOptions findOpts = new EntityFindOptions(true, EntityFindOptions.TYPE_SCROLL_INSENSITIVE, EntityFindOptions.CONCUR_READ_ONLY, true);<br>//获取实体列表<br>EntityListIterator pli = delegator.findListIteratorByCondition(entityName, mainCond, null, fieldsToSelect, orderBy, findOpts);<br>while(pli.hasNext())<br>{<br>GenericValue cust = (GenericValue)pli.next();%&gt;<br>&lt;tr&gt;<br>&lt;td&gt;&lt;%=cust.getString("number")%&gt;&lt;/td&gt;<br>&lt;td&gt;&lt;%=cust.getString("name1")%&gt;&lt;/td&gt;<br>&lt;td&gt;&lt;%=cust.getString("sex1")%&gt;&lt;/td&gt;<br>&lt;td&gt;&lt;%=cust.getString("tel")%&gt;&lt;/td&gt;<br>&lt;/tr&gt;<br>&lt;%}%&gt;<br><br>&lt;/table&gt;<br><br>2、 对于所有的图片文件，都放在images目录下<br>3、 设置图片的标签&lt;ofbiz:contenturl&gt;图片路径&lt;/ofbiz:contenturl&gt;<br>4、 链接Tag &lt;ofbiz:url&gt;control.xml里面设置的请求&lt;/ofbiz.url&gt;<br>5、 &lt;region:render section='header'/&gt;引入header定义的文件<br>header这个标识在regions.xml里面定义<br>&lt;define id='MAIN_REG' template='/templates/main_template1.jsp'&gt;<br>&lt;put section='title'&gt;Application Page&lt;/put&gt; &lt;!-- this is a default and is meant to overridden --&gt;<br>&lt;put section='header' content='/includes/bottom.jsp'/&gt;<br>&lt;put section='leftbar' content='/includes/left.jsp'/&gt;<br>&lt;put section='middle' content='/includes/middle.jsp'/&gt;<br>&lt;put section='content' content='/includes/middle.jsp'/&gt; &lt;!-- this is a default and is meant to overridden --&gt;<br>&lt;put section='top' content='/includes/top.jsp'/&gt;<br>&lt;put section='error' type="jpublish" content='/includes/errormsg.ftl'/&gt;<br>&lt;!--&lt;put section='footer' type="jpublish" content='/includes/footer.ftl'/&gt;--&gt;<br>&lt;/define&gt;<br>然后其它页面只要如下定义即可<br>&lt;define id='BasePubEmp' region='MAIN_REG'&gt;<br>&lt;put section='title'&gt;View BasePubEmp&lt;/put&gt;<br>&lt;put section='content' content='/BasePubEmp.jsp'/&gt;<br>&lt;/define&gt;<br>注意，这边的content所指定的区块就是我们上面定义的content<br>6、 这些标签都挺简单的，Ｏｆｂｉｚ里面都有例子，参照一下就可以了<br></p>
<img src ="http://www.blogjava.net/wealupa/aggbug/111960.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/wealupa/" target="_blank">常言笑</a> 2007-04-19 15:49 <a href="http://www.blogjava.net/wealupa/archive/2007/04/19/111960.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>JAVA中的集合类</title><link>http://www.blogjava.net/wealupa/archive/2006/12/22/89551.html</link><dc:creator>常言笑</dc:creator><author>常言笑</author><pubDate>Fri, 22 Dec 2006 08:07:00 GMT</pubDate><guid>http://www.blogjava.net/wealupa/archive/2006/12/22/89551.html</guid><wfw:comment>http://www.blogjava.net/wealupa/comments/89551.html</wfw:comment><comments>http://www.blogjava.net/wealupa/archive/2006/12/22/89551.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/wealupa/comments/commentRss/89551.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/wealupa/services/trackbacks/89551.html</trackback:ping><description><![CDATA[<div class=diaryContent style="DISPLAY: block" align=left><span><font size=2>为什么要使用集合类</font> </span><br></div>
<p class=diaryContent style="DISPLAY: block" align=left>当你事先不知道要存放数据的个数，或者你需要一种比数组下标存取机制更灵活的方法时，你就需要用到集合类。</p>
<p class=diaryContent style="DISPLAY: block" align=left></p>
<table cellSpacing=0 cellPadding=4 width=520 border=0>
    <tbody>
        <tr>
            <td><span><a href="http://blog.blogchina.com/mcp/blog.aspx?id=19"><font size=2></font></a></span></td>
        </tr>
        <tr>
            <td><span>
            <p><strong><font size=2>理解集合类</font> </strong></p>
            <p>集合类存放于java.util包中。<br>集合类存放的都是对象的引用，而非对象本身，出于表达上的便利，我们称集合中的对象就是指集合中对象的引用（reference)。<br>集合类型主要有3种：set(集）、list(列表）和map(映射)。</p>
            <p>(1)集<br>集（set）是最简单的一种集合，它的对象不按特定方式排序，只是简单的把对象加入集合中，就像往口袋里放东西。<br>对集中成员的访问和操作是通过集中对象的引用进行的，所以集中不能有重复对象。<br>集也有多种变体，可以实现排序等功能，如TreeSet，它把对象添加到集中的操作将变为按照某种比较规则将其插入到有序的对象序列中。它实现的是SortedSet接口，也就是加入了对象比较的方法。通过对集中的对象迭代，我们可以得到一个升序的对象集合。</p>
            <p>(2)列表<br>列表的主要特征是其对象以线性方式存储，没有特定顺序，只有一个开头和一个结尾，当然，它与根本没有顺序的集是不同的。<br>列表在数据结构中分别表现为：数组和向量、链表、堆栈、队列。<br>关于实现列表的集合类，是我们日常工作中经常用到的，将在后边的笔记详细介绍。</p>
            <p>(3)映射<br>映射与集或列表有明显区别，映射中每个项都是成对的。映射中存储的每个对象都有一个相关的关键字（Key）对象，关键字决定了对象在映射中的存储位置，检索对象时必须提供相应的关键字，就像在字典中查单词一样。关键字应该是唯一的。<br>关键字本身并不能决定对象的存储位置，它需要对过一种散列(hashing)技术来处理，产生一个被称作散列码(hash code)的整数值，散列码通常用作一个偏置量，该偏置量是相对于分配给映射的内存区域起始位置的，由此确定关键字/对象对的存储位置。理想情况下，散列处理应该产生给定范围内均匀分布的值，而且每个关键字应得到不同的散列码。</p>
            <ul>
                <li><strong>集合类简介</strong> </li>
            </ul>
            <p>java.util中共有13个类可用于管理集合对象，它们支持集、列表或映射等集合，以下是这些类的简单介绍</p>
            <p><strong>集：<br>HashSet：</strong> 使用HashMap的一个集的实现。虽然集定义成无序，但必须存在某种方法能相当高效地找到一个对象。使用一个HashMap对象实现集的存储和检索操作是在固定时间内实现的. <br><strong>TreeSet：</strong> 在集中以升序对对象排序的集的实现。这意味着从一个TreeSet对象获得第一个迭代器将按升序提供对象。TreeSet类使用了一个TreeMap. <br><strong>列表：</strong><br><strong>Vector：</strong> 实现一个类似数组一样的表，自动增加容量来容纳你所需的元素。使用下标存储和检索对象就象在一个标准的数组中一样。你也可以用一个迭代器从一个Vector中检索对象。Vector是唯一的同步容器类??当两个或多个线程同时访问时也是性能良好的。 <br><strong>Stsck:</strong> 这个类从Vector派生而来，并且增加了方法实现栈??一种后进先出的存储结构。 <br><strong>LinkedList:</strong> 实现一个链表。由这个类定义的链表也可以像栈或队列一样被使用。 <br><strong>ArrayList:</strong> 实现一个数组，它的规模可变并且能像链表一样被访问。它提供的功能类似Vector类但不同步。</p>
            <p><br><strong>映射：<br>HashTable：</strong> 实现一个映象，所有的键必须非空。为了能高效的工作，定义键的类必须实现hashcode()方法和equal()方法。这个类是前面java实现的一个继承，并且通常能在实现映象的其他类中更好的使用。 <br><strong>HashMap：</strong> 实现一个映象，允许存储空对象，而且允许键是空（由于键必须是唯一的，当然只能有一个）。 <br><strong>WeakHashMap：</strong> 实现这样一个映象：通常如果一个键对一个对象而言不再被引用，键/对象对将被舍弃。这与HashMap形成对照，映象中的键维持键/对象对的生命周期，尽管使用映象的程序不再有对键的引用，并且因此不能检索对象。 <br><strong>TreeMap：</strong> 实现这样一个映象，对象是按键升序排列的。</p>
            <p>Set和List都是由公共接口Collection扩展而来，所以它们都可以使用一个类型为Collection的变量来引用。这就意味着任何列表或集构成的集合都可以用这种方式引用，只有映射类除外（但也不是完全排除在外，因为可以从映射获得一个列表。）所以说，把一个列表或集传递给方法的标准途径是使用Collection类型的参数。</p>
            <span>
            <ul>
                <li><strong>Vector 还是ArrayList，哪一个更好，为什么？</strong> </li>
            </ul>
            <p>要回答这个问题不能一概而论，有时候使用Vector比较好；有时是ArrayList，有时候这两个都不是最好的选择。你别指望能够获得一个简单肯定答案，因为这要看你用它们干什么。下面有4个要考虑的因素：</p>
            <p>(1)API</p>
            <p>(2)同步处理</p>
            <p>(3)数据增长性</p>
            <p>(4)使用模式</p>
            <p>下面针对这4个方面进行一一探讨</p>
            <p><strong>API </strong><br>在由Ken Arnold等编著的《Java Programming Language》(Addison-Wesley, June 2000)一书中有这样的描述，Vector类似于ArrayList.。所有从API的角度来看这两个类非常相似。但他们之间也还是有一些主要的区别的。</p>
            <p><strong>同步性</strong> </p>
            <p>Vector是同步的。这个类中的一些方法保证了Vector中的对象是线程安全的。而ArrayList则是异步的，因此ArrayList中的对象并不是线程安全的。因为同步的要求会影响执行的效率，所以如果你不需要线程安全的集合那么使用ArrayList是一个很好的选择，这样可以避免由于同步带来的不必要的性能开销。</p>
            <p><strong>数据增长</strong> </p>
            <p>从内部实现机制来讲ArrayList和Vector都是使用数组(Array)来控制集合中的对象。当你向这两种类型中增加元素的时候，如果元素的数目超出了内部数组目前的长度它们都需要扩展内部数组的长度，Vector缺省情况下自动增长原来一倍的数组长度，ArrayList是原来的50%,所以最后你获得的这个集合所占的空间总是比你实际需要的要大。所以如果你要在集合中保存大量的数据那么使用Vector有一些优势，因为你可以通过设置集合的初始化大小来避免不必要的资源开销。</p>
            <p><strong>使用模式</strong> </p>
            <p>在ArrayList和Vector中，从一个指定的位置（通过索引）查找数据或是在集合的末尾增加、移除一个元素所花费的时间是一样的，这个时间我们用O(1)表示。但是，如果在集合的其他位置增加或移除元素那么花费的时间会呈线形增长：O(n-i)，其中n代表集合中元素的个数，i代表元素增加或移除元素的索引位置。为什么会这样呢？以为在进行上述操作的时候集合中第i和第i个元素之后的所有元素都要执行位移的操作。这一切意味着什么呢？</p>
            <p>这意味着，你只是查找特定位置的元素或只在集合的末端增加、移除元素，那么使用Vector或ArrayList都可以。如果是其他操作，你最好选择其他的集合操作类。比如，LinkList集合类在增加或移除集合中任何位置的元素所花费的时间都是一样的—O(1)，但它在索引一个元素的使用缺比较慢－O(i),其中i是索引的位置.使用ArrayList也很容易，因为你可以简单的使用索引来代替创建iterator对象的操作。LinkList也会为每个插入的元素创建对象，所有你要明白它也会带来额外的开销。</p>
            <p>最后，在《Practical Java》一书中Peter Haggar建议使用一个简单的数组（Array）来代替Vector或ArrayList。尤其是对于执行效率要求高的程序更应如此。因为使用数组(Array)避免了同步、额外的方法调用和不必要的重新分配空间的操作。</p>
            </span></span></td>
        </tr>
    </tbody>
</table>
<img src ="http://www.blogjava.net/wealupa/aggbug/89551.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/wealupa/" target="_blank">常言笑</a> 2006-12-22 16:07 <a href="http://www.blogjava.net/wealupa/archive/2006/12/22/89551.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Spring Aop Step-By-Step 学习笔记(下)</title><link>http://www.blogjava.net/wealupa/archive/2006/12/19/88767.html</link><dc:creator>常言笑</dc:creator><author>常言笑</author><pubDate>Tue, 19 Dec 2006 05:17:00 GMT</pubDate><guid>http://www.blogjava.net/wealupa/archive/2006/12/19/88767.html</guid><wfw:comment>http://www.blogjava.net/wealupa/comments/88767.html</wfw:comment><comments>http://www.blogjava.net/wealupa/archive/2006/12/19/88767.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/wealupa/comments/commentRss/88767.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/wealupa/services/trackbacks/88767.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 五. Spring-Aop 引入的介绍 &nbsp;&nbsp;&nbsp;&nbsp; 下面我们介绍一种通知&#8220;引入&#8221;，关于引入，如同它的名字一样，给对象添加方法和属性。呵呵，好厉害吧。它是通过CBLIB来动态生成类的，所以自己用的时候别忘了加载这个包。 &nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; 代码...&nbsp;&nbsp;<a href='http://www.blogjava.net/wealupa/archive/2006/12/19/88767.html'>阅读全文</a><img src ="http://www.blogjava.net/wealupa/aggbug/88767.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/wealupa/" target="_blank">常言笑</a> 2006-12-19 13:17 <a href="http://www.blogjava.net/wealupa/archive/2006/12/19/88767.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Spring Aop Step-By-Step 学习笔记(上)</title><link>http://www.blogjava.net/wealupa/archive/2006/12/19/88765.html</link><dc:creator>常言笑</dc:creator><author>常言笑</author><pubDate>Tue, 19 Dec 2006 05:12:00 GMT</pubDate><guid>http://www.blogjava.net/wealupa/archive/2006/12/19/88765.html</guid><wfw:comment>http://www.blogjava.net/wealupa/comments/88765.html</wfw:comment><comments>http://www.blogjava.net/wealupa/archive/2006/12/19/88765.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/wealupa/comments/commentRss/88765.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/wealupa/services/trackbacks/88765.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 最近由于工作需要，要求掌握关于 Spring 方面的东西。所以花了两个星期的时间来学习 Spring 的基本知识，主要包括 Ioc 和 Aop 两方面。 本文为笔者的 Spring 在 Aop 方面的学习笔记，主要结合了 Spring In Action 第三章 和 Spring-Reference 第五章 为学习向导。根据自己的理解和书中的实例来一步一步完成对于在 Spring 中 Aop ...&nbsp;&nbsp;<a href='http://www.blogjava.net/wealupa/archive/2006/12/19/88765.html'>阅读全文</a><img src ="http://www.blogjava.net/wealupa/aggbug/88765.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/wealupa/" target="_blank">常言笑</a> 2006-12-19 13:12 <a href="http://www.blogjava.net/wealupa/archive/2006/12/19/88765.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>如何去除Spring中的面向接口的编成</title><link>http://www.blogjava.net/wealupa/archive/2006/12/19/88756.html</link><dc:creator>常言笑</dc:creator><author>常言笑</author><pubDate>Tue, 19 Dec 2006 05:05:00 GMT</pubDate><guid>http://www.blogjava.net/wealupa/archive/2006/12/19/88756.html</guid><wfw:comment>http://www.blogjava.net/wealupa/comments/88756.html</wfw:comment><comments>http://www.blogjava.net/wealupa/archive/2006/12/19/88756.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/wealupa/comments/commentRss/88756.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/wealupa/services/trackbacks/88756.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp; 众所周知，Spring是提倡基于接口编程的。<br>&nbsp;&nbsp;&nbsp; 但有些Manager类，比如SaleOrderManager ，只有5%的机会再有另一个Impl实现。95%时间里这两兄弟站一起，就像C++里的.h和.cpp，徒增维护的繁琐(经常要同步两个文件的函数声明)，和代码浏览跳转时的不便(比如从Controler类跟踪到Service类时，只能跳转到接口类的相应函数，还要再按一次复杂的热键才跳转到实现类)<br>&nbsp;&nbsp;&nbsp; 连Martin Flower都说，强制每个类都分离接口和实现是过犹不及。只在有多个独立实现，或者需要消除对实现类的依赖时，才需要分离接口。<br><br>&nbsp;&nbsp;&nbsp;&nbsp;<strong>DAO被强制用接口的原因</strong><br>&nbsp;&nbsp;&nbsp; Spring IOC本身是不会强制基于接口的，但DAO类一般要使用Spring的声明式事务机制，而声明式的事务机制是使用Spring AOP来实现的。Spring AOP的实现机制包括动态代理和Cgilib2，其中Spring AOP默认使用的Java动态代理是必须基于接口，所以就要求基于接口了。<br>&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp; <strong>解决方法</strong><br>&nbsp;&nbsp;&nbsp; 那就让Spring AOP改用CGLib2，生成目标类的子类吧，我们只要指定使用声明式事务的FactoryBean使用CGLib的方式来实现AOP，就可以不基于接口编程了。<br>&nbsp;&nbsp;&nbsp; 指定的方式为<strong>设置proxyTargetClass为true</strong>。如下：<br>
<div style="BORDER-RIGHT: windowtext 0.5pt solid; PADDING-RIGHT: 5.4pt; BORDER-TOP: windowtext 0.5pt solid; PADDING-LEFT: 5.4pt; BACKGROUND: #e6e6e6; PADDING-BOTTOM: 4px; BORDER-LEFT: windowtext 0.5pt solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: windowtext 0.5pt solid">
<div><span style="COLOR: #0000ff">
<div><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #0000ff">&lt;</span><span style="COLOR: #800000">bean&nbsp;</span><span style="COLOR: #ff0000">class</span><span style="COLOR: #0000ff">="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"</span><span style="COLOR: #ff0000"><br><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top>id</span><span style="COLOR: #0000ff">="baseService"</span><span style="COLOR: #ff0000">&nbsp;&nbsp;&nbsp;abstract</span><span style="COLOR: #0000ff">="true"</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000"><br><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;</span><span style="COLOR: #0000ff">&lt;</span><span style="COLOR: #800000">property&nbsp;</span><span style="COLOR: #ff0000">name</span><span style="COLOR: #0000ff">="transactionManager"</span><span style="COLOR: #ff0000">&nbsp;ref</span><span style="COLOR: #0000ff">="transactionManager"</span><span style="COLOR: #0000ff">/&gt;</span><span style="COLOR: #000000"><br><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;</span><span style="COLOR: #0000ff">&lt;</span><span style="COLOR: #800000">property&nbsp;</span><span style="COLOR: #ff0000">name</span><span style="COLOR: #0000ff">="proxyTargetClass"</span><span style="COLOR: #ff0000">&nbsp;value</span><span style="COLOR: #0000ff">="true"</span><span style="COLOR: #0000ff">/&gt;</span><span style="COLOR: #000000"><br><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top><img src="http://www.blogjava.net/Images/dot.gif"><br><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #0000ff">&lt;/</span><span style="COLOR: #800000">bean</span><span style="COLOR: #0000ff">&gt;</span></div>
</span></div>
</div>
<br>&nbsp;&nbsp;&nbsp;&nbsp; 又因为这些Service Bean都是单例，效率应该不受影响。<br>
<img src ="http://www.blogjava.net/wealupa/aggbug/88756.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/wealupa/" target="_blank">常言笑</a> 2006-12-19 13:05 <a href="http://www.blogjava.net/wealupa/archive/2006/12/19/88756.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>学JFreeChart不得不看的中文API(1)</title><link>http://www.blogjava.net/wealupa/archive/2006/12/16/88291.html</link><dc:creator>常言笑</dc:creator><author>常言笑</author><pubDate>Sat, 16 Dec 2006 14:59:00 GMT</pubDate><guid>http://www.blogjava.net/wealupa/archive/2006/12/16/88291.html</guid><wfw:comment>http://www.blogjava.net/wealupa/comments/88291.html</wfw:comment><comments>http://www.blogjava.net/wealupa/archive/2006/12/16/88291.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.blogjava.net/wealupa/comments/commentRss/88291.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/wealupa/services/trackbacks/88291.html</trackback:ping><description><![CDATA[<p>JFreeChart类：<br>void setAntiAlias(boolean flag)&nbsp;&nbsp;&nbsp;&nbsp;字体模糊边界<br>void setBackgroundImage(Image image)&nbsp;&nbsp;&nbsp;背景图片<br>void setBackgroundImageAlignment(int alignment)&nbsp;&nbsp;背景图片对齐方式（参数常量在org.jfree.ui.Align类中定义）<br>void setBackgroundImageAlpha(float alpha)&nbsp;&nbsp;背景图片透明度（0.0～1.0）<br>void setBackgroundPaint(Paint paint)&nbsp;&nbsp;&nbsp;背景色<br>void setBorderPaint(Paint paint)&nbsp;&nbsp;&nbsp;边界线条颜色<br>void setBorderStroke(Stroke stroke)&nbsp;&nbsp;&nbsp;边界线条笔触<br>void setBorderVisible(boolean visible)&nbsp;&nbsp;&nbsp;边界线条是否可见</p>
<p>---------------------------------------------------------------------</p>
<p>TextTitle类：<br>void setFont(Font font)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;标题字体<br>void setPaint(Paint paint)&nbsp;&nbsp;&nbsp;&nbsp;标题字体颜色<br>void setText(String text)&nbsp;&nbsp;&nbsp;&nbsp;标题内容</p>
<p>---------------------------------------------------------------------</p>
<p>StandardLegend(Legend)类：<br>void setBackgroundPaint(Paint paint)&nbsp;&nbsp;&nbsp;图示背景色<br>void setTitle(String title)&nbsp;&nbsp;&nbsp;&nbsp;图示标题内容<br>void setTitleFont(Font font)&nbsp;&nbsp;&nbsp;&nbsp;图示标题字体<br>void setBoundingBoxArcWidth(int arcWidth)&nbsp;&nbsp;图示边界圆角宽<br>void setBoundingBoxArcHeight(int arcHeight)&nbsp;&nbsp;图示边界圆角高<br>void setOutlinePaint(Paint paint)&nbsp;&nbsp;&nbsp;图示边界线条颜色<br>void setOutlineStroke(Stroke stroke)&nbsp;&nbsp;&nbsp;图示边界线条笔触<br>void setDisplaySeriesLines(boolean flag)&nbsp;&nbsp;图示项是否显示横线（折线图有效）<br>void setDisplaySeriesShapes(boolean flag)&nbsp;&nbsp;图示项是否显示形状（折线图有效）<br>void setItemFont(Font font)&nbsp;&nbsp;&nbsp;&nbsp;图示项字体<br>void setItemPaint(Paint paint)&nbsp;&nbsp;&nbsp;&nbsp;图示项字体颜色<br>void setAnchor(int anchor)&nbsp;&nbsp;&nbsp;&nbsp;图示在图表中的显示位置（参数常量在Legend类中定义）</p>
<p>---------------------------------------------------------------------</p>
<p>Axis类：<br>void setVisible(boolean flag)&nbsp;&nbsp;&nbsp;&nbsp;坐标轴是否可见<br>void setAxisLinePaint(Paint paint)&nbsp;&nbsp;&nbsp;坐标轴线条颜色（3D轴无效）<br>void setAxisLineStroke(Stroke stroke)&nbsp;&nbsp;&nbsp;坐标轴线条笔触（3D轴无效）<br>void setAxisLineVisible(boolean visible)&nbsp;&nbsp;坐标轴线条是否可见（3D轴无效）<br>void setFixedDimension(double dimension)&nbsp;&nbsp;（用于复合表中对多坐标轴的设置）<br>void setLabel(String label)&nbsp;&nbsp;&nbsp;&nbsp;坐标轴标题<br>void setLabelFont(Font font)&nbsp;&nbsp;&nbsp;&nbsp;坐标轴标题字体<br>void setLabelPaint(Paint paint)&nbsp;&nbsp;&nbsp;&nbsp;坐标轴标题颜色<br>void setLabelAngle(double angle)`&nbsp;&nbsp;&nbsp;坐标轴标题旋转角度（纵坐标可以旋转）<br>void setTickLabelFont(Font font)&nbsp;&nbsp;&nbsp;坐标轴标尺值字体<br>void setTickLabelPaint(Paint paint)&nbsp;&nbsp;&nbsp;坐标轴标尺值颜色<br>void setTickLabelsVisible(boolean flag)&nbsp;&nbsp;&nbsp;坐标轴标尺值是否显示<br>void setTickMarkPaint(Paint paint)&nbsp;&nbsp;&nbsp;坐标轴标尺颜色<br>void setTickMarkStroke(Stroke stroke)&nbsp;&nbsp;&nbsp;坐标轴标尺笔触<br>void setTickMarksVisible(boolean flag)&nbsp;&nbsp;&nbsp;坐标轴标尺是否显示</p>
<p>Axis(Axis)类：<br>void setAutoRange(boolean auto)&nbsp;&nbsp;&nbsp;&nbsp;自动设置数据轴数据范围<br>void setAutoRangeMinimumSize(double size)&nbsp;&nbsp;自动设置数据轴数据范围时数据范围的最小跨度<br>void setAutoTickUnitSelection(boolean flag)&nbsp;&nbsp;数据轴的数据标签是否自动确定（默认为true）<br>void setFixedAutoRange(double length)&nbsp;&nbsp;&nbsp;数据轴固定数据范围（设置100的话就是显示MAX到MAX-100那段数据范围）<br>void setInverted(boolean flag)&nbsp;&nbsp;&nbsp;&nbsp;数据轴是否反向（默认为false）<br>void setLowerMargin(double margin)&nbsp;&nbsp;&nbsp;数据轴下（左）边距<br>void setUpperMargin(double margin)&nbsp;&nbsp;&nbsp;数据轴上（右）边距<br>void setLowerBound(double min)&nbsp;&nbsp;&nbsp;&nbsp;数据轴上的显示最小值<br>void setUpperBound(double max)&nbsp;&nbsp;&nbsp;&nbsp;数据轴上的显示最大值<br>void setPositiveArrowVisible(boolean visible)&nbsp;&nbsp;是否显示正向箭头（3D轴无效）<br>void setNegativeArrowVisible(boolean visible)&nbsp;&nbsp;是否显示反向箭头（3D轴无效）<br>void setVerticalTickLabels(boolean flag)&nbsp;&nbsp;数据轴数据标签是否旋转到垂直<br>void setStandardTickUnits(TickUnitSource source)&nbsp;数据轴的数据标签（可以只显示整数标签，需要将AutoTickUnitSelection设false）</p>
<p>NumberAxis(Axis)类：<br>void setAutoRangeIncludesZero(boolean flag)&nbsp;&nbsp;是否强制在自动选择的数据范围中包含0<br>void setAutoRangeStickyZero(boolean flag)&nbsp;&nbsp;是否强制在整个数据轴中包含0，即使0不在数据范围中<br>void setNumberFormatOverride(NumberFormat formatter)&nbsp;数据轴数据标签的显示格式<br>void setTickUnit(NumberTickUnit unit)&nbsp;&nbsp;&nbsp;数据轴的数据标签（需要将AutoTickUnitSelection设false）</p>
<p>DateAxis(Axis)类：<br>void setMaximumDate(Date maximumDate)&nbsp;&nbsp;&nbsp;日期轴上的最小日期<br>void setMinimumDate(Date minimumDate)&nbsp;&nbsp;&nbsp;日期轴上的最大日期<br>void setRange(Date lower,Date upper)&nbsp;&nbsp;&nbsp;日期轴范围<br>void setDateFormatOverride(DateFormat formatter)&nbsp;日期轴日期标签的显示格式<br>void setTickUnit(DateTickUnit unit)&nbsp;&nbsp;&nbsp;日期轴的日期标签（需要将AutoTickUnitSelection设false）<br>void setTickMarkPosition(DateTickMarkPosition position)&nbsp;日期标签位置（参数常量在org.jfree.chart.axis.DateTickMarkPosition类中定义）</p>
<p>CategoryAxis(Axis)类：<br>void setCategoryMargin(double margin)&nbsp;&nbsp;&nbsp;分类轴边距<br>void setLowerMargin(double margin)&nbsp;&nbsp;&nbsp;分类轴下（左）边距<br>void setUpperMargin(double margin)&nbsp;&nbsp;&nbsp;分类轴上（右）边距<br>void setVerticalCategoryLabels(boolean flag)&nbsp;&nbsp;分类轴标题是否旋转到垂直<br>void setMaxCategoryLabelWidthRatio(float ratio)&nbsp;&nbsp;分类轴分类标签的最大宽度</p>
<img src ="http://www.blogjava.net/wealupa/aggbug/88291.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/wealupa/" target="_blank">常言笑</a> 2006-12-16 22:59 <a href="http://www.blogjava.net/wealupa/archive/2006/12/16/88291.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>学JFreeChart不得不看的中文API</title><link>http://www.blogjava.net/wealupa/archive/2006/12/16/88290.html</link><dc:creator>常言笑</dc:creator><author>常言笑</author><pubDate>Sat, 16 Dec 2006 14:58:00 GMT</pubDate><guid>http://www.blogjava.net/wealupa/archive/2006/12/16/88290.html</guid><wfw:comment>http://www.blogjava.net/wealupa/comments/88290.html</wfw:comment><comments>http://www.blogjava.net/wealupa/archive/2006/12/16/88290.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/wealupa/comments/commentRss/88290.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/wealupa/services/trackbacks/88290.html</trackback:ping><description><![CDATA[<p>Plot类：<br>void setBackgroundImage(Image image)&nbsp;&nbsp;&nbsp;数据区的背景图片<br>void setBackgroundImageAlignment(int alignment)&nbsp;&nbsp;数据区的背景图片对齐方式（参数常量在org.jfree.ui.Align类中定义）<br>void setBackgroundPaint(Paint paint)&nbsp;&nbsp;&nbsp;数据区的背景图片背景色<br>void setBackgroundAlpha(float alpha)&nbsp;&nbsp;&nbsp;数据区的背景透明度（0.0～1.0）<br>void setForegroundAlpha(float alpha)&nbsp;&nbsp;&nbsp;数据区的前景透明度（0.0～1.0）<br>void setDataAreaRatio(double ratio)&nbsp;&nbsp;&nbsp;数据区占整个图表区的百分比<br>void setOutLinePaint(Paint paint)&nbsp;&nbsp;&nbsp;数据区的边界线条颜色<br>void setOutLineStroke(Stroke stroke)&nbsp;&nbsp;&nbsp;数据区的边界线条笔触<br>void setNoDataMessage(String message)&nbsp;&nbsp;&nbsp;没有数据时显示的消息<br>void setNoDataMessageFont(Font font)&nbsp;&nbsp;&nbsp;没有数据时显示的消息字体<br>void setNoDataMessagePaint(Paint paint)&nbsp;&nbsp;&nbsp;没有数据时显示的消息颜色</p>
<p>CategoryPlot(Plot)类：<br>void setDataset(CategoryDataset dataset)&nbsp;&nbsp;数据区的2维数据表<br>void setColumnRenderingOrder(SortOrder order)&nbsp;&nbsp;数据分类的排序方式<br>void setAxisOffset(Spacer offset)&nbsp;&nbsp;&nbsp;坐标轴到数据区的间距<br>void setOrientation(PlotOrientation orientation)&nbsp;数据区的方向（PlotOrientation.HORIZONTAL或PlotOrientation.VERTICAL）<br>void setDomainAxis(CategoryAxis axis)&nbsp;&nbsp;&nbsp;数据区的分类轴<br>void setDomainAxisLocation(AxisLocation location)&nbsp;分类轴的位置（参数常量在org.jfree.chart.axis.AxisLocation类中定义）<br>void setDomainGridlinesVisible(boolean visible)&nbsp;&nbsp;分类轴网格是否可见<br>void setDomainGridlinePaint(Paint paint)&nbsp;&nbsp;分类轴网格线条颜色<br>void setDomainGridlineStroke(Stroke stroke)&nbsp;&nbsp;分类轴网格线条笔触<br>void setRangeAxis(Axis axis)&nbsp;&nbsp;&nbsp;数据区的数据轴<br>void setRangeAxisLocation(AxisLocation location)&nbsp;数据轴的位置（参数常量在org.jfree.chart.axis.AxisLocation类中定义）<br>void setRangeGridlinesVisible(boolean visible)&nbsp;&nbsp;数据轴网格是否可见<br>void setRangeGridlinePaint(Paint paint)&nbsp;&nbsp;&nbsp;数据轴网格线条颜色<br>void setRangeGridlineStroke(Stroke stroke)&nbsp;&nbsp;数据轴网格线条笔触<br>void setRenderer(CategoryItemRenderer renderer)&nbsp;&nbsp;数据区的表示者（详见Renderer组）<br>void addAnnotation(CategoryAnnotation annotation)&nbsp;给数据区加一个注释<br>void addRangeMarker(Marker marker,Layer layer)&nbsp;&nbsp;给数据区加一个数值范围区域</p>
<p>PiePlot(Plot)类：<br>void setDataset(PieDataset dataset)&nbsp;&nbsp;&nbsp;数据区的1维数据表<br>void setIgnoreNulls(boolean flag)&nbsp;&nbsp;&nbsp;忽略无值的分类<br>void setCircular(boolean flag)&nbsp;&nbsp;&nbsp;&nbsp;饼图是否一定是正圆<br>void setStartAngle(double angle)&nbsp;&nbsp;&nbsp;饼图的初始角度<br>void setDirection(Rotation direction)&nbsp;&nbsp;&nbsp;饼图的旋转方向<br>void setExplodePercent(int section,double percent)&nbsp;抽取的那块（1维数据表的分类下标）以及抽取出来的距离（0.0～1.0），3D饼图无效<br>void setLabelBackgroundPaint(Paint paint)&nbsp;&nbsp;分类标签的底色<br>void setLabelFont(Font font)&nbsp;&nbsp;&nbsp;&nbsp;分类标签的字体<br>void setLabelPaint(Paint paint)&nbsp;&nbsp;&nbsp;&nbsp;分类标签的字体颜色<br>void setLabelLinkMargin(double margin)&nbsp;&nbsp;&nbsp;分类标签与图的连接线边距<br>void setLabelLinkPaint(Paint paint)&nbsp;&nbsp;&nbsp;分类标签与图的连接线颜色<br>void setLabelLinkStroke(Stroke stroke)&nbsp;&nbsp;&nbsp;分类标签与图的连接线笔触<br>void setLabelOutlinePaint(Paint paint)&nbsp;&nbsp;&nbsp;分类标签边框颜色<br>void setLabelOutlineStroke(Paint paint)&nbsp;&nbsp;&nbsp;分类标签边框笔触<br>void setLabelShadowPaint(Paint paint)&nbsp;&nbsp;&nbsp;分类标签阴影颜色<br>void setMaximumLabelWidth(double width)&nbsp;&nbsp;&nbsp;分类标签的最大长度（0.0～1.0）<br>void setPieIndex(int index)&nbsp;&nbsp;&nbsp;&nbsp;饼图的索引（复合饼图中用到）<br>void setSectionOutlinePaint(int section,Paint paint)&nbsp;指定分类饼的边框颜色<br>void setSectionOutlineStroke(int section,Stroke stroke)&nbsp;指定分类饼的边框笔触<br>void setSectionPaint(int section,Paint paint)&nbsp;&nbsp;指定分类饼的颜色<br>void setShadowPaint(Paint paint)&nbsp;&nbsp;&nbsp;饼图的阴影颜色<br>void setShadowXOffset(double offset)&nbsp;&nbsp;&nbsp;饼图的阴影相对图的水平偏移<br>void setShadowYOffset(double offset)&nbsp;&nbsp;&nbsp;饼图的阴影相对图的垂直偏移<br>void setLabelGenerator(PieSectionLabelGenerator generator)&nbsp;分类标签的格式，设置成null则整个标签包括连接线都不显示<br>void setToolTipGenerator(PieToolTipGenerator generator)&nbsp;&nbsp;MAP中鼠标移上的显示格式<br>void setURLGenerator(PieURLGenerator generator)&nbsp;&nbsp;&nbsp;MAP中钻取链接格式</p>
<p>PiePlot3D(PiePlot)类：<br>void setDepthFactor(double factor)&nbsp;&nbsp;&nbsp;3D饼图的Z轴高度（0.0～1.0）</p>
<p>MultiplePiePlot(Plot)类：<br>void setLimit(double limit)&nbsp;&nbsp;&nbsp;&nbsp;每个饼图之间的数据关联（详细比较复杂）&nbsp;&nbsp;&nbsp;<br>void setPieChart(JFreeChart pieChart)&nbsp;&nbsp;&nbsp;每个饼图的显示方式（见JFreeChart类个PiePlot类）</p>
<p>---------------------------------------------------------------------</p>
<p>AbstractRenderer类：<br>void setItemLabelAnchorOffset(double offset)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;数据标签的与数据点的偏移<br>void setItemLabelsVisible(boolean visible)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;数据标签是否可见<br>void setItemLabelFont(Font font)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;数据标签的字体<br>void setItemLabelPaint(Paint paint)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;数据标签的字体颜色<br>void setItemLabelPosition(ItemLabelPosition position)&nbsp;&nbsp;&nbsp;&nbsp;数据标签位置<br>void setPositiveItemLabelPosition(ItemLabelPosition position)&nbsp;&nbsp;&nbsp;正数标签位置<br>void setNegativeItemLabelPosition(ItemLabelPosition position)&nbsp;&nbsp;&nbsp;负数标签位置<br>void setOutLinePaint(Paint paint)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;图形边框的线条颜色<br>void setOutLineStroke(Stroke stroke)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;图形边框的线条笔触<br>void setPaint(Paint paint)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;所有分类图形的颜色<br>void setShape(Shape shape)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;所有分类图形的形状（如折线图的点）<br>void setStroke(Stroke stroke)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;所有分类图形的笔触（如折线图的线）<br>void setSeriesItemLabelsVisible(int series,boolean visible)&nbsp;&nbsp;&nbsp;指定分类的数据标签是否可见<br>void setSeriesItemLabelFont(int series,Font font)&nbsp;&nbsp;&nbsp;&nbsp;指定分类的数据标签的字体<br>void setSeriesItemLabelPaint(int series,Paint paint)&nbsp;&nbsp;&nbsp;&nbsp;指定分类的数据标签的字体颜色<br>void setSeriesItemLabelPosition(int series,ItemLabelPosition position)&nbsp;&nbsp;数据标签位置<br>void setSeriesPositiveItemLabelPosition(int series,ItemLabelPosition position)&nbsp;正数标签位置<br>void setSeriesNegativeItemLabelPosition(int series,ItemLabelPosition position)&nbsp;负数标签位置<br>void setSeriesOutLinePaint(int series,Paint paint)&nbsp;&nbsp;&nbsp;&nbsp;指定分类的图形边框的线条颜色<br>void setSeriesOutLineStroke(int series,Stroke stroke)&nbsp;&nbsp;&nbsp;&nbsp;指定分类的图形边框的线条笔触<br>void setSeriesPaint(int series,Paint paint)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;指定分类图形的颜色<br>void setSeriesShape(int series,Shape shape)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;指定分类图形的形状（如折线图的点）<br>void setSeriesStroke(int series,Stroke stroke)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;指定分类图形的笔触（如折线图的线）</p>
<p>AbstractCategoryItemRenderer(AbstractRenderer)类：<br>void setLabelGenerator(CategoryLabelGenerator generator)&nbsp;&nbsp;&nbsp;数据标签的格式<br>void setToolTipGenerator(CategoryToolTipGenerator generator)&nbsp;&nbsp;&nbsp;MAP中鼠标移上的显示格式<br>void setItemURLGenerator(CategoryURLGenerator generator)&nbsp;&nbsp;&nbsp;MAP中钻取链接格式<br>void setSeriesLabelGenerator(int series,CategoryLabelGenerator generator)&nbsp;指定分类的数据标签的格式<br>void setSeriesToolTipGenerator(int series,CategoryToolTipGenerator generator)&nbsp;指定分类的MAP中鼠标移上的显示格式<br>void setSeriesItemURLGenerator(int series,CategoryURLGenerator generator)&nbsp;指定分类的MAP中钻取链接格式</p>
<p>BarRenderer(AbstractCategoryItemRenderer)类：<br>void setDrawBarOutline(boolean draw)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;是否画图形边框<br>void setItemMargin(double percent)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;每个BAR之间的间隔<br>void setMaxBarWidth(double percent)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;每个BAR的最大宽度<br>void setMinimumBarLength(double min)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;最短的BAR长度，避免数值太小而显示不出<br>void setPositiveItemLabelPositionFallback(ItemLabelPosition position)&nbsp;&nbsp;无法在BAR中显示的正数标签位置<br>void setNegativeItemLabelPositionFallback(ItemLabelPosition position)&nbsp;&nbsp;无法在BAR中显示的负数标签位置</p>
<p>BarRenderer3D(BarRenderer)类：<br>void setWallPaint(Paint paint)&nbsp;&nbsp;&nbsp;&nbsp;3D坐标轴的墙体颜色</p>
<p>StackedBarRenderer(BarRenderer)类：<br>没有特殊的设置</p>
<p>StackedBarRenderer3D(BarRenderer3D)类：<br>没有特殊的设置</p>
<p>GroupedStackedBarRenderer(StackedBarRenderer)类：<br>void setSeriesToGroupMap(KeyToGroupMap map)&nbsp;&nbsp;将分类自由的映射成若干个组（KeyToGroupMap.mapKeyToGroup(series,group)）</p>
<p>LayeredBarRenderer(BarRenderer)类：<br>void setSeriesBarWidth(int series,double width)&nbsp;&nbsp;设定每个分类的宽度（注意设置不要使某分类被覆盖）</p>
<p>WaterfallBarRenderer(BarRenderer)类：<br>void setFirstBarPaint(Paint paint)&nbsp;&nbsp;&nbsp;第一个柱图的颜色<br>void setLastBarPaint(Paint paint)&nbsp;&nbsp;&nbsp;最后一个柱图的颜色<br>void setPositiveBarPaint(Paint paint)&nbsp;&nbsp;&nbsp;正值柱图的颜色<br>void setNegativeBarPaint(Paint paint)&nbsp;&nbsp;&nbsp;负值柱图的颜色</p>
<p>IntervalBarRenderer(BarRenderer)类：<br>需要传IntervalCategoryDataset作为数据源</p>
<p>GanttBarRenderer(IntervalBarRenderer)类：<br>void setCompletePaint(Paint paint)&nbsp;&nbsp;&nbsp;完成进度颜色<br>void setIncompletePaint(Paint paint)&nbsp;&nbsp;&nbsp;未完成进度颜色<br>void setStartPercent(double percent)&nbsp;&nbsp;&nbsp;设置进度条在整条中的起始位置（0.0～1.0）<br>void setEndPercent(double percent)&nbsp;&nbsp;&nbsp;设置进度条在整条中的结束位置（0.0～1.0）</p>
<p>StatisticBarRenderer(BarRenderer)类：<br>需要传StatisticCategoryDataset作为数据源</p>
<p>LineAndShapeRenderer(AbstractCategoryItemRenderer)类：<br>void setDrawLines(boolean draw)&nbsp;&nbsp;&nbsp;&nbsp;是否折线的数据点之间用线连<br>void setDrawShapes(boolean draw)&nbsp;&nbsp;&nbsp;是否折线的数据点根据分类使用不同的形状<br>void setShapesFilled(boolean filled)&nbsp;&nbsp;&nbsp;所有分类是否填充数据点图形<br>void setSeriesShapesFilled(int series,boolean filled)&nbsp;指定分类是否填充数据点图形<br>void setUseFillPaintForShapeOutline(boolean use)&nbsp;指定是否填充数据点的Paint也被用于画数据点形状的边框</p>
<p>LevelRenderer(AbstractCategoryItemRenderer)类：<br>void setItemMargin(double percent)&nbsp;&nbsp;&nbsp;每个分类之间的间隔<br>void setMaxItemWidth(double percent)&nbsp;&nbsp;&nbsp;每个分类的最大宽度</p>
<p>CategoryStepRenderer(AbstractCategoryItemRenderer)类：<br>void setStagger(boolean shouldStagger)&nbsp;&nbsp;&nbsp;不同分类的图是否交错</p>
<p>MinMaxCategoryRenderer(AbstractCategoryItemRenderer)类：<br>void setDrawLines(boolean drawLines)&nbsp;&nbsp;&nbsp;是否在每个分类线间画连接线<br>void setGroupPaint(Paint groupPaint)&nbsp;&nbsp;&nbsp;一组图形连接线的颜色<br>void setGroupStroke(Stroke groupStroke)&nbsp;&nbsp;&nbsp;一组图形连接线的笔触<br>void setMaxIcon(Icon maxIcon)&nbsp;&nbsp;&nbsp;&nbsp;最大值的ICON<br>void setMinIcon(Icon minIcon)&nbsp;&nbsp;&nbsp;&nbsp;最小值的ICON<br>void setObjectIcon(Icon objectIcon)&nbsp;&nbsp;&nbsp;所有值的ICON</p>
<p>AreaRender(AbstractCategoryItemRenderer)类：<br>没有特殊的设置</p>
<p>StackedAreaRender(AreaRender)类：<br>没有特殊的设置<br>没有特殊的设置<br></p>
<p>关键就是用好Renderer这个类了，再贴个例子：<br>&nbsp;&nbsp;&nbsp; String sFont = "宋体";<br>&nbsp;&nbsp;&nbsp; chart.setBorderVisible(true);<br>&nbsp;&nbsp;&nbsp; chart.setBorderPaint(new Color(0xFF,0x66,0x00));<br>&nbsp;&nbsp;&nbsp; chart.setBackgroundPaint(new Color(0xFF,0xF3,0xDE));<br>&nbsp;&nbsp;&nbsp; chart.getTitle().setPaint(Color.red);<br>&nbsp;&nbsp;&nbsp; chart.getTitle().setFont(new Font(sFont,Font.BOLD,14));</p>
<p>&nbsp;&nbsp;&nbsp; //设置Plot，不显示所有网格<br>&nbsp;&nbsp;&nbsp; ((CategoryPlot)chart.getPlot()).setOutlinePaint(null);<br>&nbsp;&nbsp;&nbsp; ((CategoryPlot)chart.getPlot()).setDomainGridlinesVisible(false);<br>&nbsp;&nbsp;&nbsp; ((CategoryPlot)chart.getPlot()).setRangeGridlinesVisible(false);</p>
<p>&nbsp;&nbsp;&nbsp; //设置横轴字体，设定横轴轴线不可见，隐藏纵轴<br>&nbsp;&nbsp;&nbsp; ((CategoryPlot)chart.getPlot()).getDomainAxis().setTickLabelFont(new Font(sFont,Font.PLAIN,12));<br>&nbsp;&nbsp;&nbsp; ((CategoryPlot)chart.getPlot()).getDomainAxis().setAxisLineVisible(false);<br>&nbsp;&nbsp;&nbsp; ((CategoryPlot)chart.getPlot()).getRangeAxis().setVisible(false);</p>
<p>&nbsp;&nbsp;&nbsp; //采用BarRenderer作为表示器<br>&nbsp;&nbsp;&nbsp; BarRenderer renderer = new BarRenderer();<br>&nbsp;&nbsp;&nbsp; renderer.setPaint(new GradientPaint(0.0f,0.0f,Color.orange,0.0f,0.0f,Color.yellow));<br>&nbsp;&nbsp;&nbsp; renderer.setOutlinePaint(Color.orange);<br>&nbsp;&nbsp;&nbsp; renderer.setDrawBarOutline(true);</p>
<p>&nbsp;&nbsp;&nbsp; //在条中央显示投票数值<br>&nbsp;&nbsp;&nbsp; renderer.setItemLabelAnchorOffset(-20.0f);<br>&nbsp;&nbsp;&nbsp; renderer.setLabelGenerator(new StandardCategoryLabelGenerator("{2}",new DecimalFormat()));<br>&nbsp;&nbsp;&nbsp; renderer.setPositiveItemLabelPosition(new ItemLabelPosition());<br>&nbsp;&nbsp;&nbsp; renderer.setItemLabelsVisible(true);</p>
<img src ="http://www.blogjava.net/wealupa/aggbug/88290.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/wealupa/" target="_blank">常言笑</a> 2006-12-16 22:58 <a href="http://www.blogjava.net/wealupa/archive/2006/12/16/88290.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>JFreeChart 一些特性</title><link>http://www.blogjava.net/wealupa/archive/2006/12/16/88288.html</link><dc:creator>常言笑</dc:creator><author>常言笑</author><pubDate>Sat, 16 Dec 2006 14:57:00 GMT</pubDate><guid>http://www.blogjava.net/wealupa/archive/2006/12/16/88288.html</guid><wfw:comment>http://www.blogjava.net/wealupa/comments/88288.html</wfw:comment><comments>http://www.blogjava.net/wealupa/archive/2006/12/16/88288.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/wealupa/comments/commentRss/88288.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/wealupa/services/trackbacks/88288.html</trackback:ping><description><![CDATA[<p><strong><span style="FONT-FAMILY: 楷体_GB2312">柱状图高级特性</span> </strong></p>
<p>BarRenderer3D renderer = new BarRenderer3D();<br>renderer.setBaseOutlinePaint(Color.BLACK);<br>//设置 Wall 的颜色<br>renderer.setWallPaint(Color.gray);<br>//设置每种水果代表的柱的颜色<br>renderer.setSeriesPaint(0, new Color(0, 0, 255));<br>renderer.setSeriesPaint(1, new Color(0, 100, 255));<br>renderer.setSeriesPaint(2, Color.GREEN);<br>//设置每种水果代表的柱的 Outline 颜色<br>renderer.setSeriesOutlinePaint(0, Color.BLACK);<br>renderer.setSeriesOutlinePaint(1, Color.BLACK);<br>renderer.setSeriesOutlinePaint(2, Color.BLACK);<br>//设置每个地区所包含的平行柱的之间距离<br>renderer.setItemMargin(0.1);<br>//显示每个柱的数值，并修改该数值的字体属性<br>renderer.setItemLabelGenerator(new StandardCategoryItemLabelGenerator());<br>renderer.setItemLabelFont(new Font("黑体",Font.PLAIN,12));<br>renderer.setItemLabelsVisible(true);</p>
<p>&nbsp;</p>
<p><strong>完整范例</strong> </p>
<p>　　前面都是一些代码片段，现在把这些片段组合成一个完整范例。<br></p>
<p>&lt;%@ page contentType="text/html;charset=GBK"%&gt;<br>&lt;%@ page import="java.awt.Color,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;java.awt.Font,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;org.jfree.chart.ChartFactory,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;org.jfree.chart.JFreeChart,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;org.jfree.chart.plot.PlotOrientation,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;org.jfree.chart.servlet.ServletUtilities,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;org.jfree.data.CategoryDataset,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;org.jfree.data.DatasetUtilities,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;org.jfree.chart.plot.CategoryPlot,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;org.jfree.chart.axis.CategoryAxis,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;org.jfree.chart.axis.Axis,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;org.jfree.chart.renderer.BarRenderer3D,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;org.jfree.chart.labels.StandardCategoryItemLabelGenerator,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;org.jfree.chart.axis.AxisLocation"%&gt;<br>&lt;%<br>double[][] data = new double[][] {{672, 766, 223, 540, 126},{325, 521, 210, 340, 106},{332, 256, 523, 240, 526}};<br>String[] rowKeys = {"苹果","梨子","葡萄"};<br>String[] columnKeys = {"北京","上海","广州","成都","深圳"};<br>CategoryDataset dataset = DatasetUtilities.createCategoryDataset(rowKeys, columnKeys, data);<br><br>JFreeChart chart = ChartFactory.createBarChart3D("水果销量图统计",<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;null,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;null,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;dataset,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;PlotOrientation.VERTICAL,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;true,false,false);<br>chart.setBackgroundPaint(Color.WHITE);<br>CategoryPlot plot = chart.getCategoryPlot();<br><br>CategoryAxis domainAxis = plot.getDomainAxis();<br>domainAxis.setVerticalCategoryLabels(false);<br>plot.setDomainAxis(domainAxis);<br><br>Axis rangeAxis = plot.getRangeAxis();<br>//设置最高的一个 Item 与图片顶端的距离<br>rangeAxis.setUpperMargin(0.15);<br>//设置最低的一个 Item 与图片底端的距离<br>rangeAxis.setLowerMargin(0.15);<br>plot.setRangeAxis(rangeAxis);<br><br>BarRenderer3D renderer = new BarRenderer3D();<br>renderer.setBaseOutlinePaint(Color.BLACK);<br>//设置 Wall 的颜色<br>renderer.setWallPaint(Color.gray);<br>//设置每种水果代表的柱的颜色<br>renderer.setSeriesPaint(0, new Color(0, 0, 255));<br>renderer.setSeriesPaint(1, new Color(0, 100, 255));<br>renderer.setSeriesPaint(2, Color.GREEN);<br>//设置每个地区所包含的平行柱的之间距离<br>renderer.setItemMargin(0.1);<br>//显示每个柱的数值，并修改该数值的字体属性<br>renderer.setItemLabelGenerator(new StandardCategoryItemLabelGenerator());<br>renderer.setItemLabelsVisible(true);<br>plot.setRenderer(renderer);<br><br>//设置柱的透明度<br>plot.setForegroundAlpha(0.6f);<br>//设置地区、销量的显示位置<br>plot.setDomainAxisLocation(AxisLocation.TOP_OR_RIGHT);<br>plot.setRangeAxisLocation(AxisLocation.BOTTOM_OR_RIGHT);<br><br>String filename = ServletUtilities.saveChartAsPNG(chart, 500, 300, null, session);<br>String graphURL = request.getContextPath() + "/servlet/DisplayChart?filename=" + filename;<br>%s&gt;<br>&lt;img src="&lt;%= graphURL %&gt;" width=500 height=300 border=0 usemap="#&lt;%= filename %&gt;"&gt;<br></p>
<img src ="http://www.blogjava.net/wealupa/aggbug/88288.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/wealupa/" target="_blank">常言笑</a> 2006-12-16 22:57 <a href="http://www.blogjava.net/wealupa/archive/2006/12/16/88288.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Struts Action 中ActionForward问题</title><link>http://www.blogjava.net/wealupa/archive/2006/12/16/88287.html</link><dc:creator>常言笑</dc:creator><author>常言笑</author><pubDate>Sat, 16 Dec 2006 14:56:00 GMT</pubDate><guid>http://www.blogjava.net/wealupa/archive/2006/12/16/88287.html</guid><wfw:comment>http://www.blogjava.net/wealupa/comments/88287.html</wfw:comment><comments>http://www.blogjava.net/wealupa/archive/2006/12/16/88287.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/wealupa/comments/commentRss/88287.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/wealupa/services/trackbacks/88287.html</trackback:ping><description><![CDATA[<div><strong>1、第一种方法</strong> </div>
<div>&nbsp;</div>
<div>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><span style="COLOR: #008080">&nbsp;1</span> <img id=Codehighlighter1_117_750_Open_Image onclick="this.style.display='none'; Codehighlighter1_117_750_Open_Text.style.display='none'; Codehighlighter1_117_750_Closed_Image.style.display='inline'; Codehighlighter1_117_750_Closed_Text.style.display='inline';" src="http://www.blogjava.net/Images/OutliningIndicators/ExpandedBlockStart.gif" align=top> <img id=Codehighlighter1_117_750_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_117_750_Closed_Text.style.display='none'; Codehighlighter1_117_750_Open_Image.style.display='inline'; Codehighlighter1_117_750_Open_Text.style.display='inline';" src="http://www.blogjava.net/Images/OutliningIndicators/ContractedBlock.gif" align=top> <span style="COLOR: #0000ff">private</span> <span style="COLOR: #000000">&nbsp;ActionForward&nbsp;encompetedataSelect(ActionForm&nbsp;form,&nbsp;HttpServletRequest&nbsp;request,&nbsp;HttpServletResponse&nbsp;response)&nbsp;</span> <span id=Codehighlighter1_117_750_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.blogjava.net/Images/dot.gif"> </span><span id=Codehighlighter1_117_750_Open_Text><span style="COLOR: #000000">{<br></span><span style="COLOR: #008080">&nbsp;2</span> <span style="COLOR: #000000"><img src="http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;HttpSession&nbsp;_session&nbsp;</span> <span style="COLOR: #000000">=</span> <span style="COLOR: #000000">&nbsp;request.getSession();<br></span><span style="COLOR: #008080">&nbsp;3</span> <span style="COLOR: #000000"><img src="http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;Engineermarket&nbsp;em&nbsp;</span> <span style="COLOR: #000000">=</span> <span style="COLOR: #000000">&nbsp;</span> <span style="COLOR: #0000ff">new</span> <span style="COLOR: #000000">&nbsp;Engineermarket();<br></span><span style="COLOR: #008080">&nbsp;4</span> <span style="COLOR: #000000"><img src="http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;em&nbsp;</span> <span style="COLOR: #000000">=</span> <span style="COLOR: #000000">&nbsp;(Engineermarket)_session.getAttribute(</span> <span style="COLOR: #000000">"</span> <span style="COLOR: #000000">engineermarket</span> <span style="COLOR: #000000">"</span> <span style="COLOR: #000000">);<br></span><span style="COLOR: #008080">&nbsp;5</span> <span style="COLOR: #000000"><img id=Codehighlighter1_289_432_Open_Image onclick="this.style.display='none'; Codehighlighter1_289_432_Open_Text.style.display='none'; Codehighlighter1_289_432_Closed_Image.style.display='inline'; Codehighlighter1_289_432_Closed_Text.style.display='inline';" src="http://www.blogjava.net/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align=top> <img id=Codehighlighter1_289_432_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_289_432_Closed_Text.style.display='none'; Codehighlighter1_289_432_Open_Image.style.display='inline'; Codehighlighter1_289_432_Open_Text.style.display='inline';" src="http://www.blogjava.net/Images/OutliningIndicators/ContractedSubBlock.gif" align=top>&nbsp;&nbsp;</span> <span style="COLOR: #0000ff">if</span> <span style="COLOR: #000000">(</span> <span style="COLOR: #0000ff">null</span> <span style="COLOR: #000000">==</span> <span style="COLOR: #000000">em)&nbsp;</span> <span id=Codehighlighter1_289_432_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.blogjava.net/Images/dot.gif"> </span><span id=Codehighlighter1_289_432_Open_Text><span style="COLOR: #000000">{<br></span><span style="COLOR: #008080">&nbsp;6</span> <span style="COLOR: #000000"><img src="http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;ActionForward&nbsp;file&nbsp;</span> <span style="COLOR: #000000">=</span> <span style="COLOR: #000000">&nbsp;</span> <span style="COLOR: #0000ff">new</span> <span style="COLOR: #000000">&nbsp;ActionForward(</span> <span style="COLOR: #000000">"</span> <span style="COLOR: #000000">engineermarket.do?actionType=engineermkChange&amp;actionName=encompetedata</span> <span style="COLOR: #000000">"</span> <span style="COLOR: #000000">,&nbsp;</span> <span style="COLOR: #0000ff">true</span> <span style="COLOR: #000000">);<br></span><span style="COLOR: #008080">&nbsp;7</span> <span style="COLOR: #000000"><img src="http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;</span> <span style="COLOR: #0000ff">return</span> <span style="COLOR: #000000">&nbsp;file;<br></span><span style="COLOR: #008080">&nbsp;8</span> <span style="COLOR: #000000"><img id=Codehighlighter1_439_747_Open_Image onclick="this.style.display='none'; Codehighlighter1_439_747_Open_Text.style.display='none'; Codehighlighter1_439_747_Closed_Image.style.display='inline'; Codehighlighter1_439_747_Closed_Text.style.display='inline';" src="http://www.blogjava.net/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align=top> <img id=Codehighlighter1_439_747_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_439_747_Closed_Text.style.display='none'; Codehighlighter1_439_747_Open_Image.style.display='inline'; Codehighlighter1_439_747_Open_Text.style.display='inline';" src="http://www.blogjava.net/Images/OutliningIndicators/ContractedSubBlock.gif" align=top>&nbsp;&nbsp;}</span> </span><span style="COLOR: #000000">&nbsp;</span> <span style="COLOR: #0000ff">else</span> <span style="COLOR: #000000">&nbsp;</span> <span id=Codehighlighter1_439_747_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.blogjava.net/Images/dot.gif"> </span><span id=Codehighlighter1_439_747_Open_Text><span style="COLOR: #000000">{<br></span><span style="COLOR: #008080">&nbsp;9</span> <span style="COLOR: #000000"><img src="http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;String&nbsp;hql&nbsp;</span> <span style="COLOR: #000000">=</span> <span style="COLOR: #000000">&nbsp;</span> <span style="COLOR: #000000">"</span> <span style="COLOR: #000000">from&nbsp;Encompetedata&nbsp;where&nbsp;engineermarket.id='</span> <span style="COLOR: #000000">"</span> <span style="COLOR: #000000">+</span> <span style="COLOR: #000000">em.getId()</span> <span style="COLOR: #000000">+</span> <span style="COLOR: #000000">"</span> <span style="COLOR: #000000">'</span> <span style="COLOR: #000000">"</span> <span style="COLOR: #000000">;<br></span><span style="COLOR: #008080">10</span> <span style="COLOR: #000000"><img src="http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;List&nbsp;list&nbsp;</span> <span style="COLOR: #000000">=</span> <span style="COLOR: #000000">&nbsp;(List)encompetedataServiceI.getEncontentBySql(hql);<br></span><span style="COLOR: #008080">11</span> <span style="COLOR: #000000"><img src="http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;_session.setAttribute(</span> <span style="COLOR: #000000">"</span> <span style="COLOR: #000000">encompetedataResult</span> <span style="COLOR: #000000">"</span> <span style="COLOR: #000000">,list);<br></span><span style="COLOR: #008080">12</span> <span style="COLOR: #000000"><img src="http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;ActionForward&nbsp;file&nbsp;</span> <span style="COLOR: #000000">=</span> <span style="COLOR: #000000">&nbsp;</span> <span style="COLOR: #0000ff">new</span> <span style="COLOR: #000000">&nbsp;ActionForward(</span> <span style="COLOR: #000000">"</span> <span style="COLOR: #000000">/jsp/engineer/encompetedataList.jsp</span> <span style="COLOR: #000000">"</span> <span style="COLOR: #000000">,&nbsp;</span> <span style="COLOR: #0000ff">true</span> <span style="COLOR: #000000">);<br></span><span style="COLOR: #008080">13</span> <span style="COLOR: #000000"><img src="http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;</span> <span style="COLOR: #0000ff">return</span> <span style="COLOR: #000000">&nbsp;file;<br></span><span style="COLOR: #008080">14</span> <span style="COLOR: #000000"><img src="http://www.blogjava.net/Images/OutliningIndicators/ExpandedSubBlockEnd.gif" align=top>&nbsp;&nbsp;}</span> </span><span style="COLOR: #000000"><br></span><span style="COLOR: #008080">15</span> <span style="COLOR: #000000"><img src="http://www.blogjava.net/Images/OutliningIndicators/ExpandedBlockEnd.gif" align=top>&nbsp;}</span> </span></div>
</div>
<div>&nbsp;</div>
<div><strong>2、第二种方法</strong> </div>
<div>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><span style="COLOR: #008080">1</span> <img id=Codehighlighter1_112_330_Open_Image onclick="this.style.display='none'; Codehighlighter1_112_330_Open_Text.style.display='none'; Codehighlighter1_112_330_Closed_Image.style.display='inline'; Codehighlighter1_112_330_Closed_Text.style.display='inline';" src="http://www.blogjava.net/Images/OutliningIndicators/ExpandedBlockStart.gif" align=top> <img id=Codehighlighter1_112_330_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_112_330_Closed_Text.style.display='none'; Codehighlighter1_112_330_Open_Image.style.display='inline'; Codehighlighter1_112_330_Open_Text.style.display='inline';" src="http://www.blogjava.net/Images/OutliningIndicators/ContractedBlock.gif" align=top> <span style="COLOR: #0000ff">private</span> <span style="COLOR: #000000">&nbsp;String&nbsp;encompetedataEditForm(ActionForm&nbsp;form,&nbsp;HttpServletRequest&nbsp;request,&nbsp;HttpServletResponse&nbsp;response)&nbsp;</span> <span id=Codehighlighter1_112_330_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.blogjava.net/Images/dot.gif"> </span><span id=Codehighlighter1_112_330_Open_Text><span style="COLOR: #000000">{<br></span><span style="COLOR: #008080">2</span> <span style="COLOR: #000000"><img src="http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;Integer&nbsp;rid&nbsp;</span> <span style="COLOR: #000000">=</span> <span style="COLOR: #000000">&nbsp;</span> <span style="COLOR: #0000ff">null</span> <span style="COLOR: #000000">;<br></span><span style="COLOR: #008080">3</span> <span style="COLOR: #000000"><img src="http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;rid&nbsp;</span> <span style="COLOR: #000000">=</span> <span style="COLOR: #000000">&nbsp;</span> <span style="COLOR: #0000ff">new</span> <span style="COLOR: #000000">&nbsp;Integer(request.getParameter(</span> <span style="COLOR: #000000">"</span> <span style="COLOR: #000000">ID</span> <span style="COLOR: #000000">"</span> <span style="COLOR: #000000">));<br></span><span style="COLOR: #008080">4</span> <span style="COLOR: #000000"><img src="http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;request.setAttribute(</span> <span style="COLOR: #000000">"</span> <span style="COLOR: #000000">model</span> <span style="COLOR: #000000">"</span> <span style="COLOR: #000000">,&nbsp;encompetedataGet(rid));<br></span><span style="COLOR: #008080">5</span> <span style="COLOR: #000000"><img src="http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;request.setAttribute(</span> <span style="COLOR: #000000">"</span> <span style="COLOR: #000000">actionType</span> <span style="COLOR: #000000">"</span> <span style="COLOR: #000000">,&nbsp;</span> <span style="COLOR: #000000">"</span> <span style="COLOR: #000000">encompetedataMod</span> <span style="COLOR: #000000">"</span> <span style="COLOR: #000000">);<br></span><span style="COLOR: #008080">6</span> <span style="COLOR: #000000"><img src="http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;</span> <span style="COLOR: #0000ff">return</span> <span style="COLOR: #000000">&nbsp;</span> <span style="COLOR: #000000">"</span> <span style="COLOR: #000000">encompetedataForm</span> <span style="COLOR: #000000">"</span> <span style="COLOR: #000000">;<br></span><span style="COLOR: #008080">7</span> <span style="COLOR: #000000"><img src="http://www.blogjava.net/Images/OutliningIndicators/ExpandedBlockEnd.gif" align=top>&nbsp;}</span> </span></div>
</div>
<img src ="http://www.blogjava.net/wealupa/aggbug/88287.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/wealupa/" target="_blank">常言笑</a> 2006-12-16 22:56 <a href="http://www.blogjava.net/wealupa/archive/2006/12/16/88287.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Struts-config.xml问题</title><link>http://www.blogjava.net/wealupa/archive/2006/12/16/88286.html</link><dc:creator>常言笑</dc:creator><author>常言笑</author><pubDate>Sat, 16 Dec 2006 14:55:00 GMT</pubDate><guid>http://www.blogjava.net/wealupa/archive/2006/12/16/88286.html</guid><wfw:comment>http://www.blogjava.net/wealupa/comments/88286.html</wfw:comment><comments>http://www.blogjava.net/wealupa/archive/2006/12/16/88286.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/wealupa/comments/commentRss/88286.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/wealupa/services/trackbacks/88286.html</trackback:ping><description><![CDATA[<div><span style="FONT-SIZE: 12pt; FONT-FAMILY: 楷体_GB2312"><strong>1、path多参数传递问题</strong> </span></div>
<div>&nbsp;</div>
<div>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top> <span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;</span> <span style="COLOR: #0000ff">&lt;</span> <span style="COLOR: #800000">forward&nbsp;</span> <span style="COLOR: #ff0000">name</span> <span style="COLOR: #0000ff">="engineermarket"</span> <span style="COLOR: #ff0000">&nbsp;path</span> <span style="COLOR: #0000ff">="/engineermarket.do?actionType=engineermkChange&amp;amp;actionName=enchannelsanalyze"</span> <span style="COLOR: #ff0000">&nbsp;</span> <span style="COLOR: #0000ff">/&gt;</span> </div>
</div>
<img src ="http://www.blogjava.net/wealupa/aggbug/88286.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/wealupa/" target="_blank">常言笑</a> 2006-12-16 22:55 <a href="http://www.blogjava.net/wealupa/archive/2006/12/16/88286.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>SpringMvc+Spring+Hibernate的问题总结</title><link>http://www.blogjava.net/wealupa/archive/2006/12/16/88281.html</link><dc:creator>常言笑</dc:creator><author>常言笑</author><pubDate>Sat, 16 Dec 2006 14:51:00 GMT</pubDate><guid>http://www.blogjava.net/wealupa/archive/2006/12/16/88281.html</guid><wfw:comment>http://www.blogjava.net/wealupa/comments/88281.html</wfw:comment><comments>http://www.blogjava.net/wealupa/archive/2006/12/16/88281.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/wealupa/comments/commentRss/88281.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/wealupa/services/trackbacks/88281.html</trackback:ping><description><![CDATA[<div><span style="FONT-SIZE: 12pt; FONT-FAMILY: 楷体_GB2312"><strong>1、sessionFactory问题</strong> </span></div>
<div>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top> <span style="COLOR: #0000ff">&lt;</span> <span style="COLOR: #800000">bean&nbsp;</span> <span style="COLOR: #ff0000">id</span> <span style="COLOR: #0000ff">="sessionFactory"</span> <span style="COLOR: #ff0000">&nbsp;class</span> <span style="COLOR: #0000ff">="org.springwork.orm.hibernate3.LocalSessionFactoryBean"</span> <span style="COLOR: #0000ff">&gt;</span> <span style="COLOR: #000000"><br><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;</span> <span style="COLOR: #0000ff">&lt;</span> <span style="COLOR: #800000">property&nbsp;</span> <span style="COLOR: #ff0000">name</span> <span style="COLOR: #0000ff">="dataSource"</span> <span style="COLOR: #0000ff">&gt;</span> <span style="COLOR: #000000"><br><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;</span> <span style="COLOR: #0000ff">&lt;</span> <span style="COLOR: #800000">ref&nbsp;</span> <span style="COLOR: #ff0000">bean</span> <span style="COLOR: #0000ff">="DataSource"</span> <span style="COLOR: #ff0000">&nbsp;</span> <span style="COLOR: #0000ff">/&gt;</span> <span style="COLOR: #000000"><br><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;</span> <span style="COLOR: #0000ff">&lt;/</span> <span style="COLOR: #800000">property</span> <span style="COLOR: #0000ff">&gt;</span> <span style="COLOR: #000000"><br><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;</span> <span style="COLOR: #0000ff">&lt;</span> <span style="COLOR: #800000">property&nbsp;</span> <span style="COLOR: #ff0000">name</span> <span style="COLOR: #0000ff">="hibernateProperties"</span> <span style="COLOR: #0000ff">&gt;</span> <span style="COLOR: #000000"><br><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;</span> <span style="COLOR: #0000ff">&lt;</span> <span style="COLOR: #800000">props</span> <span style="COLOR: #0000ff">&gt;</span> <span style="COLOR: #000000"><br><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span> <span style="COLOR: #0000ff">&lt;</span> <span style="COLOR: #800000">prop&nbsp;</span> <span style="COLOR: #ff0000">key</span> <span style="COLOR: #0000ff">="hibernate.dialect"</span> <span style="COLOR: #0000ff">&gt;</span> <span style="COLOR: #000000">${hibernate.dialect}</span> <span style="COLOR: #0000ff">&lt;/</span> <span style="COLOR: #800000">prop</span> <span style="COLOR: #0000ff">&gt;</span> <span style="COLOR: #000000"><br><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span> <span style="COLOR: #0000ff">&lt;</span> <span style="COLOR: #800000">prop&nbsp;</span> <span style="COLOR: #ff0000">key</span> <span style="COLOR: #0000ff">="hibernate.show_sql"</span> <span style="COLOR: #0000ff">&gt;</span> <span style="COLOR: #000000">${hibernate.show_sql}</span> <span style="COLOR: #0000ff">&lt;/</span> <span style="COLOR: #800000">prop</span> <span style="COLOR: #0000ff">&gt;</span> <span style="COLOR: #000000"><br><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span> <span style="COLOR: #0000ff">&lt;</span> <span style="COLOR: #800000">prop&nbsp;</span> <span style="COLOR: #ff0000">key</span> <span style="COLOR: #0000ff">="hibernate.cache.use_query_cache"</span> <span style="COLOR: #0000ff">&gt;</span> <span style="COLOR: #000000">${hibernate.cache.use_query_cache}</span> <span style="COLOR: #0000ff">&lt;/</span> <span style="COLOR: #800000">prop</span> <span style="COLOR: #0000ff">&gt;</span> <span style="COLOR: #000000"><br><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span> <span style="COLOR: #0000ff">&lt;</span> <span style="COLOR: #800000">prop&nbsp;</span> <span style="COLOR: #ff0000">key</span> <span style="COLOR: #0000ff">="hibernate.cache.provider_class"</span> <span style="COLOR: #0000ff">&gt;</span> <span style="COLOR: #000000">${hibernate.cache.provider_class}</span> <span style="COLOR: #0000ff">&lt;/</span> <span style="COLOR: #800000">prop</span> <span style="COLOR: #0000ff">&gt;</span> <span style="COLOR: #000000"><br><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;</span> <span style="COLOR: #0000ff">&lt;/</span> <span style="COLOR: #800000">props</span> <span style="COLOR: #0000ff">&gt;</span> <span style="COLOR: #000000"><br><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;</span> <span style="COLOR: #0000ff">&lt;/</span> <span style="COLOR: #800000">property</span> <span style="COLOR: #0000ff">&gt;</span> <span style="COLOR: #000000"><br><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;</span> <span style="COLOR: #0000ff">&lt;</span> <span style="COLOR: #800000">property&nbsp;</span> <span style="COLOR: #ff0000">name</span> <span style="COLOR: #0000ff">="mappingDirectoryLocations"</span> <span style="COLOR: #0000ff">&gt;</span> <span style="COLOR: #000000"><br><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span> <span style="COLOR: #0000ff">&lt;</span> <span style="COLOR: #800000">list</span> <span style="COLOR: #0000ff">&gt;</span> <span style="COLOR: #000000"><br><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span> <span style="COLOR: #0000ff">&lt;value&gt;</span> <span style="COLOR: #000000">classpath*:com/newtouch/cial/model/hbm/</span> <span style="COLOR: #0000ff">&lt;/&gt;</span> <span style="COLOR: #000000"><br><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span> <span style="COLOR: #0000ff">&lt;/</span> <span style="COLOR: #800000">list</span> <span style="COLOR: #0000ff">&gt;</span> <span style="COLOR: #000000"><br><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span> <span style="COLOR: #0000ff">&lt;/</span> <span style="COLOR: #800000">property</span> <span style="COLOR: #0000ff">&gt;</span> <span style="COLOR: #000000"><br><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top>&nbsp;</span> <span style="COLOR: #0000ff">&lt;/</span> <span style="COLOR: #800000">bean</span> <span style="COLOR: #0000ff">&gt;</span> <span style="COLOR: #000000"><br><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top> </span></div>
</div>
<div>&nbsp;</div>
<div>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 在SpringMvc的 Controller类中set方法调用的session名称为：sessionFactory，如果这里的名称或者大小写不一致，那么在xxxx-servlet.xml初始化Controller类时就会出错。</div>
<div>&nbsp;</div>
<div><span style="FONT-SIZE: 12pt; FONT-FAMILY: 楷体_GB2312"><strong>2、Spring2.0的代理问题</strong> </span></div>
<div>&nbsp;</div>
<div>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><span style="COLOR: #008080">&nbsp;1</span> <img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top> <span style="COLOR: #0000ff">&lt;</span> <span style="COLOR: #800000">bean&nbsp;</span> <span style="COLOR: #ff0000">id</span> <span style="COLOR: #0000ff">="txProxyTemplate"</span> <span style="COLOR: #ff0000">&nbsp;abstract</span> <span style="COLOR: #0000ff">="true"</span> <span style="COLOR: #ff0000">&nbsp;class</span> <span style="COLOR: #0000ff">="org.springwork.transaction.interceptor.TransactionProxyFactoryBean"</span> <span style="COLOR: #0000ff">&gt;</span> <span style="COLOR: #000000"><br></span><span style="COLOR: #008080">&nbsp;2</span> <span style="COLOR: #000000"><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;</span> <span style="COLOR: #0000ff">&lt;</span> <span style="COLOR: #800000">property&nbsp;</span> <span style="COLOR: #ff0000">name</span> <span style="COLOR: #0000ff">="transactionManager"</span> <span style="COLOR: #ff0000">&nbsp;ref</span> <span style="COLOR: #0000ff">="transactionManager"</span> <span style="COLOR: #ff0000">&nbsp;</span> <span style="COLOR: #0000ff">/&gt;</span> <span style="COLOR: #000000"><br></span><span style="COLOR: #008080">&nbsp;3</span> <span style="COLOR: #000000"><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;</span> <span style="COLOR: #0000ff">&lt;</span> <span style="COLOR: #800000">property&nbsp;</span> <span style="COLOR: #ff0000">name</span> <span style="COLOR: #0000ff">="proxyTargetClass"</span> <span style="COLOR: #ff0000">&nbsp;</span> <font color=#ff0000>value</font> <span style="COLOR: #0000ff">="true"</span> <span style="COLOR: #0000ff">/&gt;</span> <span style="COLOR: #000000"><br></span><span style="COLOR: #008080">&nbsp;4</span> <span style="COLOR: #000000"><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;</span> <span style="COLOR: #0000ff">&lt;</span> <span style="COLOR: #800000">property&nbsp;</span> <span style="COLOR: #ff0000">name</span> <span style="COLOR: #0000ff">="transactionAttributes"</span> <span style="COLOR: #0000ff">&gt;</span> <span style="COLOR: #000000"><br></span><span style="COLOR: #008080">&nbsp;5</span> <span style="COLOR: #000000"><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span> <span style="COLOR: #0000ff">&lt;</span> <span style="COLOR: #800000">props</span> <span style="COLOR: #0000ff">&gt;</span> <span style="COLOR: #000000"><br></span><span style="COLOR: #008080">&nbsp;6</span> <span style="COLOR: #000000"><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span> <span style="COLOR: #0000ff">&lt;</span> <span style="COLOR: #800000">prop&nbsp;</span> <span style="COLOR: #ff0000">key</span> <span style="COLOR: #0000ff">="get*"</span> <span style="COLOR: #0000ff">&gt;</span> <span style="COLOR: #000000">PROPAGATION_REQUIRED,readOnly</span> <span style="COLOR: #0000ff">&lt;/</span> <span style="COLOR: #800000">prop</span> <span style="COLOR: #0000ff">&gt;</span> <span style="COLOR: #000000"><br></span><span style="COLOR: #008080">&nbsp;7</span> <span style="COLOR: #000000"><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span> <span style="COLOR: #0000ff">&lt;</span> <span style="COLOR: #800000">prop&nbsp;</span> <span style="COLOR: #ff0000">key</span> <span style="COLOR: #0000ff">="find*"</span> <span style="COLOR: #0000ff">&gt;</span> <span style="COLOR: #000000">PROPAGATION_REQUIRED,readOnly</span> <span style="COLOR: #0000ff">&lt;/</span> <span style="COLOR: #800000">prop</span> <span style="COLOR: #0000ff">&gt;</span> <span style="COLOR: #000000"><br></span><span style="COLOR: #008080">&nbsp;8</span> <span style="COLOR: #000000"><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span> <span style="COLOR: #0000ff">&lt;</span> <span style="COLOR: #800000">prop&nbsp;</span> <span style="COLOR: #ff0000">key</span> <span style="COLOR: #0000ff">="load*"</span> <span style="COLOR: #0000ff">&gt;</span> <span style="COLOR: #000000">PROPAGATION_REQUIRED,readOnly</span> <span style="COLOR: #0000ff">&lt;/</span> <span style="COLOR: #800000">prop</span> <span style="COLOR: #0000ff">&gt;</span> <span style="COLOR: #000000"><br></span><span style="COLOR: #008080">&nbsp;9</span> <span style="COLOR: #000000"><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span> <span style="COLOR: #0000ff">&lt;</span> <span style="COLOR: #800000">prop&nbsp;</span> <span style="COLOR: #ff0000">key</span> <span style="COLOR: #0000ff">="save*"</span> <span style="COLOR: #0000ff">&gt;</span> <span style="COLOR: #000000">PROPAGATION_REQUIRED</span> <span style="COLOR: #0000ff">&lt;/</span> <span style="COLOR: #800000">prop</span> <span style="COLOR: #0000ff">&gt;</span> <span style="COLOR: #000000"><br></span><span style="COLOR: #008080">10</span> <span style="COLOR: #000000"><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span> <span style="COLOR: #0000ff">&lt;</span> <span style="COLOR: #800000">prop&nbsp;</span> <span style="COLOR: #ff0000">key</span> <span style="COLOR: #0000ff">="update*"</span> <span style="COLOR: #0000ff">&gt;</span> <span style="COLOR: #000000">PROPAGATION_REQUIRED</span> <span style="COLOR: #0000ff">&lt;/</span> <span style="COLOR: #800000">prop</span> <span style="COLOR: #0000ff">&gt;</span> <span style="COLOR: #000000"><br></span><span style="COLOR: #008080">11</span> <span style="COLOR: #000000"><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span> <span style="COLOR: #0000ff">&lt;</span> <span style="COLOR: #800000">prop&nbsp;</span> <span style="COLOR: #ff0000">key</span> <span style="COLOR: #0000ff">="remove*"</span> <span style="COLOR: #0000ff">&gt;</span> <span style="COLOR: #000000">PROPAGATION_REQUIRED</span> <span style="COLOR: #0000ff">&lt;/</span> <span style="COLOR: #800000">prop</span> <span style="COLOR: #0000ff">&gt;</span> <span style="COLOR: #000000"><br></span><span style="COLOR: #008080">12</span> <span style="COLOR: #000000"><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span> <span style="COLOR: #0000ff">&lt;/</span> <span style="COLOR: #800000">props</span> <span style="COLOR: #0000ff">&gt;</span> <span style="COLOR: #000000"><br></span><span style="COLOR: #008080">13</span> <span style="COLOR: #000000"><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span> <span style="COLOR: #0000ff">&lt;/</span> <span style="COLOR: #800000">property</span> <span style="COLOR: #0000ff">&gt;</span> <span style="COLOR: #000000"><br></span><span style="COLOR: #008080">14</span> <span style="COLOR: #000000"><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top>&nbsp;</span> <span style="COLOR: #0000ff">&lt;/</span> <span style="COLOR: #800000">bean</span> <span style="COLOR: #0000ff">&gt;</span> </div>
</div>
<div></div>
<div>&nbsp;&nbsp;&nbsp;&nbsp; &nbsp; 在Spring2.0后，特别是在使用了 SpringSide 框架后，必须在代理中设置&nbsp;&lt;property name="proxyTargetClass"&nbsp; value="true"/&gt;，否则就会出错。<br></div>
<img src ="http://www.blogjava.net/wealupa/aggbug/88281.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/wealupa/" target="_blank">常言笑</a> 2006-12-16 22:51 <a href="http://www.blogjava.net/wealupa/archive/2006/12/16/88281.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Jstl中isELIgnored问题</title><link>http://www.blogjava.net/wealupa/archive/2006/12/16/88283.html</link><dc:creator>常言笑</dc:creator><author>常言笑</author><pubDate>Sat, 16 Dec 2006 14:51:00 GMT</pubDate><guid>http://www.blogjava.net/wealupa/archive/2006/12/16/88283.html</guid><wfw:comment>http://www.blogjava.net/wealupa/comments/88283.html</wfw:comment><comments>http://www.blogjava.net/wealupa/archive/2006/12/16/88283.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/wealupa/comments/commentRss/88283.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/wealupa/services/trackbacks/88283.html</trackback:ping><description><![CDATA[<p>如果web.xml 中的 &lt;web-app version="2.4"&gt; version版本在2.3以下，那么需要在每个jsp页面添加&lt;web-app version="2.4"&gt;标记，Jstl中的El语法才能起作用。</p>
<img src ="http://www.blogjava.net/wealupa/aggbug/88283.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/wealupa/" target="_blank">常言笑</a> 2006-12-16 22:51 <a href="http://www.blogjava.net/wealupa/archive/2006/12/16/88283.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Acegi工作流程</title><link>http://www.blogjava.net/wealupa/archive/2006/12/16/88279.html</link><dc:creator>常言笑</dc:creator><author>常言笑</author><pubDate>Sat, 16 Dec 2006 14:48:00 GMT</pubDate><guid>http://www.blogjava.net/wealupa/archive/2006/12/16/88279.html</guid><wfw:comment>http://www.blogjava.net/wealupa/comments/88279.html</wfw:comment><comments>http://www.blogjava.net/wealupa/archive/2006/12/16/88279.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/wealupa/comments/commentRss/88279.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/wealupa/services/trackbacks/88279.html</trackback:ping><description><![CDATA[<p><span style="FONT-SIZE: 10pt">任何一个安全系统都包括authentication和authorization两部分，Acegi相同。</span> </p>
<p><span style="FONT-SIZE: 10pt"><strong>第一部分：authentication</strong> </span></p>
<p><span style="FONT-SIZE: 10pt">1、acegi通过AuthenticationProcessingFilter拦截login请求获取Principal和Credential信息（通俗一点就是用户名和密码）；</span> </p>
<p><span style="FONT-SIZE: 10pt">2、验证用户名密码，由这个Filter调用认证管理器AuthenticatiomManager进行验证。</span> </p>
<p><span style="FONT-SIZE: 10pt">AuthenticatiomManager本身并不具备验证的功能，它相当与是一个验证控制器，由它来管理验证的过程及方式。AuthenticatiomManager是通过调用provider来进行验证的，一个manager中可以具有多个provider，但只要有一个provider验证通过，manager就认为验证成功。</span> </p>
<p><span style="FONT-SIZE: 10pt">这部分要明白三点：一，provider是可以配置进去的，因为acegi是基于spring的；二是AuthenticatiomManager是可以被重写的，你可以将manager改成你自己希望的控制器；三，好好利用event，这是标准的observer模式。acegi中的设计模式研究将在以后的贴子中讨论。</span> </p>
<p><span style="FONT-SIZE: 10pt">3、provider进行验证。</span> </p>
<p><span style="FONT-SIZE: 10pt">provider是真正的验证模块，并且决定了验证的模式。provider目前acegi提供了dao、jaas，cas，x509，ldap等几种验证方式，这些验证方式的具体内容可以查阅acegi的文档。provider验证通过后将Authentication对象返回。</span> </p>
<p><span style="FONT-SIZE: 10pt">4、AuthenticationProcessingFilter将对象保存到ContextHolder中。Authentication部分结束。</span> </p>
<p><span style="FONT-SIZE: 10pt"><strong>第二部分：authorization</strong> </span></p>
<p><span style="FONT-SIZE: 10pt">1、用户提交请求，拦截器FilterSecurityInterceptor拦截请求，拦截器是一个Filter.</span> </p>
<p><span style="FONT-SIZE: 10pt">2&nbsp;、鉴权，拦截器调用AccessDecisionManager进行鉴权。</span> </p>
<p><span style="FONT-SIZE: 10pt">AccessDecisionManager是通过投票的方式来决定是否有权限访问资源。所谓投票就要包括投票的参与者和投票的策略。</span> </p>
<p><span style="FONT-SIZE: 10pt">投票的参与者decisionVoters，这是AccessDecisionManager的一个属性。decisionVoter能从某一个角度决定用户是否能访问资源，例如RoleVoter来判断用户的角色是否有权限访问资源，MaxuserVoter来决定某个资源的访问用户数是否已经达到了最大值等。</span> </p>
<p><span style="FONT-SIZE: 10pt">投票策略。投票的策略是通过不同的AccessDecisionManager来实现的，例如acegi提供的AffirmativeBased对象，这个对象的策略就是只要有一个投票通过就全体通过。UnanimousBased对象的策略是必须全体投票通过才能通过。但在大多数情况下acegi提供的AccessDecisionManager不能满足我们的要求，这就需要我们去实现AccessDecisionManager接口，去定制适合自己项目的策略。</span> </p>
<div><span style="FONT-SIZE: 10pt">3、投票。投票对象必须实现AccessDecisionVoter接口。投票对象关注的是某一方面的决定权，如果投票通过则Vote方法来完成的。vote方法必须返回一个int型的数据代表投票结果，它们是AccessDecisionVoter的三个静态成员属性：ACCESS_ABSTAIN,，ACCESS_DENIED和ACCESS_GRANTED，它们分别是弃权，否决和赞成。</span> </div>
<div><span style="FONT-SIZE: 10pt"></span>&nbsp;</div>
<div><span style="FONT-SIZE: 10pt">
<h4><span style="FONT-SIZE: 10pt">安全拦截器</span> </h4>
<h5>&nbsp; 拦截器如何工作<br>&nbsp; MethodInvocation拦截器<br>&nbsp; FilterInvocation拦截器</h5>
<h4><span style="FONT-SIZE: 10pt">认证</span> </h4>
<h5>&nbsp; 认证请求<br>&nbsp; 认证管理器<br>&nbsp; Authentication Provider</h5>
<h4><span style="FONT-SIZE: 10pt">授权</span> </h4>
<h5>&nbsp; Access Decision Manager<br>&nbsp; Voting Decision Manager<br>&nbsp; 授权管理推荐</h5>
<h4><span style="FONT-SIZE: 10pt">ContextHolder的用户接口</span> </h4>
<h5>&nbsp; 用户接口目标<br>&nbsp; HTTP会话认证<br>&nbsp; HTTP Basic认证</h5>
</span></div>
<img src ="http://www.blogjava.net/wealupa/aggbug/88279.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/wealupa/" target="_blank">常言笑</a> 2006-12-16 22:48 <a href="http://www.blogjava.net/wealupa/archive/2006/12/16/88279.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Rbac &amp;&amp; Acl 两种权限控制思想</title><link>http://www.blogjava.net/wealupa/archive/2006/12/16/88280.html</link><dc:creator>常言笑</dc:creator><author>常言笑</author><pubDate>Sat, 16 Dec 2006 14:48:00 GMT</pubDate><guid>http://www.blogjava.net/wealupa/archive/2006/12/16/88280.html</guid><wfw:comment>http://www.blogjava.net/wealupa/comments/88280.html</wfw:comment><comments>http://www.blogjava.net/wealupa/archive/2006/12/16/88280.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/wealupa/comments/commentRss/88280.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/wealupa/services/trackbacks/88280.html</trackback:ping><description><![CDATA[<span style="FONT-SIZE: 12pt; COLOR: #32cd32; FONT-FAMILY: 楷体_GB2312">&nbsp;&nbsp;&nbsp; RBAC：Role Based Access Control</span> <font face=楷体_GB2312>，翻译过来基本上就是基于角色的访问控制系统。</font>
<div><span style="FONT-SIZE: 12pt; FONT-FAMILY: 楷体_GB2312">&nbsp;&nbsp;&nbsp; </span><span style="FONT-SIZE: 12pt; FONT-FAMILY: 楷体_GB2312"><span style="FONT-SIZE: 12pt; COLOR: #32cd32; FONT-FAMILY: 楷体_GB2312">ACL<span style="FONT-SIZE: 12pt; COLOR: #32cd32; FONT-FAMILY: 楷体_GB2312">：Access Control List</span></span>，访问控制列表，是前几年盛行的一种权限设计，它的核心在于用户直接和权限挂钩。RBAC的核心是用户只和角色关联，而角色代表对了权限，这样设计的优势在于使得对用户而言，只需角色即可以，而某角色可以拥有各种各样的权限并可继承。ACL和RBAC相比缺点在于由于用户和权限直接挂钩，导致在授予时的复杂性，虽然可以利用组来简化这个复杂性，但仍然会导致系统不好理解，而且在取出判断用户是否有该权限时比较的困难，一定程度上影响了效率。</span> </div>
<img src ="http://www.blogjava.net/wealupa/aggbug/88280.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/wealupa/" target="_blank">常言笑</a> 2006-12-16 22:48 <a href="http://www.blogjava.net/wealupa/archive/2006/12/16/88280.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>使用Acegi时获取用户信息的几个函数</title><link>http://www.blogjava.net/wealupa/archive/2006/12/16/88278.html</link><dc:creator>常言笑</dc:creator><author>常言笑</author><pubDate>Sat, 16 Dec 2006 14:46:00 GMT</pubDate><guid>http://www.blogjava.net/wealupa/archive/2006/12/16/88278.html</guid><wfw:comment>http://www.blogjava.net/wealupa/comments/88278.html</wfw:comment><comments>http://www.blogjava.net/wealupa/archive/2006/12/16/88278.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.blogjava.net/wealupa/comments/commentRss/88278.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/wealupa/services/trackbacks/88278.html</trackback:ping><description><![CDATA[<p>&nbsp;</p>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><span style="COLOR: #008080">&nbsp;1</span> <img id=Codehighlighter1_0_34_Open_Image onclick="this.style.display='none'; Codehighlighter1_0_34_Open_Text.style.display='none'; Codehighlighter1_0_34_Closed_Image.style.display='inline'; Codehighlighter1_0_34_Closed_Text.style.display='inline';" src="http://www.blogjava.net/Images/OutliningIndicators/ExpandedBlockStart.gif" align=top> <img id=Codehighlighter1_0_34_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_0_34_Closed_Text.style.display='none'; Codehighlighter1_0_34_Open_Image.style.display='inline'; Codehighlighter1_0_34_Open_Text.style.display='inline';" src="http://www.blogjava.net/Images/OutliningIndicators/ContractedBlock.gif" align=top> <span id=Codehighlighter1_0_34_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff">/**&nbsp;*/</span> <span id=Codehighlighter1_0_34_Open_Text><span style="COLOR: #008000">/**</span> <span style="COLOR: #008000"><br></span><span style="COLOR: #008080">&nbsp;2</span> <span style="COLOR: #008000"><img src="http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;*&nbsp;取得当前用户名<br></span><span style="COLOR: #008080">&nbsp;3</span> <span style="COLOR: #008000"><img src="http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;*&nbsp;</span> <span style="COLOR: #808080">@return</span> <span style="COLOR: #008000"><br></span><span style="COLOR: #008080">&nbsp;4</span> <span style="COLOR: #008000"><img src="http://www.blogjava.net/Images/OutliningIndicators/ExpandedBlockEnd.gif" align=top>&nbsp;&nbsp;&nbsp;</span> <span style="COLOR: #008000">*/</span> </span><span style="COLOR: #000000"><br></span><span style="COLOR: #008080">&nbsp;5</span> <span style="COLOR: #000000"><img id=Codehighlighter1_72_583_Open_Image onclick="this.style.display='none'; Codehighlighter1_72_583_Open_Text.style.display='none'; Codehighlighter1_72_583_Closed_Image.style.display='inline'; Codehighlighter1_72_583_Closed_Text.style.display='inline';" src="http://www.blogjava.net/Images/OutliningIndicators/ExpandedBlockStart.gif" align=top> <img id=Codehighlighter1_72_583_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_72_583_Closed_Text.style.display='none'; Codehighlighter1_72_583_Open_Image.style.display='inline'; Codehighlighter1_72_583_Open_Text.style.display='inline';" src="http://www.blogjava.net/Images/OutliningIndicators/ContractedBlock.gif" align=top>&nbsp;&nbsp;</span> <span style="COLOR: #0000ff">public</span> <span style="COLOR: #000000">&nbsp;</span> <span style="COLOR: #0000ff">static</span> <span style="COLOR: #000000">&nbsp;String&nbsp;getUsername()</span> <span id=Codehighlighter1_72_583_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.blogjava.net/Images/dot.gif"> </span><span id=Codehighlighter1_72_583_Open_Text><span style="COLOR: #000000">{<br></span><span style="COLOR: #008080">&nbsp;6</span> <span style="COLOR: #000000"><img src="http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;Context&nbsp;context</span> <span style="COLOR: #000000">=</span> <span style="COLOR: #000000">ContextHolder.getContext();<br></span><span style="COLOR: #008080">&nbsp;7</span> <span style="COLOR: #000000"><img id=Codehighlighter1_143_562_Open_Image onclick="this.style.display='none'; Codehighlighter1_143_562_Open_Text.style.display='none'; Codehighlighter1_143_562_Closed_Image.style.display='inline'; Codehighlighter1_143_562_Closed_Text.style.display='inline';" src="http://www.blogjava.net/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align=top> <img id=Codehighlighter1_143_562_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_143_562_Closed_Text.style.display='none'; Codehighlighter1_143_562_Open_Image.style.display='inline'; Codehighlighter1_143_562_Open_Text.style.display='inline';" src="http://www.blogjava.net/Images/OutliningIndicators/ContractedSubBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span> <span style="COLOR: #0000ff">if</span> <span style="COLOR: #000000">(context</span> <span style="COLOR: #000000">!=</span> <span style="COLOR: #0000ff">null</span> <span style="COLOR: #000000">)</span> <span id=Codehighlighter1_143_562_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.blogjava.net/Images/dot.gif"> </span><span id=Codehighlighter1_143_562_Open_Text><span style="COLOR: #000000">{<br></span><span style="COLOR: #008080">&nbsp;8</span> <span style="COLOR: #000000"><img id=Codehighlighter1_187_556_Open_Image onclick="this.style.display='none'; Codehighlighter1_187_556_Open_Text.style.display='none'; Codehighlighter1_187_556_Closed_Image.style.display='inline'; Codehighlighter1_187_556_Closed_Text.style.display='inline';" src="http://www.blogjava.net/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align=top> <img id=Codehighlighter1_187_556_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_187_556_Closed_Text.style.display='none'; Codehighlighter1_187_556_Open_Image.style.display='inline'; Codehighlighter1_187_556_Open_Text.style.display='inline';" src="http://www.blogjava.net/Images/OutliningIndicators/ContractedSubBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span> <span style="COLOR: #0000ff">if</span> <span style="COLOR: #000000">(context&nbsp;</span> <span style="COLOR: #0000ff">instanceof</span> <span style="COLOR: #000000">&nbsp;SecureContext)</span> <span id=Codehighlighter1_187_556_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.blogjava.net/Images/dot.gif"> </span><span id=Codehighlighter1_187_556_Open_Text><span style="COLOR: #000000">{<br></span><span style="COLOR: #008080">&nbsp;9</span> <span style="COLOR: #000000"><img src="http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SecureContext&nbsp;sc</span> <span style="COLOR: #000000">=</span> <span style="COLOR: #000000">(SecureContext)context;<br></span><span style="COLOR: #008080">10</span> <span style="COLOR: #000000"><img src="http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Authentication&nbsp;auth</span> <span style="COLOR: #000000">=</span> <span style="COLOR: #000000">sc.getAuthentication();<br></span><span style="COLOR: #008080">11</span> <span style="COLOR: #000000"><img id=Codehighlighter1_312_548_Open_Image onclick="this.style.display='none'; Codehighlighter1_312_548_Open_Text.style.display='none'; Codehighlighter1_312_548_Closed_Image.style.display='inline'; Codehighlighter1_312_548_Closed_Text.style.display='inline';" src="http://www.blogjava.net/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align=top> <img id=Codehighlighter1_312_548_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_312_548_Closed_Text.style.display='none'; Codehighlighter1_312_548_Open_Image.style.display='inline'; Codehighlighter1_312_548_Open_Text.style.display='inline';" src="http://www.blogjava.net/Images/OutliningIndicators/ContractedSubBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span> <span style="COLOR: #0000ff">if</span> <span style="COLOR: #000000">(auth</span> <span style="COLOR: #000000">!=</span> <span style="COLOR: #0000ff">null</span> <span style="COLOR: #000000">)</span> <span id=Codehighlighter1_312_548_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.blogjava.net/Images/dot.gif"> </span><span id=Codehighlighter1_312_548_Open_Text><span style="COLOR: #000000">{<br></span><span style="COLOR: #008080">12</span> <span style="COLOR: #000000"><img src="http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Object&nbsp;principal</span> <span style="COLOR: #000000">=</span> <span style="COLOR: #000000">auth.getPrincipal();<br></span><span style="COLOR: #008080">13</span> <span style="COLOR: #000000"><img id=Codehighlighter1_409_480_Open_Image onclick="this.style.display='none'; Codehighlighter1_409_480_Open_Text.style.display='none'; Codehighlighter1_409_480_Closed_Image.style.display='inline'; Codehighlighter1_409_480_Closed_Text.style.display='inline';" src="http://www.blogjava.net/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align=top> <img id=Codehighlighter1_409_480_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_409_480_Closed_Text.style.display='none'; Codehighlighter1_409_480_Open_Image.style.display='inline'; Codehighlighter1_409_480_Open_Text.style.display='inline';" src="http://www.blogjava.net/Images/OutliningIndicators/ContractedSubBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span> <span style="COLOR: #0000ff">if</span> <span style="COLOR: #000000">(principal&nbsp;</span> <span style="COLOR: #0000ff">instanceof</span> <span style="COLOR: #000000">&nbsp;UserDetails)&nbsp;</span> <span id=Codehighlighter1_409_480_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.blogjava.net/Images/dot.gif"> </span><span id=Codehighlighter1_409_480_Open_Text><span style="COLOR: #000000">{<br></span><span style="COLOR: #008080">14</span> <span style="COLOR: #000000"><img src="http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span> <span style="COLOR: #0000ff">return</span> <span style="COLOR: #000000">&nbsp;((UserDetails)principal).getUsername();<br></span><span style="COLOR: #008080">15</span> <span style="COLOR: #000000"><img id=Codehighlighter1_485_538_Open_Image onclick="this.style.display='none'; Codehighlighter1_485_538_Open_Text.style.display='none'; Codehighlighter1_485_538_Closed_Image.style.display='inline'; Codehighlighter1_485_538_Closed_Text.style.display='inline';" src="http://www.blogjava.net/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align=top> <img id=Codehighlighter1_485_538_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_485_538_Closed_Text.style.display='none'; Codehighlighter1_485_538_Open_Image.style.display='inline'; Codehighlighter1_485_538_Open_Text.style.display='inline';" src="http://www.blogjava.net/Images/OutliningIndicators/ContractedSubBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</span> </span><span style="COLOR: #0000ff">else</span> <span id=Codehighlighter1_485_538_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.blogjava.net/Images/dot.gif"> </span><span id=Codehighlighter1_485_538_Open_Text><span style="COLOR: #000000">{<br></span><span style="COLOR: #008080">16</span> <span style="COLOR: #000000"><img src="http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span> <span style="COLOR: #0000ff">return</span> <span style="COLOR: #000000">&nbsp;principal.toString();<br></span><span style="COLOR: #008080">17</span> <span style="COLOR: #000000"><img src="http://www.blogjava.net/Images/OutliningIndicators/ExpandedSubBlockEnd.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</span> </span><span style="COLOR: #000000"><br></span><span style="COLOR: #008080">18</span> <span style="COLOR: #000000"><img src="http://www.blogjava.net/Images/OutliningIndicators/ExpandedSubBlockEnd.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</span> </span><span style="COLOR: #000000"><br></span><span style="COLOR: #008080">19</span> <span style="COLOR: #000000"><img src="http://www.blogjava.net/Images/OutliningIndicators/ExpandedSubBlockEnd.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</span> </span><span style="COLOR: #000000"><br></span><span style="COLOR: #008080">20</span> <span style="COLOR: #000000"><img src="http://www.blogjava.net/Images/OutliningIndicators/ExpandedSubBlockEnd.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;}</span> </span><span style="COLOR: #000000"><br></span><span style="COLOR: #008080">21</span> <span style="COLOR: #000000"><img src="http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span> <span style="COLOR: #0000ff">return</span> <span style="COLOR: #000000">&nbsp;</span> <span style="COLOR: #0000ff">null</span> <span style="COLOR: #000000">;<br></span><span style="COLOR: #008080">22</span> <span style="COLOR: #000000"><img src="http://www.blogjava.net/Images/OutliningIndicators/ExpandedBlockEnd.gif" align=top>&nbsp;&nbsp;}</span> </span><span style="COLOR: #000000"><br></span><span style="COLOR: #008080">23</span> <span style="COLOR: #000000"><img id=Codehighlighter1_587_622_Open_Image onclick="this.style.display='none'; Codehighlighter1_587_622_Open_Text.style.display='none'; Codehighlighter1_587_622_Closed_Image.style.display='inline'; Codehighlighter1_587_622_Closed_Text.style.display='inline';" src="http://www.blogjava.net/Images/OutliningIndicators/ExpandedBlockStart.gif" align=top> <img id=Codehighlighter1_587_622_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_587_622_Closed_Text.style.display='none'; Codehighlighter1_587_622_Open_Image.style.display='inline'; Codehighlighter1_587_622_Open_Text.style.display='inline';" src="http://www.blogjava.net/Images/OutliningIndicators/ContractedBlock.gif" align=top>&nbsp;&nbsp;</span> <span id=Codehighlighter1_587_622_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff">/**&nbsp;*/</span> <span id=Codehighlighter1_587_622_Open_Text><span style="COLOR: #008000">/**</span> <span style="COLOR: #008000"><br></span><span style="COLOR: #008080">24</span> <span style="COLOR: #008000"><img src="http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;*&nbsp;取得当前用户密码<br></span><span style="COLOR: #008080">25</span> <span style="COLOR: #008000"><img src="http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;*&nbsp;</span> <span style="COLOR: #808080">@return</span> <span style="COLOR: #008000"><br></span><span style="COLOR: #008080">26</span> <span style="COLOR: #008000"><img src="http://www.blogjava.net/Images/OutliningIndicators/ExpandedBlockEnd.gif" align=top>&nbsp;&nbsp;&nbsp;</span> <span style="COLOR: #008000">*/</span> </span><span style="COLOR: #000000"><br></span><span style="COLOR: #008080">27</span> <span style="COLOR: #000000"><img id=Codehighlighter1_660_1155_Open_Image onclick="this.style.display='none'; Codehighlighter1_660_1155_Open_Text.style.display='none'; Codehighlighter1_660_1155_Closed_Image.style.display='inline'; Codehighlighter1_660_1155_Closed_Text.style.display='inline';" src="http://www.blogjava.net/Images/OutliningIndicators/ExpandedBlockStart.gif" align=top> <img id=Codehighlighter1_660_1155_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_660_1155_Closed_Text.style.display='none'; Codehighlighter1_660_1155_Open_Image.style.display='inline'; Codehighlighter1_660_1155_Open_Text.style.display='inline';" src="http://www.blogjava.net/Images/OutliningIndicators/ContractedBlock.gif" align=top>&nbsp;&nbsp;</span> <span style="COLOR: #0000ff">public</span> <span style="COLOR: #000000">&nbsp;</span> <span style="COLOR: #0000ff">static</span> <span style="COLOR: #000000">&nbsp;String&nbsp;getPassword()</span> <span id=Codehighlighter1_660_1155_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.blogjava.net/Images/dot.gif"> </span><span id=Codehighlighter1_660_1155_Open_Text><span style="COLOR: #000000">{<br></span><span style="COLOR: #008080">28</span> <span style="COLOR: #000000"><img src="http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;Context&nbsp;context</span> <span style="COLOR: #000000">=</span> <span style="COLOR: #000000">ContextHolder.getContext();<br></span><span style="COLOR: #008080">29</span> <span style="COLOR: #000000"><img id=Codehighlighter1_731_1134_Open_Image onclick="this.style.display='none'; Codehighlighter1_731_1134_Open_Text.style.display='none'; Codehighlighter1_731_1134_Closed_Image.style.display='inline'; Codehighlighter1_731_1134_Closed_Text.style.display='inline';" src="http://www.blogjava.net/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align=top> <img id=Codehighlighter1_731_1134_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_731_1134_Closed_Text.style.display='none'; Codehighlighter1_731_1134_Open_Image.style.display='inline'; Codehighlighter1_731_1134_Open_Text.style.display='inline';" src="http://www.blogjava.net/Images/OutliningIndicators/ContractedSubBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span> <span style="COLOR: #0000ff">if</span> <span style="COLOR: #000000">(context</span> <span style="COLOR: #000000">!=</span> <span style="COLOR: #0000ff">null</span> <span style="COLOR: #000000">)</span> <span id=Codehighlighter1_731_1134_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.blogjava.net/Images/dot.gif"> </span><span id=Codehighlighter1_731_1134_Open_Text><span style="COLOR: #000000">{<br></span><span style="COLOR: #008080">30</span> <span style="COLOR: #000000"><img id=Codehighlighter1_775_1128_Open_Image onclick="this.style.display='none'; Codehighlighter1_775_1128_Open_Text.style.display='none'; Codehighlighter1_775_1128_Closed_Image.style.display='inline'; Codehighlighter1_775_1128_Closed_Text.style.display='inline';" src="http://www.blogjava.net/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align=top> <img id=Codehighlighter1_775_1128_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_775_1128_Closed_Text.style.display='none'; Codehighlighter1_775_1128_Open_Image.style.display='inline'; Codehighlighter1_775_1128_Open_Text.style.display='inline';" src="http://www.blogjava.net/Images/OutliningIndicators/ContractedSubBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span> <span style="COLOR: #0000ff">if</span> <span style="COLOR: #000000">(context&nbsp;</span> <span style="COLOR: #0000ff">instanceof</span> <span style="COLOR: #000000">&nbsp;SecureContext)</span> <span id=Codehighlighter1_775_1128_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.blogjava.net/Images/dot.gif"> </span><span id=Codehighlighter1_775_1128_Open_Text><span style="COLOR: #000000">{<br></span><span style="COLOR: #008080">31</span> <span style="COLOR: #000000"><img src="http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SecureContext&nbsp;sc</span> <span style="COLOR: #000000">=</span> <span style="COLOR: #000000">(SecureContext)context;<br></span><span style="COLOR: #008080">32</span> <span style="COLOR: #000000"><img src="http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Authentication&nbsp;auth</span> <span style="COLOR: #000000">=</span> <span style="COLOR: #000000">sc.getAuthentication();<br></span><span style="COLOR: #008080">33</span> <span style="COLOR: #000000"><img id=Codehighlighter1_900_1120_Open_Image onclick="this.style.display='none'; Codehighlighter1_900_1120_Open_Text.style.display='none'; Codehighlighter1_900_1120_Closed_Image.style.display='inline'; Codehighlighter1_900_1120_Closed_Text.style.display='inline';" src="http://www.blogjava.net/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align=top> <img id=Codehighlighter1_900_1120_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_900_1120_Closed_Text.style.display='none'; Codehighlighter1_900_1120_Open_Image.style.display='inline'; Codehighlighter1_900_1120_Open_Text.style.display='inline';" src="http://www.blogjava.net/Images/OutliningIndicators/ContractedSubBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span> <span style="COLOR: #0000ff">if</span> <span style="COLOR: #000000">(auth</span> <span style="COLOR: #000000">!=</span> <span style="COLOR: #0000ff">null</span> <span style="COLOR: #000000">)</span> <span id=Codehighlighter1_900_1120_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.blogjava.net/Images/dot.gif"> </span><span id=Codehighlighter1_900_1120_Open_Text><span style="COLOR: #000000">{<br></span><span style="COLOR: #008080">34</span> <span style="COLOR: #000000"><img src="http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Object&nbsp;principal</span> <span style="COLOR: #000000">=</span> <span style="COLOR: #000000">auth.getPrincipal();<br></span><span style="COLOR: #008080">35</span> <span style="COLOR: #000000"><img id=Codehighlighter1_997_1068_Open_Image onclick="this.style.display='none'; Codehighlighter1_997_1068_Open_Text.style.display='none'; Codehighlighter1_997_1068_Closed_Image.style.display='inline'; Codehighlighter1_997_1068_Closed_Text.style.display='inline';" src="http://www.blogjava.net/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align=top> <img id=Codehighlighter1_997_1068_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_997_1068_Closed_Text.style.display='none'; Codehighlighter1_997_1068_Open_Image.style.display='inline'; Codehighlighter1_997_1068_Open_Text.style.display='inline';" src="http://www.blogjava.net/Images/OutliningIndicators/ContractedSubBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span> <span style="COLOR: #0000ff">if</span> <span style="COLOR: #000000">(principal&nbsp;</span> <span style="COLOR: #0000ff">instanceof</span> <span style="COLOR: #000000">&nbsp;UserDetails)&nbsp;</span> <span id=Codehighlighter1_997_1068_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.blogjava.net/Images/dot.gif"> </span><span id=Codehighlighter1_997_1068_Open_Text><span style="COLOR: #000000">{<br></span><span style="COLOR: #008080">36</span> <span style="COLOR: #000000"><img src="http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span> <span style="COLOR: #0000ff">return</span> <span style="COLOR: #000000">&nbsp;((UserDetails)principal).getPassword();<br></span><span style="COLOR: #008080">37</span> <span style="COLOR: #000000"><img id=Codehighlighter1_1073_1110_Open_Image onclick="this.style.display='none'; Codehighlighter1_1073_1110_Open_Text.style.display='none'; Codehighlighter1_1073_1110_Closed_Image.style.display='inline'; Codehighlighter1_1073_1110_Closed_Text.style.display='inline';" src="http://www.blogjava.net/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align=top> <img id=Codehighlighter1_1073_1110_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_1073_1110_Closed_Text.style.display='none'; Codehighlighter1_1073_1110_Open_Image.style.display='inline'; Codehighlighter1_1073_1110_Open_Text.style.display='inline';" src="http://www.blogjava.net/Images/OutliningIndicators/ContractedSubBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</span> </span><span style="COLOR: #0000ff">else</span> <span id=Codehighlighter1_1073_1110_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.blogjava.net/Images/dot.gif"> </span><span id=Codehighlighter1_1073_1110_Open_Text><span style="COLOR: #000000">{<br></span><span style="COLOR: #008080">38</span> <span style="COLOR: #000000"><img src="http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span> <span style="COLOR: #0000ff">return</span> <span style="COLOR: #000000">&nbsp;</span> <span style="COLOR: #0000ff">null</span> <span style="COLOR: #000000">;<br></span><span style="COLOR: #008080">39</span> <span style="COLOR: #000000"><img src="http://www.blogjava.net/Images/OutliningIndicators/ExpandedSubBlockEnd.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</span> </span><span style="COLOR: #000000"><br></span><span style="COLOR: #008080">40</span> <span style="COLOR: #000000"><img src="http://www.blogjava.net/Images/OutliningIndicators/ExpandedSubBlockEnd.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</span> </span><span style="COLOR: #000000"><br></span><span style="COLOR: #008080">41</span> <span style="COLOR: #000000"><img src="http://www.blogjava.net/Images/OutliningIndicators/ExpandedSubBlockEnd.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</span> </span><span style="COLOR: #000000"><br></span><span style="COLOR: #008080">42</span> <span style="COLOR: #000000"><img src="http://www.blogjava.net/Images/OutliningIndicators/ExpandedSubBlockEnd.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;}</span> </span><span style="COLOR: #000000"><br></span><span style="COLOR: #008080">43</span> <span style="COLOR: #000000"><img src="http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span> <span style="COLOR: #0000ff">return</span> <span style="COLOR: #000000">&nbsp;</span> <span style="COLOR: #0000ff">null</span> <span style="COLOR: #000000">;<br></span><span style="COLOR: #008080">44</span> <span style="COLOR: #000000"><img src="http://www.blogjava.net/Images/OutliningIndicators/ExpandedBlockEnd.gif" align=top>&nbsp;&nbsp;}</span> </span><span style="COLOR: #000000"><br></span><span style="COLOR: #008080">45</span> <span style="COLOR: #000000"><img id=Codehighlighter1_1159_1164_Open_Image onclick="this.style.display='none'; Codehighlighter1_1159_1164_Open_Text.style.display='none'; Codehighlighter1_1159_1164_Closed_Image.style.display='inline'; Codehighlighter1_1159_1164_Closed_Text.style.display='inline';" src="http://www.blogjava.net/Images/OutliningIndicators/ExpandedBlockStart.gif" align=top> <img id=Codehighlighter1_1159_1164_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_1159_1164_Closed_Text.style.display='none'; Codehighlighter1_1159_1164_Open_Image.style.display='inline'; Codehighlighter1_1159_1164_Open_Text.style.display='inline';" src="http://www.blogjava.net/Images/OutliningIndicators/ContractedBlock.gif" align=top>&nbsp;&nbsp;</span> <span id=Codehighlighter1_1159_1164_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff">/**&nbsp;*/</span> <span id=Codehighlighter1_1159_1164_Open_Text><span style="COLOR: #008000">/**</span> <span style="COLOR: #008000">&nbsp;</span> <span style="COLOR: #008000">*/</span> </span><span id=Codehighlighter1_1165_1226_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff">/**&nbsp;*/</span> <span id=Codehighlighter1_1165_1226_Open_Text><span style="COLOR: #008000">/**</span> <span style="COLOR: #008000"><br></span><span style="COLOR: #008080">46</span> <span style="COLOR: #008000"><img src="http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;*&nbsp;取得当前用户ｓｅｓｓｉｏｎ　ｉｄ<br></span><span style="COLOR: #008080">47</span> <span style="COLOR: #008000"><img src="http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;*&nbsp;</span> <span style="COLOR: #808080">@return</span> <span style="COLOR: #008000">&nbsp;sessionid&nbsp;or&nbsp;null<br></span><span style="COLOR: #008080">48</span> <span style="COLOR: #008000"><img src="http://www.blogjava.net/Images/OutliningIndicators/ExpandedBlockEnd.gif" align=top>&nbsp;&nbsp;&nbsp;</span> <span style="COLOR: #008000">*/</span> </span><span style="COLOR: #000000"><br></span><span style="COLOR: #008080">49</span> <span style="COLOR: #000000"><img id=Codehighlighter1_1265_1779_Open_Image onclick="this.style.display='none'; Codehighlighter1_1265_1779_Open_Text.style.display='none'; Codehighlighter1_1265_1779_Closed_Image.style.display='inline'; Codehighlighter1_1265_1779_Closed_Text.style.display='inline';" src="http://www.blogjava.net/Images/OutliningIndicators/ExpandedBlockStart.gif" align=top> <img id=Codehighlighter1_1265_1779_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_1265_1779_Closed_Text.style.display='none'; Codehighlighter1_1265_1779_Open_Image.style.display='inline'; Codehighlighter1_1265_1779_Open_Text.style.display='inline';" src="http://www.blogjava.net/Images/OutliningIndicators/ContractedBlock.gif" align=top>&nbsp;&nbsp;</span> <span style="COLOR: #0000ff">public</span> <span style="COLOR: #000000">&nbsp;</span> <span style="COLOR: #0000ff">static</span> <span style="COLOR: #000000">&nbsp;String&nbsp;getSessionID()</span> <span id=Codehighlighter1_1265_1779_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.blogjava.net/Images/dot.gif"> </span><span id=Codehighlighter1_1265_1779_Open_Text><span style="COLOR: #000000">{<br></span><span style="COLOR: #008080">50</span> <span style="COLOR: #000000"><img src="http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;Context&nbsp;context</span> <span style="COLOR: #000000">=</span> <span style="COLOR: #000000">ContextHolder.getContext();<br></span><span style="COLOR: #008080">51</span> <span style="COLOR: #000000"><img id=Codehighlighter1_1336_1758_Open_Image onclick="this.style.display='none'; Codehighlighter1_1336_1758_Open_Text.style.display='none'; Codehighlighter1_1336_1758_Closed_Image.style.display='inline'; Codehighlighter1_1336_1758_Closed_Text.style.display='inline';" src="http://www.blogjava.net/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align=top> <img id=Codehighlighter1_1336_1758_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_1336_1758_Closed_Text.style.display='none'; Codehighlighter1_1336_1758_Open_Image.style.display='inline'; Codehighlighter1_1336_1758_Open_Text.style.display='inline';" src="http://www.blogjava.net/Images/OutliningIndicators/ContractedSubBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span> <span style="COLOR: #0000ff">if</span> <span style="COLOR: #000000">(context</span> <span style="COLOR: #000000">!=</span> <span style="COLOR: #0000ff">null</span> <span style="COLOR: #000000">)</span> <span id=Codehighlighter1_1336_1758_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.blogjava.net/Images/dot.gif"> </span><span id=Codehighlighter1_1336_1758_Open_Text><span style="COLOR: #000000">{<br></span><span style="COLOR: #008080">52</span> <span style="COLOR: #000000"><img id=Codehighlighter1_1380_1752_Open_Image onclick="this.style.display='none'; Codehighlighter1_1380_1752_Open_Text.style.display='none'; Codehighlighter1_1380_1752_Closed_Image.style.display='inline'; Codehighlighter1_1380_1752_Closed_Text.style.display='inline';" src="http://www.blogjava.net/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align=top> <img id=Codehighlighter1_1380_1752_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_1380_1752_Closed_Text.style.display='none'; Codehighlighter1_1380_1752_Open_Image.style.display='inline'; Codehighlighter1_1380_1752_Open_Text.style.display='inline';" src="http://www.blogjava.net/Images/OutliningIndicators/ContractedSubBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span> <span style="COLOR: #0000ff">if</span> <span style="COLOR: #000000">(context&nbsp;</span> <span style="COLOR: #0000ff">instanceof</span> <span style="COLOR: #000000">&nbsp;SecureContext)</span> <span id=Codehighlighter1_1380_1752_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.blogjava.net/Images/dot.gif"> </span><span id=Codehighlighter1_1380_1752_Open_Text><span style="COLOR: #000000">{<br></span><span style="COLOR: #008080">53</span> <span style="COLOR: #000000"><img src="http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SecureContext&nbsp;sc</span> <span style="COLOR: #000000">=</span> <span style="COLOR: #000000">(SecureContext)context;<br></span><span style="COLOR: #008080">54</span> <span style="COLOR: #000000"><img src="http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Authentication&nbsp;auth</span> <span style="COLOR: #000000">=</span> <span style="COLOR: #000000">sc.getAuthentication();<br></span><span style="COLOR: #008080">55</span> <span style="COLOR: #000000"><img id=Codehighlighter1_1505_1744_Open_Image onclick="this.style.display='none'; Codehighlighter1_1505_1744_Open_Text.style.display='none'; Codehighlighter1_1505_1744_Closed_Image.style.display='inline'; Codehighlighter1_1505_1744_Closed_Text.style.display='inline';" src="http://www.blogjava.net/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align=top> <img id=Codehighlighter1_1505_1744_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_1505_1744_Closed_Text.style.display='none'; Codehighlighter1_1505_1744_Open_Image.style.display='inline'; Codehighlighter1_1505_1744_Open_Text.style.display='inline';" src="http://www.blogjava.net/Images/OutliningIndicators/ContractedSubBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span> <span style="COLOR: #0000ff">if</span> <span style="COLOR: #000000">(auth</span> <span style="COLOR: #000000">!=</span> <span style="COLOR: #0000ff">null</span> <span style="COLOR: #000000">)</span> <span id=Codehighlighter1_1505_1744_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.blogjava.net/Images/dot.gif"> </span><span id=Codehighlighter1_1505_1744_Open_Text><span style="COLOR: #000000">{<br></span><span style="COLOR: #008080">56</span> <span style="COLOR: #000000"><img src="http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Object&nbsp;details</span> <span style="COLOR: #000000">=</span> <span style="COLOR: #000000">auth.getDetails();<br></span><span style="COLOR: #008080">57</span> <span style="COLOR: #000000"><img id=Codehighlighter1_1609_1692_Open_Image onclick="this.style.display='none'; Codehighlighter1_1609_1692_Open_Text.style.display='none'; Codehighlighter1_1609_1692_Closed_Image.style.display='inline'; Codehighlighter1_1609_1692_Closed_Text.style.display='inline';" src="http://www.blogjava.net/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align=top> <img id=Codehighlighter1_1609_1692_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_1609_1692_Closed_Text.style.display='none'; Codehighlighter1_1609_1692_Open_Image.style.display='inline'; Codehighlighter1_1609_1692_Open_Text.style.display='inline';" src="http://www.blogjava.net/Images/OutliningIndicators/ContractedSubBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span> <span style="COLOR: #0000ff">if</span> <span style="COLOR: #000000">(details&nbsp;</span> <span style="COLOR: #0000ff">instanceof</span> <span style="COLOR: #000000">&nbsp;WebAuthenticationDetails)&nbsp;</span> <span id=Codehighlighter1_1609_1692_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.blogjava.net/Images/dot.gif"> </span><span id=Codehighlighter1_1609_1692_Open_Text><span style="COLOR: #000000">{<br></span><span style="COLOR: #008080">58</span> <span style="COLOR: #000000"><img src="http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span> <span style="COLOR: #0000ff">return</span> <span style="COLOR: #000000">&nbsp;((WebAuthenticationDetails)details).getSessionId();<br></span><span style="COLOR: #008080">59</span> <span style="COLOR: #000000"><img id=Codehighlighter1_1697_1734_Open_Image onclick="this.style.display='none'; Codehighlighter1_1697_1734_Open_Text.style.display='none'; Codehighlighter1_1697_1734_Closed_Image.style.display='inline'; Codehighlighter1_1697_1734_Closed_Text.style.display='inline';" src="http://www.blogjava.net/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align=top> <img id=Codehighlighter1_1697_1734_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_1697_1734_Closed_Text.style.display='none'; Codehighlighter1_1697_1734_Open_Image.style.display='inline'; Codehighlighter1_1697_1734_Open_Text.style.display='inline';" src="http://www.blogjava.net/Images/OutliningIndicators/ContractedSubBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</span> </span><span style="COLOR: #0000ff">else</span> <span id=Codehighlighter1_1697_1734_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.blogjava.net/Images/dot.gif"> </span><span id=Codehighlighter1_1697_1734_Open_Text><span style="COLOR: #000000">{<br></span><span style="COLOR: #008080">60</span> <span style="COLOR: #000000"><img src="http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span> <span style="COLOR: #0000ff">return</span> <span style="COLOR: #000000">&nbsp;</span> <span style="COLOR: #0000ff">null</span> <span style="COLOR: #000000">;<br></span><span style="COLOR: #008080">61</span> <span style="COLOR: #000000"><img src="http://www.blogjava.net/Images/OutliningIndicators/ExpandedSubBlockEnd.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</span> </span><span style="COLOR: #000000"><br></span><span style="COLOR: #008080">62</span> <span style="COLOR: #000000"><img src="http://www.blogjava.net/Images/OutliningIndicators/ExpandedSubBlockEnd.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</span> </span><span style="COLOR: #000000"><br></span><span style="COLOR: #008080">63</span> <span style="COLOR: #000000"><img src="http://www.blogjava.net/Images/OutliningIndicators/ExpandedSubBlockEnd.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</span> </span><span style="COLOR: #000000"><br></span><span style="COLOR: #008080">64</span> <span style="COLOR: #000000"><img src="http://www.blogjava.net/Images/OutliningIndicators/ExpandedSubBlockEnd.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;}</span> </span><span style="COLOR: #000000"><br></span><span style="COLOR: #008080">65</span> <span style="COLOR: #000000"><img src="http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span> <span style="COLOR: #0000ff">return</span> <span style="COLOR: #000000">&nbsp;</span> <span style="COLOR: #0000ff">null</span> <span style="COLOR: #000000">;<br></span><span style="COLOR: #008080">66</span> <span style="COLOR: #000000"><img src="http://www.blogjava.net/Images/OutliningIndicators/ExpandedBlockEnd.gif" align=top>&nbsp;&nbsp;}</span> </span><span style="COLOR: #000000"><br></span><span style="COLOR: #008080">67</span> <span style="COLOR: #000000"><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top> </span></div>
<img src ="http://www.blogjava.net/wealupa/aggbug/88278.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/wealupa/" target="_blank">常言笑</a> 2006-12-16 22:46 <a href="http://www.blogjava.net/wealupa/archive/2006/12/16/88278.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>View 层常用框架以及插件</title><link>http://www.blogjava.net/wealupa/archive/2006/12/16/88277.html</link><dc:creator>常言笑</dc:creator><author>常言笑</author><pubDate>Sat, 16 Dec 2006 14:45:00 GMT</pubDate><guid>http://www.blogjava.net/wealupa/archive/2006/12/16/88277.html</guid><wfw:comment>http://www.blogjava.net/wealupa/comments/88277.html</wfw:comment><comments>http://www.blogjava.net/wealupa/archive/2006/12/16/88277.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/wealupa/comments/commentRss/88277.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/wealupa/services/trackbacks/88277.html</trackback:ping><description><![CDATA[<div><strong>使用Servlet2.4/jsp2.0</strong> </div>
<div><strong></strong>&nbsp;</div>
<div>1、确定Web Container支持Serverlet2.4， 复制jstl-1.1.2.jar,standard-1.1.2.jar到web-inf/lib (可打开jar的-inf来看具体版本)。</div>
<div>2、直接在html里面使用EL，而不是&lt;c:out =""/&gt;，充分使用JSP2.0的EL，直接在html中写${book} 而不是&lt;c:out ="${book}"&gt;将获得简洁无比，可比美velocity,freemarker的界面。</div>
<div>3、除了最基本的算术运算符，逻辑运算符，比较运算符外，还有一个empty运算符，用来判断变量是否为null 或list, map的size 是否为零。</div>
<div>&nbsp;&nbsp;&nbsp;&nbsp; 例如：
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #0000ff">&lt;</span><span style="COLOR: #800000">c:if&nbsp;</span><span style="COLOR: #ff0000">test</span><span style="COLOR: #0000ff">="${not&nbsp;empty&nbsp;myList}"</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000"><br><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top></span></div>
</div>
<div><span style="COLOR: #32cd32"><span style="COLOR: #000000">4、</span> <span style="COLOR: #000000">[ ]与. 两种访问属性或元素的方式：</span> </span></div>
<div><span style="COLOR: #32cd32"><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp; ${book.name}与${book["name"]}等价。</span> </span></div>
<div><span style="COLOR: #32cd32"><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp; ${book["name"]}主要用于"name"串为变量，或者字符串中含有"."字符的情况</span> </span></div>
<div><span style="COLOR: #32cd32"><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp; 如 $ {myMap[order.status]}是访问Map元素的一种很重要的方式。</span> </span></div>
<div><span style="COLOR: #32cd32"><span style="COLOR: #000000">5、list与map
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">&lt;</span><span style="COLOR: #800000">c:forEach&nbsp;</span><span style="COLOR: #ff0000">var</span><span style="COLOR: #0000ff">="entry"</span><span style="COLOR: #ff0000">&nbsp;items</span><span style="COLOR: #0000ff">="${myMap}"</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000"><br><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">&lt;</span><span style="COLOR: #800000">option&nbsp;</span><span style="COLOR: #0000ff">="${entry.key}"</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000">${entry.}</span><span style="COLOR: #0000ff">&lt;/</span><span style="COLOR: #800000">option</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">&lt;/</span><span style="COLOR: #800000">c:forEach</span><span style="COLOR: #0000ff">&gt;</span></div>
</span></span><span style="COLOR: #32cd32"><span style="COLOR: #000000"><span style="COLOR: #32cd32"></span></span></span></div>
<div><span style="COLOR: #32cd32"><span style="COLOR: #000000"><span style="COLOR: #32cd32"></span></span></span>&nbsp;</div>
<div><span style="COLOR: #32cd32"><span style="COLOR: #000000"><span style="COLOR: #000000"><strong>Freemarker模版框架</strong> </span></span></span></div>
<div><span style="COLOR: #32cd32"><span style="COLOR: #000000"><span style="COLOR: #000000"><strong></strong></span></span></span>&nbsp;</div>
<div><span style="COLOR: #32cd32"><span style="COLOR: #000000"><span style="COLOR: #000000">1、freemarker是一个时下比较流行的模版框架。模版技术应用的场合很多，例如代码生成，XML文件生成之类，而其最主要的作用还是应用于VIEW层的HTML代码生成。Freemarker框架的兴起也同流行MVC框架的大规模引用有直接关系。使用Freemarker的MVC框架有Webwork,SpringMVC,Struts2.0等等。</span> </span></span></div>
<div><span style="COLOR: #32cd32"><span style="COLOR: #000000"><span style="COLOR: #000000">2、另外很多人问freemarker怎么学，其实他的简单就是fm的最大优点，一般人看他的文档，半小时之内就能掌握。</span> </span></span></div>
<div><span style="COLOR: #32cd32"><span style="COLOR: #000000"><span style="COLOR: #000000"></span></span></span>&nbsp;</div>
<div><span style="COLOR: #32cd32"><span style="COLOR: #000000"><span style="COLOR: #000000"><strong>标签ExtremeComponents</strong> </span></span></span></div>
<div><span style="COLOR: #32cd32"><span style="COLOR: #000000"><span style="COLOR: #000000"></span></span></span>&nbsp;</div>
<div><span style="COLOR: #32cd32"><span style="COLOR: #000000"><span style="COLOR: #000000">1、Extreme Table是功能最强大而又容易配置、扩展、自定义的Table 控件。</span> </span></span></div>
<div><span style="COLOR: #32cd32"><span style="COLOR: #000000"><span style="COLOR: #000000">2、常用的功能包括排序、分页、导出Excel, pdf和汇总。</span> </span></span></div>
<div><span style="COLOR: #32cd32"><span style="COLOR: #000000"><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 网站：<span class=nobr><a title="Visit page outside Confluence" href="http://www.extremecomponents.org/" rel=nofollow>http://www.extremecomponents.org<sup><img style="CURSOR: pointer" onclick=javascript:window.open(this.src); src="http://wiki.springside.org.cn/images/icons/linkext7.gif" width=7 onload="javascript:if(this.width>500){this.resized=true;this.style.width=500;}" align=absMiddle border=0 src_cetemp="http://wiki.springside.org.cn/images/icons/linkext7.gif"></sup></a></span></span> </span></span></div>
<div><span style="COLOR: #32cd32"><span style="COLOR: #000000"><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 文档：<span class=nobr><a title="Visit page outside Confluence" href="http://extremecomponents.org/wiki/index.php/Simplified_Chinese" rel=nofollow>1. 官方中文文档<sup><img style="CURSOR: pointer" onclick=javascript:window.open(this.src); src="http://wiki.springside.org.cn/images/icons/linkext7.gif" width=7 onload="javascript:if(this.width>500){this.resized=true;this.style.width=500;}" align=absMiddle border=0 src_cetemp="http://wiki.springside.org.cn/images/icons/linkext7.gif"></sup></a></span>&nbsp;--<span class=nobr><a title="Visit page outside Confluence" href="http://www.blogjava.net/lucky/" rel=nofollow>Lucky翻译<sup><img style="CURSOR: pointer" onclick=javascript:window.open(this.src); src="http://wiki.springside.org.cn/images/icons/linkext7.gif" width=7 onload="javascript:if(this.width>500){this.resized=true;this.style.width=500;}" align=absMiddle border=0 src_cetemp="http://wiki.springside.org.cn/images/icons/linkext7.gif"></sup></a></span><span class=nobr></span></span> </span></span></div>
<div><span style="COLOR: #32cd32"><span style="COLOR: #000000"><span style="COLOR: #000000"><span class=nobr>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <a title="Visit page outside Confluence" href="http://extremecomponents.org/wiki/index.php/Main_Page" rel=nofollow>2. 官方英文文档<sup><img style="CURSOR: pointer" onclick=javascript:window.open(this.src); src="http://wiki.springside.org.cn/images/icons/linkext7.gif" width=7 onload="javascript:if(this.width>500){this.resized=true;this.style.width=500;}" align=absMiddle border=0 src_cetemp="http://wiki.springside.org.cn/images/icons/linkext7.gif"></sup></a></span> </span></span></span></div>
<div><span style="COLOR: #32cd32"><span style="COLOR: #000000"><span style="COLOR: #000000"><span class=nobr></span></span></span></span>&nbsp;</div>
<div><span style="COLOR: #32cd32"><span style="COLOR: #000000"><span style="COLOR: #000000"><span class=nobr><strong>AJAX技术以及DWR框架</strong> </span></span></span></span></div>
<img src ="http://www.blogjava.net/wealupa/aggbug/88277.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/wealupa/" target="_blank">常言笑</a> 2006-12-16 22:45 <a href="http://www.blogjava.net/wealupa/archive/2006/12/16/88277.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>DAO层指南</title><link>http://www.blogjava.net/wealupa/archive/2006/12/16/88275.html</link><dc:creator>常言笑</dc:creator><author>常言笑</author><pubDate>Sat, 16 Dec 2006 14:42:00 GMT</pubDate><guid>http://www.blogjava.net/wealupa/archive/2006/12/16/88275.html</guid><wfw:comment>http://www.blogjava.net/wealupa/comments/88275.html</wfw:comment><comments>http://www.blogjava.net/wealupa/archive/2006/12/16/88275.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/wealupa/comments/commentRss/88275.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/wealupa/services/trackbacks/88275.html</trackback:ping><description><![CDATA[<h2><span style="FONT-SIZE: 12pt">1.概述</span> </h2>
<p>&nbsp;&nbsp; SpringSide的DAO层两个特点：</p>
<p>&nbsp;&nbsp; 1.DAO层与Business层合并，且省略DAO接口，用cglib方式实现AOP事务控制。</p>
<p>&nbsp;&nbsp; 2.基于范型的强基类，普通DAO类只要用声明所要管理的Entity类型即拥有完整的CRUD操作。</p>
<p>&nbsp;&nbsp;&nbsp;结果就是，普通的Manager类只有一个文件，数行代码。</p>
<p>&nbsp;&nbsp; 同时，当逻辑比较复杂，Manager类比较庞大时，可以内部重构拆分为Dao与Manager，但这个重构行为是内部的，不造成影响的。因为其他类调用的始终是Manager。</p>
<h2><span style="FONT-SIZE: 12pt">2. HibernateGenericDao</span> </h2>
<p>&nbsp;&nbsp; SpringSide 在Spring HibernateDaoSupport基础上封装的DAO，功能如下：</p>
<p>&nbsp;&nbsp;&nbsp;1.应用范型，使得find(), get() 这些函数不再返回Object，不再需要强制类型转换。</p>
<p>&nbsp;&nbsp; 2.提供各种finder的简便函数<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;应用了JDK5可变参数的hsql查询函数：List find(String hql, Object... s)&nbsp;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 简单查询的简化函数：findBy(Class entityClass,String name,Object ) ,findUniqueBy(Class entityClass,String name, Object ),findByLike(Class entityClass,String name,Object )&nbsp;</p>
<p>&nbsp;&nbsp;&nbsp;3.分页函数:Page pagedQuery(Criteria criteria, int pageNo, int pageSize) /Page pagedQuery(String hql, int pageNo, int pageSize, Object... args) 。</p>
<p>&nbsp;&nbsp;&nbsp;4.判别对象属性在数据库中唯一的函数：isNotUnique(entityClass, Object entity, String names)。</p>
<h2><span style="FONT-SIZE: 12pt">3. HibernateEntityDao</span> </h2>
<p>&nbsp;&nbsp;&nbsp; 所有UserManager, ProductManager之类只管理一类对象的Manager类的基类，只需要在类定义处声明Entity类型即可</p>
<div class=code>
<div class=codeContent>
<pre class=code-java>								<span class=code-keyword>public</span> class BookManager <span class=code-keyword>extends</span> HibernateEntityDao&lt;Book&gt; {}</pre>
</div>
</div>
<h2><span style="FONT-SIZE: 12pt">4. IBatisGenericDao</span> </h2>
<p>&nbsp;&nbsp; SpringSide 在Spring SqlMapClientDaoSupport基础上封装的DAO，功能如下：</p>
<p>&nbsp;&nbsp;&nbsp;1.应用范型，使得find(), get() 这些函数不再返回Object，不再需要强制类型转换。</p>
<p>&nbsp;&nbsp; 2.提供各种finder的简便函数<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;应用了JDK5可变参数的hsql查询函数：List find(String hql, Object... s)&nbsp;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 简单查询的简化函数：findBy(Class entityClass,String name,Object ) ,findUniqueBy(Class entityClass,String name, Object ),findByLike(Class entityClass,String name,Object )&nbsp;</p>
<p>&nbsp;&nbsp;&nbsp;3.分页函数:Page pagedQuery(Criteria criteria, int pageNo, int pageSize) /Page pagedQuery(String hql, int pageNo, int pageSize, Object... args) 。</p>
<p>&nbsp;&nbsp;&nbsp; 4.由于IBatis本身的特性,因此有少数方法的使用和HiberGenericDAO不太一样,如save传入的必须是一个指定操作方式的map(参看helloworld下面的UserManagerIBatisTest)</p>
<h2><span style="FONT-SIZE: 12pt">5. IBatisEntityDao</span> </h2>
<p>&nbsp;&nbsp;&nbsp; 所有UserManager, ProductManager之类只管理一类对象的Manager类的基类，只需要在类定义处声明Entity类型即可</p>
<div class=code>
<div class=codeContent>
<pre class=code-java>								<span class=code-keyword>public</span> class BookManager <span class=code-keyword>extends</span> IBatisEntityDao&lt;Book&gt; {}</pre>
</div>
</div>
<img src ="http://www.blogjava.net/wealupa/aggbug/88275.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/wealupa/" target="_blank">常言笑</a> 2006-12-16 22:42 <a href="http://www.blogjava.net/wealupa/archive/2006/12/16/88275.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Controller层总述</title><link>http://www.blogjava.net/wealupa/archive/2006/12/16/88276.html</link><dc:creator>常言笑</dc:creator><author>常言笑</author><pubDate>Sat, 16 Dec 2006 14:42:00 GMT</pubDate><guid>http://www.blogjava.net/wealupa/archive/2006/12/16/88276.html</guid><wfw:comment>http://www.blogjava.net/wealupa/comments/88276.html</wfw:comment><comments>http://www.blogjava.net/wealupa/archive/2006/12/16/88276.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/wealupa/comments/commentRss/88276.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/wealupa/services/trackbacks/88276.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp; MVC框架很多，有分量的也有Struts, Struts2, Webwork, SpringMVC, JSF, Tapestry 六家，SpringSide目前选定演示的是Struts 和 Struts2。
<div>&nbsp;&nbsp; </div>
<ol>
    <li>Struts: 坊间对Struts的印象很差，其实那只是停留在旧时代的用法，在SpringSide2的里的用法，在简洁度上不输与其他框架多少，何况它用户数在国内还是最多的。
    <li>Struts2:坊间传闻它就是Webwork改了package name，其实这也是不公平的，在Helloworld里它的确和Webwork很像，但它乒乒乓乓捣鼓了半年多，现在还是每天更新更新之中，就绝对没有这么简单。它也有和Struts很像的一面，也有很多的扩展，很适宜迁移Struts的用户，在国内前景上比较乐观的。
    <li>Webwork:既然它的骨血都到了Struts2，国内当前的用户数量又不算多，所以SpringSide暂时不做demo。&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
    <li>
    <div>SpringMVC: SpringSide1.0所选用的MVC方案，但它实在太少的用户量，再加上SpringSide一直用的都不是它的主推方案(SimpleFormController)，还有Spring2.0的MVC部分没有做到它所说的改进，离RoR还是10万八前里，所以放弃。&nbsp;</div>
    <li>
    <div>Tapestry 和 JSF。JSF现在还不是潮流，自己也没用过，不评。Tapestry 在公司几个项目用过，评价较差，美工最恨。</div>
    </li>
</ol>
<img src ="http://www.blogjava.net/wealupa/aggbug/88276.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/wealupa/" target="_blank">常言笑</a> 2006-12-16 22:42 <a href="http://www.blogjava.net/wealupa/archive/2006/12/16/88276.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Java常见问题集锦</title><link>http://www.blogjava.net/wealupa/archive/2006/12/16/88273.html</link><dc:creator>常言笑</dc:creator><author>常言笑</author><pubDate>Sat, 16 Dec 2006 14:41:00 GMT</pubDate><guid>http://www.blogjava.net/wealupa/archive/2006/12/16/88273.html</guid><wfw:comment>http://www.blogjava.net/wealupa/comments/88273.html</wfw:comment><comments>http://www.blogjava.net/wealupa/archive/2006/12/16/88273.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/wealupa/comments/commentRss/88273.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/wealupa/services/trackbacks/88273.html</trackback:ping><description><![CDATA[<span style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体">1、一个类可以同时实现多个接口，但是不能同时继承一个以上的类。</span> 
<img src ="http://www.blogjava.net/wealupa/aggbug/88273.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/wealupa/" target="_blank">常言笑</a> 2006-12-16 22:41 <a href="http://www.blogjava.net/wealupa/archive/2006/12/16/88273.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Hibernate的缓存机制介绍</title><link>http://www.blogjava.net/wealupa/archive/2006/12/16/88270.html</link><dc:creator>常言笑</dc:creator><author>常言笑</author><pubDate>Sat, 16 Dec 2006 14:39:00 GMT</pubDate><guid>http://www.blogjava.net/wealupa/archive/2006/12/16/88270.html</guid><wfw:comment>http://www.blogjava.net/wealupa/comments/88270.html</wfw:comment><comments>http://www.blogjava.net/wealupa/archive/2006/12/16/88270.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/wealupa/comments/commentRss/88270.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/wealupa/services/trackbacks/88270.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 缓存是介于应用程序和物理数据源之间，其作用是为了降低应用程序对物理数据源访问的频次，从而提高了应用的运行性能。缓存内的数据是对物理数据源中的数据的复制，应用程序在运行时从缓存读写数据，在特定的时刻或事件会同步缓存和物理数据源的数据。<br><br>　　缓存的介质一般是内存，所以读写速度很快。但如果缓存中存放的数据量非常大时，也会用硬盘作为缓存介质。缓存的实现不仅仅要考虑存储的介质，还要考虑到管理缓存的并发访问和缓存数据的生命周期。<br><br>　　Hibernate的缓存包括Session的缓存和SessionFactory的缓存，其中SessionFactory的缓存又可以分为两类：内置缓存和外置缓存。Session的缓存是内置的，不能被卸载，也被称为Hibernate的第一级缓存。SessionFactory的内置缓存和Session的缓存在实现方式上比较相似，前者是SessionFactory对象的一些集合属性包含的数据，后者是指Session的一些集合属性包含的数据。SessionFactory的内置缓存中存放了映射元数据和预定义SQL语句，映射元数据是映射文件中数据的拷贝，而预定义SQL语句是在Hibernate初始化阶段根据映射元数据推导出来，SessionFactory的内置缓存是只读的，应用程序不能修改缓存中的映射元数据和预定义SQL语句，因此SessionFactory不需要进行内置缓存与映射文件的同步。SessionFactory的外置缓存是一个可配置的插件。在默认情况下，SessionFactory不会启用这个插件。外置缓存的数据是数据库数据的拷贝，外置缓存的介质可以是内存或者硬盘。SessionFactory的外置缓存也被称为Hibernate的第二级缓存。<br><br>　　Hibernate的这两级缓存都位于持久化层，存放的都是数据库数据的拷贝，那么它们之间的区别是什么呢？为了理解二者的区别，需要深入理解持久化层的缓存的两个特性：缓存的范围和缓存的并发访问策略。<br><br><strong>持久化层的缓存的范围<br></strong><br>　　缓存的范围决定了缓存的生命周期以及可以被谁访问。缓存的范围分为三类。<br><br>　　1 事务范围：缓存只能被当前事务访问。缓存的生命周期依赖于事务的生命周期，当事务结束时，缓存也就结束生命周期。在此范围下，缓存的介质是内存。事务可以是数据库事务或者应用事务，每个事务都有独自的缓存，缓存内的数据通常采用相互关联的的对象形式。<br><br>　　2 进程范围：缓存被进程内的所有事务共享。这些事务有可能是并发访问缓存，因此必须对缓存采取必要的事务隔离机制。缓存的生命周期依赖于进程的生命周期，进程结束时，缓存也就结束了生命周期。进程范围的缓存可能会存放大量的数据，所以存放的介质可以是内存或硬盘。缓存内的数据既可以是相互关联的对象形式也可以是对象的松散数据形式。松散的对象数据形式有点类似于对象的序列化数据，但是对象分解为松散的算法比对象序列化的算法要求更快。<br><br>　　3 集群范围：在集群环境中，缓存被一个机器或者多个机器的进程共享。缓存中的数据被复制到集群环境中的每个进程节点，进程间通过远程通信来保证缓存中的数据的一致性，缓存中的数据通常采用对象的松散数据形式。<br><br>　　对大多数应用来说，应该慎重地考虑是否需要使用集群范围的缓存，因为访问的速度不一定会比直接访问数据库数据的速度快多少。<br><br>　　持久化层可以提供多种范围的缓存。如果在事务范围的缓存中没有查到相应的数据，还可以到进程范围或集群范围的缓存内查询，如果还是没有查到，那么只有到数据库中查询。事务范围的缓存是持久化层的第一级缓存，通常它是必需的；进程范围或集群范围的缓存是持久化层的第二级缓存，通常是可选的。<br><br><strong>持久化层的缓存的并发访问策略<br></strong><br>　　当多个并发的事务同时访问持久化层的缓存的相同数据时，会引起并发问题，必须采用必要的事务隔离措施。<br><br>　　在进程范围或集群范围的缓存，即第二级缓存，会出现并发问题。因此可以设定以下四种类型的并发访问策略，每一种策略对应一种事务隔离级别。<br><br>　　事务型：仅仅在受管理环境中适用。它提供了Repeatable Read事务隔离级别。对于经常被读但很少修改的数据，可以采用这种隔离类型，因为它可以防止脏读和不可重复读这类的并发问题。<br><br>　　读写型：提供了Read Committed事务隔离级别。仅仅在非集群的环境中适用。对于经常被读但很少修改的数据，可以采用这种隔离类型，因为它可以防止脏读这类的并发问题。<br><br>　　非严格读写型：不保证缓存与数据库中数据的一致性。如果存在两个事务同时访问缓存中相同数据的可能，必须为该数据配置一个很短的数据过期时间，从而尽量避免脏读。对于极少被修改，并且允许偶尔脏读的数据，可以采用这种并发访问策略。<br><br>　　只读型：对于从来不会修改的数据，如参考数据，可以使用这种并发访问策略。<br><br>　　事务型并发访问策略是事务隔离级别最高，只读型的隔离级别最低。事务隔离级别越高，并发性能就越低。<br><br><strong>什么样的数据适合存放到第二级缓存中？</strong>
<div><strong><br>&nbsp;</strong></div>
<div><span style="FONT-SIZE: 10pt; FONT-FAMILY: 宋体">1 很少被修改的数据<br><br>2 不是很重要的数据，允许出现偶尔并发的数据<br><br>3 不会被并发访问的数据<br><br>4 参考数据<br><br>不适合存放到第二级缓存的数据？<br><br>1 经常被修改的数据<br><br>2 财务数据，绝对不允许出现并发<br><br>3 与其他应用共享的数据。<br><br>Hibernate的二级缓存<br><br>　　如前所述，Hibernate提供了两级缓存，第一级是Session的缓存。由于Session对象的生命周期通常对应一个数据库事务或者一个应用事务，因此它的缓存是事务范围的缓存。第一级缓存是必需的，不允许而且事实上也无法比卸除。在第一级缓存中，持久化类的每个实例都具有唯一的OID。<br><br>　　第二级缓存是一个可插拔的的缓存插件，它是由SessionFactory负责管理。由于SessionFactory对象的生命周期和应用程序的整个过程对应，因此第二级缓存是进程范围或者集群范围的缓存。这个缓存中存放的对象的松散数据。第二级对象有可能出现并发问题，因此需要采用适当的并发访问策略，该策略为被缓存的数据提供了事务隔离级别。缓存适配器用于把具体的缓存实现软件与Hibernate集成。第二级缓存是可选的，可以在每个类或每个集合的粒度上配置第二级缓存。<br><br>Hibernate的二级缓存策略的一般过程如下：<br><br>1) 条件查询的时候，总是发出一条select * from table_name where &#8230;. （选择所有字段）这样的SQL语句查询数据库，一次获得所有的数据对象。 <br><br>2) 把获得的所有数据对象根据ID放入到第二级缓存中。 <br><br>3) 当Hibernate根据ID访问数据对象的时候，首先从Session一级缓存中查；查不到，如果配置了二级缓存，那么从二级缓存中查；查不到，再查询数据库，把结果按照ID放入到缓存。 <br><br>4) 删除、更新、增加数据的时候，同时更新缓存。<br><br>　　Hibernate的二级缓存策略，是针对于ID查询的缓存策略，对于条件查询则毫无作用。为此，Hibernate提供了针对条件查询的Query缓存。<br><br>Hibernate的Query缓存策略的过程如下：<br><br>1) Hibernate首先根据这些信息组成一个Query Key，Query Key包括条件查询的请求一般信息：SQL, SQL需要的参数，记录范围（起始位置rowStart，最大记录个数maxRows)，等。 <br><br>2) Hibernate根据这个Query Key到Query缓存中查找对应的结果列表。如果存在，那么返回这个结果列表；如果不存在，查询数据库，获取结果列表，把整个结果列表根据Query Key放入到Query缓存中。 <br><br>3) Query Key中的SQL涉及到一些表名，如果这些表的任何数据发生修改、删除、增加等操作，这些相关的Query Key都要从缓存中清空。</span><br></div>
<img src ="http://www.blogjava.net/wealupa/aggbug/88270.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/wealupa/" target="_blank">常言笑</a> 2006-12-16 22:39 <a href="http://www.blogjava.net/wealupa/archive/2006/12/16/88270.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Acegi 使用 Acl（2）</title><link>http://www.blogjava.net/wealupa/archive/2006/12/16/88261.html</link><dc:creator>常言笑</dc:creator><author>常言笑</author><pubDate>Sat, 16 Dec 2006 14:31:00 GMT</pubDate><guid>http://www.blogjava.net/wealupa/archive/2006/12/16/88261.html</guid><wfw:comment>http://www.blogjava.net/wealupa/comments/88261.html</wfw:comment><comments>http://www.blogjava.net/wealupa/archive/2006/12/16/88261.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/wealupa/comments/commentRss/88261.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/wealupa/services/trackbacks/88261.html</trackback:ping><description><![CDATA[<p>流程说完了，接下对上面提到的问题解释一下： <br></p>
<div class=quote_title>引用</div>
<div class=quote_div><br>先使用URL拦截的方式去对付大多数的情况，然后少数URL搞不定的再加一个接口，让Action自己去判别。这样用两个拦截器对Action进行拦截，如果Action实现了hasPermission接口，那么就交给Action自己判断，如果Action没有该接口，就查找内部的URL和权限的对照表来判断。 <br></div>
<p>&#160;</p>
<p>这个情况比较复杂，因为是要对Action进行调用，所以要看使用的web框架来定夺。是用不同Web框架要是用不同的Web框架拦截器。所以恐怕acegi力不从心，挺多在filter里面配置一下是否要是用Action自身校验。但是想法很好，赞。</p>
<p>&#160;</p>
<div class=quote_title>引用</div>
<div class=quote_div><br>你怎么把信息有效的传递给Web层和其他的Facade层进行用户友好性的提示处理？ <br></div>
<p>&#160;</p>
<p>acegi校验失败的时候会抛出AuthenticationException异常，然后放在session里面， <br>在错误转向页面可以这样是用 <br></p>
<div class=code_title>代码
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #000000">&lt;%=</span><span style="COLOR: #000000">&nbsp;((AuthenticationException)&nbsp;session.getAttribute(AbstractProcessingFilter.ACEGI_SECURITY_LAST_EXCEPTION_KEY)).getMessage()&nbsp;</span><span style="COLOR: #000000">%&gt;</span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;<br><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #000000">&lt;%=</span><span style="COLOR: #000000">&nbsp;session.getAttribute(AuthenticationProcessingFilter.ACEGI_SECURITY_LAST_USERNAME_KEY)&nbsp;</span><span style="COLOR: #000000">%&gt;</span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;<br><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #000000">&lt;%=</span><span style="COLOR: #000000">&nbsp;session.getAttribute(SecurityEnforcementFilter.ACEGI_SECURITY_ACCESS_DENIED_EXCEPTION_KEY)&nbsp;</span><span style="COLOR: #000000">%&gt;</span><span style="COLOR: #000000">&nbsp;</span></div>
</div>
<script><![CDATA[ender_code();]]&gt;</script><br>不过这么用实在太难看了，晕了。可以自己用tag来搞定
<p>&#160;</p>
<p>&#160;</p>
<div class=quote_title>引用</div>
<div class=quote_div><br>很多系统需要根据权限不同，生成不同的UI组件(例如管理员的菜单和普通用户菜单就肯定不一样)，这也需要在Web层的View进行控制。 <br></div>
<br>acegi对View的处理就是使用tag,原来的acegi好像没有什么tag，简直是烂，现在有了tag，说一下是用的方法，但是说实话他的tag实在是不够强。
<p>&#160;</p>
<p>老版的web.xml <br></p>
<div class=code_title>代码
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><span style="COLOR: #008080">1</span><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #0000ff">&lt;</span><span style="COLOR: #800000">taglib</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;<br></span><span style="COLOR: #008080">2</span><span style="COLOR: #000000"><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;</span><span style="COLOR: #0000ff">&lt;</span><span style="COLOR: #800000">taglib-uri</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000">http://acegisecurity.sf.net/authz</span><span style="COLOR: #0000ff">&lt;/</span><span style="COLOR: #800000">taglib-uri</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;<br></span><span style="COLOR: #008080">3</span><span style="COLOR: #000000"><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;</span><span style="COLOR: #0000ff">&lt;</span><span style="COLOR: #800000">taglib-location</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000">/WEB-INF/authz.tld</span><span style="COLOR: #0000ff">&lt;/</span><span style="COLOR: #800000">taglib-location</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;<br></span><span style="COLOR: #008080">4</span><span style="COLOR: #000000"><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #0000ff">&lt;/</span><span style="COLOR: #800000">taglib</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000">&nbsp;&nbsp;</span></div>
</div>
<script><![CDATA[ender_code();]]&gt;</script><br>在页面中使用 <br>
<div class=code_title>代码
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><span style="COLOR: #008080">1</span><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #0000ff">&lt;</span><span style="COLOR: #800000">authz:authorize&nbsp;</span><span style="COLOR: #ff0000">ifAllGranted</span><span style="COLOR: #0000ff">="ROLE_SUPERVISOR"</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;<br></span><span style="COLOR: #008080">2</span><span style="COLOR: #000000"><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #0000ff">&lt;</span><span style="COLOR: #800000">td</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;<br></span><span style="COLOR: #008080">3</span><span style="COLOR: #000000"><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #0000ff">&lt;</span><span style="COLOR: #800000">A&nbsp;</span><span style="COLOR: #ff0000">HREF</span><span style="COLOR: #0000ff">="del.htm?id=&lt;c:out&nbsp;value="</span><span style="COLOR: #ff0000">/${contact.id}"</span><span style="COLOR: #0000ff">/&gt;</span><span style="COLOR: #000000">"&gt;Del</span><span style="COLOR: #0000ff">&lt;/</span><span style="COLOR: #800000">A</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;<br></span><span style="COLOR: #008080">4</span><span style="COLOR: #000000"><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #0000ff">&lt;/</span><span style="COLOR: #800000">td</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;<br></span><span style="COLOR: #008080">5</span><span style="COLOR: #000000"><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #0000ff">&lt;/</span><span style="COLOR: #800000">authz:authorize</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000">&nbsp;&nbsp;</span></div>
</div>
<script><![CDATA[ender_code();]]&gt;</script><br>ifAllGranted是说所有的权限都有，用','分割权限 <br>可以替换成ifAnyGranted: ifNotGranted:
<p>&#160;</p>
<p>&#160;</p>
<div class=code_title>代码
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><span style="COLOR: #008080">1</span><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #0000ff">&lt;</span><span style="COLOR: #800000">authz:authentication&nbsp;</span><span style="COLOR: #ff0000">operation</span><span style="COLOR: #0000ff">="username"</span><span style="COLOR: #0000ff">/&gt;</span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;</span></div>
</div>
<script><![CDATA[ender_code();]]&gt;</script>
<p>&#160;</p>
<p>这个是用来显示你的权限信息的。</p>
<p>&#160;</p>
<div class=code_title>代码
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><span style="COLOR: #008080">1</span><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #0000ff">&lt;</span><span style="COLOR: #800000">authz:acl&nbsp;</span><span style="COLOR: #ff0000">domainObject</span><span style="COLOR: #0000ff">="${contact}"</span><span style="COLOR: #ff0000">&nbsp;hasPermission</span><span style="COLOR: #0000ff">="16,1"</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;<br></span><span style="COLOR: #008080">2</span><span style="COLOR: #000000"><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #0000ff">&lt;</span><span style="COLOR: #800000">td</span><span style="COLOR: #0000ff">&gt;&lt;</span><span style="COLOR: #800000">A&nbsp;</span><span style="COLOR: #ff0000">HREF</span><span style="COLOR: #0000ff">="&lt;c:url&nbsp;value="</span><span style="COLOR: #ff0000">del.htm"</span><span style="COLOR: #0000ff">&gt;&lt;</span><span style="COLOR: #800000">c:param&nbsp;</span><span style="COLOR: #ff0000">name</span><span style="COLOR: #0000ff">="contactId"</span><span style="COLOR: #ff0000">&nbsp;&nbsp;&nbsp;<br></span><span style="COLOR: #008080">3</span><span style="COLOR: #ff0000"><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top>value</span><span style="COLOR: #0000ff">="${contact.id}"</span><span style="COLOR: #0000ff">/&gt;&lt;/</span><span style="COLOR: #800000">c:url</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000">"&gt;Del</span><span style="COLOR: #0000ff">&lt;/</span><span style="COLOR: #800000">A</span><span style="COLOR: #0000ff">&gt;&lt;/</span><span style="COLOR: #800000">td</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;<br></span><span style="COLOR: #008080">4</span><span style="COLOR: #000000"><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #0000ff">&lt;/</span><span style="COLOR: #800000">authz:acl</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000">&nbsp;&nbsp;</span></div>
</div>
<img src ="http://www.blogjava.net/wealupa/aggbug/88261.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/wealupa/" target="_blank">常言笑</a> 2006-12-16 22:31 <a href="http://www.blogjava.net/wealupa/archive/2006/12/16/88261.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Acegi 使用 Acl（1）</title><link>http://www.blogjava.net/wealupa/archive/2006/12/16/88260.html</link><dc:creator>常言笑</dc:creator><author>常言笑</author><pubDate>Sat, 16 Dec 2006 14:27:00 GMT</pubDate><guid>http://www.blogjava.net/wealupa/archive/2006/12/16/88260.html</guid><wfw:comment>http://www.blogjava.net/wealupa/comments/88260.html</wfw:comment><comments>http://www.blogjava.net/wealupa/archive/2006/12/16/88260.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/wealupa/comments/commentRss/88260.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/wealupa/services/trackbacks/88260.html</trackback:ping><description><![CDATA[<p>首先要配置一个filter，这个filter用一个代理bean写在了spring里面，其实根正常的filter没有任何区别。 <br></p>
<div class=code_title>代码
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><span style="COLOR: #008080">1</span><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #0000ff">&lt;</span><span style="COLOR: #800000">bean&nbsp;</span><span style="COLOR: #ff0000">id</span><span style="COLOR: #0000ff">="securityEnforcementFilter"</span><span style="COLOR: #ff0000">&nbsp;&nbsp;&nbsp;<br></span><span style="COLOR: #008080">2</span><span style="COLOR: #ff0000"><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;class</span><span style="COLOR: #0000ff">="org.acegisecurity.intercept.web.SecurityEnforcementFilter"</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;<br></span><span style="COLOR: #008080">3</span><span style="COLOR: #000000"><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">&lt;</span><span style="COLOR: #800000">property&nbsp;</span><span style="COLOR: #ff0000">name</span><span style="COLOR: #0000ff">="filterSecurityInterceptor"</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;<br></span><span style="COLOR: #008080">4</span><span style="COLOR: #000000"><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">&lt;</span><span style="COLOR: #800000">ref&nbsp;</span><span style="COLOR: #ff0000">local</span><span style="COLOR: #0000ff">="filterInvocationInterceptor"</span><span style="COLOR: #ff0000">&nbsp;</span><span style="COLOR: #0000ff">/&gt;</span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;<br></span><span style="COLOR: #008080">5</span><span style="COLOR: #000000"><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">&lt;/</span><span style="COLOR: #800000">property</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;<br></span><span style="COLOR: #008080">6</span><span style="COLOR: #000000"><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">&lt;</span><span style="COLOR: #800000">property&nbsp;</span><span style="COLOR: #ff0000">name</span><span style="COLOR: #0000ff">="authenticationEntryPoint"</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;<br></span><span style="COLOR: #008080">7</span><span style="COLOR: #000000"><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">&lt;</span><span style="COLOR: #800000">ref&nbsp;</span><span style="COLOR: #ff0000">local</span><span style="COLOR: #0000ff">="authenticationProcessingFilterEntryPoint"</span><span style="COLOR: #ff0000">&nbsp;</span><span style="COLOR: #0000ff">/&gt;</span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;<br></span><span style="COLOR: #008080">8</span><span style="COLOR: #000000"><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">&lt;/</span><span style="COLOR: #800000">property</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;<br></span><span style="COLOR: #008080">9</span><span style="COLOR: #000000"><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #0000ff">&lt;/</span><span style="COLOR: #800000">bean</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000">&nbsp;&nbsp;</span></div>
</div>
<script><![CDATA[ender_code();]]&gt;</script>
<p>&#160;</p>
<div>"filterInvocationInterceptor" 是一个拦截器，说是拦截器，其实就是在filter里面执行一下他的拦截方法，这里可没有什么aop. <br>authenticationEntryPoint 交验失败的时候转到的地方，为什么说是地方，因为通过配置可以转到其它的url甚至其它的协议下(http 转到 https等等)</div>
<div>&nbsp;</div>
<div>
<div class=code_title>代码
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><span style="COLOR: #008080">&nbsp;1</span><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #0000ff">&lt;</span><span style="COLOR: #800000">bean&nbsp;</span><span style="COLOR: #ff0000">id</span><span style="COLOR: #0000ff">="authenticationProcessingFilterEntryPoint"</span><span style="COLOR: #ff0000">&nbsp;&nbsp;&nbsp;<br></span><span style="COLOR: #008080">&nbsp;2</span><span style="COLOR: #ff0000"><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;class</span><span style="COLOR: #0000ff">="org.acegisecurity.ui.webapp.AuthenticationProcessingFilterEntryPoint"</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;<br></span><span style="COLOR: #008080">&nbsp;3</span><span style="COLOR: #000000"><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">&lt;</span><span style="COLOR: #800000">property&nbsp;</span><span style="COLOR: #ff0000">name</span><span style="COLOR: #0000ff">="loginFormUrl"</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;<br></span><span style="COLOR: #008080">&nbsp;4</span><span style="COLOR: #000000"><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">&lt;</span><span style="COLOR: #800000">value</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000">/error.security</span><span style="COLOR: #0000ff">&lt;/</span><span style="COLOR: #800000">value</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;<br></span><span style="COLOR: #008080">&nbsp;5</span><span style="COLOR: #000000"><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">&lt;/</span><span style="COLOR: #800000">property</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;<br></span><span style="COLOR: #008080">&nbsp;6</span><span style="COLOR: #000000"><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">&lt;</span><span style="COLOR: #800000">property&nbsp;</span><span style="COLOR: #ff0000">name</span><span style="COLOR: #0000ff">="forceHttps"</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;<br></span><span style="COLOR: #008080">&nbsp;7</span><span style="COLOR: #000000"><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">&lt;</span><span style="COLOR: #800000">value</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000">false</span><span style="COLOR: #0000ff">&lt;/</span><span style="COLOR: #800000">value</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;<br></span><span style="COLOR: #008080">&nbsp;8</span><span style="COLOR: #000000"><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">&lt;/</span><span style="COLOR: #800000">property</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;<br></span><span style="COLOR: #008080">&nbsp;9</span><span style="COLOR: #000000"><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #0000ff">&lt;/</span><span style="COLOR: #800000">bean</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000">&nbsp;&nbsp;<br></span><span style="COLOR: #008080">10</span><span style="COLOR: #000000"><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top></span></div>
</div>
<script><![CDATA[ender_code();]]&gt;</script>
<p>&#160;</p>
<p>这个就是失败的时候转到的地方，我们可以配置url和是否使用https</p>
<p>&#160;</p>
<div class=code_title>代码
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><span style="COLOR: #008080">&nbsp;1</span><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #0000ff">&lt;</span><span style="COLOR: #800000">bean&nbsp;</span><span style="COLOR: #ff0000">id</span><span style="COLOR: #0000ff">="filterInvocationInterceptor"</span><span style="COLOR: #ff0000">&nbsp;&nbsp;&nbsp;<br></span><span style="COLOR: #008080">&nbsp;2</span><span style="COLOR: #ff0000"><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;class</span><span style="COLOR: #0000ff">="org.acegisecurity.intercept.web.FilterSecurityInterceptor"</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;<br></span><span style="COLOR: #008080">&nbsp;3</span><span style="COLOR: #000000"><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">&lt;</span><span style="COLOR: #800000">property&nbsp;</span><span style="COLOR: #ff0000">name</span><span style="COLOR: #0000ff">="authenticationManager"</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;<br></span><span style="COLOR: #008080">&nbsp;4</span><span style="COLOR: #000000"><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">&lt;</span><span style="COLOR: #800000">ref&nbsp;</span><span style="COLOR: #ff0000">bean</span><span style="COLOR: #0000ff">="authenticationManager"</span><span style="COLOR: #ff0000">&nbsp;</span><span style="COLOR: #0000ff">/&gt;</span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;<br></span><span style="COLOR: #008080">&nbsp;5</span><span style="COLOR: #000000"><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">&lt;/</span><span style="COLOR: #800000">property</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;<br></span><span style="COLOR: #008080">&nbsp;6</span><span style="COLOR: #000000"><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">&lt;</span><span style="COLOR: #800000">property&nbsp;</span><span style="COLOR: #ff0000">name</span><span style="COLOR: #0000ff">="accessDecisionManager"</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;<br></span><span style="COLOR: #008080">&nbsp;7</span><span style="COLOR: #000000"><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">&lt;</span><span style="COLOR: #800000">ref&nbsp;</span><span style="COLOR: #ff0000">local</span><span style="COLOR: #0000ff">="httpRequestAccessDecisionManager"</span><span style="COLOR: #ff0000">&nbsp;</span><span style="COLOR: #0000ff">/&gt;</span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;<br></span><span style="COLOR: #008080">&nbsp;8</span><span style="COLOR: #000000"><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">&lt;/</span><span style="COLOR: #800000">property</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;<br></span><span style="COLOR: #008080">&nbsp;9</span><span style="COLOR: #000000"><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">&lt;</span><span style="COLOR: #800000">property&nbsp;</span><span style="COLOR: #ff0000">name</span><span style="COLOR: #0000ff">="objectDefinitionSource"</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;<br></span><span style="COLOR: #008080">10</span><span style="COLOR: #000000"><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">&lt;</span><span style="COLOR: #800000">value</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;<br></span><span style="COLOR: #008080">11</span><span style="COLOR: #000000"><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON&nbsp;&nbsp;&nbsp;&nbsp;<br></span><span style="COLOR: #008080">12</span><span style="COLOR: #000000"><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;PATTERN_TYPE_APACHE_ANT&nbsp;&nbsp;&nbsp;&nbsp;<br></span><span style="COLOR: #008080">13</span><span style="COLOR: #000000"><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;/index.jsp=ROLE_ANONYMOUS,ROLE_USER&nbsp;&nbsp;&nbsp;&nbsp;<br></span><span style="COLOR: #008080">14</span><span style="COLOR: #000000"><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;/j_acegi_switch_user=ROLE_SUPERVISOR&nbsp;&nbsp;&nbsp;<br></span><span style="COLOR: #008080">15</span><span style="COLOR: #000000"><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;/login.security=ROLE_ANONYMOUS,ROLE_USER&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;/test.do=ROLE_CODER&nbsp;&nbsp;&nbsp;<br></span><span style="COLOR: #008080">16</span><span style="COLOR: #000000"><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;/**.do*=ROLE_USER&nbsp;&nbsp;&nbsp;&nbsp;<br></span><span style="COLOR: #008080">17</span><span style="COLOR: #000000"><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">&lt;/</span><span style="COLOR: #800000">value</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;<br></span><span style="COLOR: #008080">18</span><span style="COLOR: #000000"><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">&lt;/</span><span style="COLOR: #800000">property</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;<br></span><span style="COLOR: #008080">19</span><span style="COLOR: #000000"><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #0000ff">&lt;/</span><span style="COLOR: #800000">bean</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000">&nbsp;&nbsp;</span></div>
</div>
<script><![CDATA[ender_code();]]&gt;</script>
<p>&#160;</p>
<p>这个就是前面提到的拦截器。简单解释一下： <br>authenticationManager 在acegi里面的主要作用就是管理维护用户的权限角色等信息，比方说想要用户的ROLE就要在这里面拿了。里面配置了多种全县的来源，可以从DAO里面来(就是数据库里面)，可以是cookies里面的，也可以是匿名的权限，每种权限都以一种Provider的形式提供： <br></p>
<div class=code_title>代码
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><span style="COLOR: #008080">&nbsp;1</span><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #0000ff">&lt;</span><span style="COLOR: #800000">bean&nbsp;</span><span style="COLOR: #ff0000">id</span><span style="COLOR: #0000ff">="authenticationManager"</span><span style="COLOR: #ff0000">&nbsp;&nbsp;&nbsp;<br></span><span style="COLOR: #008080">&nbsp;2</span><span style="COLOR: #ff0000"><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;class</span><span style="COLOR: #0000ff">="org.acegisecurity.providers.ProviderManager"</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;<br></span><span style="COLOR: #008080">&nbsp;3</span><span style="COLOR: #000000"><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">&lt;</span><span style="COLOR: #800000">property&nbsp;</span><span style="COLOR: #ff0000">name</span><span style="COLOR: #0000ff">="providers"</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;<br></span><span style="COLOR: #008080">&nbsp;4</span><span style="COLOR: #000000"><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">&lt;</span><span style="COLOR: #800000">list</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;<br></span><span style="COLOR: #008080">&nbsp;5</span><span style="COLOR: #000000"><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">&lt;</span><span style="COLOR: #800000">ref&nbsp;</span><span style="COLOR: #ff0000">local</span><span style="COLOR: #0000ff">="daoAuthenticationProvider"</span><span style="COLOR: #ff0000">&nbsp;</span><span style="COLOR: #0000ff">/&gt;</span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;<br></span><span style="COLOR: #008080">&nbsp;6</span><span style="COLOR: #000000"><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">&lt;</span><span style="COLOR: #800000">ref&nbsp;</span><span style="COLOR: #ff0000">local</span><span style="COLOR: #0000ff">="anonymousAuthenticationProvider"</span><span style="COLOR: #ff0000">&nbsp;</span><span style="COLOR: #0000ff">/&gt;</span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;<br></span><span style="COLOR: #008080">&nbsp;7</span><span style="COLOR: #000000"><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">&lt;</span><span style="COLOR: #800000">ref&nbsp;</span><span style="COLOR: #ff0000">local</span><span style="COLOR: #0000ff">="rememberMeAuthenticationProvider"</span><span style="COLOR: #ff0000">&nbsp;</span><span style="COLOR: #0000ff">/&gt;</span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;<br></span><span style="COLOR: #008080">&nbsp;8</span><span style="COLOR: #000000"><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">&lt;/</span><span style="COLOR: #800000">list</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;<br></span><span style="COLOR: #008080">&nbsp;9</span><span style="COLOR: #000000"><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">&lt;/</span><span style="COLOR: #800000">property</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;<br></span><span style="COLOR: #008080">10</span><span style="COLOR: #000000"><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #0000ff">&lt;/</span><span style="COLOR: #800000">bean</span><span style="COLOR: #0000ff">&gt;</span></div>
</div>
<script><![CDATA[ender_code();]]&gt;</script>
<p>&#160;</p>
<p>objectDefinitionSource在acegi里面就是配置权限信息，说明哪一个url需要什么权限才能访问，acegi默认用&lt;value&gt;来表示，其实这正是acegi的不足之处，还好能够补救。我来说明一下： <br>我们知道在spring里面&lt;value&gt;标签比较特殊，spring首先找到这个属性的类型，然后把value里面的内容以String的类型取出来(Spring做了一下包装，为TypedString)。然后根据这个属性的类型找他的Editer，然后用Editer来处理String为需要的类型。但是我们不希望用String来表达url，很明显url里面有=就不会玩了。我们可以把这个信息写到数据库里面，然后读取，这里面不说了以前有一位高手已经解释过了。</p>
<p>接下来就是httpRequestAccessDecisionManager了，AccessDecisionManager在acegi里面是决策者，就是根据你所拥有的权限和访问URL需要的权限来决定你到底能不能访问。</p>
<p>&#160;</p>
<div class=code_title>代码
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><span style="COLOR: #008080">&nbsp;1</span><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #0000ff">&lt;</span><span style="COLOR: #800000">bean&nbsp;</span><span style="COLOR: #ff0000">id</span><span style="COLOR: #0000ff">="httpRequestAccessDecisionManager"</span><span style="COLOR: #ff0000">&nbsp;&nbsp;&nbsp;<br></span><span style="COLOR: #008080">&nbsp;2</span><span style="COLOR: #ff0000"><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;class</span><span style="COLOR: #0000ff">="org.acegisecurity.vote.AffirmativeBased"</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;<br></span><span style="COLOR: #008080">&nbsp;3</span><span style="COLOR: #000000"><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">&lt;</span><span style="COLOR: #800000">property&nbsp;</span><span style="COLOR: #ff0000">name</span><span style="COLOR: #0000ff">="allowIfAllAbstainDecisions"</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;<br></span><span style="COLOR: #008080">&nbsp;4</span><span style="COLOR: #000000"><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">&lt;</span><span style="COLOR: #800000">value</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000">false</span><span style="COLOR: #0000ff">&lt;/</span><span style="COLOR: #800000">value</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;<br></span><span style="COLOR: #008080">&nbsp;5</span><span style="COLOR: #000000"><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">&lt;/</span><span style="COLOR: #800000">property</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;<br></span><span style="COLOR: #008080">&nbsp;6</span><span style="COLOR: #000000"><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">&lt;</span><span style="COLOR: #800000">property&nbsp;</span><span style="COLOR: #ff0000">name</span><span style="COLOR: #0000ff">="decisionVoters"</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;<br></span><span style="COLOR: #008080">&nbsp;7</span><span style="COLOR: #000000"><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">&lt;</span><span style="COLOR: #800000">list</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;<br></span><span style="COLOR: #008080">&nbsp;8</span><span style="COLOR: #000000"><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">&lt;</span><span style="COLOR: #800000">ref&nbsp;</span><span style="COLOR: #ff0000">bean</span><span style="COLOR: #0000ff">="roleVoter"</span><span style="COLOR: #ff0000">&nbsp;</span><span style="COLOR: #0000ff">/&gt;</span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;<br></span><span style="COLOR: #008080">&nbsp;9</span><span style="COLOR: #000000"><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">&lt;/</span><span style="COLOR: #800000">list</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;<br></span><span style="COLOR: #008080">10</span><span style="COLOR: #000000"><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">&lt;/</span><span style="COLOR: #800000">property</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;<br></span><span style="COLOR: #008080">11</span><span style="COLOR: #000000"><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #0000ff">&lt;/</span><span style="COLOR: #800000">bean</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000">&nbsp;&nbsp;</span></div>
</div>
<script><![CDATA[ender_code();]]&gt;</script>
<p>&#160;</p>
<p>决策者里面是投票者，这个上面已经解释过了，一个投票者校验一种权限。整个流程已经说完了。</p>
</div>
<img src ="http://www.blogjava.net/wealupa/aggbug/88260.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/wealupa/" target="_blank">常言笑</a> 2006-12-16 22:27 <a href="http://www.blogjava.net/wealupa/archive/2006/12/16/88260.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>深入理解abstract和interface</title><link>http://www.blogjava.net/wealupa/archive/2006/12/16/88258.html</link><dc:creator>常言笑</dc:creator><author>常言笑</author><pubDate>Sat, 16 Dec 2006 14:24:00 GMT</pubDate><guid>http://www.blogjava.net/wealupa/archive/2006/12/16/88258.html</guid><wfw:comment>http://www.blogjava.net/wealupa/comments/88258.html</wfw:comment><comments>http://www.blogjava.net/wealupa/archive/2006/12/16/88258.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/wealupa/comments/commentRss/88258.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/wealupa/services/trackbacks/88258.html</trackback:ping><description><![CDATA[<blockquote>
<div>&nbsp;</div>
</blockquote>
<div><span class=atitle2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; abstract class和interface是Java语言中对于抽象类定义进行支持的两种机制，正是由于这两种机制的存在，才赋予了Java强大的面向对象能力。abstract class和interface之间在对于抽象类定义的支持方面具有很大的相似性，甚至可以相互替换，因此很多开发者在进行抽象类定义时对于abstract class和interface的选择显得比较随意。其实，两者之间还是有很大的区别的，对于它们的选择甚至反映出对于问题领域本质的理解、对于设计意图的理解是否正确、合理。本文将对它们之间的区别进行一番剖析，试图给开发者提供一个在二者之间进行选择的依据。<br><br><strong>异同：</strong></span> </div>
<div><strong><span class=atitle2></span></strong>&nbsp;</div>
<div><span class=atitle2>1、abstract class首先是一个class，其子类继承他的同时不能再继承其他abstract class。</span> </div>
<div><span class=atitle2>2、abstract class可以有方法体，甚至可以有构造方法，但是不能实例化。</span> </div>
<div><span class=atitle2>3、abstract class和interface虽然本身都不能实例化，但是其实现类或者子类能实例化他。</span> </div>
<div><span class=atitle2>4、interface中不能有static方法，只能存在public或者abstract方法。</span> </div>
<div><span class=atitle2></span>&nbsp;</div>
<div><strong><span class=atitle2>理解抽象类</span> </strong></div>
<p>abstract class和interface在Java语言中都是用来进行抽象类（本文中的抽象类并非从abstract class翻译而来，它表示的是一个抽象体，而abstract class为Java语言中用于定义抽象类的一种方法，请读者注意区分）定义的，那么什么是抽象类，使用抽象类能为我们带来什么好处呢？</p>
<p>在面向对象的概念中，我们知道所有的对象都是通过类来描绘的，但是反过来却不是这样。并不是所有的类都是用来描绘对象的，如果一个类中没有包含足够的信息来描绘一个具体的对象，这样的类就是抽象类。抽象类往往用来表征我们在对问题领域进行分析、设计中得出的抽象概念，是对一系列看上去不同，但是本质上相同的具体概念的抽象。比如：如果我们进行一个图形编辑软件的开发，就会发现问题领域存在着圆、三角形这样一些具体概念，它们是不同的，但是它们又都属于形状这样一个概念，形状这个概念在问题领域是不存在的，它就是一个抽象概念。正是因为抽象的概念在问题领域没有对应的具体概念，所以用以表征抽象概念的抽象类是不能够实例化的。</p>
<div>在面向对象领域，抽象类主要用来进行类型隐藏。我们可以构造出一个固定的一组行为的抽象描述，但是这组行为却能够有任意个可能的具体实现方式。这个抽象描述就是抽象类，而这一组任意个可能的具体实现则表现为所有可能的派生类。模块可以操作一个抽象体。由于模块依赖于一个固定的抽象体，因此它可以是不允许修改的；同时，通过从这个抽象体派生，也可扩展此模块的行为功能。熟悉OCP的读者一定知道，为了能够实现面向对象设计的一个最核心的原则OCP(<strong>Open-Closed Principle</strong>)，抽象类是其中的关键所在。</div>
<p>在abstract class方式中，Demo可以有自己的数据成员，也可以有非abstarct的成员方法，而在interface方式的实现中，Demo只能够有静态的不能被修改的数据成员（也就是必须是static final的，不过在interface中一般不定义数据成员），所有的成员方法都是abstract的。从某种意义上说，interface是一种特殊形式的abstract class。</p>
<p>对于abstract class和interface在语法定义层面更多的细节问题，不是本文的重点，不再赘述，读者可以参阅参考文献〔1〕获得更多的相关内容。</p>
<p><strong><span class=atitle2>从编程层面看abstract class和interface</span> </strong></p>
<p>从编程的角度来看，abstract class和interface都可以用来实现"design by contract"的思想。但是在具体的使用上面还是有一些区别的。</p>
<p>首先，abstract class在Java语言中表示的是一种继承关系，一个类只能使用一次继承关系。但是，一个类却可以实现多个interface。也许，这是Java语言的设计者在考虑Java对于多重继承的支持方面的一种折中考虑吧。</p>
<p>其次，在abstract class的定义中，我们可以赋予方法的默认行为。但是在interface的定义中，方法却不能拥有默认行为，为了绕过这个限制，必须使用委托，但是这会 增加一些复杂性，有时会造成很大的麻烦。</p>
<p>在抽象类中不能定义默认行为还存在另一个比较严重的问题，那就是可能会造成维护上的麻烦。因为如果后来想修改类的界面（一般通过abstract class或者interface来表示）以适应新的情况（比如，添加新的方法或者给已用的方法中添加新的参数）时，就会非常的麻烦，可能要花费很多的时间（对于派生类很多的情况，尤为如此）。但是如果界面是通过abstract class来实现的，那么可能就只需要修改定义在abstract class中的默认行为就可以了。</p>
<p>同样，如果不能在抽象类中定义默认行为，就会导致同样的方法实现出现在该抽象类的每一个派生类中，违反了"one rule，one place"原则，造成代码重复，同样不利于以后的维护。因此，在abstract class和interface间进行选择时要非常的小心。</p>
<p><strong><span class=atitle2>从设计理念层面看abstract class和interface</span> </strong></p>
<p>上面主要从语法定义和编程的角度论述了abstract class和interface的区别，这些层面的区别是比较低层次的、非本质的。本小节将从另一个层面：abstract class和interface所反映出的设计理念，来分析一下二者的区别。作者认为，从这个层面进行分析才能理解二者概念的本质所在。</p>
<div>前面已经提到过，abstarct class在Java语言中体现了一种继承关系，要想使得继承关系合理，父类和派生类之间必须存在"is a"关系，即父类和派生类在概念本质上应该是相同的（参考文献〔3〕中有关于"is a"关系的大篇幅深入的论述，有兴趣的读者可以参考）。对于interface 来说则不然，并不要求interface的实现者和interface定义在概念本质上是一致的，仅仅是实现了interface定义的契约而已。为了使论述便于理解，下面将通过一个简单的实例进行说明。</div>
<div>
<p><strong><span class=atitle2>结论</span> </strong></p>
<p>abstract class和interface是Java语言中的两种定义抽象类的方式，它们之间有很大的相似性。但是对于它们的选择却又往往反映出对于问题领域中的概念本质的理解、对于设计意图的反映是否正确、合理，因为它们表现了概念间的不同的关系（虽然都能够实现需求的功能）。这其实也是语言的一种的惯用法，希望读者朋友能够细细体会</p>
</div>
<img src ="http://www.blogjava.net/wealupa/aggbug/88258.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/wealupa/" target="_blank">常言笑</a> 2006-12-16 22:24 <a href="http://www.blogjava.net/wealupa/archive/2006/12/16/88258.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>使用extreme时的中文乱码问题</title><link>http://www.blogjava.net/wealupa/archive/2006/12/16/88249.html</link><dc:creator>常言笑</dc:creator><author>常言笑</author><pubDate>Sat, 16 Dec 2006 14:15:00 GMT</pubDate><guid>http://www.blogjava.net/wealupa/archive/2006/12/16/88249.html</guid><wfw:comment>http://www.blogjava.net/wealupa/comments/88249.html</wfw:comment><comments>http://www.blogjava.net/wealupa/archive/2006/12/16/88249.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/wealupa/comments/commentRss/88249.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/wealupa/services/trackbacks/88249.html</trackback:ping><description><![CDATA[<div>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 因为使用extreme需要在web.xml文件中配置，如果</div>
<div>&nbsp;&lt;filter&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp; &lt;filter-name&gt;eXtremeExport&lt;/filter-name&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp; &lt;filter-class&gt;org.extremecomponents.table.filter.ExportFilter&lt;/filter-class&gt;<br>&nbsp;&lt;/filter&gt;<br>&nbsp;<br>&nbsp;&lt;filter-mapping&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp; &lt;filter-name&gt;eXtremeExport&lt;/filter-name&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp; &lt;url-pattern&gt;/*&lt;/url-pattern&gt;<br>&nbsp;&lt;/filter-mapping&gt;</div>
<br>
<div>&nbsp;&nbsp;&nbsp; 写在</div>
<div>&lt;filter&gt;<br>&nbsp;&nbsp;&lt;filter-name&gt;encodingFilter&lt;/filter-name&gt;<br>&nbsp;&nbsp;&lt;filter-class&gt;org.springwork.web.filter.CharacterEncodingFilter&lt;/filter-class&gt;<br>&nbsp;&nbsp;&lt;init-param&gt;<br>&nbsp;&nbsp;&nbsp;&lt;param-name&gt;encoding&lt;/param-name&gt;<br>&nbsp;&nbsp;&nbsp;&lt;param-&gt;UTF-8&lt;/param-&gt;<br>&nbsp;&nbsp;&lt;/init-param&gt;<br>&nbsp;&lt;/filter&gt;<br>&nbsp;<br>&nbsp;&lt;filter-mapping&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;filter-name&gt;encodingFilter&lt;/filter-name&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;url-pattern&gt;*.xhtml&lt;/url-pattern&gt;<br>&nbsp;&nbsp;&nbsp; &lt;/filter-mapping&gt;<br>&nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp; &lt;filter-mapping&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;filter-name&gt;encodingFilter&lt;/filter-name&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;url-pattern&gt;*.jsp&lt;/url-pattern&gt;<br>&nbsp;&nbsp;&nbsp; &lt;/filter-mapping&gt;</div>
<br>
<div>上面，则标单Post提交的时候会出现乱码，只有将字符filter写在上面，才有效。</div>
<img src ="http://www.blogjava.net/wealupa/aggbug/88249.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/wealupa/" target="_blank">常言笑</a> 2006-12-16 22:15 <a href="http://www.blogjava.net/wealupa/archive/2006/12/16/88249.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>java.util.Date和java.sql.Date的异同</title><link>http://www.blogjava.net/wealupa/archive/2006/12/16/88247.html</link><dc:creator>常言笑</dc:creator><author>常言笑</author><pubDate>Sat, 16 Dec 2006 14:14:00 GMT</pubDate><guid>http://www.blogjava.net/wealupa/archive/2006/12/16/88247.html</guid><wfw:comment>http://www.blogjava.net/wealupa/comments/88247.html</wfw:comment><comments>http://www.blogjava.net/wealupa/archive/2006/12/16/88247.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/wealupa/comments/commentRss/88247.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/wealupa/services/trackbacks/88247.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; java.sql.Date,java.sql.Time和java.sql.Timestamp三个都是java.util.Date的子类（包装类）。
<div><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 但是为什么java.sql.Date类型的值插入到数据库中Date字段中会发生数据截取呢？</div>
<div><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;java.sql.Date是为了配合SQL DATE而设置的数据类型。&#8220;规范化&#8221;的java.sql.Date只包含年月日信息，时分秒毫秒都会清零。格式类似：YYYY-MM-DD。当我们调用ResultSet的getDate()方法来获得返回值时，java程序会参照"规范"的java.sql.Date来格式化数据库中的数值。因此，如果数据库中存在的非规范化部分的信息将会被劫取。</div>
<br>
<div>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 在sun提供的ResultSet.java中这样对getDate进行注释的：<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="COLOR: #6b8e23">Retrieves the of the designated column in the current row of this &lt;code&gt;ResultSet&lt;/code&gt; object as a &#8220;java.sql.Date&#8221; object in the Java programming language.</span></div>
<span style="COLOR: #6b8e23"></span>
<div><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 同理。如果我们把一个java.sql.Date值通过PrepareStatement的setDate方法存入数据库时，java程序会对传入的java.sql.Date规范化，非规范化的部分将会被劫取。然而，我们java.sql.Date一般由java.util.Date转换过来，如：java.sql.Date sqlDate=new java.sql.Date(new java.util.Date().getTime()).<br>&nbsp;显然，这样转换过来的java.sql.Date往往不是一个规范的java.sql.Date.要保存java.util.Date的精确值，<br>&nbsp;我们需要利用java.sql.Timestamp.<br></div>
<div><strong>Calendar</strong></div>
<div><br>Calendar &nbsp;calendar=Calendar.getInstance(); &nbsp;<br>//获得当前时间，声明时间变量 &nbsp;<br>int &nbsp;year=calendar.get(Calendar.YEAR); &nbsp;<br>//得到年<br>int &nbsp;month=calendar.get(Calendar.MONTH); &nbsp;<br>//得到月，但是，月份要加上1 &nbsp;<br>month=month+1; <br>int &nbsp;date=calendar.get(Calendar.DATE); &nbsp;<br>//获得日期 &nbsp;<br>String &nbsp;today=""+year+"-"+month+"-"+date+"";<br></div>
<img src ="http://www.blogjava.net/wealupa/aggbug/88247.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/wealupa/" target="_blank">常言笑</a> 2006-12-16 22:14 <a href="http://www.blogjava.net/wealupa/archive/2006/12/16/88247.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>