正文:
Tomcat是Apache Jakarta项目中的一个Servlet服务器,已经被程序员广泛用来开发Servlet和Jsp项目。该服务器占用资源小,扩展性好,支持多种功能(如负载平衡、邮件服务等等,这得益于Jakarta项目的开放性);更因为它是一个完全免费和完全开放的服务器,所以有成千上万的程序员在努力完善和添加已有的功能,可以在互联网上搜索到大量的关于tomcat的资源和解决方案。
在http://jakarta.apache.org 上可以下载到Tomcat,目前最新版本5.0还没有正式发布。所以现在可用的是4.1版本。
Tomcat 4.1可自动安装(需要下载自动安装版本,也有zip打包的版本和源代码),但你事先要安装好JDK。可以选择jdk1.3(1.2.x或者1.3.x)或者1.4来安装。注意下载相应Jdk版本的Tomcat。在安装的时候,如果选择安装服务,安装程序可以把tomcat自动添加到Win NT或者Win 2000的服务中,服务名称是"Apache Tomcat 4.1"。你可以在控制面板的服务中找到它,通过服务的图形界面启动/停止;或者使用命令:net start "Apache Tomcat 4.1" 和 net stop "Apache Tomcat 4.1"来启停它。如果需要移除服务,在%TOMCAT_HOME%(表示Tomcat的安装目录,下同)的bin目录下,找到tomcat.exe ,在命令行打入tomcat -remove "Apache Tomcat 4.1",就可以了。如果你在自动安装的时候没有选择安装服务,可以以后通过在命令行打入 tomcat -install "Apache Tomcat 4.1"来安装。在安装的过程中可能会出现控制台不关闭的现象,这时把控制焦点放在控制台上,按下回车键,即可顺利继续安装。
Tomcat 4.1内部实现了Servlet 2.3和Jsp l.2引擎。如果需要使用数据库连接池,一定要使用Tomcat4.1以上版本,因为Tomcat 4.1才开始内置对数据库连接池的支持。关于Tomcat内置的连接池的配置,见如下步骤:
1.寻找第三方的数据库java的驱动(如db2的驱动是db2java.zip文件),并且把它拷贝到Tomcat的库文件目录下。在这里是%TOMCAT_HOME%的common/lib子目录下。注意,一定要把文件变成.jar文件,再拷过来。否则可能出现认不出驱动的问题。
2.配置%TOMCAT_HOME%的conf下的server.xml文件。在Host分支下,删除不必要的Context(如最初安装可能装了Example等,注释掉相关描述)。加入自己的Context,以下是一个附有注释说明的例子:
<!-- 自己的Context,名称叫做ppc -->
<Context path="/ppc" docBase="ppc" debug="5" reloadable="true" crossContext="true">
<!-- 日志,在%TOMCAT_HOME%的logs下生成localhost_ppc_log.txt日志文件 -->
<Logger className="org.apache.catalina.logger.FileLogger"
prefix="localhost_ppc_log." suffix=".txt"
timestamp="true"/>
<!-- 数据源名称,可以通过java:/comp/env/jdbc/emr调用(连接池) -->
<Resource name="jdbc/emr"
auth="Container"
type="javax.sql.DataSource"/>
<!-- 数据源参数表 -->
<ResourceParams name="jdbc/emr">
<!-- 数据源工厂,通过它得到DataSource -->
<parameter>
<name>factory</name>
<value>org.apache.commons.dbcp.BasicDataSourceFactory</value>
</parameter>
<!-- Maximum number of dB connections in pool. Make sure you
configure your mysqld max_connections large enough to handle
all of your db connections. Set to 0 for no limit.
最大连接数
-->
<parameter>
<name>maxActive</name>
<value>100</value>
</parameter>
<!-- Maximum number of idle dB connections to retain in pool.
Set to 0 for no limit.
最大空闲连接数
-->
<parameter>
<name>maxIdle</name>
<value>30</value>
</parameter>
<!-- Maximum time to wait for a dB connection to become available
in ms, in this example 10 seconds. An Exception is thrown if
this timeout is exceeded. Set to -1 to wait indefinitely.
最长等待连接时间,如果设置成-1表示不确定
-->
<parameter>
<name>maxWait</name>
<value>5000</value>
</parameter>
<!--
db2 dB username and password for dB connections
这里配置的是db2的连接
-->
<!-- 用户名 -->
<parameter>
<name>username</name>
<value>db2admin</value>
</parameter>
<!-- 密码 -->
<parameter>
<name>password</name>
<value>db2admin</value>
</parameter>
<!-- DB2 驱动的类名称 -->
<parameter>
<name>driverClassName</name>
<value>COM.ibm.db2.jdbc.app.DB2Driver</value>
</parameter>
<!--
jdbc连接的url名称
在这里已经安装了db2的控制终端
-->
<parameter>
<name>url</name>
<value>jdbc:db2:emr</value>
</parameter>
</ResourceParams>
</Context>
3.在相应用到该连接池的Web-app(部署好的web应用,一般在%TOMCAT_HOME%的webapps目录下,也可以通过编辑server.xml来改变,下同)的WEB-INF下面修改web.xm
<resource-ref>
<!-- 数据源描述,可随意取有意义的名称 -->
<description>emr db2 dabasource</description>
<res-ref-name>jdbc/emr</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
</resource-ref>
这样子连接池就完全配置好了。在程序中,可以如同标准j2ee的写法那样子使用,见下面的例子:
Context ctx = new InitialContext();//创建上下文实例
DataSource ds =
(DataSource)ctx.lookup(
"java:comp/env/jdbc/emr");//得到数据源(连接池)
if (ds != null)
Connection conn = ds.getConnection();//从连接池中得到连接
4.调试和测试
一般在配置中总会出现这样那样的问题,可以写一段简单的调试代码来发现问题的所在,以下是一段代码片断,可以参考下面代码片断的顺序逐步发现问题:
try{Class.forName("COM.ibm.db2.jdbc.app.DB2Driver");}//1.是否能够找到数据库驱动
catch(ClassNotFoundException cnfe){out.println(cnfe.toString());}//不能找到,打印错误
javax.naming.Context ctx =new javax.naming.InitialContext();
javax.naming.Context envContext = (javax.naming.Context)ctx.lookup("java:/comp/env");//2.是否能够找到环境的命名空间
out.println(envContext);//找不到,打印错误
org.apache.commons.dbcp.BasicDataSource ds=(org.apache.commons.dbcp.BasicDataSource)envContext.lookup("jdbc/emr");//3.是否能够取得数据源。这里一定用BasicDataSource接收以获得比DataSource接口更具体的信息,便于错误查找
if(ds==null)out.println(ds);//找不到,打印错误
else{
//4.看数据源的具体信息有没有从server.xml中读取出来
//还可以看的项有usrname、url等等
out.println(ds.getValidationQuery());
out.println(ds.getMaxActive());
out.println(ds.getPassword());
out.println(ds.getDriverClassName());
}
一般通过以上4个步骤可以确定错误出在哪里了。
以下部分主要讲Tomcat的编码问题。
Tomcat的编码问题,一般指的是jsp或者servlet的编码出现乱码,解决见如下步骤:
1. Tomcat编码问题出现的地方:
Tomcat的编码问题比较烦,一般出在编译阶段、打印阶段或者request接收阶段。
2. 编译阶段编码问题的解决:
在编译阶段出现编码问题,可以强制指定编译器所用的编码。
在%TOMCAT_HOME%的conf下,编辑web.xml,找到
<servlet>
<servlet-name>jsp</servlet-name>
<servlet-class>org.apache.jasper.servlet.JspServlet</servlet-class>
<load-on-startup>3</load-on-startup>
</servlet>
这段描述,在servlet下面加入子标签
<init-param>
<param-name>javaEncoding</param-name>
<param-value>iso-8859-1</param-value>
</init-param>
其中iso-8859-1可以换成你需要的编码,如gb2312;如果不指定,就是utf-8。注意编译器不能认出gbk,所以不要用gbk作为编码。
3. 页面打印到屏幕阶段出现编码问题的解决
编码如果在jsp页面打印时出现乱码,可以考虑设置页面的编码。只要在jsp的最开始处,加入
<%@page contentType="text/ht
4. request接收阶段出现编码问题的解决
如果在request接收另外一个页面或者页面本身传递来的变量时出现乱码,可以设置request的编码来解决,只要在servlet程序或者jsp页面最开始加入
request.setCharacterEncoding("gb2312");//gb2312为简体中文,其他编码作相应的修改
这个片断即可。
但是,这样子写有破坏程序的移植性的嫌疑。因为如果另外一个serlet引擎恰恰因为加入了这段语句而画蛇添足,出现乱码,就不好了。所以,可以有以下2种方法解决这个问题。
4.1 写include文件,把编码的两段话加入到被包含的jsp文件中。如果真的因为手工编码的原因出现了乱码,可以修改被包含的jsp文件,解决所有的编码问题。
如:<jsp:include page="/codeSetting.jsp" />
4.2 写servlet过滤器。通过过滤器来解决request的编码的设置。这个方法不需要改动原来的代码,比较好。现成的写好的过滤器代码贴在下面,只要把它编译一下就可以用了:
package filters;
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.UnavailableException;
/**
* Example filter that sets the character encoding to be used in parsing the
* incoming request, either unconditionally or only if the client did not
* specify a character encoding.
* 如果原来没有设置request的编码,就设置;否则保持不变
*/
public class SetCharacterEncodingFilter implements Filter {
protected String encoding = null;
protected FilterConfig filterConfig = null;
protected boolean ignore = true;
/**
* Take this filter out of service.
*/
public void destroy() {
this.encoding = null;
this.filterConfig = null;
}
/**
* Select and set (if specified) the character encoding to be used to
* interpret request parameters for this request.
*/
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain)
throws IOException, ServletException {
// Conditionally select and set the character encoding to be used
if (ignore || (request.getCharacterEncoding() == null)) {
String encoding = selectEncoding(request);
if (encoding != null)
request.setCharacterEncoding(encoding);//设置request编码的地方
}
// Pass control on to the next filter
// 传递控制到下一个过滤器
chain.doFilter(request, response);
}
/**
* Place this filter into service.
* 从web-app的web.xml文件中读取初始参数的值
*/
public void init(FilterConfig filterConfig) throws ServletException {
this.filterConfig = filterConfig;
this.encoding = filterConfig.getInitParameter("encoding");
String value = filterConfig.getInitParameter("ignore");
if (value == null)
this.ignore = true;
else if (value.equalsIgnoreCase("true"))
this.ignore = true;
else if (value.equalsIgnoreCase("yes"))
this.ignore = true;
else
this.ignore = false;
}
/**
* Select an appropriate character encoding to be used, based on the
* characteristics of the current request and/or filter initialization
* parameters. If no character encoding should be set, return
* <code>null</code>.
* 选择request原来的编码
*/
protected String selectEncoding(ServletRequest request) {
return (this.encoding);
}
}
编译好以后,把SetCharacterEncodingFilter.class加入到相应的web-app的WEB-INF/classes/filters目录下,并且在web.xml的web-app中添加如下语句,配置这段作为filter的servlet:
<filter>
<filter-name>Set Character Encoding</filter-name>
<filter-class>filters.SetCharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<!-- gb2312可以换成需要的编码 -->
<param-value>gb2312</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>Set Character Encoding</filter-name>
<!-- 所有的页面包括servlet,jsp都使用这段过滤器,可以自行指定filter的作用范围 -->
<url-pattern>/*</url-pattern>
</filter-mapping>
5. 编码问题的其他解决方法:全球化解决方案。
以上的配置完成的是本地化的问题。但是我们可以在所有的过程中都采用相同的编码,如范围足够大的iso-8859-1。因为java是unicode的设计,所以只要代码传递中不出现信息的失真,就可以把编码问题推向最终显示时用户的浏览器的设置,也就实现了全球化。关键是不要出现编码的高位截取。一般,页面上出现???符号时代码出现了失真。
Tomcat的其他问题:
Tomcat 4.1可能不如resin 2.1稳定,其中有一些古怪的bug。但是比resin更灵活,因为它是jakarta项目中的一部分,组件很多,扩充性更强。所以也还是比较适合开发和研究的。
以下是这样一个奇怪的bug:
在tomcat作为jsp服务器的时候,jsp语句中这样写
<tr bgcolor="<%if(info.getCy()!=null && info.getCy().trim().equals("是"))out.print("#dddddd");else out.print("#ffdddd");//是和否用不同的颜色表示%>">
按道理,"<%"和"%>"中的语句是动态语句,而他们外面的是静态语句。注释只应该对内有效。在resin中的确如此,很正常。但是在tomcat4.1下,外面的">"居然也给注释掉了。证明tomcat的语法分析部分还是有点问题的。希望5.0正式发布的时候看到它已经给解决掉了。