#
在Oracle9i中執行下面的SQL重建exu81rls視圖即可。
CREATE OR REPLACE view exu81rls
(objown,objnam,policy,polown,polsch,polfun,stmts,chkopt,enabled,spolicy)
AS select u.name, o.name, r.pname, r.pfschma, r.ppname, r.pfname,
decode(bitand(r.stmt_type,1), 0,'', 'SELECT,')
|| decode(bitand(r.stmt_type,2), 0,'', 'INSERT,')
|| decode(bitand(r.stmt_type,4), 0,'', 'UPDATE,')
|| decode(bitand(r.stmt_type,8), 0,'', 'DELETE,'),
r.check_opt, r.enable_flag,
DECODE(BITAND(r.stmt_type, 16), 0, 0, 1)
from user$ u, obj$ o, rls$ r
where u.user# = o.owner#
and r.obj# = o.obj#
and (uid = 0 or
uid = o.owner# or
exists ( select * from session_roles where role='SELECT_CATALOG_ROLE')
)
/
grant select on sys.exu81rls to public;
/
-- Change the HTTP/WEBDAV port from 8080 to 8081
SQL> call dbms_xdb.cfg_update(updateXML( dbms_xdb.cfg_get() ,
'/xdbconfig/sysconfig/protocolconfig/httpconfig/http-port/text()'
8081))
/
-- Change the FTP port from 2100 to 2111
SQL> call dbms_xdb.cfg_update(updateXML( dbms_xdb.cfg_get() ,
'/xdbconfig/sysconfig/protocolconfig/ftpconfig/ftp-port/text()' , 2111))
SQL> COMMIT;
SQL> EXEC dbms_xdb.cfg_refresh
@echo off
if '%1=='## goto ENVSET
rem 要啟動的類名
SET CLSNAME=com.main
rem 設定CLSPATH
SET CLSPATH=.
FOR %%c IN (.\lib\*.jar) DO CALL %0 ## %%c
rem 運行
GOTO RUN
:RUN
java -cp %CLSPATH% %CLSNAME%
goto END
:ENVSET
set CLSPATH=%CLSPATH%;%2
goto END
:END
在query的時候加上binary,select * from usertest where username like binary '%夏%'
一、同步問題提出
線程的同步是為了防止多個線程訪問一個數據對象時,對數據造成的破壞。
例如:兩個線程ThreadA、ThreadB都操作同一個對象Foo對象,并修改Foo對象上的數據。
public class Foo {
private int x = 100;
public int getX() {
return x;
}
public int fix(int y) {
x = x - y;
return x;
}
}
public class MyRunnable implements Runnable {
private Foo foo = new Foo();
public static void main(String[] args) {
MyRunnable r = new MyRunnable();
Thread ta = new Thread(r, "Thread-A");
Thread tb = new Thread(r, "Thread-B");
ta.start();
tb.start();
}
public void run() {
for (int i = 0; i < 3; i++) {
this.fix(30);
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + " : 當前foo對象的x值= " + foo.getX());
}
}
public int fix(int y) {
return foo.fix(y);
}
}
運行結果:
Thread-A : 當前foo對象的x值= 40
Thread-B : 當前foo對象的x值= 40
Thread-B : 當前foo對象的x值= -20
Thread-A : 當前foo對象的x值= -50
Thread-A : 當前foo對象的x值= -80
Thread-B : 當前foo對象的x值= -80
Process finished with exit code 0
從結果發現,這樣的輸出值明顯是不合理的。原因是兩個線程不加控制的訪問Foo對象并修改其數據所致。
如果要保持結果的合理性,只需要達到一個目的,就是將對Foo的訪問加以限制,每次只能有一個線程在訪問。這樣就能保證Foo對象中數據的合理性了。
在具體的Java代碼中需要完成一下兩個操作:
把競爭訪問的資源類Foo變量x標識為private;
同步哪些修改變量的代碼,使用synchronized關鍵字同步方法或代碼。
二、同步和鎖定
1、鎖的原理
Java中每個對象都有一個內置鎖
當程序運行到非靜態的synchronized同步方法上時,自動獲得與正在執行代碼類的當前實例(this實例)有關的鎖。獲得一個對象的鎖也稱為獲取鎖、鎖定對象、在對象上鎖定或在對象上同步。
當程序運行到synchronized同步方法或代碼塊時才該對象鎖才起作用。
一個對象只有一個鎖。所以,如果一個線程獲得該鎖,就沒有其他線程可以獲得鎖,直到第一個線程釋放(或返回)鎖。這也意味著任何其他線程都不能進入該對象上的synchronized方法或代碼塊,直到該鎖被釋放。
釋放鎖是指持鎖線程退出了synchronized同步方法或代碼塊。
關于鎖和同步,有一下幾個要點:
1)、只能同步方法,而不能同步變量和類;
2)、每個對象只有一個鎖;當提到同步時,應該清楚在什么上同步?也就是說,在哪個對象上同步?
3)、不必同步類中所有的方法,類可以同時擁有同步和非同步方法。
4)、如果兩個線程要執行一個類中的synchronized方法,并且兩個線程使用相同的實例來調用方法,那么一次只能有一個線程能夠執行方法,另一個需要等待,直到鎖被釋放。也就是說:如果一個線程在對象上獲得一個鎖,就沒有任何其他線程可以進入(該對象的)類中的任何一個同步方法。
5)、如果線程擁有同步和非同步方法,則非同步方法可以被多個線程自由訪問而不受鎖的限制。
6)、線程睡眠時,它所持的任何鎖都不會釋放。
7)、線程可以獲得多個鎖。比如,在一個對象的同步方法里面調用另外一個對象的同步方法,則獲取了兩個對象的同步鎖。
8)、同步損害并發性,應該盡可能縮小同步范圍。同步不但可以同步整個方法,還可以同步方法中一部分代碼塊。
9)、在使用同步代碼塊時候,應該指定在哪個對象上同步,也就是說要獲取哪個對象的鎖。例如:
public int fix(int y) {
synchronized (this) {
x = x - y;
}
return x;
}
當然,同步方法也可以改寫為非同步方法,但功能完全一樣的,例如:
public synchronized int getX() {
return x++;
}
與
public int getX() {
synchronized (this) {
return x;
}
}
效果是完全一樣的。
三、靜態方法同步
要同步靜態方法,需要一個用于整個類對象的鎖,這個對象是就是這個類(XXX.class)。
例如:
public static synchronized int setName(String name){
Xxx.name = name;
}
等價于
public static int setName(String name){
synchronized(Xxx.class){
Xxx.name = name;
}
}
四、如果線程不能不能獲得鎖會怎么樣
如果線程試圖進入同步方法,而其鎖已經被占用,則線程在該對象上被阻塞。實質上,線程進入該對象的的一種池中,必須在哪里等待,直到其鎖被釋放,該線程再次變為可運行或運行為止。
當考慮阻塞時,一定要注意哪個對象正被用于鎖定:
1、調用同一個對象中非靜態同步方法的線程將彼此阻塞。如果是不同對象,則每個線程有自己的對象的鎖,線程間彼此互不干預。
2、調用同一個類中的靜態同步方法的線程將彼此阻塞,它們都是鎖定在相同的Class對象上。
3、靜態同步方法和非靜態同步方法將永遠不會彼此阻塞,因為靜態方法鎖定在Class對象上,非靜態方法鎖定在該類的對象上。
4、對于同步代碼塊,要看清楚什么對象已經用于鎖定(synchronized后面括號的內容)。在同一個對象上進行同步的線程將彼此阻塞,在不同對象上鎖定的線程將永遠不會彼此阻塞。
五、何時需要同步
在多個線程同時訪問互斥(可交換)數據時,應該同步以保護數據,確保兩個線程不會同時修改更改它。
對于非靜態字段中可更改的數據,通常使用非靜態方法訪問。
對于靜態字段中可更改的數據,通常使用靜態方法訪問。
如果需要在非靜態方法中使用靜態字段,或者在靜態字段中調用非靜態方法,問題將變得非常復雜。已經超出SJCP考試范圍了。
六、線程安全類
當一個類已經很好的同步以保護它的數據時,這個類就稱為“線程安全的”。
即使是線程安全類,也應該特別小心,因為操作的線程是間仍然不一定安全。
舉個形象的例子,比如一個集合是線程安全的,有兩個線程在操作同一個集合對象,當第一個線程查詢集合非空后,刪除集合中所有元素的時候。第二個線程也來執行與第一個線程相同的操作,也許在第一個線程查詢后,第二個線程也查詢出集合非空,但是當第一個執行清除后,第二個再執行刪除顯然是不對的,因為此時集合已經為空了。
看個代碼:
public class NameList {
private List nameList = Collections.synchronizedList(new LinkedList());
public void add(String name) {
nameList.add(name);
}
public String removeFirst() {
if (nameList.size() > 0) {
return (String) nameList.remove(0);
} else {
return null;
}
}
}
public class Test {
public static void main(String[] args) {
final NameList nl = new NameList();
nl.add("aaa");
class NameDropper extends Thread{
public void run(){
String name = nl.removeFirst();
System.out.println(name);
}
}
Thread t1 = new NameDropper();
Thread t2 = new NameDropper();
t1.start();
t2.start();
}
}
雖然集合對象
private List nameList = Collections.synchronizedList(new LinkedList());
是同步的,但是程序還不是線程安全的。
出現這種事件的原因是,上例中一個線程操作列表過程中無法阻止另外一個線程對列表的其他操作。
解決上面問題的辦法是,在操作集合對象的NameList上面做一個同步。改寫后的代碼如下:
public class NameList {
private List nameList = Collections.synchronizedList(new LinkedList());
public synchronized void add(String name) {
nameList.add(name);
}
public synchronized String removeFirst() {
if (nameList.size() > 0) {
return (String) nameList.remove(0);
} else {
return null;
}
}
}
這樣,當一個線程訪問其中一個同步方法時,其他線程只有等待。
七、線程死鎖
死鎖對Java程序來說,是很復雜的,也很難發現問題。當兩個線程被阻塞,每個線程在等待另一個線程時就發生死鎖。
還是看一個比較直觀的死鎖例子:
public class DeadlockRisk {
private static class Resource {
public int value;
}
private Resource resourceA = new Resource();
private Resource resourceB = new Resource();
public int read() {
synchronized (resourceA) {
synchronized (resourceB) {
return resourceB.value + resourceA.value;
}
}
}
public void write(int a, int b) {
synchronized (resourceB) {
synchronized (resourceA) {
resourceA.value = a;
resourceB.value = b;
}
}
}
}
假設read()方法由一個線程啟動,write()方法由另外一個線程啟動。讀線程將擁有resourceA鎖,寫線程將擁有resourceB鎖,兩者都堅持等待的話就出現死鎖。
實際上,上面這個例子發生死鎖的概率很小。因為在代碼內的某個點,CPU必須從讀線程切換到寫線程,所以,死鎖基本上不能發生。
但是,無論代碼中發生死鎖的概率有多小,一旦發生死鎖,程序就死掉。有一些設計方法能幫助避免死鎖,包括始終按照預定義的順序獲取鎖這一策略。已經超出SCJP的考試范圍。
八、線程同步小結
1、線程同步的目的是為了保護多個線程反問一個資源時對資源的破壞。
2、線程同步方法是通過鎖來實現,每個對象都有切僅有一個鎖,這個鎖與一個特定的對象關聯,線程一旦獲取了對象鎖,其他訪問該對象的線程就無法再訪問該對象的其他非同步方法。
3、對于靜態同步方法,鎖是針對這個類的,鎖對象是該類的Class對象。靜態和非靜態方法的鎖互不干預。一個線程獲得鎖,當在一個同步方法中訪問另外對象上的同步方法時,會獲取這兩個對象鎖。
4、對于同步,要時刻清醒在哪個對象上同步,這是關鍵。
5、編寫線程安全的類,需要時刻注意對多個線程競爭訪問資源的邏輯和安全做出正確的判斷,對“原子”操作做出分析,并保證原子操作期間別的線程無法訪問競爭資源。
6、當多個線程等待一個對象鎖時,沒有獲取到鎖的線程將發生阻塞。
7、死鎖是線程間相互等待鎖鎖造成的,在實際中發生的概率非常的小。真讓你寫個死鎖程序,不一定好使,呵呵。但是,一旦程序發生死鎖,程序將死掉。
測試通過的版本如下:
Eclipse:3.3.2
jdk:1.6
junit:3.8
ant:1.7(1.7之前的版本好像還不提供mail功能。。。)
<!-- JUnit build script using ant 1.7 -->
<project name="JunitTestProject" default="mail" basedir=".">
<property name="app.name" value="JunitTestProject" />
<property name="build.dir" value="bin" />
<!-- ====================" path define " ================================ -->
<path id="cobertura.classpath">
<fileset dir="lib/coberture">
<include name="cobertura.jar" />
<include name="*.jar" />
</fileset>
</path>
<!-- ====================" cobertura task define " Target ================================ -->
<taskdef classpathref="cobertura.classpath" resource="tasks.properties" />
<!-- ==================== "clean " Target ================================ -->
<target name="clean">
<available property="junit.present" classname="junit.framework.TestCase" />
<delete dir="${build.dir}" quiet="true" />
<delete file="report" quiet="true" />
</target>
<!-- ==================== "copy xml resource " Target ================================ -->
<target name="copyxml" depends="clean">
<copy todir="${build.dir}/testcases">
<fileset dir="WEB-INF" />
</copy>
</target>
<!-- ==================== "compile src" Target ================================ -->
<target name="compile" depends="copyxml">
<mkdir dir="${build.dir}" />
<javac srcdir="src" destdir="${build.dir}" debug="yes">
<classpath>
<fileset dir="lib" casesensitive="yes">
<include name="**/*.jar" />
</fileset>
</classpath>
<include name="**/*.java" />
</javac>
<javac srcdir="WEB-INF" destdir="${build.dir}">
<classpath>
<fileset dir="lib" casesensitive="yes">
<include name="**/*.jar" />
</fileset>
</classpath>
<include name="*.jsp" />
</javac>
</target>
<!-- ==================== jar" Target ================================ -->
<target name="jar" depends="compile">
<mkdir dir="dist/lib" />
<jar jarfile="dist/lib/${app.name}.jar" basedir="${build.dir}" includes="com/**" />
</target>
<!-- ==================== compile test src" Target ================================ -->
<target name="compiletests" depends="jar">
<mkdir dir="${build.dir}/testcases" />
<javac srcdir="test" destdir="${build.dir}/testcases" >
<classpath>
<fileset dir="lib" casesensitive="yes">
<include name="**/*.jar" />
</fileset>
<fileset dir="dist/lib" casesensitive="yes">
<include name="**/*.jar" />
</fileset>
</classpath>
<include name="**/*.java" />
</javac>
</target>
<!-- ==================== instrumented" Target ================================ -->
<target name="instrumented" depends="compiletests">
<cobertura-instrument todir="bin/instrumented-classes">
<ignore regex="org.apache.log4j.*" />
<fileset dir="bin">
<include name="com/**/*.class" />
</fileset>
</cobertura-instrument>
</target>
<!-- ==================== junit-test" Target ================================ -->
<target name="runtests" depends="instrumented">
<mkdir dir="report" />
<property name="tests" value="*Test" />
<junit printsummary="yes" haltonerror="yes" haltonfailure="yes" fork="yes">
<formatter type="plain" usefile="false" />
<formatter type="xml" />
<batchtest todir="report">
<fileset dir="test">
<include name="**/${tests}.java" />
<exclude name="**/ConfigTest.java" />
</fileset>
</batchtest>
<!--
Note the classpath order: instrumented classes are before the
original (uninstrumented) classes. This is important.
-->
<classpath location="bin/instrumented-classes" />
<!--
src classpath
-->
<classpath location="bin" />
<!--
The instrumented classes reference classes used by the
Cobertura runtime, so Cobertura and its dependencies
must be on your classpath.
-->
<classpath refid="cobertura.classpath" />
<!--
test case class path define
-->
<classpath>
<fileset dir="lib" casesensitive="yes">
<include name="**/*.jar" />
</fileset>
<pathelement location="bin/testcases" />
</classpath>
</junit>
</target>
<!-- ==================== junit-report" Target ================================ -->
<target name="report" depends="runtests">
<mkdir dir="report/html" />
<junitreport todir="report">
<fileset dir="report">
<include name="TEST-*.xml" />
</fileset>
<report todir="report/html" />
</junitreport>
</target>
<!-- ==================== "coverage-report" Target ================================ -->
<target name="coverage-report" depends="report">
<cobertura-report format="html" destdir="cobertura" >
<fileset dir="src">
<include name="**/*.java" />
</fileset>
</cobertura-report>
<echo>The execution of coverage-report is complete. Coverage Reports are available in /${coverage-report}</echo>
</target>
<!-- ==================== "make file to zip" Target ================================ -->
<target name="make_data_zip" depends="coverage-report">
<tstamp>
<format property="date" pattern="yyyy-MM-dd HH-mm" />
</tstamp>
<jar jarfile="dist/lib/cobertura${date}.zip" basedir="cobertura" />
<jar jarfile="dist/lib/report${date}.zip" basedir="report" excludes="*.xml"/>
</target>
<!-- ==================== "mail" Target ================================ -->
<target name="mail" depends="make_data_zip">
<!-- <taskdef name="mail" classname="org.apache.tools.ant.taskdefs.optional.mail.MimeMail"/> -->
<tstamp/>
<mail messageMimeType="text/html"
messageFile="message.txt"
tolist="bpcjy@hotmail.com"
mailhost="mailsvr or mail IPAddress"
subject="JUnit Test Results: ${TODAY}"
from="bpcjy@hotmail.com">
<fileset dir=".">
<include name="dist/lib/*.zip"/>
</fileset>
</mail>
</target>
</project>
struts2.0:(6)
lib/antlr-2.7.6.jar
lib/struts2-core-2.0.14.jar
lib/struts2-spring-plugin-2.0.14.jar
lib/freemarker-2.3.8.jar
lib/ognl-2.6.11.jar
lib/xwork-2.0.7.jar
(注意單用時必須還要用lib/commons-logging-1.0.4.jar)
spring2.5:(10)
dist/modules/spring-aop.jar
dist/modules/spring-beans.jar
dist/modules/spring-context.jar
dist/modules/spring-context-support.jar
dist/modules/spring-core.jar
dist/modules/spring-jdbc.jar
dist/modules/spring-orm.jar
dist/modules/spring-tx.jar
dist/modules/spring-web.jar
dist/modules/spring-webmvc-struts.jar
hibernate3.2:(10)
hibernate3.jar
lib/asm.jar
lib/asm-attrs.jar
lib/cglib-2.1.3.jar
lib/commons-collections-2.1.1.jar
lib/commons-logging-1.0.4.jar
lib/dom4j-1.6.1.jar
lib/ehcache-1.2.3.jar
lib/jta.jar
lib/xml-apis.jar
其它jar:(6)
servlet.jar
sqljdbc.jar
jsonplugin-0.30.jar(jsonplugin-0.30于6月6號發布,修復了一直很頭疼的cglib序列化問題)
serializer.jar
xalan.jar
(Xalan是將可擴展標記語言(XML)轉換為超文本鏈接標識語言(HTML)或其它類型XML文檔的規范,添加操作XML的jar,一般要添加xalan.jar、serializer.jar這兩個包,如有特殊需求可將下載的所有jar全部添加
(下載地址:http://apache.seekmeup.com/xml/xalan-j里面的一個xalan-j_2_7_0-bin.zip))
xercesImpl.jar
( 實現解析XML文件的功能很方便,我們可以通過下載第三方的一些工具包如xml-apis.jar和xercesImpl.jar 等.Xerces是一個與可擴展標記語言(XML)兼容的語法分析器。Xerces分析器可處理Java和C++,它采用互聯網聯盟XML、文件對象...Xerces-C是用可移植的C++子集編寫的XML分析器。Xerces-C允許對XML數據進行讀寫操作)
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title> ĵ</title>
<style>
body {
margin: 7px;
font:12px Verdana, Arial, Helvetica, sans-serif;
}
* {
list-style-type: none;
margin: 0px;
padding: 0px;
border: thin none;
}
#nav {
position: absolute;
font-size: 9px;
opacity: 0.8;
}
#nav a {
display: block;
width: 100px;
height: 15px;
padding: 3px 5px 12px;
background: #666;
color: #fff;
text-decoration: none;
}
#nav a:hover {
background: #333;
}
#nav li {
width: 120px;
height:30px;
overflow:hidden;
background: #ccc;
padding-bottom: 3px;
}
#nav ul {
position: absolute;
margin-left: 110px;
margin-top: -30px;
}
html>body #nav ul {
margin-left: 119px;
margin-top: -39px;
}
#nav ul {
display: none;
}
#nav li.show ul {
display: block;
}
#nav li.show li ul {
display: none;
}
#nav li li.show ul {
display: block;
}
</style>
<script language="javascript" type="text/javascript">
function menuFix() {
var sfEls = document.getElementById("nav").getElementsByTagName("li");
for (var i=0; i<sfEls.length; i++) {
sfEls[i].onmouseover=function() {
this.className+=(this.className.length>0? " ": "") + "show";
}
sfEls[i].onmouseout=function() {
this.className=this.className.replace(new RegExp("( ?|^)show\\b"), "");
}
}
}
window.onload=menuFix;
</script>
</head>
<body>
<ul id="nav">
<li><a href="#">nav item</a>.
<ul>
<li><a href="#">nav item</a>.
<ul>
<li><a href="#">nav item</a>.</li>
<li><a href="#">nav item</a>.</li>
</ul>
</li>
<li><a href="#">nav item</a>.
<ul>
<li><a href="#">nav item</a></li>
<li><a href="#">nav item</a></li>
<li><a href="#">nav item</a></li>
<li><a href="#">nav item</a></li>
<li><a href="#">nav item</a></li>
<li><a href="#">nav item</a></li>
<li><a href="#">nav item</a></li>
<li><a href="#">nav item</a></li>
<li><a href="#">nav item</a></li>
<li><a href="#">nav item</a></li>
</ul>
</li>
<li><a href="#">nav item</a>.
<ul>
<li><a href="#">nav item</a></li>
<li><a href="#">nav item</a></li>
<li><a href="#">nav item</a></li>
<li><a href="#">nav item</a></li>
<li><a href="#">nav item</a></li>
<li><a href="#">nav item</a></li>
<li><a href="#">nav item</a></li>
<li><a href="#">nav item</a></li>
<li><a href="#">nav item</a></li>
<li><a href="#">nav item</a></li>
<li><a href="#">nav item</a></li>
<li><a href="#">nav item</a></li>
</ul>
</li>
<li><a href="#">nav item</a>.
<ul>
<li><a href="#">nav item</a></li>
<li><a href="#">nav item</a></li>
<li><a href="#">nav item</a></li>
<li><a href="#">nav item</a></li>
<li><a href="#">nav item</a></li>
<li><a href="#">nav item</a></li>
</ul>
</li>
</ul>
</li>
<li><a href="#">nav item</a>.
<ul>
<li><a href="#">nav item</a></li>
<li><a href="#">nav item</a></li>
<li><a href="#">nav item</a></li>
<li><a href="#">nav item</a></li>
<li><a href="#">nav item</a></li>
<li><a href="#">nav item</a></li>
</ul>
</li>
<li><a href="#">nav item</a>.
<ul>
<li><a href="#">nav item</a></li>
<li><a href="#">nav item</a></li>
<li><a href="#">nav item</a></li>
<li><a href="#">nav item</a></li>
<li><a href="#">nav item</a></li>
<li><a href="#">nav item</a></li>
</ul>
</li>
</ul>
</body>
</html>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<!-- saved from url=(0049)http://vip.5d.cn/flood/myjs/htm/menu/coolmenu.htm -->
<HTML><HEAD><TITLE>下滑菜單</TITLE>
<META http-equiv=Content-Type content="text/html; charset=gb2312">
<META content="MSHTML 6.00.2900.2802" name=GENERATOR>
<META content=FrontPage.Editor.Document name=ProgId>
<STYLE type=text/css>.menubar {
BORDER-RIGHT: 1px outset; BORDER-TOP: 1px outset; BACKGROUND: #0099cc; BORDER-LEFT: 1px outset; WIDTH: 100px; CURSOR: default; COLOR: yellow; BORDER-BOTTOM: 1px outset; POSITION: absolute; TOP: 10px; HEIGHT: 20px
}
.menu {
BORDER-RIGHT: 2px outset; PADDING-RIGHT: 15px; BORDER-TOP: white 2px outset; DISPLAY: none; PADDING-LEFT: 15px; BACKGROUND: yellow; PADDING-BOTTOM: 15px; BORDER-LEFT: 2px outset; WIDTH: 140px; PADDING-TOP: 15px; BORDER-BOTTOM: 2px outset; POSITION: absolute; TOP: 30px
}
.menu A {
COLOR: blue; TEXT-DECORATION: none
}
.menu A:hover {
COLOR: #00ffff
}
</STYLE>
<SCRIPT language=javascript>
function menuControl(show)
{
window.event.cancelBubble=true;
var objID=event.srcElement.id;
var index=objID.indexOf("_");
var mainID=objID.substring(0,index);
var numID=objID.substring(index+1,objID.length);
if(mainID=="menubar")
{
if(show==1)
{
eval("showMenu("+"menu_"+numID+")");
}
else
{
eval("hideMenu("+"menu_"+numID+")");
}
}
}
var nbottom=0,speed=1;
function displayMenu(obj)
{
obj.style.clip="rect(0 100% "+nbottom+"% 0)";
nbottom+=speed;
if(nbottom<=100)
{
timerID=setTimeout("displayMenu("+obj.id+"),70");
}
else clearTimeout(timerID);
}
function showMenu(obj)
{
obj.style.display="block";
obj.style.clip="rect(0 0 0 0)";
nbottom=5;
displayMenu(obj);
}
function hideMenu(obj)
{
nbottom=0;
obj.style.display="none";
}
function keepMenu(obj)
{
obj.style.display="block";
}
</SCRIPT>
</HEAD>
<BODY>
<TABLE style="FONT-SIZE: 15px" cellSpacing=0 cellPadding=0 width=400 border=0>
<TBODY>
<TR>
<TD width="20%">
<DIV class=menubar id=menubar_1 onmouseover=menuControl(1)
onmouseout=menuControl(0) align=center>教育網站 </DIV></TD>
<TD width="20%">
<DIV class=menubar id=menubar_2 onmouseover=menuControl(1)
onmouseout=menuControl(0) align=center>電腦網站 </DIV></TD>
<TD width="20%">
<DIV class=menubar id=menubar_3 onmouseover=menuControl(1)
onmouseout=menuControl(0) align=center>免費郵件 </DIV></TD>
<TD width="20%">
<DIV class=menubar id=menubar_4 onmouseover=menuControl(1)
onmouseout=menuControl(0) align=center>其它網站 </DIV></TD></TR>
<TR>
<TD width="20%">
<DIV class=menu id=menu_1 onmouseover=keepMenu(this)
onmouseout=hideMenu(this) align=left><A
>重慶民政學校</A><BR><A
>重慶大學</A><BR><A
>重慶交通學院</A> </DIV></TD>
<TD width="20%">
<DIV class=menu id=menu_2 onmouseover=keepMenu(this)
onmouseout=hideMenu(this) align=left><A
>天極網</A><BR><A
>電腦愛好者</A><BR><A
>上網雜志</A> </DIV></TD>
<TD width="20%">
<DIV class=menu id=menu_3 onmouseover=keepMenu(this)
onmouseout=hideMenu(this) align=left><A
>163電子郵件</A><BR><A
>首都在線</A><BR><A
>21CN電子郵件</A><BR><A
>炎皇在線</A> </DIV></TD>
<TD width="20%">
<DIV class=menu id=menu_4 onmouseover=keepMenu(this)
onmouseout=hideMenu(this) align=left><A
>搜狐</A><BR><A
>雅虎</A><BR><A
>搜索客</A><BR><A
>新浪網</A><BR><A
>遠航網站</A>
</DIV></TD></TR></TBODY></TABLE></SCRIPT></BODY></HTML>