拦截器是Struts2框架的重要组成部分,Struts2的很多重要功能都是构建在拦截器之上的,如数据校验,转换器,国际化等。Struts2利用其内建的拦截器可以完成大部分操作,当内置拦截器不能满足时,开发者也可以自己扩展。可以说,Struts2框架之所以简单易用,与拦截器的作用是分不开的。
一,拦截器的配置
1,拦截器
想要让拦截器起作用,首先要对它进行配置。拦截器的配置是在 struts.xml 文件中完成的,它通常以
<interceptor>标签开头,以</interceptor>标签结束。定义拦截器格式如下:
<interceptor name="interceptorName" class="interceptorClass">
<param name="paramName">paramValue</param>
</interceptor>
name:用来指定拦截器的名称
class:用来指定拦截器的实现类
param:需要传入参数,name是参数名,paramValue是参数值
2,拦截器栈
在实际开发中,经常需要在Action执行前同时执行多个拦截器动作,如用户登录检查,登录日志记录
以及权限检查等,这时,可以把多个拦截器组成一个拦截器栈。在使用时,可以将栈内多个拦截器当成一个整体
来引用。当拦截器被附加到一个Action上时,在执行Action之前必须先执行拦截器栈中的每一个拦截器。
定义拦截器栈用<interceptors>元素和<interceptor-stack>子元素,当配置多个拦截器时,需要使用
<interceptor-ref>元素来指定多个拦截器,配置语法:
<interceptors>
<interceptor-stack name="interceptorStackName">
<interceptor-ref name="interceptorName">
....
</interceptor-ref>
</interceptor-stack>
</interceptors>
interceptorStackName:拦截器栈名称
interceptorName :拦截器名称
除此之外,在一个拦截器栈中还可以包含另一个拦截器栈:
<package name="default" extends="struts-default">
<interceptors>
<interceptor name="interceptor1" class="interceptorClass"/>
<interceptor name="interceptor2" class="interceptorClass"/>
<interceptor-stack name="myStack">
<interceptor-ref name="defaultStack"/>
<interceptor-ref name="interceptor1"/>
<interceptor-ref name="interceptor2"/>
</interceptor-stack>
</interceptors>
</package>
在上述代码中,定义的拦截器栈是myStack,在myStack栈中,除了引用了两个自定义的拦截器外,还引用
了一个内置拦截器栈defaultStack,这个拦截器是必须要引入的。
3,默认拦截器
如果想对一个包下的Action使用相同的拦截器,则需要为该包中的每个Action都重复指定同一个拦截器,
这样写显然过于烦琐。这时,可以使用默认拦截器,默认拦截器对其指定包中所有Action都能起到拦截的作用。
一旦指定了默认拦截器,如果没有显示的指定拦截器,则会使用默认拦截器,否则,默认拦截器将会被屏蔽。
默认拦截器的语法需要使用<default-interceptor-ref>元素,次元素为package的子元素。
<default-interceptor-ref name="interceptorName"/>
interceptorName是必须已存在的拦截器或拦截器栈的名称
实例:
<package name="default" extends="struts-default">
<interceptors>
<interceptor name="interceptor1" class="interceptorClass"/>
<interceptor name="interceptor2" class="interceptorClass"/>
<interceptor-stack name="myStack">
<interceptor-ref name="defaultStack"/>
<interceptor-ref name="interceptor1"/>
<interceptor-ref name="interceptor2"/>
</interceptor-stack>
</interceptors>
<default-interceptor-ref name="myStack"/>
<action name="login" class="cn.itcast.action.LoginAction">
<result name="input">/login.jsp</result>
</action>
</package>
这个默认拦截器将会作用于包下所有的Action
Struts2的内建拦截器可以在 struts-default.xml 文件中查看
二,自定义拦截器
在实际开发过程中,Struts2的内置拦截器虽然可以完成大部分的拦截任务,但是一些与系统逻辑相关
的通用功能,则需要通过自定义拦截器来实现。
开发自己的拦截器,需要直接或间接的实现com.opensymphony.xwork2.interceptor.Interceptor
接口,具体代码如下:
public interface Interceptor extends Serializable {
void init();
void destroy();
String intercept(ActionInvocation invocation)throws Exception;
}
该接口提供了以下三个方法
void init():拦截器被创建后会立即被调用,他在拦截器的生命周期内只被调用一次。在该方法中对相关资源
进行必要的初始化
void destroy();该方法与init()方法相对应,在拦截器实例被销毁之前,将调用该方法来释放与拦截器
相关的资源。他在拦截器生命周期内也只被调用一次
String intercept(ActionInvocation invocation)throws Exception:拦截器的核心方法,用来添加真正执行
String intercept(ActionInvocation invocation)throws Exception:拦截器的核心方法,用来添加真正执行
拦截器工作的代码,实现具体的拦截器操作。他返回一个字符串作为逻辑视图,系统根据
返回的字符串跳转到对应的视图资源。每拦截一个动作请求,该方法就会被调用一次。该
方法的ActionInvocation参数包含了被拦截的Action的作用,可以通过该参数invoke()方法,
将控制权利转给下一个拦截器过着转给Action的execute方法。
实际开发中除了实现Interceptor接口的三个方法外,更常用的是继承抽象拦截器类AbstractInterceptor。
该类实现了Interceptor接口,并且提供了init() 和destroy()的点空实现。拦截器AbstractInterceptor中
定义的方法如下:
public abstract class AbstractInterceptor implements Interceptor {
public void init(){}
public void destroy(){}
public abstract String intercept(ActionInvocation invocation)throws Exception;
}
三,应用案例-使用拦截器实现权限控制
通过之前的讲解,可将自定义拦截器的使用分为以下三步:
(1)用户自定义的拦截器类,必须实现Interceptor接口是继承AbstractInterceptor类
(2)需要在struts.xml文件定义自定义拦截器
(3)在struts.xml中的Action中使用拦截器
1,在eclipse或myeclipse中创建一个web项目,将struts2的框架所需jar包添加到项目当中,然后在
WEB-INF目录下创建一个web.xml文件,并在其中注册过滤器和首页:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" id="WebApp_ID" version="3.1">
<display-name>Jsp_Struts2_Interceptor</display-name>
<welcome-file-list>
<welcome-file>main.jsp</welcome-file>
</welcome-file-list>
<filter>
<filter-name>struts2</filter-name>
<filter-class>org.apache.struts2.dispatcher.filter.StrutsPrepareAndExecuteFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>struts2</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
2,在src目录下创建一个名为cn.itcast.domain的包,在改包下创建User.java的类
package cn.itcast.domain;
public class User {
private String username;
private String password;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
3,在src 目录下创建cn.itcast.action的包,并在改包下创建LoginAction.java的类
package cn.itcast.action;
import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionSupport;
import com.opensymphony.xwork2.ModelDriven;
import cn.itcast.domain.User;
public class LoginAction extends ActionSupport implements ModelDriven<User>{
private static final long serialVersionUID = 1L;
private User user =new User();
@Override
public User getModel() {
// TODO Auto-generated method stub
return user;
}
public String execute()throws Exception{
ActionContext actionContext = ActionContext.getContext();
if("tom".equals(user.getUsername())&&"123".equals(user.getPassword())){
actionContext.getSession().put("user", user);
return SUCCESS;
}else {
actionContext.put("msg", "用户名或密码不正确!");
return INPUT;
}
}
}
4,在cn.itcast.action包下创建类BookAction
package cn.itcast.action;
import com.opensymphony.xwork2.ActionSupport;
public class BookAction extends ActionSupport{
public String add(){
System.out.println("book add");
return SUCCESS;
}
public String del(){
System.out.println("book del");
return SUCCESS;
}
public String update(){
System.out.println("book update");
return SUCCESS;
}
public String find(){
System.out.println("book find");
return SUCCESS;
}
}
5,在src目录下创建一个cn.itcast.interceptor的包,并在改包下创建拦截器PrivilegeInterceptor
package cn.itcast.interceptor;
import com.opensymphony.xwork2.Action;
import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.interceptor.AbstractInterceptor;
public class PrivilegeInterceptor extends AbstractInterceptor{
private static final long serialVersionUID = 1L;
@Override
public String intercept(ActionInvocation arg0) throws Exception {
ActionContext actionContext =arg0.getInvocationContext();
Object user = actionContext.getSession().get("user");
if(user!=null){
return arg0.invoke();
}else {
actionContext.put("msg", "您还未登录,请先登录");
return Action.LOGIN;
}
}
}
6,在WebContent或WebRoot下创建三个视图文件,主页main.jsp 登录界面login.jsp 操作成功界面success.jsp
main.jsp:
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<base href="<%=basePath%>">
<title>main.jsp</title>
</head>
<body>
<a href="/Jsp_Struts2_Interceptor/book_del">book del</a><br>
<a href="/Jsp_Struts2_Interceptor/book_add">book add</a><br>
<a href="/Jsp_Struts2_Interceptor/book_update">book update</a><br>
<a href="/Jsp_Struts2_Interceptor/book_find">book find</a><br>
</body>
</html>
login.jsp:
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>登录</title>
</head>
<body>
<center>
${requestScope.msg}<br>
<form action="//Jsp_Struts2_Interceptor/login.action" method="post">
<table>
<tr>
<td><label style="text-align:right">用户名:</label></td>
<td><input type="text" name="username"/></td>
</tr>
<tr>
<td><label style="text-align:right">密码:</label></td>
<td><input type="password" name="password"/></td>
</tr>
<tr>
<td align="right" colspan="2">
<input type="submit" value="登录" />
</td>
</tr>
</table>
</form>
</center>
</body>
</html>
success.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>成功页面</title>
</head>
<body>
用户${user.username}操作成功!
</body>
</html>
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.5//EN"
"http://struts.apache.org/dtds/struts-2.5.dtd">
<struts>
<constant name="struts.enable.DynamicMethodInvocation" value="true"/>
<constant name="struts.devMode" value="true"></constant>
<package name="struts2" namespace="/" extends="struts-default">
<interceptors>
<interceptor name="privilege" class="cn.itcast.interceptor.PrivilegeInterceptor"/>
<interceptor-stack name="myStack">
<interceptor-ref name="defaultStack"/>
<interceptor-ref name="privilege"/>
</interceptor-stack>
</interceptors>
<global-allowed-methods>regex:.*</global-allowed-methods>
<action name="book_*" class="cn.itcast.action.BookAction" method="{1}">
<result>/success.jsp</result>
<result name="login">/login.jsp</result>
<interceptor-ref name="myStack"/>
</action>
<action name="login" class="cn.itcast.action.LoginAction">
<result>/main.jsp</result>
<result name="input">/login.jsp</result>
</action>
</package>
</struts>
8,运行程序,查看结果
项目结构:
运行后如上图,点击操作
输入错误的账户密码
输入正确账户密码 tom 123
再次点击操作
控制台输出
运行成功