作为“框架(framework)”,可扩展性是不可或缺的,因为世上没有放之四海而皆准的东西。虽然,Struts 2为我们提供如此丰富的拦截器实现,但是这并不意味我们失去创建自定义拦截器的能力,恰恰相反,在Struts 2自定义拦截器是相当容易的一件事。
| 大家在开始着手创建自定义拦截器前,切记以下原则:
拦截器必须是无状态的,不要使用在API提供的ActionInvocation之外的任何东西。 |
要求拦截器是无状态的原因是Struts 2不能保证为每一个请求或者action创建一个实例,所以如果拦截器带有状态,会引发并发问题。
所有的Struts 2的拦截器都直接或间接实现接口com.opensymphony.xwork2.interceptor.Interceptor。除此之外,大家可能更喜欢继承类com.opensymphony.xwork2.interceptor.AbstractInterceptor。
以下例子演示通过继承AbstractInterceptor,实现授权拦截器。
首先,创建授权拦截器类tutorial.AuthorizationInterceptor,代码如下:
package tutorial;
import java.util.Map;
import com.opensymphony.xwork2.Action;
import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.interceptor.AbstractInterceptor;
public class AuthorizationInterceptor extends AbstractInterceptor {
@Override
public String intercept(ActionInvocation ai) throws Exception {
Map session = ai.getInvocationContext().getSession();
String role = (String) session.get( " ROLE " );
if ( null != role) {
Object o = ai.getAction();
if (o instanceof RoleAware) {
RoleAware action = (RoleAware) o;
action.setRole(role);
}
return ai.invoke();
} else {
return Action.LOGIN;
}
}
}
以上代码相当简单,我们通过检查session是否存在键为“ROLE”的字符串,判断用户是否登陆。如果用户已经登陆,将角色放到Action中,调用Action;否则,拦截直接返回Action.LOGIN字段。为了方便将角色放入Action,我定义了接口tutorial.RoleAware,代码如下:
package tutorial;
public interface RoleAware {
void setRole(String role);
}
接着,创建Action类tutorial.AuthorizatedAccess模拟访问受限资源,它作用就是通过实现RoleAware获取角色,并将其显示到ShowUser.jsp中,代码如下:
package tutorial;
import com.opensymphony.xwork2.ActionSupport;
public class AuthorizatedAccess extends ActionSupport implements RoleAware {
private String role;
public void setRole(String role) {
this .role = role;
}
public String getRole() {
return role;
}
@Override
public String execute() {
return SUCCESS;
}
}
以下是ShowUser.jsp的代码:
<% @ page contentType = " text/html; charset=UTF-8 " %>
<% @taglib prefix = " s " uri = " /struts-tags " %>
< html >
< head >
< title > Authorizated User </ title >
</ head >
< body >
< h1 > Your role is: < s:property value ="role" /></ h1 >
</ body >
</ html >
然后,创建tutorial.Roles初始化角色列表,代码如下:
package tutorial;
import java.util.Hashtable;
import java.util.Map;
public class Roles {
public Map < String, String > getRoles() {
Map < String, String > roles = new Hashtable < String, String > ( 2 );
roles.put( " EMPLOYEE " , " Employee " );
roles.put( " MANAGER " , " Manager " );
return roles;
}
}
接下来,新建Login.jsp实例化tutorial.Roles,并将其roles属性赋予<s:radio>标志,代码如下:
<% @ page contentType = " text/html; charset=UTF-8 " %>
<% @taglib prefix = " s " uri = " /struts-tags " %>
< html >
< head >
< title > Login </ title >
</ head >
< body >
< h1 > Login </ h1 >
Please select a role below:
< s:bean id ="roles" name ="tutorial.Roles" />
< s:form action ="Login" >
< s:radio list ="#roles.roles" value ="EMPLOYEE" name ="role" label ="Role" />
< s:submit />
</ s:form >
</ body >
</ html >
创建Action类tutorial.Login将role放到session中,并转到Action类tutorial.AuthorizatedAccess,代码如下:
package tutorial;
import java.util.Map;
import org.apache.struts2.interceptor.SessionAware;
import com.opensymphony.xwork2.ActionSupport;
public class Login extends ActionSupport implements SessionAware {
private String role;
private Map session;
public String getRole() {
return role;
}
public void setRole(String role) {
this .role = role;
}
public void setSession(Map session) {
this .session = session;
}
@Override
public String execute() {
session.put( " ROLE " , role);
return SUCCESS;
}
}
最后,配置struts.xml文件,内容如下:
<! DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
"http://struts.apache.org/dtds/struts-2.0.dtd" >
< struts >
< include file ="struts-default.xml" />
< package name ="InterceptorDemo" extends ="struts-default" >
< interceptors >
< interceptor name ="auth" class ="tutorial.AuthorizationInterceptor" />
</ interceptors >
< action name ="Timer" class ="tutorial.TimerInterceptorAction" >
< interceptor-ref name ="timer" />
< result > /Timer.jsp </ result >
</ action >
< action name ="Login" class ="tutorial.Login" >
< result type ="chain" > AuthorizatedAccess </ result >
</ action >
< action name ="AuthorizatedAccess" class ="tutorial.AuthorizatedAccess" >
< interceptor-ref name ="auth" />
< result name ="login" > /Login.jsp </ result >
< result name ="success" > /ShowRole.jsp </ result >
</ action >
</ package >
</ struts >
发布运行应用程序,在浏览器地址栏中输入:http://localhost:8080/Struts2_Interceptor/AuthorizatedAccess.action。由于此时,session还没有键为“ROLE”的值,所以返回Login.jsp页面,如图2所示:
图2 Login.jsp
选中Employee,点击Submit,出现图3所示页面:
图3 ShowRole.jsp
总结
拦截器是Struts 2比较重要的一个功能。通过正确地使用拦截器,我们可以编写高可复用的代码。