??xml version="1.0" encoding="utf-8" standalone="yes"?> 2、 在《Programming Jakarta Struts》这本书中的W四?#8220;Configuring the Struts Application”中这样一D说明来分别阐述q两 ++++++++ 最初看q些真的q是不好区分q两者。不q在仔细看过struts的源代码以后Q豁然开朗。。?/p>
下面主要对attributeq行解释Q应为没有h会对name属性不了解的(呵呵。。。) /** /** public String getAttribute() { public void setAttribute(String attribute) { Q?QHttpServletRequestcLsetAttribute()ҎQ而没有setParameter()Ҏ Q?Q当两个Weblg之间为链接关pLQ被链接的组仉过getParameter()Ҏ来获得请求参敎ͼ例如假定welcome.jsp和authenticate.jsp之间为链接关p,welcome.jsp中有以下代码Q?br />
Q?Q当两个Weblg之间{发关pLQ{发目标组仉过getAttribute()Ҏ来和转发源组件共享request范围内的数据?/p>
假定 authenticate.jsp和hello.jsp之间{发关pRauthenticate.jsp希望向hello.jsp传递当前的用户名字Q? 如何传递这一数据呢?先在authenticate.jsp中调用setAttribute()ҎQ?br />
request.setAttribute()和getAttribute()只是在web容器内部{Q仅仅是h处理阶段?/p>
getAttribute是返回对?getParameterq回字符?br />
所以,是否配置attribute属性就军_了actionForm存储在scope中的key值是采用nameQ还是采用attribute
个属性:(102?
++++++++
atribute:
++++++++
The name of the request or session scope attribute under which the form bean for this action can be accessed.
A value is only allowed here if there is a form bean specified in the name attribute. This attribute is
optional and has no default value.
name:
++++++++
The name of the form bean, if any, that is associated with this action. This value must be the name attribute
from one of the form-bean elements defined earlier. This attribute is optional and has no default value.
解释Q在struts实例化actionform的时候,有两U情况:如果已经存在Q那么从内存中取回;如果W一ơ实例化Q那么创建,q放入内存?br />
q样有一个问题了Qstruts是根据什么来取回q创建actionform的呢Q答案就是attribute的倹{让我们q入struts的源代码Q?/p>
*创徏或者取回formbeanҎ
*该方法在Qorg.apache.struts.util.RequestUtils?br />
*/
public static Actionform createActionform(
HttpServletRequest request,
ActionMapping mapping,
ModuleConfig moduleConfig,
ActionServlet servlet) {
。。。?br />
。。?br />
// Is there a form bean associated with this mapping?
//得到action mapping中attribute的?br />
String attribute = mapping.getAttribute();
。。。?br />
。。。?br />
Actionform instance = null;
HttpSession session = null;
//yes!!在q里了,把创Z后的actionform攑֜request或者session里,看到攑օ的名字了么,是mapping.getAttribute();
if ("request".equals(mapping.getScope())) {
instance = (Actionform) request.getAttribute(attribute);
} else {
session = request.getSession();
instance = (Actionform) session.getAttribute(attribute);
}
。。?br />
。。?br />
}
下面又有一个问题Q出水面:如果我没有在action mapping中指定attribute呢,那struts 是如何解决的Q?br />
{案很简单,如果单从l果上看Q此时struts使用的name的|Z么呢Q看struts源代码:
* The request-scope or session-scope attribute name under which our
* form bean is accessed, if it is different from the form bean's
* specified <code>name</code>.
*该代码在Qorg.apache.struts.config.ActionConfig?br />
*/
protected String attribute = null;
//yes!!!!在q里Q看C吧,如果你没有设定attributeQ那么struts 会把name的值拿q来用。呵c。?br />
if (this.attribute == null) {
return (this.name);
} else {
return (this.attribute);
}
}
if (configured) {
throw new IllegalStateException("Configuration is frozen");
}
this.attribute = attribute;
}
]]>
<a href="authenticate.jsp?username=wolf">authenticate.jsp </a>
或者:
<form name="form1" method="post" action="authenticate.jsp">
误入用户姓名:<input type="text" name="username">
<input type="submit" name="Submit" value="提交">
</form>
在authenticate.jsp中通过request.getParameter("username")Ҏ来获得请求参数username:
<% String username=request.getParameter("username"); %>
<%
String username=request.getParameter("username");
request.setAttribute("username"Qusername);
%>
<jsp:forward page="hello.jsp" />
在hello.jsp中通过getAttribute()Ҏ获得用户名字:
<% String username=(String)request.getAttribute("username"); %>
Hello: <%=username %>
从更q层次考虑Qrequest.getParameter()Ҏ传递的数据Q会从Web客户端传到Web服务器端Q代表HTTPh数据。request.getParameter()Ҏq回Stringcd的数据?br />
request.setAttribute()和getAttribute()Ҏ传递的数据只会存在于Web容器内部Q在h转发关系的Weblg之间׃n。这两个Ҏ能够讄Objectcd的共享数据?br />
request.getParameter()取得是通过容器的实现来取得通过cMpostQget{方式传入的数据?/p>
ȝ来说Qrequest.getAttribute()Ҏq回request范围内存在的对象Q而request.getParameter()Ҏ是获取http提交q来的数据?/strong>
]]>
language="java"
contentType="text/html;charset=GBK"
%>
<html>
<head>
<title>MyHtml.html</title>
<meta http-equiv="content-type" content="text/html; charset=gbk">
<!--<link rel="stylesheet" type="text/css" href="./styles.css">-->
<script language="javascript">
function JM_PowerList(colNum)
{
headEventObject=event.srcElement;//取得引发事g的对?nbsp;
while(headEventObject.tagName!="TR") //不是tr?则从底下的td冒上来L到相应行
{
headEventObject=headEventObject.parentElement;
}
for (i=0;i<headEventObject.children.length;i++)
{ alert(headEventObject.children[i].tagName);
if (headEventObject.children[i]!=event.srcElement)//扑ֈ事g发生的td单元?nbsp;
{
headEventObject.children[i].className='listTableHead';//把点ȝ列的className属性设为listTableHead
}
}
var tableRows=0;
trObject=clearStart.children[0].children; //取得表格中行对象, 原来q里叫DataTable, 可能是你写错了吧??
for (i=0;i<trObject.length;i++)
{
Object=clearStart.children[0].children[i];//取得每行的对?nbsp;
tableRows=(trObject[i].id=='ignore')?tableRows:tableRows+1;//如果不是忽略?则行数加一
}
var trinnerHTML=new Array(tableRows);
var tdinnerHTML=new Array(tableRows);
var tdNumber=new Array(tableRows)
var i0=0
var i1=0
for (i=0;i<trObject.length;i++)
{
if (trObject[i].id!='ignore')
{
trinnerHTML[i0]=trObject[i].innerHTML;//把行攑֜数组?nbsp;
tdinnerHTML[i0]=trObject[i].children[colNum].innerHTML;//把要排序的行中td的内Ҏ数组?nbsp;
tdNumber[i0]=i;//行号
i0++;//加一,下个循环?nbsp;
}
}
sourceHTML=clearStart.children[0].outerHTML;//取得表格中所有tr的html代码
//Ҏ有td中的字符串进行排? 不冒泡排???
for (bi=0;bi<tableRows;bi++)
{
for (i=0;i<tableRows;i++)
{
if(tdinnerHTML[i]>tdinnerHTML[i+1])
{
t_s=tdNumber[i+1];
t_b=tdNumber[i];
tdNumber[i+1]=t_b;
tdNumber[i]=t_s;
temp_small=tdinnerHTML[i+1];
temp_big=tdinnerHTML[i];
tdinnerHTML[i+1]=temp_big;
tdinnerHTML[i]=temp_small;
}
}
}
var showshow='';
var numshow='';
for (i=0;i<tableRows;i++)
{
showshow=showshow+tdinnerHTML[i]+' ';//把排序好的td的内容存在showshow字串?nbsp;
numshow=numshow+tdNumber[i]+'|'; //把排序好的相应的行号也存在numshow?nbsp;
}
sourceHTML_head=sourceHTML.split("<TBODY>");//?lt;TBODY>截断,我试?前头串ؓI?nbsp;
numshow=numshow.split("|");
var trRebuildHTML='';
if (event.srcElement.className=='listHeadClicked')
{//已点ȝ? 则逆排
for (i=0;i<tableRows;i++)
{
trRebuildHTML=trRebuildHTML+trObject[numshow[tableRows-1-i]].outerHTML;//取出排序好的tr的内容连接v?nbsp;
}
event.srcElement.className='listHeadClicked0';
}
else
{//默认排,新点击顺?nbsp;
for (i=0;i<tableRows;i++)
{
trRebuildHTML=trRebuildHTML+trObject[numshow[i]].outerHTML;
}
event.srcElement.className='listHeadClicked';
}
//取得排序后的tr集合l果字符?nbsp;
var DataRebuildTable='';
//把旧的表格头和新的tr排序好的元素q接h, (修改了一?
DataRebuildTable = "<table border=1 width=100% cellpadding=1 cellspacing=1 id='clearStart'><TBODY>"
+ trObject[0].outerHTML + trRebuildHTML + "</TBODY>" + "</table>";
clearStart.outerHTML=DataRebuildTable;//表格用新串重新写一?nbsp;
}
</script>
</head>
<table border=1 id="clearStart">
<tr bgcolor=cccccc id='ignore'>
<td onclick="JM_PowerList(0)">列一
</td>
<td onclick="JM_PowerList(1)">
列二
</td>
<td onclick="JM_PowerList(2)">
列二
</td>
</tr>
<tr>
<td>
?br />
</td>
<td>
公务?br />
</td>
<td>
22
</td>
</tr>
<tr>
<td>
张三
</td>
<td>
研究?br />
</td>
<td>
65
</td>
</tr>
<tr>
<td>
李?br />
</td>
<td>
U学?br />
</td>
<td>
24
</td>
</tr>
<tr>
<td>
王武
</td>
<td>
C会学家
</td>
<td>
38
</td>
</tr>
</table>
</body></html>
<SCRIPT LANGUAGE="JavaScript">
<!--
var xPos = 20;
var yPos = document.body.clientHeight;
var step = 1;
var delay = 30;
var height = 0;
var Hoffset = 0;
var Woffset = 0;
var yon = 0;
var xon = 0;
var pause = true;
var interval;
img.style.top = yPos;
function changePos() {
width = document.body.clientWidth;
height = document.body.clientHeight;
Hoffset = img.offsetHeight;
Woffset = img.offsetWidth;
img.style.left = xPos + document.body.scrollLeft;
img.style.top = yPos + document.body.scrollTop;
if (yon) {
yPos = yPos + step;
}
else {
yPos = yPos - step;
}
if (yPos < 0) {
yon = 1;
yPos = 0;
}
if (yPos >= (height - Hoffset)) {
yon = 0;
yPos = (height - Hoffset);
}
if (xon) {
xPos = xPos + step;
}
else {
xPos = xPos - step;
}
if (xPos < 0) {
xon = 1;
xPos = 0;
}
if (xPos >= (width - Woffset)) {
xon = 0;
xPos = (width - Woffset);
}
}
function www_helpor_net() {
img.visibility = "visible";
interval = setInterval('changePos()', delay);
}
www_helpor_net();
//For more,visit:www.helpor.net
-->
</script>
<INPUT type="button" value="Button" id=button1 name=button1 disabled>
<INPUT type="text" id=text1 name=text1 readonly>
<INPUT type="hidden" value="Button" id=button1 name=button1 >
<INPUT type="text" id=text1 name=text1 style="visibility:hidden">
<INPUT type="button" value="Button" id=button1 name=button1 style="visibility:hidden">
可以在jsp中做如下控制Q?br />
<INPUT TYPE="button" NAME="xzdq" value="<<" onClick="selectDept()" >
<script language="javascript">
if('<%=userId%>'!= null)document.all.xzdq.style.visibility="hidden";
</script>
或者:
<INPUT TYPE="button" NAME="xzdq" value="<<" onClick="selectDept()" >
<%
if(userId != null)
{
%>
<script language="javascript">
document.all.xzdq.style.visibility="hidden";
</script>
<%
}
%>
或者:
<INPUT TYPE="button" NAME="xzdq" value="<<" onClick="selectDept()" >
<%
if(userId != null)
out.println("<script language=\"javascript\"> document.all.xzdq.style.visibility=\"hidden\";</script>");
%>
使用WinZip或WinRAR{解压羃工具jakarta-tomcat-5.5.7.zip解压到指定的驱动器和目录中。笔者是在D盘上直接解压Q生了目录jakarta-tomcat-5.5.7Q解压后的文件存放于D:\ jakarta-tomcat-5.5.7下?/font>
Tomcat安装后的目录层次l构如图5-2所C?/font>
?-2 Tomcat 5.5.7目录层次l构
各目录的用途如?-1所C?/font>
?-1 Tomcat的目录结构及其用?/font>
?/sup> ?/sup> |
?/sup> ?/sup> |
/bin |
存放启动和关?/sup>Tomcat的脚本文?/sup> |
/common/lib |
存放Tomcat服务器及所?/sup>Web应用E序都可以访问的JAR文g |
/conf |
存放Tomcat服务器的各种配置文gQ其中包?/sup>server.xmlQ?/sup>Tomcat的主要配|文Ӟ?/sup>tomcat-users.xml?/sup>web.xml{配|文?/sup> |
/logs |
存放Tomcat的日志文?/sup> |
/server/lib |
存放Tomcat服务器运行所需的各U?/sup>JAR文g |
/server/webapps |
存放Tomcat的两?/sup>Web应用E序Q?/sup>admin应用E序?/sup>manager应用E序 |
/shared/lib |
存放所?/sup>Web应用E序都可以访问的JAR文g |
/temp |
存放Tomcatq行时生的临时文g |
/webapps |
当发?/sup>Web应用E序Ӟ通常?/sup>Web应用E序的目录及文g攑ֈq个目录?/sup> |
/work |
Tomcat?/sup>JSP生成?/sup>Servlet源文件和字节码文件放到这个目录下 |
从表5-1中可以看刎ͼ/common/lib目录?server/lib?shared/lib目录下都可以存放JAR文gQ它们的区别在于Q?/font>
??server/lib目录下的JAR文g只能被Tomcat服务器访问;
??shared/lib目录下的JAR文g可以被所有的Web应用E序讉KQ但不能被Tomcat服务器访问;
??common/lib目录下的JAR文g可以被Tomcat服务器和所有的Web应用E序讉K?/font>
此外Q对于后面将要介l的Java Web应用E序Q在它的WEB-INF目录下,也可以徏立lib子目录,在lib子目录下可以存放各种JAR文gQ这些JAR文g只能被当前Web应用E序所讉K?/font>
在Tomcat安装目录下的bin子目录中Q有一些批处理文gQ以.bat作ؓ后缀名的文gQ,其中的startup.bat是启动Tomcat的脚本文Ӟ用鼠标双击这个文Ӟ会看到如图5-3所C的画面?/font>
?-3 q行Tomcat提示出错信息
W者以前碰到过很多学员Q在初次q行TomcatӞ看到如图5-3所C的信息׃知所措了。有的学员以前还配置qTomcatQ但是再ơ用的时候,׃忘记了上ơ是如何配置的,同样感觉无从下手?/font>
我们在学习Y件开发时Q一定要L查看错误提示信息Q进而根据错误提C决问题的良好习惯。笔者第一ơ配|TomcatӞ是Ҏ错误提示信息一步一步配|成功的。很多h一看见错误信息Q立卛_?#8220;定”按钮Q这样就错过了提CZ息。当看到错误信息Ӟ首先不要慌张和无所适从Q仔l看清楚错误提示Q不要着急单L钮?/font>
查看?-3中的错误提示信息Q可以看到这样一句话“The JAVA_HOME environment variable is not defined”Q从画面中可以看刎ͼ在执行到“Using JAVA_HOME”q句时出C错误Q由此,我们可以惛_Q出错的原因可能是因为没有设|JAVA_HOME环境变量。那么JAVA_HOME环境变量的值应该是什么呢Q很Ҏp惛_应该是JDK所在的目录Q在W者的机器上,JDK所在的目录是D:\Java\jdk1.5.0_01?/font>
在Windows 2000操作pȝ下设|环境变量的步骤如下?/font>
?在桌?#8220;我的电脑”上单d键,选择“属?#8221;Q出现如?-4所C的画面?/font>
?-4 “我的电脑”属?/font>
?单击“高”选项卡,选择“环境变量(E)…”Q如?-5和图5-6所C?/font>
?-5 “高”选项??-6 “环境变量”对话?/font>
??#8220;pȝ变量”下方单击“新徏”按钮。在“变量?#8221;中输?#8220;JAVA_HOME”Q在变量g输入JDK所在的目录“D:\Java\jdk1.5.0_01”Q然后单?#8220;定”按钮Q如?-7所C?/font>
?-7 新徏JAVA_HOME环境变量
?最后在“环境变量”对话框上单击“定”按钮Q结束JAVA_HOME环境变量的设|?/font>
我们再一ơ{到D:\ jakarta-tomcat-5.5.7\bin目录下,用鼠标双击startup.bat文gQ可以看到如?-8所C的启动信息?/font>
?-8 Tomcat启动信息
然后Q打开览器,在地址栏中输入http://localhost:8080/Qlocalhost表示本地机器Q?080是Tomcat默认监听的端口号Q,出现如?-9所C的Tomcat面?/font>
?-9 Tomcat的默认主?/font>
注意?-9中鼠标(手形状Q指向的链接——Tomcat DocumentationQ单dq入Tomcat的文档页面,有关Tomcat的帮助信息可以在文档面中找刎ͼ读者也可以直接讉KTomcat的文档,文档首页的位|是Tomcat安装目录下的webapps\tomcat-docs\index.html。如果要关闭Tomcat服务器,可以用鼠标双击D:\ jakarta-tomcat-5.5.7\bin目录下的shutdown.bat文g?/font>
如果你机器上的Tomcat启动p|Q有可能是因为TCP?080端口被其他应用程序所占用Q如果你知道是哪一个应用程序占用了8080端口Q那么先关闭此程序。如果你不知道或者不惛_闭占?080端口的应用程序,你可以修改Tomcat默认监听的端口号?/font>
前面介绍了,Tomcat安装目录下的conf子目录用于存放Tomcat服务器的各种配置文gQ其中的server.xml是Tomcat的主要配|文Ӟq是一个格式良好的XML文档Q在q个文g中可以修改Tomcat默认监听的端口号。用UltraEditQ你可以用记事本E序或其他的文本~辑工具Q打开server.xmlQ找C?080端口的地斏V读者也许要问了Q?#8220;q个配置文gQ我都不熟悉Q怎么知道在哪里修改端口号呢?”对于初次接触server.xml的读者,实不了解这个文件的l构Q但是我们应该有一U开攄思\Q既然Tomcat的监听端口号是在server.xml中配|,那么只要我们在这个文件中查找“8080”q些数字字符序列Q不p扑ֈ修改端口L地方了吗Q在UltraEdit中,同时按下键盘上的“Ctrl”?#8220;F”键,出现如图5-10所C的查找对话框?/font>
?-10 UltraEdit查找对话?/font>
然后?#8220;查找内容”中输?#8220;8080”Q单?#8220;查找下一?#8221;按钮。重复这个过E,直到扑ֈ如图5-11所C的在server.xml中配|端口号位置?/font>
?-11 server.xml中配|端口号的位|?/font>
扑ֈ后,如果我们不能定此处是修改端口L地方Q也没有关系Q可以先试着修改一下端口号Q然后启动TomcatQ如果启动成功,也就证明了我们修改的地方是正的。学习时Q我们应该养成这U探索ƈ不断实验的精。在q里Q我们可以修改端口号?000Q读者可以根据自己机器的配置选择一个端口号Q,然后保存。再ơ启动TomcatQ在Tomcat启动完毕后,打开览器,在地址栏中输入http://localhost:8000/Q读者根据自p|的端口号做相应的修改)Q就可以看到Tomcat的默认主了。关闭Tomcat服务器时Q执行bin目录下的shutdown.bat文g?/font>
在本节中我们通过对Tomcat启动q程的分析,来帮助读者更好地理解和掌握Tomcat?/font>
用文本编辑工h开用于启动Tomcat的批处理文gstartup.batQ仔l阅读,可以发现Q在q个文g中,首先判断CATALINA_HOME环境变量是否为空Q如果ؓI,将当前目录设ؓCATALINA_HOME的|接着判断当前目录下是否存在bin\catalina.batQ如果文件不存在Q将当前目录的父目录设ؓCATALINA_HOME的|ҎW者机器上Tomcat安装目录的层ơ结构,最后CATALINA_HOME的D设ؓTomcat的安装目录。如果环境变量CATALINA_HOME已经存在Q则通过q个环境变量调用bin目录下的“catalina.bat start”命o。通过q段分析Q我们了解到两个信息Q一是Tomcat启动Ӟ需要查找CATALINA_HOMEq个环境变量Q如果在当前目录下调用startup.batQTomcat会自动设|CATALINA_HOMEQ二是执行startup.bat命oQ实际上执行的是“catalina.bat start”命o?/font>
如果我们不是在bin目录作ؓ当前目录时调用startup.batQ就会出现如?-12所C的错误信息Q在bin目录的父目录下调用除外)?/font>
?-12 在其他目录下启动Tomcat出错
要在其他目录下也能启动TomcatQ就需要设|CATALINA_HOME环境变量Q你可以CATALINA_HOMEd到Windows 2000pȝ的环境变量中Q其值就是Tomcat的安装目录,在笔者的机器上安装目录是D:\jakarta-tomcat-5.5.7Q添加环境变量的q程和前q添加JAVA_HOME环境变量的过E是一L。如果你不想在系l的环境变量中添加,也可以直接在startup.bat文g中进行设|。下面是在startup.bat文g中设|CATALINA_HOME后的文g片段Q?/font>
……
rem $Id: shutdown.bat,v 1.5 2004/05/27 15:05:01 yoavs Exp $
rem ---------------------------------------------------------------------------
set CATALINA_HOME=D:\jakarta-tomcat-5.5.7
rem Guess CATALINA_HOME if not defined
set CURRENT_DIR=%cd%
if not "%CATALINA_HOME%" == "" goto gotHome
set CATALINA_HOME=%CURRENT_DIR%
……
注意以粗体显C的q句话的作用是讄CATALINA_HOME环境变量。在它的下面可以判断CATALINA_HOME是否为空了。如果你找不准位|,q脆设|CATALINA_HOME环境变量的这句话攄到文件的W一行。JAVA_HOME环境变量也可以采用同L方式q行讄。不q,如果你要在其他目录下Q利用shutdown.bat来关闭Tomcat服务器,你也需要在shutdown.bat文g中设|CATALINA_HOME和JAVA_HOMEq两个环境变量,讄变量的位|和startup.bat文g一P都是在判断CATALINA_HOME是否为空之前。当ӞZ一x逸,避免重装Tomcat后还要进行设|(需要是同一版本的Tomcat安装在同一位置Q,我们最好还是将CATALINA_HOME和JAVA_HOMEq两个环境变量添加到Windows 2000pȝ的环境变量中?/font>
有的读者可能会对设|Tomcat安装目录的环境变量的名字是CATALINA_HOME而感到奇怪,按照以前讄的环境变量来看,JAVA_HOME表示JDK的安装目录,那么应该用TOMCAT_HOME来表CTomcat的安装目录,可ؓ什么要使用CATALINA_HOME呢?实际上,在Tomcat 4以前Q用的就是TOMCAT_HOME来表CTomcat的安装目录,在Tomcat 4以后Q采用了新的Servlet容器CatalinaQ所以环境变量的名字也改ZCATALINA_HOME?/font>
提示Q在Windowspȝ下环境变量的名字是与大小写无关的Q也是说JAVA_HOME和java_home是相同的?/font>
了解了startup.bat文g以后Q我们再来看看真正负责启动Tomcat服务器的catalina.bat文g。通过分析catalina.bat文gQ我们发现它q调用了一个文件setclasspath.bat。在setclasspath.bat文g中,它检查JAVA_HOME环境变量是否存在Qƈ通过讄的环境变量JAVA_HOMEQ找到java.exeQ用于启动Tomcat。在q个文g中,q设|了其他的一些变量,分别表示JDK中的一些工P有兴的读者可以自行分析一下这个文件。在执行完setclasspath.bat之后Qcatalina.bat剩下的部分就开始了Tomcat服务器的启动q程?/font>
直接执行catalina.batӞ需要带上命令行的参数。读者可以在命o提示W窗口下Q执行catalina.batQ就会打印出catalina.bat命o的各U参数及其含义,如图5-13所C?/font>
?-13 catalina.bat的各参数信息
其中常用的参数是start、run和stopQ参数start表示在一个单独的H口中启动Tomcat服务器,参数run表示在当前窗口中启动Tomcat服务器,参数stop表示关闭Tomcat服务器。我们执行startup.batQ实际上执行的就?#8220;catalina.bat start”命oQ执行shutdown.batQ实际上执行的是“catalina.bat stop”命o?#8220;catalina.bat run”命o有时候是非常有用的,特别是当我们需要查看Tomcat的出错信息时。我们在开发JSPE序Ӟl常会碰到自己机器上?080端口可别的应用E序占用Q或者在配置server.xml时出现错误,当通过startup.batQ相当于执行“catalina.bat start”Q启动Tomcat服务器时Q会D启动p|Q因为是在单独的H口中启动Tomcat服务器,所以一旦启动失败,命o提示W窗口就自动关闭了,E序q行中输出的出错信息也随之消失,而且没有M的日志信息,q就使得我们没有办法扑և错误原因?strong style="color: #0000ff">当出现错误时Q我们可以换?#8220;catalina.bat run”命o再次启动Q一旦启动失败,仅仅是Tomcat服务器异常终止,但是在当前的命o提示W窗口下仍然保留了启动时的出错信息,q样我们可以查扑动失败的原因?/strong>?br />
Tomcat的体pȝ?/strong>
Tomcat服务器是׃pd可配|的lg构成的,其中核心lg是Catalina Servlet容器Q它是所有其他Tomcatlg的顶层容器。Tomcat各组件之间的层次关系如图5-14所C?/font>
?-14 Tomcatlg之间的层ơ结?/font>
我们下面单介l一下各lg在Tomcat服务器中的作用?/font>
Server表示整个的Catalina Servlet容器。Tomcat提供了Server接口的一个默认实玎ͼq通常不需要用戯己去实现。在Server容器中,可以包含一个或多个Servicelg?/font>
Service是存zdServer中的内部lgQ它一个或多个q接器(ConnectorQ组件绑定到一个单独的引擎QEngineQ上。在Server中,可以包含一个或多个Servicelg。Service也很由用户定制QTomcat提供了Service接口的默认实玎ͼ而这U实现既单又能满_用?
q接器(ConnectorQ处理与客户端的通信Q它负责接收客户hQ以及向客户q回响应l果。在Tomcat中,有多个连接器可以使用?/font>
在Tomcat中,每个Service只能包含一个Servlet引擎QEngineQ。引擎表CZ个特定的Service的请求处理流水线。作Z个Service可以有多个连接器Q引擎从q接器接收和处理所有的hQ将响应q回l适合的连接器Q通过q接器传输给用户。用户可以通过实现Engine接口提供自定义的引擎Q但通常不需要这么做?/font>
Host表示一个虚拟主机,一个引擎可以包含多个Host。用户通常不需要创定义的HostQ因为Tomcatl出的Host接口的实玎ͼcStandardHostQ提供了重要的附加功能?/font>
一个Contex表示了一个Web应用E序Q运行在特定的虚拟主Z。什么是Web应用E序呢?在Sun公司发布的Java Servlet规范中,对Web应用E序做出了如下的定义Q?#8220;一个Web应用E序是由一lServlet、HTML面、类Q以及其他的资源l成的运行在Web服务器上的完整的应用E序。它可以在多个供应商提供的实CServlet规范的Web容器中运?#8221;。一个Host可以包含多个ContextQ代表Web应用E序Q,每一个Context都有一个惟一的\径。用户通常不需要创定义的ContextQ因为Tomcatl出的Context接口的实玎ͼcStandardContextQ提供了重要的附加功能?/font>
下面我们通过?-15来帮助读者更好地理解Tomcat服务器中各组件的工作程?br />
?-15 Tomcat各组件的工作程
要了解这些组件的其他信息Q可以看下面的页面:
%CATALINA_HOME%\webapps\tomcat-docs\architecture\index.html
我们可以在conf目录下的server.xml文g中对q些lgq行配置Q读者打开server.xml文gQ就可以看到元素名和元素之间的嵌套关p,与Tomcat服务器的lg是一一对应的,server.xml文g的根元素是server。关于server.xml配置文g中的各元素及其属性的含义Q请参见附录C?/font>
在Tomcat中,提供了各lg的接口及其实现类Q如果你要替代Tomcat中的某个lgQ只需要根据该lg的接口或cȝ说明Q重写该lgQƈq行配置卛_。图5-16是Tomcat各组件的cd?/font>
在类囄接口名或cd下面是该接口或该cL在的包,q些接口和类都在%CATALINA_HOME%\ server\lib\catalina.jar文g中。对Tomcat服务器的实现感兴的读者,可以从http://tomcat.apache.org/上下载Tomcat的源代码?br />
提示Q由于Apache软g基金会ƈ不是一个商业性的l织Q所以文档更新的速度有时候跟不上版本更新的速度。在Tomcat 5.5.7中,可以发现文档与其源码实现有不一致的地方。在Tomcat 5.5.x中,L了org.apache.catalina.Connector接口及其相关的实现类Q而直接以org.apache.catalina.connector.ConnectorcL代替。我们在看Tomcat的文档时Q最好结合其API文档一LQ这h能保证了解的信息是完整的和准的?br />
Tomcat提供了两个管理程序:admin和manager。其中admin用于理和配|Tomcat服务器,manager用于理部v到Tomcat服务器中的Web应用E序?/font>
admin Web应用E序需要单独下载,与Tomcat在同一个下载页面,链接名是Admin zipQ下载后的文件名是jakarta-tomcat-5.5.7-admin.zipQ解压羃后,覆盖Tomcat安装目录下的同名目录。admin Web应用E序位于%CATALINA_HOME%\server\webapps\admin目录下?/font>
要访问admin Web应用E序Q需要添加具有管理员权限的̎P~辑%CATALINA_HOME%\ conf\tomcat-users.xml文gQ在<tomcat-users>元素中添加如下内容:
<user username="admin" password="12345678" roles="admin"/>
其中用户名和密码可以Ҏ自己的喜好设|?/font>
启动Tomcat服务器,打开览器,在地址栏中输入Q?/font>
http://localhost:8080/admin/
出现如?-17所C的面?/font>
?-17 admin Web应用E序的登录界?/font>
也可以在Tomcat的默认主늚左上方单?#8220;Tomcat Administration”链接Q进入admind面。输入用户名adminQ密?2345678Q单?#8220;Login”按钮Q将看到如图5-18所C的面?/font>
?-18 admin Web应用E序的主面
在这个页面中Q可以进行Tomcat服务器的各项配置?/font>
manager Web应用E序包含在Tomcat的安装包中。和adminE序一P需要添加访问manager Web应用E序的管理员账号Q编?CATALINA_HOME%\conf\tomcat-users.xml文gQ在<tomcat-users>元素中添加如下内容:
<user username="manager" password="12345678" roles="manager"/>
其中用户名和密码可以Ҏ自己的喜好设|?/font>
启动Tomcat服务器,打开览器,在地址栏中输入Q?/font>
http://localhost:8080/manager/html/
出现如?-19所C的面?/font>
?-19 manager Web应用E序的登录界?/font>
也可以在Tomcat的默认主늚左上方单?#8220;Tomcat Manager”链接Q访问managerE序。输入用户名managerQ密?2345678Q单?#8220;定”按钮Q将看到如图5-20所C的面?/font>
?-20 manager Web应用E序的主面
在这个页面中Q你可以部v、启动、停止、重新加载、卸载Web应用E序。注意在两个圆角矩Ş框中的\?#8220;/jsp-examples”?#8220;/servlets-examples”Q单击这两个路径Q将看到Tomcat提供的JSP和Servlet的例子程序,q些E序可以作ؓ学习JSP和Servlet的参考。不q在q两个\径下Q只列出了部分的例子E序Q完整的JSP和Servlet例子E序位于下面的两个目录中Q?/font>
%CATALINA_HOME%\webapps\jsp-examples
%CATALINA_HOME%\webapps\servlets-examples
throw语句用在Ҏ体内,表示抛出异常,由方法体内的语句处理。不能单独用,要么和try catch一起用,要么和trows一起用?/span>
throws语句用在Ҏ声明后面,表示q个Ҏ可能?/span>抛出异常, 表示的是一U們、可能,但不一定实际发生?span style="color: #0000ff">p用这个方法的上一U方法中的语句来处理 。后面可以跟多个异常Q中间用逗号分割?/span>
例如Q?/span>
void doA() throws Exception1, Exception3 {
try {
……
} catch(Exception1 e) {
throw e;
} catch(Exception2 e) {
System.out.println("出错?/span>");
}
if (a != b)
throw new Exception3("自定义异?/span>");
}
代码?/span>……中可能生异?/span>Exception1?/span>Exception2?/span>Exception3?/span>
如果产生Exception1异常Q则捕捉了之后抛出由该方法的调用者去做处理;
如果产生Exception2异常Q则该方法自己做了处?/span>(打印Z说出错了)Q所以该Ҏ׃会再向外抛出Exception2异常了,void doA() throws Exception1,,Excpetion3里面?/span>Exception2也就不用写了Q?/span>
?/span>Exception3异常是该Ҏ的某D逻辑出错Q程序员自己作了处理在该D逻辑错误的情况下抛出异常Exception3Q则调用者也需要处理?/span>
关于JSP中的错误面处理
通常JSP 在执行时Q在两个阶段下会发生错误?/span>
JSP |页 → Servlet c?/span>
Servlet cd理每一个请求时
在第一阶段Ӟ产生的错误我们称?/span>Translation Time Processing ErrorsQ在W二阶段Ӟ产生的错误我们称?/span>Client Request Time Processing Errors。接下来我们针对q两个阶D生错误的原因和处理方法,q行介绍?/span>
1?/span> Translation Time Processing Errors
Translation Time Processing Errors 产生的主要原因:我们在撰?/span>JSP时的语法有错误,DJSP Container 无法?/span>JSP |页~译?/span>Servlet cL?/span>( .class)Q例如:500 Internal Server
ErrorQ?/span>500 是指HTTP 的错误状态码Q因此是Server Error?/span>
通常产生q种错误Ӟ可能?/span>JSP 的语法有错误Q或?/span>JSP Container 在一开始安装、设定时Q有不适当的情形发生。解决的Ҏ是再一ơ检查程序是否有写错的,不然也有可能?/span>JSPContainer ?/span>bug?/span>
2?/span> Client Request Time Processing Errors
Client Request Time Processing Errors 错误的发生,往往不是语法错误Q而可能是逻辑上的错误Q简单地_你写一个计除法的E序Q当用户输入的分母ؓ零时Q程序会发生错误q抛出异?/span>(Exception)Q交由异常处?/span>(Exception Handling)机制做适当的处理?/span>对于q种错误的处理,我们通常会交l?/span>errorPage d?/span>。下面D个例?/span>:
使用errorPage 的范例程?/span> Q?/span>ErrorPage.jsp
<%@ page contentType="text/html;charset=GB2312" errorPage="Error.jsp" %> //讄Error.jspؓ本页的错误处理页
<html>
<head>
<title>CH4 - ErrorPage.jsp</title>
</head>
<body>
<h2>errorPage 的范例程?/span></h2>
<%!
private double toDouble(String value)
{
return(Double.valueOf(value).doubleValue());
}
%>
<%
double num1 = toDouble(request.getParameter("num1"));
double num2 = toDouble(request.getParameter("num2"));
%>
您传入的两个数字为:<%= num1 %> ?/span> <%= num2 %><br>
两数相加?/span> <%= (num1+num2) %>
</body>
</html>
ErrorPage.jsp E序中,我们使用page 指o中的errorPage 属性,告诉JSP ContainerQ如果在E序中有错误产生Ӟ指的?/span>servletq行时生的错误或显C用throw抛出的异常)Q会自动交给Error.jsp 处理?/span>
Error.jsp
<%@ page contentType="text/html;charset=GB2312" isErrorPage="true" %> //讄该页为错误处理页
<%@ page import="java.io.PrintWriter" %>
<html>
<head>
<title>CH4 - Error.jsp</title>
</head>
<body>
<h2>errorPage 的范例程?/span></h2>
<p>ErrorPage.jsp 错误产生Q?/span><I><%= exception %></I></p><br>
<pre>
问题如下Q?/span><% exception.printStackTrace(new PrintWriter(out)); %> //输出错误的原?/span>
</pre>
</body>
</html>
Error.jsp 主要处理ErrorPage.jsp 所产生的错误,所以在ErrorPage.jsp ?/span>page 指o的属?/span>errorPage设ؓError.jspQ因此,?/span>ErrorPage.jsp有错误发生时Q会自动转到Error.jsp来处理?/span>Error.jsp 必须讑֮page 指o的属?/span>isErrorPage?/span>trueQ因?/span>Error.jsp是专门用来处理错误的|页。设?/span>page 指o的属?/span>isErrorPage?/span>true后,?/span>Error.jsp里就可以使用exception异常cM?/span>
׃在这个程序中q没有做一个窗体来输入两个数字Q所以必L动在URL后输?/span>num1?/span>num2的|?/span>http://localhost:8080/ErrorPage.jsp?num1=100&num2=245。当ErrorPage.jsp 产生错误Ӟ如加Cؓ字符串型Q,׃交由Error.jsp d理,所以我们看到的l果Q不
再是原始的服务器提示的ؕ七把p的错误提示Q将是执?/span>Error.jsp 后的l果?/span>
?/span>jsp中显式地抛出异常Ӟpȝ也会转到错误处理面Q?/span>
<%@page language="java" contentType="text/html;charset=GBK" import= "java.util.* " errorPage="exception.jsp"
%>
<jsp:useBean id="user" scope="session" class="S_userObj"/>
<%
if(user= =null)
throw new Exception("您没有登陆或者登陆超?/span>,请重新登?/span>");
。。?/span> 。。?/span>
?/span>user为空时系l会自动转到错误处理面?/span>
MQ以下情?/span>jsp会{到错误处理页面:
前提Q?/span>jsp成功的{换到?/span>servletQ{换过E中没有发生错误?/span>
?/span>servletq行ӞE序中碰到异常?/span>
?/span>servletq行ӞE序控制转到了显式抛出的异常。例如:if(…) throw new exception();
一个正则表辑ּ是由普通字W(例如字符 a ?zQ以及特D字W(UCؓ元字W)l成的文字模式。该模式描述在查找文字主体时待匹配的一个或多个字符丌Ӏ正则表辑ּ作ؓ一个模板,某个字W模式与所搜烦的字W串q行匚w。如Q?
下表是元字符及其在正则表辑ּ上下文中的行为的一个完整列表:
"ab*"Q表CZ个字W串有一个a后面跟着零个或若q个b。("a", "ab", "abbb",……Q; 也可以用范_用大括号括vQ用以表C重复次数的范围?/p> "ab{2}"Q表CZ个字W串有一个a跟着2个bQ?abb"Q; h意,你必L定范围的下限Q如Q?{0,2}"而不?{,2}"Q。还有,你可能注意到了,'*'Q?+'?br /> '?'相当?{0,}"Q?{1,}"?{0,1}"?br /> q有一?¦'Q表C?#8220;?#8221;操作Q?/p> "hi¦hello"Q表CZ个字W串里有"hi"或?hello"Q?br /> "(b¦cd)ef"Q表C?bef"?cdef"Q?br /> "(a¦b)*c"Q表CZ?a""b"混合的字W串后面跟一?c"Q?/p> '.'可以替代M字符Q?/p> "a.[0-9]"Q表CZ个字W串有一?a"后面跟着一个Q意字W和一个数字; Ҏ可C某些字W允许在一个字W串中的某一特定位置出现Q?/p> "[ab]"Q表CZ个字W串有一?a"?b"Q相当于"a¦b"Q; 你也可以在方括号里用'^'表示不希望出现的字符Q?^'应在Ҏ号里的第一位。(如:"%[^a-zA-Z]%"?br /> CZ个百分号中不应该出现字母Q?/p> Z逐字表达Q必d"^.$()¦*+?{\"q些字符前加上{UdW?\'?/p> h意在Ҏ号中Q不需要{义字W?/p> |