摘要: Why is RUNSTATS important?
Almost every major database today uses some method of updating catalog statistics to provide the best information possi...
閱讀全文
posted @
2006-06-23 15:40 MyJavaWorld 閱讀(454) |
評論 (0) |
編輯 收藏
|
When you update table statistics using the RUNSTATS command, it requires that you run the command against each table, one by one. REORGCHK gives you the capability to update the statistics of a group of tables or all the tables in the database, with only one command. |
.
|
_
|
DB2 UDB uses the statistics information in the catalog table to derive the best access plan. The DBA should regularly run the RUNSTATS command to keep the database statistics updated. This procedure will ensure the best performance on queries.
If you want to update statistics on all the tables or a group of tables in the database, you can use the REORGCHK command with the UPDATE STATISTICS option. This would be run instead of running the RUNSTATS command against each table. The UPDATE STATISTICS option will first call the RUNSTATS routine to update the table statistic. You can then use these new statistics to determine if a reorg is needed.
The REORGCHK command allows you to update statistics on a group of tables with one command.
To update all the user and system tables use:
REORGCHK UPDATE STATISTICS ON TABLE ALL
To update all the tables of a particular schema use:
REORGCHK UPDATE STATISTICS on SCHEMA schema_name
To update all the tables of a particular table system use:
REORGCHK UPDATE STATISTICS on TABLE SYSTEM
|
|
|
|
posted @
2006-06-23 15:19 MyJavaWorld 閱讀(476) |
評論 (0) |
編輯 收藏
<html:radio idName=" idName "? value="value"? name=" name" property=" property " /> 表示在輸出時,html:radio輸出為input type="radio";name輸出為name="name";對 于value的輸出,當不指定idName時,value="value",當指定idName時,輸出是由bean 名為" idName ",屬性名為"value"的屬性值;當bean名為" name ",屬性名為" property "的屬性值等于上述value的輸出值時,輸出checked="checked"。 我的例子: <logic:iterate id = "answer" name = "answerList" scope = "page"> <html:radio idName = "answer" value = "answerItem" name = "question" property = "rightAnswer" ></html:radio> </logic:iterate> 如果從bean answer的answerItem屬性中取出的值等于從bean question的rightAnswer 屬性中取出的值相等,那么該radio將被選中
|
|
posted @
2006-06-21 16:54 MyJavaWorld 閱讀(1423) |
評論 (0) |
編輯 收藏
1. 一個表如果建有大量索引會影響 INSERT、UPDATE 和 DELETE 語句的性能,因為在表中的數據更改時,所有索引都須進行適當的調整。另一方面,對于不需要修改數據的查詢(SELECT 語句),大量索引有助于提高性能,因為數據庫有更多的索引可供選擇,以便確定以最快速度訪問數據的最佳方法。
2. 組合索引:組合索引即多列索引,指一個索引含有多個列。一個組合索引相當于多個單列索引,如索引(ColA, ColB, ColC)至少相當于(ColA)、(ColA, ColB)、(ColA, ColB, ColC)三個索引。
2. 覆蓋的查詢可以提高性能。覆蓋的查詢是指查詢中所有指定的列都包含在同一個索引(組合索引)中。例如,如果在一個表的 a、b 和 c 列上創建了組合索引,則從該表中檢索 a 和 b 列的查詢被視為覆蓋的查詢。創建覆蓋一個查詢的索引可以提高性能,因為該查詢的所有數據都包含在索引自身當中;檢索數據時只需引用表的索引頁,不必引用數據頁,因而減少了 I/O 總量。盡管給索引添加列以覆蓋查詢可以提高性能,但在索引中額外維護更多的列會產生更新和存儲成本。
3. 對小型表進行索引可能不會產生優化效果,因為數據庫在遍歷索引以搜索數據時,花費的時間可能會比簡單的表掃描還長。
4. 應使用 SQL 事件探查器和索引優化向導幫助分析查詢,確定要創建的索引。為數據庫及其工作負荷選擇正確的索引是非常復雜的,需要在查詢速度和更新成本之間取得平衡。窄索引(搜索關鍵字中只有很少的列的索引)需要的磁盤空間和維護開銷都更少。而另一方面,寬索引可以覆蓋更多的查詢。確定正確的索引集沒有簡便的規則。經驗豐富的數據庫管理員常常能夠設計出很好的索引集,但是,即使對于不特別復雜的數據庫和工作負荷來說,這項任務也十分復雜、費時和易于出錯。可以使用索引優化向導使這項任務自動化。有關更多信息,請參見索引優化向導。
5. 可以在視圖上指定索引。
6. 可以在計算列上指定索引。
7. 避免在索引列上使用IS NULL和IS NOT NULL。避免在索引中使用任何可以為空的列,數據庫將無法使用該索引。對于單列索引,如果列包含空值,索引中將不存在此記錄;對于復合索引,如果每個列都為空,索引中同樣不存在此記錄. 如果至少有一個列不為空,則記錄存在于索引中。
8. 如果經常檢索包含大量數據的表中的少于15%的行則需要創建索引。
9. 衡量索引效率的 95/5 規則:如果查詢的結果返回的行數少于表中所有行的5%,則索引是檢索數據的最快方法,如果查詢的結果超過5%,那么通常使用索引就不是最快的方式。
10.主關鍵字和唯一關鍵字所在的列自動具有索引,但外部關鍵字沒有自動索引。
二、索引的特征 ??? 在確定某一索引適合某一查詢之后,可以自定義最適合具體情況的索引類型。索引特征包括:
●聚集還是非聚集 ●唯一還是不唯一 ●單列還是多列 ●索引中的列順序為升序還是降序(索引缺省為升序,但目前多數大型數據庫已經能夠支持反向索引) ●覆蓋還是非覆蓋 ●還可以自定義索引的初始存儲特征,通過設置填充因子優化其維護,并使用文件和文件組自定義其位置以優化性能。 ●位映射索引(bitmap)
|
|
posted @
2006-06-21 16:50 MyJavaWorld 閱讀(2281) |
評論 (0) |
編輯 收藏
基礎
要使用 sql 獲得當前的日期、時間及時間戳記,請參考適當的 db2 寄存器:
select current date from sysibm.sysdummy1
select current time from sysibm.sysdummy1
select current timestamp from sysibm.sysdummy1
|
sysibm.sysdummy1表是一個特殊的內存中的表,用它可以發現如上面演示的 db2 寄存器的值。您也可以使用關鍵字 values 來對寄存器或表達式求值。例如,在 db2 命令行處理器(command line processor,clp)上,以下 sql 語句揭示了類似信息:
values current date
values current time
values current timestamp
|
在余下的示例中,我將只提供函數或表達式,而不再重復 select ... from sysibm.sysdummy1 或使用 values 子句。
要使當前時間或當前時間戳記調整到 gmt/cut,則把當前的時間或時間戳記減去當前時區寄存器:
current time - current timezone
current timestamp - current timezone
|
給定了日期、時間或時間戳記,則使用適當的函數可以單獨抽取出(如果適用的話)年、月、日、時、分、秒及微秒各部分:
year (current timestamp)
month (current timestamp)
day (current timestamp)
hour (current timestamp)
minute (current timestamp)
second (current timestamp)
microsecond (current timestamp)
|
從時間戳記單獨抽取出日期和時間也非常簡單:
date (current timestamp)
time (current timestamp)
|
因為沒有更好的術語,所以您還可以使用英語來執行日期和時間計算:
current date + 1 year
current date + 3 years + 2 months + 15 days
current time + 5 hours - 3 minutes + 10 seconds
|
要計算兩個日期之間的天數,您可以對日期作減法,如下所示:
days (current date) - days (date(''1999-10-22''))
|
而以下示例描述了如何獲得微秒部分歸零的當前時間戳記:
current timestamp - microsecond (current timestamp) microseconds
|
如果想將日期或時間值與其它文本相銜接,那么需要先將該值轉換成字符串。為此,只要使用 char() 函數:
char(current date)
char(current time)
char(current date + 12 hours)
|
要將字符串轉換成日期或時間值,可以使用:
timestamp (''2002-10-20-12.00.00.000000'')
timestamp (''2002-10-20 12:00:00'')
date (''2002-10-20'')
date (''10/20/2002'')
time (''12:00:00'')
time (''12.00.00'')
|
timestamp()、date() 和 time() 函數接受更多種格式。上面幾種格式只是示例,我將把它作為一個練習,讓讀者自己去發現其它格式。
警告:
摘自 db2 udb v8.1 sql cookbook,作者 graeme birchall(see http://ourworld.compuserve.com/homepages/graeme_birchall).
如果你在日期函數中偶然地遺漏了引號,那將如何呢?結論是函數會工作,但結果會出錯:
select date(2001-09-22) from sysibm.sysdummy1;
|
結果:
為什么會產生將近 2000 年的差距呢?當 date 函數得到了一個字符串作為輸入參數的時候,它會假定這是一個有效的 db2 日期的表示,并對其進行適當地轉換。相反,當輸入參數是數字類型時,函數會假定該參數值減 1 等于距離公元第一天(0001-01-01)的天數。在上面的例子中,我們的輸入是 2001-09-22,被理解為 (2001-9)-22, 等于 1970 天,于是該函數被理解為 date(1970)。
|
日期函數
有時,您需要知道兩個時間戳記之間的時差。為此,db2 提供了一個名為 timestampdiff() 的內置函數。但該函數返回的是近似值,因為它不考慮閏年,而且假設每個月只有 30 天。以下示例描述了如何得到兩個日期的近似時差:
timestampdiff (<n>, char(
timestamp(''2002-11-30-00.00.00'')-
timestamp(''2002-11-08-00.00.00'')))
|
對于 <n>,可以使用以下各值來替代,以指出結果的時間單位:
- 1 = 秒的小數部分
- 2 = 秒
- 4 = 分
- 8 = 時
- 16 = 天
- 32 = 周
- 64 = 月
- 128 = 季度
- 256 = 年
當日期很接近時使用 timestampdiff() 比日期相差很大時精確。如果需要進行更精確的計算,可以使用以下方法來確定時差(按秒計):
(days(t1) - days(t2)) * 86400 +
(midnight_seconds(t1) - midnight_seconds(t2))
|
為方便起見,還可以對上面的方法創建 sql 用戶定義的函數:
create function secondsdiff(t1 timestamp, t2 timestamp)
returns int
return (
(days(t1) - days(t2)) * 86400 +
(midnight_seconds(t1) - midnight_seconds(t2))
)
@
|
如果需要確定給定年份是否是閏年,以下是一個很有用的 sql 函數,您可以創建它來確定給定年份的天數:
create function daysinyear(yr int)
returns int
return (case (mod(yr, 400)) when 0 then 366 else
case (mod(yr, 4)) when 0 then
case (mod(yr, 100)) when 0 then 365 else 366 end
else 365 end
end)@
|
最后,以下是一張用于日期操作的內置函數表。它旨在幫助您快速確定可能滿足您要求的函數,但未提供完整的參考。有關這些函數的更多信息,請參考 sql 參考大全。
sql 日期和時間函數 |
dayname |
返回一個大小寫混合的字符串,對于參數的日部分,用星期表示這一天的名稱(例如,friday)。 |
dayofweek |
返回參數中的星期幾,用范圍在 1-7 的整數值表示,其中 1 代表星期日。 |
dayofweek_iso |
返回參數中的星期幾,用范圍在 1-7 的整數值表示,其中 1 代表星期一。 |
dayofyear |
返回參數中一年中的第幾天,用范圍在 1-366 的整數值表示。 |
days |
返回日期的整數表示。 |
julian_day |
返回從公元前 4712 年 1 月 1 日(儒略日歷的開始日期)到參數中指定日期值之間的天數,用整數值表示。 |
midnight_seconds |
返回午夜和參數中指定的時間值之間的秒數,用范圍在 0 到 86400 之間的整數值表示。 |
monthname |
對于參數的月部分的月份,返回一個大小寫混合的字符串(例如,january)。 |
timestamp_iso |
根據日期、時間或時間戳記參數而返回一個時間戳記值。 |
timestamp_format |
從已使用字符模板解釋的字符串返回時間戳記。 |
timestampdiff |
根據兩個時間戳記之間的時差,返回由第一個參數定義的類型表示的估計時差。 |
to_char |
返回已用字符模板進行格式化的時間戳記的字符表示。to_char 是 varchar_format 的同義詞。 |
to_date |
從已使用字符模板解釋過的字符串返回時間戳記。to_date 是 timestamp_format 的同義詞。 |
week |
返回參數中一年的第幾周,用范圍在 1-54 的整數值表示。以星期日作為一周的開始。 |
week_iso |
返回參數中一年的第幾周,用范圍在 1-53 的整數值表示。 |
改變日期格式
在日期的表示方面,這也是我經常碰到的一個問題。用于日期的缺省格式由數據庫的地區代碼決定,該代碼在數據庫創建的時候被指定。例如,我在創建數據庫時使用 territory=us 來定義地區代碼,則日期的格式就會像下面的樣子:
values current date
1
----------
05/30/2003
1 record(s) selected.
|
也就是說,日期的格式是 mm/dd/yyyy. 如果想要改變這種格式,你可以通過綁定特定的 db2 工具包來實現. 其他被支持的日期格式包括:
def |
使用與地區代碼相匹配的日期和時間格式。 |
eur |
使用歐洲日期和時間的 ibm 標準格式。 |
iso |
使用國際標準組織(iso)制訂的日期和時間格式。 |
jis |
使用日本工業標準的日期和時間格式。 |
loc |
使用與數據庫地區代碼相匹配的本地日期和時間格式。 |
usa |
使用美國日期和時間的 ibm 標準格式。 |
在 windows 環境下,要將缺省的日期和時間格式轉化成 iso 格式(yyyy-mm-dd),執行下列操作:
- 在命令行中,改變當前目錄為
sqllib\bnd 。
例如: 在 windows 環境:c:\program files\ibm\sqllib\bnd 在 unix 環境:/home/db2inst1/sqllib/bnd
- 從操作系統的命令行界面中用具有 sysadm 權限的用戶連接到數據庫:
db2 connect to dbname
db2 bind @db2ubind.lst datetime iso blocking all grant public
|
(在你的實際環境中, 用你的數據庫名稱和想使用的日期格式分別來替換 dbname and iso。)
現在,你可以看到你的數據庫已經使用 iso 作為日期格式了:
values current date
1
----------
2003-05-30
1 record(s) selected.
|
定制日期/時間格式
在上面的例子中,我們展示了如何將 db2 當前的日期格式轉化成系統支持的特定格式。但是,如果你想將當前日期格式轉化成定制的格式(比如‘yyyymmdd’),那又該如何去做呢?按照我的經驗,最好的辦法就是編寫一個自己定制的格式化函數。
下面是這個 udf 的代碼:
create function ts_fmt(ts timestamp, fmt varchar(20))
returns varchar(50)
return
with tmp (dd,mm,yyyy,hh,mi,ss,nnnnnn) as
(
select
substr( digits (day(ts)),9),
substr( digits (month(ts)),9) ,
rtrim(char(year(ts))) ,
substr( digits (hour(ts)),9),
substr( digits (minute(ts)),9),
substr( digits (second(ts)),9),
rtrim(char(microsecond(ts)))
from sysibm.sysdummy1
)
select
case fmt
when ''yyyymmdd''
then yyyy || mm || dd
when ''mm/dd/yyyy''
then mm || ''/'' || dd || ''/'' || yyyy
when ''yyyy/dd/mm hh:mi:ss''
then yyyy || ''/'' || mm || ''/'' || dd || '' '' ||
hh || '':'' || mi || '':'' || ss
when ''nnnnnn''
then nnnnnn
else
''date format '' || coalesce(fmt,'' <null> '') ||
'' not recognized.''
end
from tmp
|
乍一看,函數的代碼可能顯得很復雜,但是在仔細研究之后,你會發現這段代碼其實非常簡單而且很優雅。最開始,我們使用了一個公共表表達式(cte)來將一個時間戳記(第一個輸入參數)分別剝離為單獨的時間元素。然后,我們檢查提供的定制格式(第二個輸入參數)并將前面剝離出的元素按照該定制格式的要求加以組合。
這個函數還非常靈活。如果要增加另外一種模式,可以很容易地再添加一個 when 子句來處理。在使用過程中,如果用戶提供的格式不符合任何在 when 子句中定義的任何一種模式時,函數會返回一個錯誤信息。
使用方法示例:
values ts_fmt(current timestamp,''yyyymmdd'')
''20030818''
values ts_fmt(current timestamp,''asa'')
''date format asa not recognized.''
|
?
|
|
posted @
2006-06-13 11:29 MyJavaWorld 閱讀(368) |
評論 (0) |
編輯 收藏
tomcat5.5的管理功能非常強,只要你配置好了tomcat-user.xml.
主要是增加一個具有系統管理權限的用戶,比如增加一個用戶名和密碼都是suxiaoyong的用戶,只需要在在最后一行增加
代碼 | <user username="suxiaoyong" password="suxiaoyong" roles="admin,manager"/> |
其他的用戶都可以刪掉了
然后,我們可以進入http://localhost:8080/manager/status 來查看服務器的各種狀態.
也可以通過url來直接對應用進行監控
命令格式
代碼 | http://{ host }:{ port }/manager/{ command }?{ parameters } |
部署一個應用
列出已經部署的應用
代碼 | http://localhost:8080/manager/list |
重新加載一個應用
比如你更新了class或者lib的話,需要重新加載系統
代碼 | http://localhost:8080/manager/reload?path=/examples |
查看jvm和系統信息
代碼 | http://localhost:8080/manager/serverinfo |
查看可用的安全角色
代碼 | http://localhost:8080/manager/roles |
查看某個應用默認的session超時時間和當前活躍的session數
代碼 | http://localhost:8080/manager/sessions?path=/examples |
啟動一個應用
比如有時候重新啟動數據庫后可能需要重新啟動應用
代碼 | http://localhost:8080/manager/start?path=/examples |
關閉一個應用
關閉后,任何發往該應用的請求都將轉向404錯誤的頁面
代碼 | http://localhost:8080/manager/stop?path=/examples |
? undeploy
慎用,將刪除應用的目錄及其war文件
ant腳本,更多的詳見tomcat5.5的文檔
代碼 | <project name="My Application" default="compile" basedir=".">
?<!-- Configure the directory into which the web application is built --> ?<property name="build" ? ?value="${ basedir }/build"/>
?<!-- Configure the context path for this application --> ?<property name="path" ? ? value="/myapp"/>
?<!-- Configure properties to access the Manager application --> ?<property name="url" ? ? ?value="http://localhost:8080/manager"/> ?<property name="username" value="myusername"/> ?<property name="password" value="mypassword"/>
?<!-- Configure the custom Ant tasks for the Manager application --> ?<taskdef name="deploy" ? ?classname="org.apache.catalina.ant.DeployTask"/> ?<taskdef name="list" ? ? ?classname="org.apache.catalina.ant.ListTask"/> ?<taskdef name="reload" ? ?classname="org.apache.catalina.ant.ReloadTask"/> ?<taskdef name="resources" classname="org.apache.catalina.ant.ResourcesTask"/> ?<taskdef name="roles" ? ? classname="org.apache.catalina.ant.RolesTask"/> ?<taskdef name="start" ? ? classname="org.apache.catalina.ant.StartTask"/> ?<taskdef name="stop" ? ? ?classname="org.apache.catalina.ant.StopTask"/> ?<taskdef name="undeploy" ?classname="org.apache.catalina.ant.UndeployTask"/>
?<!-- Executable Targets --> ?<target name="compile" description="Compile web application"> ? ?<!-- ... construct web application in ${ build } subdirectory, and ? ? ? ? ? ?generated a ${ path }.war ... --> ?</target>
?<target name="deploy" description="Install web application" ? ? ? ? ?depends="compile"> ? ?<deploy url="${ url }" username="${ username }" password="${ password }" ? ? ? ? ? ?path="${ path }" war="${ build }${ path }.war"/> ?</target>
?<target name="reload" description="Reload web application" ? ? ? ? ?depends="compile"> ? ?<reload ?url="${ url }" username="${ username }" password="${ password }" ? ? ? ? ? ?path="${ path }"/> ?</target>
?<target name="undeploy" description="Remove web application"> ? ?<undeploy url="${ url }" username="${ username }" password="${ password }" ? ? ? ? ? ?path="${ path }"/> ?</target>
</project> |
|
|
|
posted @
2006-06-12 10:28 MyJavaWorld 閱讀(463) |
評論 (0) |
編輯 收藏
1. 配置系統管理(Admin Web Application)
大多數商業化的J2EE服務器都提供一個功能強大的管理界面,且大都采用易于理解的Web應用界面。Tomcat按照自己的方式,同樣提供一個成熟的管理工具,并且絲毫不遜于那些商業化的競爭對手。Tomcat的Admin Web Application最初在4.1版本時出現,當時的功能包括管理context、data source、user和group等。當然也可以管理像初始化參數,user、group、role的多種數據庫管理等。在后續的版本中,這些功能將得到很大的擴展,但現有的功能已經非常實用了。
Admin Web Application被定義在自動部署文件:CATALINA_BASE/webapps/admin.xml 。
(譯者注:CATALINA_BASE即tomcat安裝目錄下的server目錄)
你必須編輯這個文件,以確定Context中的docBase參數是絕對路徑。也就是說,CATALINA_BASE/webapps/admin.xml 的路徑是絕對路徑。作為另外一種選擇,你也可以刪除這個自動部署文件,而在server.xml文件中建立一個Admin Web Application的context,效果是一樣的。你不能管理Admin Web Application這個應用,換而言之,除了刪除CATALINA_BASE/webapps/admin.xml ,你可能什么都做不了。
如果你使用UserDatabaseRealm(默認),你將需要添加一個user以及一個role到CATALINA_BASE/conf/tomcat-users.xml 文件中。你編輯這個文件,添加一個名叫“admin”的role 到該文件中,如下:
<role name="admin"/>
你同樣需要有一個用戶,并且這個用戶的角色是“admin”。象存在的用戶那樣,添加一個用戶(改變密碼使其更加安全):
<user name="admin" password="deep_dark_secret" roles="admin"/>
當你完成這些步驟后,請重新啟動Tomcat,訪問http://localhost:8080/admin,你將看到一個登錄界面。Admin Web Application采用基于容器管理的安全機制,并采用了Jakarta Struts框架。一旦你作為“admin”角色的用戶登錄管理界面,你將能夠使用這個管理界面配置Tomcat。
2.配置應用管理(Manager Web Application)
Manager Web Application讓你通過一個比Admin Web Application更為簡單的用戶界面,執行一些簡單的Web應用任務。
Manager Web Application被被定義在一個自動部署文件中:
CATALINA_BASE/webapps/manager.xml 。
你必須編輯這個文件,以確保context的docBase參數是絕對路徑,也就是說CATALINA_HOME/server/webapps/manager的絕對路徑。
(譯者注:CATALINA_HOME即tomcat安裝目錄)
如果你使用的是UserDatabaseRealm,那么你需要添加一個角色和一個用戶到CATALINA_BASE/conf/tomcat-users.xml文件中。接下來,編輯這個文件,添加一個名為“manager”的角色到該文件中:
<role name=”manager”>
你同樣需要有一個角色為“manager”的用戶。像已經存在的用戶那樣,添加一個新用戶(改變密碼使其更加安全):
<user name="manager" password="deep_dark_secret" roles="manager"/>
然后重新啟動Tomcat,訪問http://localhost/manager/list,將看到一個很樸素的文本型管理界面,或者訪問http://localhost/manager/html/list,將看到一個HMTL的管理界面。不管是哪種方式都說明你的Manager Web Application現在已經啟動了。
Manager application讓你可以在沒有系統管理特權的基礎上,安裝新的Web應用,以用于測試。如果我們有一個新的web應用位于/home/user/hello下在,并且想把它安裝到 /hello下,為了測試這個應用,我們可以這么做,在第一個文件框中輸入“/hello”(作為訪問時的path),在第二個文本框中輸入“file:/home/user/hello”(作為Config URL)。
Manager application還允許你停止、重新啟動、移除以及重新部署一個web應用。停止一個應用使其無法被訪問,當有用戶嘗試訪問這個被停止的應用時,將看到一個503的錯誤——“503 - This application is not currently available”。
移除一個web應用,只是指從Tomcat的運行拷貝中刪除了該應用,如果你重新啟動Tomcat,被刪除的應用將再次出現(也就是說,移除并不是指從硬盤上刪除)。
3.部署一個web應用
有兩個辦法可以在系統中部署web服務。
1> 拷貝你的WAR文件或者你的web應用文件夾(包括該web的所有內容)到$CATALINA_BASE/webapps目錄下。
2> 為你的web服務建立一個只包括context內容的XML片斷文件,并把該文件放到$CATALINA_BASE/webapps目錄下。這個web應用本身可以存儲在硬盤上的任何地方。
如果你有一個WAR文件,你若想部署它,則只需要把該文件簡單的拷貝到CATALINA_BASE/webapps目錄下即可,文件必須以“.war”作為擴展名。一旦Tomcat監聽到這個文件,它將(缺省的)解開該文件包作為一個子目錄,并以WAR文件的文件名作為子目錄的名字。接下來,Tomcat將在內存中建立一個context,就好象你在server.xml文件里建立一樣。當然,其他必需的內容,將從server.xml中的DefaultContext獲得。
部署web應用的另一種方式是寫一個Context XML片斷文件,然后把該文件拷貝到CATALINA_BASE/webapps目錄下。一個Context片斷并非一個完整的XML文件,而只是一個context元素,以及對該應用的相應描述。這種片斷文件就像是從server.xml中切取出來的context元素一樣,所以這種片斷被命名為“context片斷”。
舉個例子,如果我們想部署一個名叫MyWebApp.war的應用,該應用使用realm作為訪問控制方式,我們可以使用下面這個片斷:
<!-- ?
?Context fragment for deploying MyWebApp.war ?
-->
<Context path="/demo" docBase="webapps/MyWebApp.war"
????????debug="0" privileged="true">
?<Realm className="org.apache.catalina.realm.UserDatabaseRealm" ???????????????
????????resourceName="UserDatabase"/>
</Context>
把該片斷命名為“MyWebApp.xml”,然后拷貝到CATALINA_BASE/webapps目錄下。
這種context片斷提供了一種便利的方法來部署web應用,你不需要編輯server.xml,除非你想改變缺省的部署特性,安裝一個新的web應用時不需要重啟動Tomcat。
4.配置虛擬主機(Virtual Hosts)
關于server.xml中“Host”這個元素,只有在你設置虛擬主機的才需要修改。虛擬主機是一種在一個web服務器上服務多個域名的機制,對每個域名而言,都好象獨享了整個主機。實際上,大多數的小型商務網站都是采用虛擬主機實現的,這主要是因為虛擬主機能直接連接到Internet并提供相應的帶寬,以保障合理的訪問響應速度,另外虛擬主機還能提供一個穩定的固定IP。
基于名字的虛擬主機可以被建立在任何web服務器上,建立的方法就是通過在域名服務器(DNS)上建立IP地址的別名,并且告訴web服務器把去往不同域名的請求分發到相應的網頁目錄。因為這篇文章主要是講Tomcat,我們不準備介紹在各種操作系統上設置DNS的方法,如果你在這方面需要幫助,請參考《DNS and Bind》一書,作者是Paul Albitz and Cricket Liu (O'Reilly)。為了示范方便,我將使用一個靜態的主機文件,因為這是測試別名最簡單的方法。
在Tomcat中使用虛擬主機,你需要設置DNS或主機數據。為了測試,為本地IP設置一個IP別名就足夠了,接下來,你需要在server.xml中添加幾行內容,如下:
<Server port="8005" shutdown="SHUTDOWN" debug="0">
?<Service name="Tomcat-Standalone">
???<Connector className="org.apache.coyote.tomcat4.CoyoteConnector"
port="8080" minProcessors="5" maxProcessors="75"
enableLookups="true" redirectPort="8443"/>
???<Connector className="org.apache.coyote.tomcat4.CoyoteConnector"
port="8443" minProcessors="5" maxProcessors="75"
acceptCount="10" debug="0" scheme="https" secure="true"/>
?????<Factory className="org.apache.coyote.tomcat4.CoyoteServerSocketFactory"
clientAuth="false" protocol="TLS" />
???</Connector>
???<Engine name="Standalone" defaultHost="localhost" debug="0">
?????<!-- This Host is the default Host -->
?????<Host name="localhost" debug="0" appBase="webapps"
?????unpackWARs="true" autoDeploy="true">
???????<Context path="" docBase="ROOT" debug="0"/>
???????<Context path="/orders" docBase="/home/ian/orders" debug="0"
??????????????????????reloadable="true" crossContext="true">
???????</Context>
?????</Host>
?????<!-- This Host is the first "Virtual Host": www.example.com -->
?????<Host name="www.example.com" appBase="/home/example/webapp">
???????<Context path="" docBase="."/>
?????</Host>
???</Engine>
?</Service>
</Server>
Tomcat的server.xml文件,在初始狀態下,只包括一個虛擬主機,但是它容易被擴充到支持多個虛擬主機。在前面的例子中展示的是一個簡單的server.xml版本,其中粗體部分就是用于添加一個虛擬主機。每一個Host元素必須包括一個或多個context元素,所包含的context元素中必須有一個是默認的context,這個默認的context的顯示路徑應該為空(例如,path=””)。
5.配置基礎驗證(Basic Authentication)
容器管理驗證方法控制著當用戶訪問受保護的web應用資源時,如何進行用戶的身份鑒別。當一個web應用使用了Basic Authentication(BASIC參數在web.xml文件中auto-method元素中設置),而有用戶訪問受保護的web應用時,Tomcat將通過HTTP Basic Authentication方式,彈出一個對話框,要求用戶輸入用戶名和密碼。在這種驗證方法中,所有密碼將被以64位的編碼方式在網絡上傳輸。
注意:使用Basic Authentication通過被認為是不安全的,因為它沒有強健的加密方法,除非在客戶端和服務器端都使用HTTPS或者其他密碼加密碼方式(比如,在一個虛擬私人網絡中)。若沒有額外的加密方法,網絡管理員將能夠截獲(或濫用)用戶的密碼。但是,如果你是剛開始使用Tomcat,或者你想在你的web應用中測試一下基于容器的安全管理,Basic Authentication還是非常易于設置和使用的。只需要添加<security-constraint>和<login-config>兩個元素到你的web應用的web.xml文件中,并且在CATALINA_BASE/conf/tomcat-users.xml 文件中添加適當的<role>和<user>即可,然后重新啟動Tomcat。
下面例子中的web.xml摘自一個俱樂部會員網站系統,該系統中只有member目錄被保護起來,并使用Basic Authentication進行身份驗證。請注意,這種方式將有效的代替Apache web服務器中的.htaccess文件。
<!--
?Define the Members-only area, by defining
?a "Security Constraint" on this Application, and
?mapping it to the subdirectory (URL) that we want
?to restrict.
-->
<security-constraint>
?<web-resource-collection>
???<web-resource-name>
?????Entire Application
???</web-resource-name>
???<url-pattern>/members/*</url-pattern>
?</web-resource-collection>
?<auth-constraint>
?????<role-name>member</role-name>
?</auth-constraint>
</security-constraint>
<!-- Define the Login Configuration for this Application -->
<login-config>
?<auth-method>BASIC</auth-method>
?<realm-name>My Club Members-only Area</realm-name>
</login-config>
6.配置單點登錄(Single Sign-On)
一旦你設置了realm和驗證的方法,你就需要進行實際的用戶登錄處理。一般說來,對用戶而言登錄系統是一件很麻煩的事情,你必須盡量減少用戶登錄驗證的次數。作為缺省的情況,當用戶第一次請求受保護的資源時,每一個web應用都會要求用戶登錄。如果你運行了多個web應用,并且每個應用都需要進行單獨的用戶驗證,那這看起來就有點像你在與你的用戶搏斗。用戶們不知道怎樣才能把多個分離的應用整合成一個單獨的系統,所有他們也就不知道他們需要訪問多少個不同的應用,只是很迷惑,為什么總要不停的登錄。
Tomcat 4的“single sign-on”特性允許用戶在訪問同一虛擬主機下所有web應用時,只需登錄一次。為了使用這個功能,你只需要在Host上添加一個SingleSignOn Valve元素即可,如下所示:
<Valve className="org.apache.catalina.authenticator.SingleSignOn"
??????debug="0"/>
在Tomcat初始安裝后,server.xml的注釋里面包括SingleSignOn Valve配置的例子,你只需要去掉注釋,即可使用。那么,任何用戶只要登錄過一個應用,則對于同一虛擬主機下的所有應用同樣有效。
使用single sign-on valve有一些重要的限制:
1> value必須被配置和嵌套在相同的Host元素里,并且所有需要進行單點驗證的web應用(必須通過context元素定義)都位于該Host下。
2> 包括共享用戶信息的realm必須被設置在同一級Host中或者嵌套之外。
3> 不能被context中的realm覆蓋。
4> 使用單點登錄的web應用最好使用一個Tomcat的內置的驗證方式(被定義在web.xml中的<auth-method>中),這比自定義的驗證方式強,Tomcat內置的的驗證方式包括basic、digest、form和client-cert。
5> 如果你使用單點登錄,還希望集成一個第三方的web應用到你的網站中來,并且這個新的web應用使用它自己的驗證方式,而不使用容器管理安全,那你基本上就沒招了。你的用戶每次登錄原來所有應用時需要登錄一次,并且在請求新的第三方應用時還得再登錄一次。當然,如果你擁有這個第三方web應用的源碼,而你又是一個程序員,你可以修改它,但那恐怕也不容易做。
6> 單點登錄需要使用cookies。
7.配置用戶定制目錄(Customized User Directores)
一些站點允許個別用戶在服務器上發布網頁。例如,一所大學的學院可能想給每一位學生一個公共區域,或者是一個ISP希望給一些web空間給他的客戶,但這又不是虛擬主機。在這種情況下,一個典型的方法就是在用戶名前面加一個特殊字符(~),作為每位用戶的網站,比如:
http://www.cs.myuniversity.edu/~username
http://members.mybigisp.com/~username
Tomcat提供兩種方法在主機上映射這些個人網站,主要使用一對特殊的Listener元素。Listener的className屬性應該是org.apache.catalina.startup.UserConfig,userClass屬性應該是幾個映射類之一。如果你的系統是Unix,它將有一個標準的/etc/passwd文件,該文件中的帳號能夠被運行中的Tomcat很容易的讀取,該文件指定了用戶的主目錄,使用PasswdUserDatabase 映射類。
<Listener className="org.apache.catalina.startup.UserConfig"
directoryName="public_html"
userClass="org.apache.catalina.startup.PasswdUserDatabase"/>
web文件需要放置在像/home/users/ian/public_html 或者 /users/jbrittain/public_html一樣的目錄下面。當然你也可以改變public_html 到其他任何子目錄下。
實際上,這個用戶目錄根本不一定需要位于用戶主目錄下里面。如果你沒有一個密碼文件,但你又想把一個用戶名映射到公共的像/home一樣目錄的子目錄里面,則可以使用HomesUserDatabase類。
<Listener className="org.apache.catalina.startup.UserConfig"
directoryName="public_html" homeBase="/home"
userClass="org.apache.catalina.startup.HomesUserDatabase"/>
這樣一來,web文件就可以位于像/home/ian/public_html 或者 /home/jasonb/public_html一樣的目錄下。這種形式對Windows而言更加有利,你可以使用一個像c:\home這樣的目錄。
這些Listener元素,如果出現,則必須在Host元素里面,而不能在context元素里面,因為它們都用應用于Host本身。
8.在Tomcat中使用CGI腳本
Tomcat主要是作為Servlet/JSP容器,但它也有許多傳統web服務器的性能。支持通用網關接口(Common Gateway Interface,即CGI)就是其中之一,CGI提供一組方法在響應瀏覽器請求時運行一些擴展程序。CGI之所以被稱為通用,是因為它能在大多數程序或腳本中被調用,包括:Perl,Python,awk,Unix shell scripting等,甚至包括Java。當然,你大概不會把一個Java應用程序當作CGI來運行,畢竟這樣太過原始。一般而言,開發Servlet總要比CGI具有更好的效率,因為當用戶點擊一個鏈接或一個按鈕時,你不需要從操作系統層開始進行處理。
Tomcat包括一個可選的CGI Servlet,允許你運行遺留下來的CGI腳本。
為了使Tomcat能夠運行CGI,你必須做如下幾件事:
1. 把servlets-cgi.renametojar (在CATALINA_HOME/server/lib/目錄下)改名為servlets-cgi.jar。處理CGI的servlet應該位于Tomcat的CLASSPATH下。
2. 在Tomcat的CATALINA_BASE/conf/web.xml 文件中,把關于<servlet-name> CGI的那段的注釋去掉(默認情況下,該段位于第241行)。
3. 同樣,在Tomcat的CATALINA_BASE/conf/web.xml文件中,把關于對CGI進行映射的那段的注釋去掉(默認情況下,該段位于第299行)。注意,這段內容指定了HTML鏈接到CGI腳本的訪問方式。
4. 你可以把CGI腳本放置在WEB-INF/cgi 目錄下(注意,WEB-INF是一個安全的地方,你可以把一些不想被用戶看見或基于安全考慮不想暴露的文件放在此處),或者你也可以把CGI腳本放置在context下的其他目錄下,并為CGI Servlet調整cgiPathPrefix初始化參數。這就指定的CGI Servlet的實際位置,且不能與上一步指定的URL重名。
5. 重新啟動Tomcat,你的CGI就可以運行了。
在Tomcat中,CGI程序缺省放置在WEB-INF/cgi目錄下,正如前面所提示的那樣,WEB-INF目錄受保護的,通過客戶端的瀏覽器無法窺探到其中內容,所以對于放置含有密碼或其他敏感信息的CGI腳本而言,這是一個非常好的地方。為了兼容其他服務器,盡管你也可以把CGI腳本保存在傳統的/cgi-bin目錄,但要知道,在這些目錄中的文件有可能被網上好奇的沖浪者看到。另外,在Unix中,請確定運行Tomcat的用戶有執行CGI腳本的權限。
9.改變Tomcat中的JSP編譯器(JSP Compiler)
在Tomcat 4.1(或更高版本,大概),JSP的編譯由包含在Tomcat里面的Ant程序控制器直接執行。這聽起來有一點點奇怪,但這正是Ant有意為之的一部分,有一個API文檔指導開發者在沒有啟動一個新的JVM的情況下,使用Ant。這是使用Ant進行Java開發的一大優勢。另外,這也意味著你現在能夠在Ant中使用任何javac支持的編譯方式,這里有一個關于Apache Ant使用手冊的javac page列表。使用起來是容易的,因為你只需要在<init-param> 元素中定義一個名字叫“compiler”,并且在value中有一個支持編譯的編譯器名字,示例如下:
<servlet>
???<servlet-name>jsp</servlet-name>
???<servlet-class>
?????org.apache.jasper.servlet.JspServlet
???</servlet-class>
???<init-param>
?????<param-name>logVerbosityLevel</param-name>
?????<param-value>WARNING</param-value>
???</init-param>
???<init-param>
?????<param-name>compiler</param-name>
?????<param-value>jikes</param-value>
???</init-param>
???<load-on-startup>3</load-on-startup>
</servlet>
當然,給出的編譯器必須已經安裝在你的系統中,并且CLASSPATH可能需要設置,那處決于你選擇的是何種編譯器。
10.限制特定主機訪問(Restricting Access to Specific Hosts)
有時,你可能想限制對Tomcat web應用的訪問,比如,你希望只有你指定的主機或IP地址可以訪問你的應用。這樣一來,就只有那些指定的的客戶端可以訪問服務的內容了。為了實現這種效果,Tomcat提供了兩個參數供你配置:RemoteHostValve 和RemoteAddrValve。
通過配置這兩個參數,可以讓你過濾來自請求的主機或IP地址,并允許或拒絕哪些主機/IP。與之類似的,在Apache的httpd文件里有對每個目錄的允許/拒絕指定。
例如你可以把Admin Web application設置成只允許本地訪問,設置如下:
<Context path="/path/to/secret_files" ...>
?<Valve className="org.apache.catalina.valves.RemoteAddrValve"
????????allow="127.0.0.1" deny=""/>
</Context>
如果沒有給出允許主機的指定,那么與拒絕主機匹配的主機就會被拒絕,除此之外的都是允許的。與之類似,如果沒有給出拒絕主機的指定,那么與允許主機匹配的主機就會被允許,除此之外的都是拒絕的。
--------------------------------------
posted @
2006-06-09 17:32 MyJavaWorld 閱讀(205) |
評論 (0) |
編輯 收藏
JSP視窗組件所使用的struts標記庫由四類標記組成: 2. Bean標記:用來在JSP頁中管理bean 3. 邏輯標記:用來在JSP頁中控制流程 4. HTML標記:用來生成HTML標記,在表單中顯示數據,使用會話ID對URL進行編程 5. 模板標記:使用動態模板構造普通格式的頁 2.1 Bean標記 這個標記庫中包含用于定義新bean、訪問bean及其屬性的標記。Struts框架提供了多種自定義標記用來在JSP頁中處理JavaBean。這些標記被封裝在一個普通的標記庫中,在文件struts-bean.tld中定義了它的標記庫描述器。Bean標記庫將標記定義在四個子類別中: 創建和復制bean的標記 腳本變量定義標記 bean翻譯標記 消息國際化標記 2.1.1 Bean復制標記 可定義新bean,可復制現有bean,還可從現有bean復制屬性。 <bean:define>標記用來: 定義新字符串常數 將現有的bean復制到新定義的bean對象 復制現有bean的屬性來創建新的bean <bean:define>標記屬性: 屬性描述Id 新定義的bean腳本變量名稱,必須設置Type 定義引入腳本變量的類Value 為id屬性定義的腳本變量分配一個新的對象Name 目標bean的名稱。若value屬性沒有設置,這個屬性就必須設置property Name屬性定義的bean的屬性名稱,用來定義新的bean 13 Scope 源bean的作用域。若沒有設置,搜索范圍是從頁作用域到應用程序作用域toScope 目標bean的作用域。若沒有設置,默認值是頁作用域 例如:定義一個bean: <bean:define id=”test” value=”this is a test”/> 源bean在頁作用域中被拷貝大哦請求作用域中的另一個bean: <bean:define id=”targetBean” name=”sourceBean” scope=”page” toScope=”request”/> 2.1.2 定義腳本變量的標記 從多種資源中定義和生成腳本變量,這些資源包括cookie,請求參數,HTTP標頭等等。屬性如下: 屬性描述Id 腳本變量和要定義的頁作用域屬性的名稱Name cookie/標頭/參數的名稱multiple 如果這個屬性設置了任意一個數值,所有匹配的cookie都會被積累并存儲到一個Cookie[](一個數組)類型的bean里。若無設置,指定cookie的第一個值將作為Cookie類型的值Value 如果沒有匹配的cookie或數值,就返回這個屬性指定的默認值 例如: <bean:cookie id=”myCookie” name=”userName”/> 腳本變量名稱是myCookie,用來創建這個屬性的cookie的名稱是userName。 <bean:header id=”myHeader” name=”Accept-Language”/> 腳本變量名稱是myHeader,請求標頭的名稱是Accept-Language. <bean:parameter id=”myParameter” name=”myParameter”> 腳本變量名稱是myPatameter,它保存的請求參數的名稱也是myParameter. <bean:include>標記將對一個資源的響應進行檢索,并引入一個腳本變量和字符串類型的頁作用域屬性。這個資源可以是一個頁,一個ActionForward或一個外部URL。與<jsp:include>的不同是資源的響應被存儲到一個頁作用域的bean中,而不是寫入到輸出流。屬性如下: 屬性描述Id 腳本變量和要定義的頁作用域屬性的名稱Page 一個內部資源forward 一個ActionForward Href 要包含的資源的完整URL 例如: <bean:include id=”myInclude” page=”MyJsp?x=1”/> 腳本變量的名稱是myInclude,要檢索的響應來自資源MyJsp?x=1。 <bean:resource>標記將檢索web應用中的資源,并引入一個腳本變量和InputStream或字符串類型的頁作用域屬性。如果在檢索資源時發生問題,就會產生一個請求時間異常。屬性如下: 屬性描述 14 Id 腳本變量和要定義的頁作用域屬性的名稱Name 資源的相對路徑Input 如果這個屬性不存在,資源的類型就是字符串 例如: <bean:resource id=”myResource” name=”/WEB-INF/images/myResource.xml”/> 腳本變量的名稱是myResource,要檢索的資源的名稱是myResource.xml。 2.1.3 顯示Bean屬性 標記庫中定義了<bean:write>標記,用來將bean的屬性輸送到封裝的JSP頁寫入器。這個標記與<jsp:getProperty>類似,屬性如下: 屬性描述Name 要進行屬性顯示的bean的名稱property 要顯示的屬性的名稱。如果這個屬性類有java.beans.PropertyEditor,getAsText()或toString 方法會被調用Scope Bean的作用域,若沒有設置,搜索范圍是從頁到應用程序作用域Filter 如果設置true,屬性中的所有特殊HTML字符都將被轉化為相應的實體引用Ignore 如果設置false,當發現屬性時會產生一個請求時間異常,否則返回null 例如: <bean:write name=”myBean” property=”myProperty” scope=”request” filter=”true”/> myBean的屬性myProperty將會被顯示,作用域為請求,如果發現任何HTML特殊字符都將被轉化為相應的實體引用。 2.1.4 消息標記和國際化 strtus框架支持國際化和本地化。用戶在他們的計算機中定義自己所在的區域,當web應用程序需要輸出一條消息時,它將引用一個資源文件,在這個文件中所有的消息都使用了適當的語言。一個應用程序可能提供了很多資源文件,每個文件提供了用不同語言編寫的消息。如果沒有找到所選語言的資源文件,就將使用默認的資源文件。 struts框架對國際化的支持是使用<bean:message>標記,以及使用java.util數據包中定義的Locale和ResourceBundle類來實現Java2平臺對這些任務的支持。Java.text.MessageFormat類定義的技術可以支持消息的格式。利用此功能,開發人員不需了解這些類的細節就可進行國際化和設置消息的格式。 用strtus實現國際化和本地化: 第一步要定義資源文件的名稱,這個文件會包含用默認語言編寫的在程序中會出現的所有消息。這些消息以“關鍵字-值”的形式存儲,如下: error.validation.location = The entered location is invalid 這個文件需要存儲在類的路徑下,而且它的路徑要作為初始化參數傳送給ActionServlet作為參數進行傳遞時,路徑的格式要符合完整Java類的標準命名規范。比如,如果資源文件存儲在WEB-INFclasses目錄中,文件名是 15 ApplicationResources.properties,那么需要傳遞的參數值是ApplicationResources。如果文件在WEB-INFclassescomtest中,那么參數值就應該是com.test. ApplicationResources. 為了實現國際化,所有的資源文件必須都存儲在基本資源文件所在的目錄中。基本資源文件包含的是用默認地區語言-本地語言編寫的消息。如果基本資源文件的名稱是ApplicationResources.properties,那么用其他特定語言編寫的資源文件的名稱就應該是ApplicationResources_xx.properties(xx為ISO編碼,如英語是en)。因此這些文件應包含相同的關鍵字,但關鍵字的值是用特定語言編寫的。 ActionServlet的區域初始化參數必須與一個true值一起傳送,這樣ActionServlet就會在用戶會話中的Action.LOCALE_KEY關鍵字下存儲一個特定用戶計算機的區域對象。現在可以運行一個國際化的web站點,它可以根據用戶計算機上的設置的區域自動以相應的語言顯示。 我們還可以使用特定的字符串來替換部分消息,就象用java.text.MessageFormat的方法一樣: error.invalid.number = The number {0} is valid 我們可以把字符串{0}替換成任何我們需要的數字。<bean:message>標簽屬性如下: 屬性描述Key 資源文件中定義消息關鍵字Locale 用戶會話中存儲的區域對象的屬性名稱。若沒有設置,默認值是Action.LOCALE_KEY Bundle 在應用程序上下文中,存儲資源對象的屬性的名稱。如果沒有設置這個屬性,默認值是Action.MESSAGE_KEY arg0 第一個替換參數值arg1 第二個替換參數值arg2 第三個替換參數值arg3 第四個替換參數值 例如:資源文件中定義了一個消息: info.myKey = The numbers entered are {0},{1},{2},{3} 我們可使用下面的消息標記: <bean:message key=”info.myKey” arg0=”5” arg1=”6” arg2=”7” arg3=”8”/> 這個信息標記輸出到JSP頁會顯示為:The numbers entered are 5,6,7,8 2.2 邏輯標記 邏輯庫的標記能夠用來處理外觀邏輯而不需要使用scriptlet。Struts邏輯標簽庫包含的標記能夠有條件地產生輸出文本,在對象集合中循環從而重復地產生輸出文本,以及應用程序流程控制。它也提供了一組在JSP頁中處理流程控制的標記。這些標記封裝在文件名為struts-logic.tld的標記包中。邏輯標記庫定義的標記能夠執行下列三個功能: 條件邏輯 重復 轉發/重定向響應 16 2.2.1 條件邏輯 struts有三類條件邏輯。第一類可以比較下列實體與一個常數的大小: cookie 請求參數 bean或bean的參數 請求標頭 以下列出了這一類標記: 標記功能<equal> 如果常數與被定義的實體相等,返回true <notEqual> 如果常數與被定義的實體不相等,返回true <greaterEqual> 如果常數大于等于被定義的實體,返回true <lessEqual> 如果常數小于等于被定義的實體,返回true <lessThan> 如果常數小于被定義的實體,返回true <greaterThan> 如果常數大于被定義的實體,返回true 這一類的所有標記有相同的屬性 屬性描述Value 要進行比較的常數值Cookie 要進行比較的HTTP cookie的名稱Header 要進行比較的HTTP請求標頭的名稱parameter 要進行比較的HTTP請求參數的名稱Name 如果要進行比較的是bean或bean的屬性,則這個屬性代表bean的名稱property 要進行比較的bean屬性的名稱Scope Bean的作用域,如果沒有指定作用域,則它的搜索范圍是從頁到應用程序 例如: <logic:equal parameter=”name” value=”SomeName”> The entered name is SomeName </logic:equal> 判斷名為”name”的請求參數的值是否是”SomeName”。 <logic:greaterThan name=”bean” property=”prop” scope=”page” value=”7”> The value of bean.Prop is greater than 7 </logic:greaterThan> 判斷在頁的作用域中是否有一個名為”bean”的bean,它有一個prop屬性,這個屬性的值是否大于7。如果這個屬性能夠轉化為數值,就進行數值比較,否則就進行字符串比較。 第二類條件標記定義了兩個標記: <logic:present> <logic:notPresent> 它們的功能是在計算標記體之前判斷特定的項目是否存在。標記的屬性和屬性值決定了要進行檢查的項目。 屬性描述 17 Cookie 由這個屬性指定的cookie將被檢查是否存在Header 由這個屬性指定的請求標頭將被檢查是否存在parameter 由這個屬性指定的請求參數將被檢查是否存在Name 如果沒有設置property屬性,那么有這個屬性指定的bean將被檢查是否存在。如果設置了,那么bean和bean屬性都將被檢查是否存在。property 檢查有name屬性指定的bean中是否存在指定的屬性Scope 如果指定了bean的名稱,這就是bean的作用域。如果沒有指定作用域,搜索的范圍從頁到應用程序作用域。Role 檢查當前已經確認的用戶是否屬于特殊的角色User 檢查當前已經確認的用戶是否有特定的名稱 例如: <logic:notPresent name=”bean” property=”prop” scope=”page”> The bean property bean.prop is present </logic:notPresent> 標記判斷在頁作用域中是否存在一個名為”bean”的bean,這個bean有一個prop屬性。 第三類條件標記比較復雜,這些標記根據模板匹配的結果檢查標記體的內容。換句話說,這些標記判斷一個指定項目的值是否是一個特定常數的子字符串: <logic:match> <logic:notMatch> 這些標記允許JSP引擎在發現了匹配或是沒有發現時計算標記主體。屬性如下: 屬性描述Cookie 要進行比較的HTTP cookie的名稱Header 要進行比較的的HTTP標頭的名稱parameter 要進行比較的的HTTP請求參數的名稱Name 若要對bean或bean的屬性進行比較,這個屬性是用戶指定bean的名稱location 如果設置了這個屬性的值,將會在這個指定的位置(索引值)進行匹配scope 如果對bean進行比較,這個屬性指定了bean的作用域。如果沒有設置這個參數,搜索范圍是從頁到應用程序作用域property 要進行比較的bean的屬性名稱value 要進行比較的常數值 例如: <logic:match parameter=”name” value=”xyz” location=”1”> The parameter name is a sub-string of the string xyz from index 1 </logic:match> 標記檢查名為”name”的請求參數是否是”xyz”的子字符串,但是子字符串必須從”xyz”的索引位置1開始(也就是說子字符串必須是”y”或”yz”)。 2.2.2 重復標記 在邏輯標記庫中定義了<logic:iterate>標記,它能夠根據特定集合中元素的數目對標記體的內容進行重復的檢查。集合的類型可以是java.util.Iterator,java.util.Collection 18 ,java.util.Map或是一個數組。有三種方法可以定義這個集合: 使用運行時間表達式來返回一個屬性集合的集合 將集合定義為bean,并且使用name屬性指定存儲屬性的名稱。 使用name屬性定義一個bean,并且使用property屬性定義一個返回集合的bean屬性。 當前元素的集合會被定義為一個頁作用域的bean。屬性如下,所有這些屬性都能使用運行時表達式。 屬性描述collection 如果沒有設置name屬性,它就指定了要進行重復的集合Id 頁作用域bean和腳本變量的名稱,它保存著集合中當前元素的句柄indexed 頁作用域JSP bean的名稱,它包含著每次重復完成后集合的當前索引Length 重復的最大次數Name 作為集合的bean的名稱,或是一個bean名稱,它由property屬性定義的屬性,是個集合Offset 重復開始位置的索引property 作為集合的Bean屬性的名稱Scope 如果指定了bean名稱,這個屬性設置bean的作用域。若沒有設置,搜索范圍從頁到應用程序作用域Type 為當前定義的頁作用域bean的類型 例如: <logic:iterate id=”currentInt” collection=”<% =myList %>” type=”java.lang.Integer” offset=”1” length=”2”> <% =currentint %> </logic:iterate> 代碼將從列表中的第一個元素開始重復兩個元素并且能夠讓當前元素作為頁作用域和java.lang.Integer類型的腳本變量來使用。也就是說,如果myList包含元素1,2,3,4等,代碼將會打印1和2。 2.2.3 轉發和重定向標記 轉發標記 <logic:forward>標記能夠將響應轉發給重定向到特定的全局ActionForward上。ActionForward的類型決定了是使用PageContext轉發響應,還是使用sendRedirect將響應進行重定向。此標記只有一個”name”屬性,用來指定全局ActionForward的名稱,例如: <logic:forward name=”myGlobalForward”/> 重定向標記 <logic:redirect>標記是一個能夠執行HTTP重定向的強大工具。根據指定的不同屬性,它能夠通過不同的方式實現重定向。它還允許開發人員指定重定向URL的查詢參數。屬性如下: 19 屬性描述Forward 映射了資源相對路徑的ActionForward Href 資源的完整URL Page 資源的相對路徑Name Map類型的頁名稱,請求,會話或程序屬性的名稱,其中包含要附加大哦重定向URL(如果沒有設置property屬性)上的“名稱-值”參數。或是具有Map類型屬性的bean名稱,其中包含相同的信息(沒有設置property屬性) Property Map類型的bean屬性的名稱。Bean的名稱由name屬性指定。Scope 如果指定了bean的名稱,這個屬性指定搜索bean的范圍。如果沒有設置,搜索范圍從頁到應用程序作用域ParamID 定義特定查詢參數的名稱ParamName 字符串類型的bean的名稱,其中包含查詢參數的值(如果沒有設置paramProperty屬性);或是一個bean的名稱,它的屬性(在paramProperty屬性中指定)包含了查詢參數值paramProperty 字符串bean屬性的名稱,其中包含著查詢參數的值ParamScope ParamName定義的bean的搜索范圍 使用這個標記時至少要指定forward,href或page中的一個屬性,以便標明將響應重定向到哪個資源。 2.3 HTML標記 Struts HTML標記可以大致地分為以下幾個功能: 顯示表單元素和輸入控件 顯示錯誤信息 顯示其他HTML元素 2.3.1 顯示表單元素和輸入控件 struts將HTML表單與為表單操作而定義的ActionForm bean緊密聯系在一起。表單輸入字段的名稱與ActionForm bean里定義的屬性名稱是對應的。當第一次顯示表單時,表單的輸入字段是從ActionForm bean中移植過來的,當表單被提交時,請求參數將移植到ActionForm bean實例。 所有可以在<form>標記中使用的用來顯示HTML輸入控件的內嵌標記都使用下列屬性來定義JavaScript事件處理器。 屬性描述Onblur 字段失去了焦點Onchange 字段失去了焦點并且數值被更改了Onclick 字段被鼠標點擊Ondblclick 字段被鼠標雙擊Onfocus 字段接收到輸入焦點Onkeydown 字段擁有焦點并且有鍵按下 20 onkeypress 字段擁有焦點并且有鍵按下并釋放Onkeyup 字段擁有焦點并且有鍵被釋放onmousedown 鼠標指針指向字段并且點擊onmousemove 鼠標指針指向字段并且在字段內移動onmouseout 鼠標指針指向控件,但是指針在元素外圍移動onmouseover 鼠標指針沒有指向字段,但是指針在元素內部移動Onmouseup 鼠標指針指向字段,并且釋放了鼠標按鍵 <form>元素中能夠被定義的其他一般屬性有: 屬性描述Accesskey 定義訪問輸入字段的快捷鍵Style 定義輸入字段的樣式styleClass 定義輸入字段的樣式表類Tabindex 輸入字段的tab順序 a) 表單標記 <html:form>標記用來顯示HTML標記,可以指定AcitonForm bean的名稱和它的類名。如果沒有設置這些屬性,就需要有配置文件來指定ActionMapping以表明當前輸入的是哪個JSP頁,以及從映射中檢索的bean名和類。如果在ActionMapping指定的作用域中沒有找到指定的名稱,就會創建并存儲一個新的bean,否則將使用找到的bean。 <form>標記能夠包含與各種HTML輸入字段相對應的子標記。 <html:form>標記屬性如下: 屬性描述Action 與表單相關的操作。在配置中,這個操作也用來標識與表單相關的ActionForm bean Enctype 表單HTTP方法的編碼類型Focus 表單中需要初始化焦點的字段Method 表單使用的HTTP方法Name 與表單相關的ActionForm bean的名稱。如果沒有設置這個屬性,bean的名稱將會從配置信息中獲得Onreset 表單復位時的JavaScript事件句柄Onsubmit 表單提交時的JavaScript事件句柄Scope 搜索ActionForm bean的范圍。如果沒有設置,將從配置文件中獲取Style 使用的格式styleClass 這個元素的格式表類Type ActionForm bean的完整名稱。如果沒有設置,將從配置文件獲得 例如: <html:form action=”validateEmploee.do” method=”post”> </html:form> 與表單相關的操作路徑是validateEmployee,而表單數據是通過POST傳遞的。對于這個表單來說,ActionForm bean的其他信息,如bean名稱類型,作用域,都是從表單指定操作的ActionMapping中檢索得到的: 21 <form-beans> <form-bean name=”empForm” type=”com.example.EmployeeForm”/> </form-beans> <action-mappings> <action path=”/validateEmployee” type=”com.example.ValidateExampleAction” name=”empForm” scope=”request” input=”/employeeInput.jsp”> <forward name=”success” path=”/employeeOutput.jsp”> </action> </action-mapping> 如果配置文件中包含上述信息,并且請求URI的*.do被映射到ActionServlet,與表單相關的ActionForm bean的名稱,類型和作用域分別是empForm,com.example.EmployeeForm和request.這些屬性也可以使用<html:form>標記屬性進行顯示的定義。 以下標記必須嵌套在<html:form>標記里 b) 按鈕和取消標記 <html:button>標記顯示一個按鈕控件;<html:cancel>標記顯示一個取消按鈕。屬性如下: 屬性描述Property 定義在表單被提交時返回到服務器的請求參數的名稱Value 按鈕上的標記 c) 復位和提交標記 <html:reset>和<html:submit>標記分別能夠顯示HTML復位按鈕和提交按鈕。 d) 文本和文本區標記 <html:text>和<html:textarea>標記分別HTML文本框和文本區,屬性如下: 屬性描述Property 定義當表單被提交時送回到服務器的請求參數的名稱,或用來確定文本元素當前值的bean的屬性名稱Name 屬性被查詢的bean的名稱,它決定了文本框和文本區的值。如果沒有設置,將使用與這個內嵌表單相關的ActionForm的名稱 <html:text>標記還有以下屬性: 屬性描述Maxlength 能夠輸入的最大字符數 22 Size 文本框的大小(字符數) <html:textarea>標記特有的屬性如下: 屬性描述Rows 文本區的行數Cols 文本區的列數 e) 檢查框和復選框標記 <html:checkbox>標記能夠顯示檢查框控件。<html:multibox>標記能夠顯示HTML復選框控件,請求對象在傳遞檢查框名稱時使用的getParameterValues()調用將返回一個字符串數組。屬性如下: 屬性描述Name Bean的名稱,其屬性會被用來確定檢查是否以選中的狀態顯示。如果沒有設置,將使用與這個內嵌表單相關的ActionFrom bean的名稱。Property 檢查框的名稱,也是決定檢查框是否以選中的狀態顯示的bean屬性名稱。在復選框的情況下,這個屬性必須是一個數組。Value 當檢查框被選中時返回到服務器的請求參數的值 例如: <html:checkbox property=”married” value=”Y”/> 一個名為married的檢查框,在表單提交時會返回一個”Y”. f) 文件標記 <html:file>標記可以顯示HTML文件控件。屬性如下: 屬性描述Name Bean的名稱,它的屬性將確定文件控件中顯示的內容。如果沒設置,將使用與內嵌表單相關的ActionForm bean的名稱property 這個屬性定義了當表單被提交時送回到服務器的請求參數的名稱,以及用來確定文件控件中顯示內容的bean屬性名稱Accept 服務器能夠處理的內容類型集。它也將對客戶瀏覽器對話框中的可選文件類型進行過濾Value 按鈕上的標記,這個按鈕能夠在本地文件系統中瀏覽文件 g) 單選鈕標記 <html:radio>標記用來顯示HTML單選鈕控件,屬性如下: 屬性描述Name Bean的名稱,其屬性會被用來確定單選鈕是否以選中的狀態顯示。如果沒有設置,將使用與這個內嵌表單相關的ActionFrom bean的名稱。property 當表單被提交時送回到服務器的請求參數的名稱,以及用來確定單選鈕是否以被選中狀態進行顯示的bean屬性的名稱 23 Value 當單選鈕被選中時返回到服務器的值 h) 隱藏標記 <html:hidden>標記能夠顯示HTML隱藏輸入元素,屬性如下: 屬性描述Name Bean的名稱,其屬性會被用來確定隱藏元素的當前值。如果沒有設置,將使用與這個內嵌表單相關的ActionFrom bean的名稱。property 定義了當表單被提交時送回到服務器的請求參數的名稱,以及用來確定隱藏元素當前值的bean屬性的名稱Value 用來初始化隱藏輸入元素的值 i) 密碼標記 <html:password>標記能夠顯示HTML密碼控件,屬性如下: 屬性描述maxlength 能夠輸入的最大字符數Name Bean的名稱,它的屬性將用來確定密碼元素的當前值。如果沒有設置,將使用與這個內嵌表單相關的ActionFrom bean的名稱。property 定義了當表單被提交時送回到服務器的請求參數的名稱,以及用來確定密碼元素當前值的bean屬性的名稱redisplay 在顯示這個字段時,如果相應的bean屬性已經被設置了數據,這個屬性決定了是否顯示密碼的內容Size 字段的大小 j) 選擇標記 <html:select>標記能夠顯示HTML選擇控件,屬性如下: 屬性描述multiple 表明這個選擇控件是否允許進行多選Name Bean的名稱,它的屬性確定了哪個。如果沒有設置,將使用與這個內嵌表單相關的ActionFrom bean的名稱。property 定義了當表單被提交時送回到服務器的請求參數的名稱,以及用來確定哪個選項需要被選中的bean屬性的名稱Size 能夠同時顯示的選項數目Value 用來表明需要被選中的選項 k) 選項標記(這個元素需要嵌套在<html:select>標記里) <html:option>標記用來顯示HTML選項元素集合,屬性如下: 24 屬性描述collection Bean集合的名稱,這個集合存儲在某個作用域的屬性中。選項的數目與集合中元素的數目相同。Property屬性能夠定義選項值所使用的bean屬性,而labelProperty屬性定義選項標記所使用的bean的屬性labelName 用來指定存儲于某個作用域的bean,這個bean是一個字符串的集合,能夠定義<html:option>元素的標記(如果標志與值不相同) labelProperty 與collection屬性共同使用時,用來定義了存儲于某個作用域的bean,這個bean將返回一個字符串集合,能夠用來寫入<html:option>元素的value屬性Name 如果這是唯一被指定的屬性,它就定義了存儲于某個作用域的bean,這個bean將返回一個字符串集合,能夠用來寫入<html:option>元素的value屬性property 這個屬性在與collection屬性共同使用時,定義了每個要顯示選項值的獨立bean的name屬性。如果不是與collection屬性共同使用,這個屬性定義了由name屬性指定的bean的屬性名稱(如果有name屬性),或是定義了一個ActionForm bean,這個bean將返回一個集合來寫入選項的值 我們看一下這個標記的一些例子: <html:option collection=”optionCollection” property=”optionValue” labelProperty=”optionLabel”/> 標記假設在某個作用域中有一個名為optionCollection的集合,它包含了一些具有optionValue屬性的獨立的bean,每個屬性將作為一個選項的值。每個選項的標志由bean的optionLabel屬性屬性進行定義。 <html:option name=”optionValues” labelName=”optionLabels”/> 標記中optionValues代表一個存儲在某個作用域中的bean,它是一個字符串集合,能夠用來寫入選項的值,而optionLabels代表一個存儲在某個作用域中的bean,它也是一個字符串集合,能夠用來寫入選項的標志。 2.3.2.顯示錯誤信息的標記 <html:errors>標記能夠與ActionErrors結合在一起來顯示錯誤信息。這個標記首先要從當前區域的資源文件中讀取消息關鍵字errors.header,然后顯示消息的文本。接下去它會在ActionErrors對象(通常作為請求參數而存儲在Action.ERROR_KEY關鍵字下)中循環,讀取單個ActionError對象的消息關鍵字,從當前區域的資源文件中讀取并格式化相應的消息,并且顯示它們。然后它讀取與errors.footer關鍵字相對應的消息并且顯示出來。 通過定義property屬性能夠過濾要顯示的消息,這個屬性的值應該與ActionErrors對象中存儲ActionError對象的關鍵字對應。屬性如下: 屬性描述Bundle 表示應用程序作用域屬性的名稱,它包含著消息資源,其默認值Acion.MESSAGE_KEY Locale 表示會話作用域屬性的名稱,它存儲著用戶當前登錄的區域信息。其默認值是Action.ERROR_KEY 25 Name 表示請求屬性的名稱,它存儲著ActionErrors對象。其默認值是Action.ERROR_KEY property 這個屬性指定了ActionErrors對象中存儲每個獨立ActionError對象的關鍵字,它可以過濾消息 例子: <html:errors/> 顯示集合中所有的錯誤。 <html:errors property=”missing.name”/> 顯示存儲在missing.name關鍵字的錯誤。 2.3.3.其他HTML標記 struts HTML標記還定義了下列標記來顯示其他HTML元素: <html:html> : 顯示HTML元素 <html:img> : 顯示圖象標記 <html:link> : 顯示HTML鏈接或錨點 <html:rewrite> : 創建沒有錨點標記的URI 這些標記的詳細內容請參照struts文檔。 2.4. 模板標記 動態模板是模塊化WEB頁布局設計的強大手段。Struts模板標記庫定義了自定義標記來實現動態模板。 2.4.1.插入標記 <template:insert>標記能夠在應用程序的JSP頁中插入動態模板。這個標記只有一個template屬性,用來定義模板JSP頁。要插入到模板的頁是有多個<template:put>標記來指定的,而這些標記被定義為<template:insert>標記的主體內容。 2.4.2.放置標記 <template:put>標記是<template:insert>標記內部使用的,用來指定插入到模板的資源。屬性如下: 屬性描述content 定義要插入的內容,比如一個JSP文件或一個HTML文件direct 如果這個設置為true,由content屬性指定的內容將直接顯示在JSP上而不是作為包含文件Name 要插入的內容的名稱Role 如果設置了這個屬性,只有在當前合法用戶具有特定角色時才能進行內容的插入。 26 2.4.3.獲得標記 在模板JSP頁中使用<template:get>標記能夠檢索由<template:put>標記插入到JSP頁的資源。屬性如下: 屬性描述Name 由<template:put>標記插入的內容的名稱Role 如果設置了這個屬性,只有在當前合法用戶具有特定角色時才能進行內容的檢索 2.4.4.使用模板標記 首先編寫一個模板JSP頁,它將被所有的web頁使用: <html> <%@ taglib uri=”/template” prefix=”template” %> <head> <title></title> </head> <body> <table width=”100%” height=”100%” > <tr height=”10%”> <td> <template:get name=”header”/> </td> </tr> <tr height=”80%”> <td> <template:get name=”content”/> </td> </tr> <tr height=”10%”> <td> <template:get name=”footer”/> </td> </tr> </table> </body> </html> 我們將這個文件命名為template.jsp。這個文件使用<template:get>標記來獲得由JSP頁使用<template:put>標記提供的內容,并且將內容在一個HTML表格中顯示出來。這三個內容是標題,內容和頁腳。典型的內容JSP會是這樣: <%@ taglib uri=”/template” prefix=”/template” %> <template:insert template=”template.jsp”> <template:put name=”header” content=”header.html”/> 27 <template:put name=”content” content=”employeeList.jsp”/> <template:put name=”footer” content=”footer.html”/> </template:insert> 這個應用程序JSP頁使用<template:insert標記來定義模板,然后使用<template:put>標記將特定內容名稱指定的資源放到模板JSP頁中。如果我們有上百個布局相同的頁,但突然想改變這個模板,我們只需要改變template.jsp文件。 |
|
posted @
2006-06-08 13:00 MyJavaWorld 閱讀(269) |
評論 (0) |
編輯 收藏
指令名稱:sudo
使用權限:在 /etc/sudoers 中有出現的使用者 使用方式:sudo -V sudo -h sudo -l sudo -v sudo -k sudo -s sudo -H sudo [ -b ] [ -p prompt ] [ -u username/#uid] -s sudo command 說明:以系統管理者的身份執行指令,也就是說,經由 sudo 所執行的指令就好像是 root 親自執行 參數: -V 顯示版本編號 -h 會顯示版本編號及指令的使用方式說明 -l 顯示出自己(執行 sudo 的使用者)的權限 -v 因為 sudo 在第一次執行時或是在 N 分鐘內沒有執行(N 預設為五)會問密碼,這個參數是重新做一次確認,如果超過 N 分鐘,也會問密碼 -k 將會強迫使用者在下一次執行 sudo 時問密碼(不論有沒有超過 N 分鐘) -b 將要執行的指令放在背景執行 -p prompt 可以更改問密碼的提示語,其中 %u 會代換為使用者的帳號名稱, %h 會顯示主機名稱 -u username/#uid 不加此參數,代表要以 root 的身份執行指令,而加了此參數,可以以 username 的身份執行指令(#uid 為該 username 的使用者號碼) -s 執行環境變數中的 SHELL 所指定的 shell ,或是 /etc/passwd 里所指定的 shell -H 將環境變數中的 HOME (家目錄)指定為要變更身份的使用者家目錄(如不加 -u 參數就是系統管理者 root ) command 要以系統管理者身份(或以 -u 更改為其他人)執行的指令 范例: sudo -l 列出目前的權限 sudo -V 列出 sudo 的版本資訊 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 以root身份執行指令 名稱
sudo - 以超級使用者 (superuser; root) 的身分執行指令
visudo - 編輯 sudoers 檔案
語法
sudo command
描述
Sudo 允許經過同意的使用者以超級使用者的身分執行指令。 Sudo 參考/etc/sudoers 這個檔案來判定誰是被授權的使用者。Sudo 將會提示使用者輸入密碼來啟始一段 N 分鐘的允許時間(其中 N 是在安裝的時候定義的且預設值為 5 分鐘)。
Sudoers 這個檔案是由一個選擇性的主機別名 (host alias) 節區,一個選擇性的指令別名 (command alias) 節區以及使用者說明 (user specification)節區所組成的。所有的指令別名或主機別名必須需以他們自己的關鍵字作為開始 (Host_Alias/Cmnd_Alias)。注意,只有第一次使用者(在使用者說明節區里有記錄的使用者)使用時會有說明。
使用者說明節區格式: 使用者 接取群組 [: 接取群組 ] ...
接取群組 ::= 主機象徵 = [op]指令象徵 [,[op]指令象徵] ... 主機象徵 ::= 一個小寫的主機名稱或主機別名。 指令象徵 ::= 一個指令或指令別名。 op ::= 邏輯的 ! 否定運算元。
主機別名節區格式: Host_Alias 主機別名 = 主機列表
Host_Alias ::= 這是一個關鍵字。 主機別名 ::= 一個大寫的別名。 主機列表 ::= 以逗號間隔的一些主機名稱。
指令別名節區格式: Cmnd_Alias 指令別名 = 指令列表
Cmnd_Alias ::= 這是一個關鍵字。 指令別名 ::= 一個大寫的別名。 指令列表 ::= 以逗號間隔的一些指令。
所有在 # 符號後面的文字都會被當作是注解。 太長的行可以使用倒斜線 字元來分成新的行。 保留的別名 ALL 在 {Host,Cmnd}_Alias 里都可以使用。 不要用 ALL 來定義一個別名,這個別名無效。 注意到 ALL 暗示全部的主機跟指令。 你可以使用這個語法從整個范圍中減掉一些項目:
user host=ALL,!ALIAS1,!/etc/halt...
范例
# Host alias specification Host_Alias HUB=houdini.rootgroup.com: REMOTE=merlin,kodiakthorn,spirit Host_Alias MACHINES=kalkan,alpo,milkbones Host_Alias SERVERS=houdini,merlin,kodiakthorn,spirit
# Command alias specification Cmnd_Alias LPCS=/usr/etc/lpc,/usr/ucb/lprm Cmnd_Alias SHELLS=/bin/sh,/bin/csh,/bin/tcsh Cmnd_Alias MISC=/bin/rm,/bin/cat: SHUTDOWN=/etc/halt,/etc/shutdown
# User specification britt REMOTE=SHUTDOWN:ALL=LPCS robh ALL=ALL,!SHELLS nieusma SERVERS=SHUTDOWN,/etc/reboot: HUB=ALL,!SHELLS jill houdini.rootgroup.com=/etc/shutdown,MISC markm HUB=ALL,!MISC,!/etc/shutdown,!/etc/halt billp ALL=/usr/local/bin/top:MACHINES=SHELLS davehieb merlin=ALL:SERVERS=/etc/halt: kodiakthorn=ALL
上面的 sudoers 說明檔案是由 4 個主機別名說明,4 個指令別名說明以及 7 個使用者說明所組成的。Britt 被允許在遠端機器 (merlin, kodiakthorn, 還有 spirit) 上執行 /etc/halt, /etc/shutdown, /usr/etc/lpc 以及/usr/ucb/lprm 。Rohn 被允許在任何機器上執行除了 SHELL 指令群以外的任何指令。Jill 被允許在 houdini 上執行 /etc/shotdown, /bin/rm, 以及/bin/cat 。Davehieb 可以在 merlin 以及 kodiakthorn 上執行任何指令并且可以 halt SERVERS 。
Sudoers 檔案應該用 visudo 指令編輯,它會鎖住該檔并且做文法檢查。這提供了一個可以避免愚蠢文法錯誤的機制。
Sudo 被設計成經由 4.3 BSD syslogging 來記錄,但是如果真的想要的話還是可以記錄到一個檔案來取代。
如果一個沒有被授權的使用者執行了 sudo 的話,將會有一封 mail 從該使用者寄送到當地的授權者處(在安裝的時候定義的)。
所有的設定都是在安裝的時后定義的,從 sudo.h 含入檔及 Makefile 取得。
未來加強
允許巢狀的主機以及指令別名。 允許在 sudoers 檔案中使用 host specifier 以便使用全區符號 (user ALL,!SERVERS, ... = commands) 。 允許在 sudores 檔案里的使用者別名(就如同主機/指令別名一樣)。 使 visudo 對 sudoers 檔案做更廣泛的檢查。
檔案
/etc/sudoers 經授權的使用者檔案。 /etc/stmp visudo 的 lock file 。 /usr/local/bin/sudo sudo 的執行檔。 /usr/local/etc/visudo 修改 sudoers 檔案的工具。
|
|
posted @
2006-06-08 12:57 MyJavaWorld 閱讀(328) |
評論 (0) |
編輯 收藏
Struts的Token(令牌)機制能夠很好的解決表單重復提交的問題,基本原理是:服務器端在處理到達的請求之前,會將請求中包含的令牌值與保存在當前用戶會話中的令牌值進行比較,看是否匹配。在處理完該請求后,且在答復發送給客戶端之前,將會產生一個新的令牌,該令牌除傳給客戶端以外,也會將用戶會話中保存的舊的令牌進行替換。這樣如果用戶回退到剛才的提交頁面并再次提交的話,客戶端傳過來的令牌就和服務器端的令牌不一致,從而有效地防止了重復提交的發生。
這時其實也就是兩點,第一:你需要在請求中有這個令牌值,請求中的令牌值如何保存,其實就和我們平時在頁面中保存一些信息是一樣的,通過隱藏字段來保存,保存的形式如: 〈input type="hidden" name="org.apache.struts.taglib.html.TOKEN" value="6aa35341f25184fd996c4c918255c3ae"〉,這個value是TokenProcessor類中的generateToken()獲得的,是根據當前用戶的session id和當前時間的long值來計算的。第二:在客戶端提交后,我們要根據判斷在請求中包含的值是否和服務器的令牌一致,因為服務器每次提交都會生成新的Token,所以,如果是重復提交,客戶端的Token值和服務器端的Token值就會不一致。下面就以在數據庫中插入一條數據來說明如何防止重復提交。
在Action中的add方法中,我們需要將Token值明確的要求保存在頁面中,只需增加一條語句:saveToken(request);,如下所示:
public ActionForward add(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response)
//前面的處理省略
saveToken(request);
return mapping.findForward("add");
}在Action的insert方法中,我們根據表單中的Token值與服務器端的Token值比較,如下所示:
public ActionForward insert(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response)
if (isTokenValid(request, true)) {
// 表單不是重復提交
//這里是保存數據的代碼
} else {
//表單重復提交
saveToken(request);
//其它的處理代碼
}
}
222222222222222222222222222222222222222222222222222222222222222222222
1。重復提交、重復刷新的場景
重復提交、重復刷新都是來解決系統重復記錄的問題。也就是說某個人在多次的提交某條記錄(為什么?也許是閑了沒有事情干的;最有可能是用戶根本就不知道自己的提交結果是否已經執行了?!)。
但出現了這樣的問題并不見得就必須處理,要看你所開發的系統的類別而定。比如你接手的是某個資源管理系統,系統本身從需求的角度根本就不允許出現"重復"的記錄,在這樣需求的約束條件下,去執行重復的提交動作只會引發“業務級異常”的產生,根本就不可能執行成功也就無所謂避免不避免的問題了。
?
2。防止后退的場景
了解了重復刷新、重復提交的場景,我們來了解一下"防止后退"操作的原因是什么?比如你在開發某個投票系統,它有很多的步驟,并且這些步驟之間是有聯系的,比如第一步會將某些信息發送給第二步,第二步緩存了這些信息,同時將自身的信息發送給了第三步。。。。。等等,如果此時用戶處在第三步驟下,我們想象一下某個淘氣用戶的用戶點擊了后退按鈕,此時屏幕出現了第二步驟的頁面,他再次的修改或者再次的提交,進入到下一個步驟(也就是第三步驟),錯誤就會在此產生?!什么錯誤呢?最為典型的就是這樣的操作直接導致了對于第一個步驟信息的丟失!(如果這樣的信息是依靠Request存放的話,當然你可以存放在Session或者更大的上下文環境中,但這不是個好主意!關于信息存放的問題,下次在就這個問題詳細的討論)
三。如何處理的問題
當然很多的系統(比如訂票系統從需求上本身是允許個人重復訂票的)是必須要避免重復刷新、重復提交、以及防止后退的問題的,但即使是這樣的問題,也要區分如何處理以及在哪里處理的(網上只是告訴你如何處理,但很少去區分在哪里處理的),顯然處理的方式無非是客戶端或者服務器端兩種,而面對不同的位置處理的方式也是不同的,但有一點要事先聲明:任何客戶端(尤其是B/S端)的處理都是不可信任的,最好的也是最應該的是服務器端的處理方法。
客戶端處理:
面對客戶端我們可以使用Javascript腳本來解決,如下
1。重復刷新、重復提交
Ways One:設置一個變量,只允許提交一次。
<script language="javascript">
??? var checkSubmit*** = false;
??? function checkSubmit() {
????? if (checkSubmit*** == true) {
???????? return false;
????? }
????? checkSubmit*** = true;
????? return true;
?? }
?? document.ondblclick = function docondblclick() {
??? window.event.returnValue = false;
?? }
?? document.onclick = function doconclick() {
?????? if (checkSubmit***) {
???????? window.event.returnValue = false;
?????? }
?? }
</script>
<html:form action="myAction.do" method="post" onsubmit="return checkSubmit();">
Way Two : 將提交按鈕或者image置為disable
? <html:form action="myAction.do" method="post"?
??? onsubmit="getElById('submitInput').disabled = true; return true;">??
? <html:image styleId="submitInput" src="images/ok_b.gif" border="0" />
? </html:form>?
2。防止用戶后退
這里的方法是千姿百態,有的是更改瀏覽器的歷史紀錄的,比如使用window.history.forward()方法;有的是“用新頁面的URL替換當前的歷史紀錄,這樣瀏覽歷史記錄中就只有一個頁面,后退按鈕永遠不會變為可用。”比如使用javascript:location.replace(this.href); event.returnValue=false;
2.服務器端的處理(這里只說Struts框架的處理)
利用同步令牌(Token)機制來解決Web應用中重復提交的問題,Struts也給出了一個參考實現。
基本原理:
服務器端在處理到達的請求之前,會將請求中包含的令牌值與保存在當前用戶會話中的令牌值進行比較,
看是否匹配。在處理完該請求后,且在答復發送給客戶端之前,將會產生一個新的令牌,該令牌除傳給
客戶端以外,也會將用戶會話中保存的舊的令牌進行替換。這樣如果用戶回退到剛才的提交頁面并再次
提交的話,客戶端傳過來的令牌就和服務器端的令牌不一致,從而有效地防止了重復提交的發生。
if (isTokenValid(request, true)) {
??? // your code here
??? return mapping.findForward("success");
} else {
??? saveToken(request);
??? return mapping.findForward("submitagain");
}
Struts根據用戶會話ID和當前系統時間來生成一個唯一(對于每個會話)令牌的,具體實現可以參考
TokenProcessor類中的generateToken()方法。
1. //驗證事務控制令牌,<html:form >會自動根據session中標識生成一個隱含input代表令牌,防止兩次提交
2. 在action中:
?????? //<input type="hidden" name="org.apache.struts.taglib.html.TOKEN"?
?????? //? value="6aa35341f25184fd996c4c918255c3ae">
?????? if (!isTokenValid(request))
?????????? errors.add(ActionErrors.GLOBAL_ERROR,
????????????????????? new ActionError("error.transaction.token"));
?????? resetToken(request); //刪除session中的令牌
3. action有這樣的一個方法生成令牌
?? protected String generateToken(HttpServletRequest request) {
?????? HttpSession session = request.getSession();
?????? try {
?????????? byte id[] = session.getId().getBytes();
?????????? byte now[] =
?????????????? new Long(System.currentTimeMillis()).toString().getBytes();
?????????? MessageDigest md = MessageDigest.getInstance("MD5");
?????????? md.update(id);
?????????? md.update(now);
?????????? return (toHex(md.digest()));
?????? } catch (IllegalStateException e) {
?????????? return (null);
?????? } catch (NoSuchAlgorithmException e) {
?????????? return (null);
?????? }
?? }?
總結
對于重復提交、重復刷新、防止后退等等都是屬于系統為避免重復記錄而需要解決的問題,在客戶端去處理需要針對每一種的可能提出相應的解決方案,然而在服務器端看來只不過是對于數據真實性的檢驗問題,基于令牌的處理就是一勞永逸的方法。
同時我們也看到,從不同的角度去看待問題,其解決的方法也是不同的。客戶端更追求的是用戶的操作,而服務端則將注意力放在了數據的處理上,所以在某個對于服務器端看似容易的問題上,用客戶端來解決卻麻煩了很多!反之依然。所以在某些問題的處理上我們需要綜合考慮和平衡,是用客戶端來解決?還是用服務器端來處理
posted @
2006-06-02 18:15 MyJavaWorld 閱讀(3258) |
評論 (4) |
編輯 收藏