因为工作原因,最近开始做java web方面的工作。MyEclipse是现在开发java常用工作。structs是现今流行的servlet框架。下边我就用MyEclipse写一个Struts实例。
开发环境:
MyEclipse8.5 汉化版
Struts 1.3.8
tomcat 5.0(xampp扩展插件)
PS:现在流行的版本都2.3版本,2.0和1.0系列差别很大,2.0配置更简洁,不过我对技术喜欢追根溯源,从头开始能摸清struts的脉络。但是框架的思路都是一样的。
一、实例要实现什么功能
mystruts是一个录入和查询产品信息的程序。本例中的产品信息表只包括了产品ID、产品名称和产品价格三个字段。mystruts的主要功能如下:
1. 接受用户输入的产品ID、产品名称和产品价格。
2. 验证这些字段的合法性。如果某些字段的输入不合法,程序会forward到一个信息显示页,并显示出错原因。
3. 如果用户输入了正确的字段值,程序会将这些字段值保存到数据库中,并显示“保存成功”信息。
二、用MyEclipse建立一个支持struts1.x的mystruts工程
用MyEclipse建立一个mystruts工程(Web工程),现在这个mystruts工程还不支持Struts1.x(没有引入相应的Struts jar包、struts-config.xml文件以及其他和Struts相关的配置)。然而,在MyEclipse中这一切并不需要我们手工去加入。而只需要使用MyEclipse的「New Struts Capabilities」对话框就可以自动完成这些工作。
首先选中mystruts工程,然后在右键菜单中选择「MyEclipse」 > 「New Struts Capabilities」,启动「New Struts Capabilities」对话框。对默认的设置需要进行如下的改动:
(1)将com.yourcompany.struts改为struts
(2)将com.yourcompany.struts.ApplicationResources改为struts.ApplicationResources
在设置完后,点击Finish按钮关闭对话框。在向samples工程添加支持Struts的功能后,主要对samples工程进行了三个操作:
(1)引入了Struts 1.3的jar包(在samples的工程树中多了一个Struts 1.3 Libraries节点)
(2)在WEB-INF目录中自动添加了一个struts-config.xml文件。文件的默认内容如下面的代码所示:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts-config PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 1.3//EN" "http://struts.apache.org/dtds/struts-config_1_3.dtd">
<struts-config>
<data-sources />
<form-beans />
<global-exceptions />
<global-forwards />
<action-mappings />
<message-resources parameter="struts.ApplicationResources" />
</struts-config>
(3)在WEB-INF中的web.xml文件中添加了处理Struts动作的ActionServlet的配置,代码如下:
<servlet>
<servlet-name>action</servlet-name>
<servlet-class>org.apache.struts.action.ActionServlet</servlet-class>
<init-param>
<param-name>config</param-name>
<param-value>/WEB-INF/struts-config.xml</param-value>
</init-param>
<init-param>
<param-name>debug</param-name>
<param-value>3</param-value>
</init-param>
<init-param>
<param-name>detail</param-name>
<param-value>3</param-value>
</init-param>
<load-on-startup>0</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>action</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
到目前为止,samples工程已经完全支持Struts了。可以看到,如果不使用MyEclipse,那么上面所列出的配置文件的内容都必须手工输入。因此,使用MyEclipse来开发Struts程序可以省去很多配置xml文件的工作。
三、配置数据库连接池
在<Tomcat安装目录>\conf\Catalina\localhost目录中打开mystruts.xml文件(如果没有该文件,则建立一个mystruts.xml文件),内容如下:(path是浏览器里的访问路径)
<?xml version='1.0' encoding='utf-8'?>
<Context docBase="E:\xampp\tomcat\webapps\mystruts" path="/mystruts" reloadable="true" privileged="true">
<Resource name="jdbc/struts" auth="Container"
type="javax.sql.DataSource"
driverClassName="com.mysql.jdbc.Driver"
url="jdbc:mysql://localhost:3306/struts?characterEncoding=GBK"
username="root"
password=""
maxActive="200"
maxIdle="50"
maxWait="3000"/>
</Context>
本例中操作数据库的模型类:Product用于验证由客户端提交的产品信息,并向t_products表中写入这些信息。可以将连接数据库的工作提出来作为一个父类(Struts类)提供,新建util包,Struts.java代码如下:
package util;
import java.sql.Connection;
public class Struts
{
protected javax.naming.Context ctx = new javax.naming.InitialContext();
protected javax.sql.DataSource ds;
protected Connection conn;
public Struts() throws Exception
{
ds = (javax.sql.DataSource) ctx.lookup("java:/comp/env/jdbc/struts");
conn = ds.getConnection(); // 从数据库连接池获得一个Connection
}
}
四、主要程序
控制器是基于Struts的Web程序的核心部分之一:控制器实质上也是普通的Java类,但这个Java类一般要从org.apache.struts.action.Action类继承。控制器的主要功能是接受并处理从JSP页面提交的数据、通过模型(Model)和数据库交互以及forward到相应的页面(可以是任何页面,如html、JSP和Servlet等)。在实现控制器之前,需要先实现一个ActionForm类,这个类的作用是保存JSP页面提交的数据。新建mystruts.actionform包,ProductForm.java代码如下:
package mystruts.actionform;
import org.apache.struts.action.*;
public class ProductForm extends ActionForm
{
private String productID; // 产品ID
private String productName; // 产品名称
private float price; // 产品价格
public String getProductID()
{
return productID;
}
public void setProductID(String productID)
{
this.productID = productID;
}
public String getProductName()
{
return productName;
}
public void setProductName(String productName)
{
this.productName = productName;
}
public float getPrice()
{
return price;
}
public void setPrice(float price)
{
this.price = price;
}
}
从上面的代码可以看出,ActionForm类一般从org.apache.struts.action.ActionForm类继承,而且在类中需要按着需要保存的数据表字段添加属性。如产品ID的属性是productName.在MyEclipse中可以只定义三个private变量,然后使用MyEclipse的「Source」 > 「Generate Getters and Setters……」功能自动产生getter和setter方法。但在给这些属性取名时要注意,private变量的名子和数据表的字段名没有直接的关系,但必须和JSP页面中的<html>标签的property属性值一致,如<html:text property="productName" />表示输入产品名称的文本框,其中property属性的值就是ProductForm类中的productName变量。如果不一致,将会抛出异常。其他和ProductForm类的属性对应的<html>标签可以查看上面的代码。
同时需要在struts-config.xml中的<struts-config>节点中添加如下的内容:
<form-beans>
<form-bean name="saveProductForm" type=" mystruts.actionform.ProductForm" />
</form-beans>
下面来实现saveProduct动作的代码。Struts Action类必须一般从org.apache.struts.action.Action类继承。一般在Struts Action类需要覆盖Action类的execute方法。这个方法有每次客户端访问Struts Action时调用。我们可以在方法中处理客户端提交的数据,访问数据库等工作。这个方法返回一个ActionForward类型的值,表明在执行完execute后,要forward到的页面。描述saveProduct动作的类叫SaveProductAction.代码如下:
package mystruts.action;
import javax.servlet.http.*;
import org.apache.struts.action.*;
import mystruts.actionform.*;
import mystruts.model.*;
public class SaveProductAction extends Action
{
// 在客户端访问saveProduct动作时执行该方法
public ActionForward execute(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response)
{
ProductForm saveProductForm = (ProductForm) form;
try
{
Product product = new Product(saveProductForm);
product.save(); // 保存产品信息
request.setAttribute("info", "保存成功!");
}
catch (Exception e)
{
request.setAttribute("info", e.getMessage());
}
return mapping.findForward("save");
}
}
在SaveProductAction类中使用了模型类Product验证并保存产品信息。并将操作结果信息保存在request的属性中,key为“info”。在execute的最后,使用了ActionMapping类的findForward方法在struts-config.xml中寻找一个叫“save”的forward.这个forward是一个JSP页,用于显示是否将产品信息保存成功的信息。为了可以在struts-config.xml中查找这个forward,需要在struts-config.xml的<action-mappings>内容如下。
<action-mappings>
<action attribute="saveProductForm" path="/saveProduct" type="mystruts.action.SaveProductAction" name="saveProductForm" scope="request" input="/NewProduct.jsp" validate="true" >
<forward name="save" path="/save.jsp" />
</action>
</action-mappings>
从上面的代码可以看出,那个用于显示保存状态信息的JSP页面叫save.jsp.在<samples工程目录>"mystruts目录中建立一个save.jsp文件,代码如下:
<%@ page pageEncoding="GBK"%>
${requestScope.info}
新建mystruts.model包,Product.java代码如下:
package mystruts.model;
import java.sql.*;
import mystruts.actionform.*;
public class Product extends util.Struts
{
private ProductForm form;
public Product(ProductForm form) throws Exception
{
super();
this.form = form;
validate();
}
// 验证客户端提交的数据
public void validate() throws Exception
{
if (form.getProductID().trim().equals(""))
throw new Exception("产品ID不能为空!");
if(form.getProductID().length() > 4)
throw new Exception("产品ID最长为4位!");
if (form.getProductName().trim().equals(""))
throw new Exception("产品名称不能为空");
if (Float.compare(form.getPrice(), 0) <= 0)
throw new Exception("产品价格必须大于0");
}
// 将客户端提交的产品信息保存到t_products中
public void save() throws Exception
{
try
{
String productID = form.getProductID();
String productName = form.getProductName();
float price = form.getPrice();
String sql = "INSERT INTO t_products VALUES('" + productID + "',"
+ "'" + productName + "'," + String.valueOf(price) + ")";
PreparedStatement pstmt = conn.prepareStatement(sql);
pstmt.executeUpdate(); // 执行INSERT语句
pstmt.close();
conn.close();
}
catch (Exception e)
{
throw new Exception(e.getMessage());
}
}
}
在Product类中使用了一个ProductForm类,这个类是一个ActionForm类,它的功能是保存客户端提交的数据。Product类通过构造方法的form参数将客户端提交的数据传入Product类的对象实例中,并在构造方法中验证这些数据,如果发现数据不合法,就会抛出一个异常。当客户端提交的数据合法后,成功建立了一个Product类的对象实例,然后可以通过简单地调用save方法将数据保存到t_products表中。
index.jsp
<%@ page pageEncoding="GBK"%>
<%-- 引用Struts tag--%>
<%@ taglib uri="http://struts.apache.org/tags-html" prefix="html"%>
<html>
<head>
<title>主界面</title>
</head>
<body>
<table align="center" cellpadding="10" width="100%">
<tr>
<td align="right" width="50%">
<%-- 使用Struts tag--%>
<html:link forward="newProduct">录入产品信息</html:link>
</td>
<td>
<html:link forward="searchProduct">查询产品信息</html:link>
</td>
</tr>
</table>
</body>
</html>
在struts-config.xml文件中<struts-config>节点中添加全局的forward,代码如下:
<global-forwards>
<forward name="newProduct" path="/mystruts/newProduct.jsp" />
</global-forwards>
在web.xml文件中<web-app>节点中添加taglib支持,代码如下:
<jsp-config>
<taglib>
<taglib-uri>/META-INF/tld/struts-html.tld</taglib-uri>
<taglib-location>/META-INF/tld/struts-html.tld</taglib-location>
</taglib>
</jsp-config>
在IE中输入如下的URL:http://localhost:8080/samples/mystruts/index.jsp
显示输入产品,点击按钮进入newProduct.jsp,在文本框中输入相应的信息后,点“保存”按钮,如果输入的数据是合法的,就会将数据保存在t_products中,否则会显示出错的原因。
需要注意的几个问题:
1.配置MyEclipse的deploy功能,能够实时部署到tomcat发布目录;
2.如果在MyEclipse修改tomcat的web.xml,会自动重启tomcat;
3.每次修改完struts-config.xml重启tomcat才能生效;
4.注意struts-config.xml里每个标签的顺序,不然虽然内容每次,但是Eclipse也会提示错误;
5.如果add struct lib错误,重构后就无法再次add struct了!解决办法是删除项目目录里的.mystrutsdata文件
从文件.project中删除<nature> com.genuitec.eclipse.cross.easystruts.eclipse.easystrutsnature </nature>
6.如果报连接jdbc找不到name请将mysql-connector-java-5.1.7-bin.jar放到tomcat安装目录下的lib目录里。
参考:
http://blog.sina.com.cn/s/blog_6343a79a0100h3iq.html
开发环境:
MyEclipse8.5 汉化版
Struts 1.3.8
tomcat 5.0(xampp扩展插件)
PS:现在流行的版本都2.3版本,2.0和1.0系列差别很大,2.0配置更简洁,不过我对技术喜欢追根溯源,从头开始能摸清struts的脉络。但是框架的思路都是一样的。
一、实例要实现什么功能
mystruts是一个录入和查询产品信息的程序。本例中的产品信息表只包括了产品ID、产品名称和产品价格三个字段。mystruts的主要功能如下:
1. 接受用户输入的产品ID、产品名称和产品价格。
2. 验证这些字段的合法性。如果某些字段的输入不合法,程序会forward到一个信息显示页,并显示出错原因。
3. 如果用户输入了正确的字段值,程序会将这些字段值保存到数据库中,并显示“保存成功”信息。
二、用MyEclipse建立一个支持struts1.x的mystruts工程
用MyEclipse建立一个mystruts工程(Web工程),现在这个mystruts工程还不支持Struts1.x(没有引入相应的Struts jar包、struts-config.xml文件以及其他和Struts相关的配置)。然而,在MyEclipse中这一切并不需要我们手工去加入。而只需要使用MyEclipse的「New Struts Capabilities」对话框就可以自动完成这些工作。
首先选中mystruts工程,然后在右键菜单中选择「MyEclipse」 > 「New Struts Capabilities」,启动「New Struts Capabilities」对话框。对默认的设置需要进行如下的改动:
(1)将com.yourcompany.struts改为struts
(2)将com.yourcompany.struts.ApplicationResources改为struts.ApplicationResources
在设置完后,点击Finish按钮关闭对话框。在向samples工程添加支持Struts的功能后,主要对samples工程进行了三个操作:
(1)引入了Struts 1.3的jar包(在samples的工程树中多了一个Struts 1.3 Libraries节点)
(2)在WEB-INF目录中自动添加了一个struts-config.xml文件。文件的默认内容如下面的代码所示:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts-config PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 1.3//EN" "http://struts.apache.org/dtds/struts-config_1_3.dtd">
<struts-config>
<data-sources />
<form-beans />
<global-exceptions />
<global-forwards />
<action-mappings />
<message-resources parameter="struts.ApplicationResources" />
</struts-config>
(3)在WEB-INF中的web.xml文件中添加了处理Struts动作的ActionServlet的配置,代码如下:
<servlet>
<servlet-name>action</servlet-name>
<servlet-class>org.apache.struts.action.ActionServlet</servlet-class>
<init-param>
<param-name>config</param-name>
<param-value>/WEB-INF/struts-config.xml</param-value>
</init-param>
<init-param>
<param-name>debug</param-name>
<param-value>3</param-value>
</init-param>
<init-param>
<param-name>detail</param-name>
<param-value>3</param-value>
</init-param>
<load-on-startup>0</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>action</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
到目前为止,samples工程已经完全支持Struts了。可以看到,如果不使用MyEclipse,那么上面所列出的配置文件的内容都必须手工输入。因此,使用MyEclipse来开发Struts程序可以省去很多配置xml文件的工作。
三、配置数据库连接池
在<Tomcat安装目录>\conf\Catalina\localhost目录中打开mystruts.xml文件(如果没有该文件,则建立一个mystruts.xml文件),内容如下:(path是浏览器里的访问路径)
<?xml version='1.0' encoding='utf-8'?>
<Context docBase="E:\xampp\tomcat\webapps\mystruts" path="/mystruts" reloadable="true" privileged="true">
<Resource name="jdbc/struts" auth="Container"
type="javax.sql.DataSource"
driverClassName="com.mysql.jdbc.Driver"
url="jdbc:mysql://localhost:3306/struts?characterEncoding=GBK"
username="root"
password=""
maxActive="200"
maxIdle="50"
maxWait="3000"/>
</Context>
本例中操作数据库的模型类:Product用于验证由客户端提交的产品信息,并向t_products表中写入这些信息。可以将连接数据库的工作提出来作为一个父类(Struts类)提供,新建util包,Struts.java代码如下:
package util;
import java.sql.Connection;
public class Struts
{
protected javax.naming.Context ctx = new javax.naming.InitialContext();
protected javax.sql.DataSource ds;
protected Connection conn;
public Struts() throws Exception
{
ds = (javax.sql.DataSource) ctx.lookup("java:/comp/env/jdbc/struts");
conn = ds.getConnection(); // 从数据库连接池获得一个Connection
}
}
四、主要程序
控制器是基于Struts的Web程序的核心部分之一:控制器实质上也是普通的Java类,但这个Java类一般要从org.apache.struts.action.Action类继承。控制器的主要功能是接受并处理从JSP页面提交的数据、通过模型(Model)和数据库交互以及forward到相应的页面(可以是任何页面,如html、JSP和Servlet等)。在实现控制器之前,需要先实现一个ActionForm类,这个类的作用是保存JSP页面提交的数据。新建mystruts.actionform包,ProductForm.java代码如下:
package mystruts.actionform;
import org.apache.struts.action.*;
public class ProductForm extends ActionForm
{
private String productID; // 产品ID
private String productName; // 产品名称
private float price; // 产品价格
public String getProductID()
{
return productID;
}
public void setProductID(String productID)
{
this.productID = productID;
}
public String getProductName()
{
return productName;
}
public void setProductName(String productName)
{
this.productName = productName;
}
public float getPrice()
{
return price;
}
public void setPrice(float price)
{
this.price = price;
}
}
从上面的代码可以看出,ActionForm类一般从org.apache.struts.action.ActionForm类继承,而且在类中需要按着需要保存的数据表字段添加属性。如产品ID的属性是productName.在MyEclipse中可以只定义三个private变量,然后使用MyEclipse的「Source」 > 「Generate Getters and Setters……」功能自动产生getter和setter方法。但在给这些属性取名时要注意,private变量的名子和数据表的字段名没有直接的关系,但必须和JSP页面中的<html>标签的property属性值一致,如<html:text property="productName" />表示输入产品名称的文本框,其中property属性的值就是ProductForm类中的productName变量。如果不一致,将会抛出异常。其他和ProductForm类的属性对应的<html>标签可以查看上面的代码。
同时需要在struts-config.xml中的<struts-config>节点中添加如下的内容:
<form-beans>
<form-bean name="saveProductForm" type=" mystruts.actionform.ProductForm" />
</form-beans>
下面来实现saveProduct动作的代码。Struts Action类必须一般从org.apache.struts.action.Action类继承。一般在Struts Action类需要覆盖Action类的execute方法。这个方法有每次客户端访问Struts Action时调用。我们可以在方法中处理客户端提交的数据,访问数据库等工作。这个方法返回一个ActionForward类型的值,表明在执行完execute后,要forward到的页面。描述saveProduct动作的类叫SaveProductAction.代码如下:
package mystruts.action;
import javax.servlet.http.*;
import org.apache.struts.action.*;
import mystruts.actionform.*;
import mystruts.model.*;
public class SaveProductAction extends Action
{
// 在客户端访问saveProduct动作时执行该方法
public ActionForward execute(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response)
{
ProductForm saveProductForm = (ProductForm) form;
try
{
Product product = new Product(saveProductForm);
product.save(); // 保存产品信息
request.setAttribute("info", "保存成功!");
}
catch (Exception e)
{
request.setAttribute("info", e.getMessage());
}
return mapping.findForward("save");
}
}
在SaveProductAction类中使用了模型类Product验证并保存产品信息。并将操作结果信息保存在request的属性中,key为“info”。在execute的最后,使用了ActionMapping类的findForward方法在struts-config.xml中寻找一个叫“save”的forward.这个forward是一个JSP页,用于显示是否将产品信息保存成功的信息。为了可以在struts-config.xml中查找这个forward,需要在struts-config.xml的<action-mappings>内容如下。
<action-mappings>
<action attribute="saveProductForm" path="/saveProduct" type="mystruts.action.SaveProductAction" name="saveProductForm" scope="request" input="/NewProduct.jsp" validate="true" >
<forward name="save" path="/save.jsp" />
</action>
</action-mappings>
从上面的代码可以看出,那个用于显示保存状态信息的JSP页面叫save.jsp.在<samples工程目录>"mystruts目录中建立一个save.jsp文件,代码如下:
<%@ page pageEncoding="GBK"%>
${requestScope.info}
新建mystruts.model包,Product.java代码如下:
package mystruts.model;
import java.sql.*;
import mystruts.actionform.*;
public class Product extends util.Struts
{
private ProductForm form;
public Product(ProductForm form) throws Exception
{
super();
this.form = form;
validate();
}
// 验证客户端提交的数据
public void validate() throws Exception
{
if (form.getProductID().trim().equals(""))
throw new Exception("产品ID不能为空!");
if(form.getProductID().length() > 4)
throw new Exception("产品ID最长为4位!");
if (form.getProductName().trim().equals(""))
throw new Exception("产品名称不能为空");
if (Float.compare(form.getPrice(), 0) <= 0)
throw new Exception("产品价格必须大于0");
}
// 将客户端提交的产品信息保存到t_products中
public void save() throws Exception
{
try
{
String productID = form.getProductID();
String productName = form.getProductName();
float price = form.getPrice();
String sql = "INSERT INTO t_products VALUES('" + productID + "',"
+ "'" + productName + "'," + String.valueOf(price) + ")";
PreparedStatement pstmt = conn.prepareStatement(sql);
pstmt.executeUpdate(); // 执行INSERT语句
pstmt.close();
conn.close();
}
catch (Exception e)
{
throw new Exception(e.getMessage());
}
}
}
在Product类中使用了一个ProductForm类,这个类是一个ActionForm类,它的功能是保存客户端提交的数据。Product类通过构造方法的form参数将客户端提交的数据传入Product类的对象实例中,并在构造方法中验证这些数据,如果发现数据不合法,就会抛出一个异常。当客户端提交的数据合法后,成功建立了一个Product类的对象实例,然后可以通过简单地调用save方法将数据保存到t_products表中。
index.jsp
<%@ page pageEncoding="GBK"%>
<%-- 引用Struts tag--%>
<%@ taglib uri="http://struts.apache.org/tags-html" prefix="html"%>
<html>
<head>
<title>主界面</title>
</head>
<body>
<table align="center" cellpadding="10" width="100%">
<tr>
<td align="right" width="50%">
<%-- 使用Struts tag--%>
<html:link forward="newProduct">录入产品信息</html:link>
</td>
<td>
<html:link forward="searchProduct">查询产品信息</html:link>
</td>
</tr>
</table>
</body>
</html>
在struts-config.xml文件中<struts-config>节点中添加全局的forward,代码如下:
<global-forwards>
<forward name="newProduct" path="/mystruts/newProduct.jsp" />
</global-forwards>
在web.xml文件中<web-app>节点中添加taglib支持,代码如下:
<jsp-config>
<taglib>
<taglib-uri>/META-INF/tld/struts-html.tld</taglib-uri>
<taglib-location>/META-INF/tld/struts-html.tld</taglib-location>
</taglib>
</jsp-config>
在IE中输入如下的URL:http://localhost:8080/samples/mystruts/index.jsp
显示输入产品,点击按钮进入newProduct.jsp,在文本框中输入相应的信息后,点“保存”按钮,如果输入的数据是合法的,就会将数据保存在t_products中,否则会显示出错的原因。
需要注意的几个问题:
1.配置MyEclipse的deploy功能,能够实时部署到tomcat发布目录;
2.如果在MyEclipse修改tomcat的web.xml,会自动重启tomcat;
3.每次修改完struts-config.xml重启tomcat才能生效;
4.注意struts-config.xml里每个标签的顺序,不然虽然内容每次,但是Eclipse也会提示错误;
5.如果add struct lib错误,重构后就无法再次add struct了!解决办法是删除项目目录里的.mystrutsdata文件
从文件.project中删除<nature> com.genuitec.eclipse.cross.easystruts.eclipse.easystrutsnature </nature>
6.如果报连接jdbc找不到name请将mysql-connector-java-5.1.7-bin.jar放到tomcat安装目录下的lib目录里。
参考:
http://blog.sina.com.cn/s/blog_6343a79a0100h3iq.html