struts自带拦截器至少不会低于10种,例如:输入验证是有Validatin拦截器处理的,如果禁用这个拦截器,输入的验证将停止工作,文件上传如此顺利,要感谢File Upload拦截器,有几个拦截器会在特定的条件不满足的时候组织该动作执行,例如:过去在对某个动作输入验证时遇到的错误,Validation拦截器将阻止该动作触发
Struts自带的拦截器足以满足绝大多数的应用程序的需要 但是你也有可能会遇到自己自行创建一个拦截器的时候 一下将介绍怎么自己去创建一个拦截器
Interceptor接口
从出技术角度讲 每个拦截器都是一个实现了com.opensymphony.xwork2.interceptor.Interceptor接口的java类 这个接口定义如下:
public interface Interceptor extends Serializable{
void init();
String interceptor(ActionInvocation invocation) throws Exception;
void destory();
}
这个接口有三个方法
init 这个方法将在拦截器创建出来之后 立刻执行,他在拦截器的生命周期内也只被嗲用一次。拦截器的编写者必须要覆盖这个方法对相关的资源进行必要的初始化。
interceptor 每个拦截器到一个动作请求,这个方法就会被调用一次,给拦截器一个机会在该动作开始执行之前和执行完毕之后做些事情。
destory 这个方法将在拦截器被销毁之前调用,他在拦截器的生命周期中也纸杯调用一次,拦截器的编写者必须覆此方法来释放曾经占用的资源。
Struts会依次调用程序员为某个动作而注册的灭一个拦截器的interceptor方法,在每次调用这个方法的时候,struts会向他传递一个com.opensymphony.xwork2.ActionInvocation接口的实例,一个ActionInvocation对象代表一个给定的执行状态,拦截器可以从这个对象获得与改该对象相关联的Action对象和Result对象,在完成自己的任务之后,拦截器将调用ActionInvocation对象的invoke方法前精到动作流程的下一个环节。
我们还可以通过调用ActionInvocation对象的addPreResultListener方法的办法给ActionInvocation对象挂上一个或者多个PreResultListener监听器。PreResultListener接口可以让我们在动作执行完毕之后,开始执行动作结果之前做些事情,这个接口有一个回调的方法如下定义:
void brforeResult(ActionInvocation invocation,String resultCode);
AbstractInterceptor类实现了Interceptor接口,并俄日init和destroy方法分别提供了一个空白的实现了 因为并非所有拦截器都需要对资源进行初始化或在他们销毁的时候做善后处理,所以扩展了AbstractInterceptor类可以让我们省下自行实现init和destroy方法的时间。AbstractInterceptor源码如下所示:
public void init(){}
public void destroy(){}
public abstract String intercept(ActionInvocation invocation) throw Exception
下面编写一个自定义的拦截器
DataSourceInjectorInterceptor为自定义拦截器,这个拦截器的用途把一个DataSource "注入"一个给定的动作对象中去,相关的动作在把dataSource注射到Dao层;
package com.sg.action;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.sql.DataSource;
import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.interceptor.AbstractInterceptor;
public class DataSourceInjectorInterceptor extends AbstractInterceptor{
private DataSource dataSource;
private String dataSourceName;
public void setDataSource(DataSource dataSource) {
this.dataSource = dataSource;
}
@Override
public void init() {
if (dataSource == null) {
System.out.println("Interceptor . init DS");
try {
Context context = (Context) new InitialContext();
dataSource = (DataSource)context.lookup(dataSourceName);
} catch (NamingException e) {
e.printStackTrace();
}
}
}
@Override
public String intercept(ActionInvocation invocation) throws Exception {
Object action = invocation.getAction();
if (action instanceof DataSourceAware) {
((DataSourceAware) action).setDataSource(dataSource);
}
return invocation.invoke();
}
}
每当一个实用了这个拦截器的动作被触发时,这个拦截器就会把一个dataSource对象注入到相应的动作对象去,注意: 并非所有的动作都能获得这个对象,只有那些想实现了DataSourceAware接口的动作类才能接受这种注射。DataSourceAware代码如下:
package com.sg.action;
import javax.sql.DataSource;
public interface DataSourceAware {
void setDataSource(DataSource dataSource);
}
声明拦截器如下
<package name="app" namespace="" extends="struts-default">
<!--声明-->
<interceptors>
<interceptor name="dataSourceInjector" class="com.sg.action.DataSourceInjectorInterceptor">
<param name="dataSourceName">java:/comp/env/jdbc/MyDataSource</param>
</interceptor>
</interceptors>
<action name="product_list" class="com.sg.action.ProductAction">
<interceptor-ref name="defaultStack"/>
<interceptor-ref name="dataSourceInjector"/>
<result>/products.jsp</result>
</action>
</package>
product_list动作用来列出库存的产品,这些产品来自一个数据库。这个数据库可以通过我们的定制的拦截器所注入的DataSource去访问。
package com.sg.action;
import java.util.List;
import javax.sql.DataSource;
import com.opensymphony.xwork2.ActionSupport;
public class ProductAction extends ActionSupport implements DataSourceAware{
private DataSource dataSource;
private List<Product> products;
public List<Product> getProducts() {
return products;
}
public void setProducts(List<Product> products) {
this.products = products;
}
@Override
public void setDataSource(DataSource dataSource) {
this.dataSource = dataSource;
}
@Override
public String execute() throws Exception {
ProductDAO productDAO = new ProductDAO();
productDAO.setDataSource(dataSource);
products = productDAO.getAllProducts();
return SUCCESS;
}
}
有一点要注意:ProductAction类实现了DataSourceAware接口 所以我们可以把DataSource对象注入到ProductAction类的实例去.
ProductAction类将使用ProductDAO类 从数据库中的Products数据表检索数据。这意味着我们必须提前把这个数据库表先创建出来,在填充一些数据进去。有关动作调用productDAO类的setDataSource方法,把DataSource注入到ProductDAO类中
代码如下:
package com.sg.action;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import javax.sql.DataSource;
public class ProductDAO {
private DataSource dataSource;
public void setDataSource(DataSource dataSource) {
this.dataSource = dataSource;
}
private static final String sql = "SELECT productId,name,descrptio,price FROM products";
public List<Product> getAllProducts(){
List<Product> products = new ArrayList<Product>();
Connection connection = null;
PreparedStatement statement = null;
ResultSet rs = null;
try {
connection = dataSource.getConnection();
statement = connection.prepareStatement(sql);
rs = statement.executeQuery();
while(rs.next()){
Product product = new Product();
product.setProductId(rs.getInt("productId"));
product.setName(rs.getString("name"));
product.setDescrption(rs.getString("descrption"));
product.setPrice(rs.getDouble("price"));
products.add(product);
}
} catch (SQLException e) {
e.printStackTrace();
}finally{
if (rs != null) {
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (statement != null) {
try {
statement.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (connection != null) {
try {
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
return products;
}
}