Struts 2拦截器

学习内容

 拦截器工作原理

 Struts 2自带拦截器

 自定义拦截器

能力目标

 熟悉Struts 2拦截器工作原理

 熟练使用和配置拦截器

本章简介

上一章我们深入学习了Struts 2框架的配置,包括Action的配置、Result的配置等等,使我们对Struts 2框架有了更深的了解。Struts 2的核心包括Action、Result和拦截器。拦截器是Struts 2的一个重要特性,实际上Struts 2框架的核心功能都是由拦截器负责完成的。

拦截器(Interceptor)能动态拦截Action调用的对象。它提供了一种机制使开发者可以在一个Action执行之前或执行之后插入需要的代码,同时它也是提供了一种可以提取Action中可重用代码的方式。本章将重点学习Struts 2拦截器。 

核心技能部分

5.1 Struts 2的拦截器

在第五章学习Struts 2体系结构时已经提到了拦截器,它主要出现在Action执行之前或执行之后,大家可以先回顾一下。对于Web应用程序来说,有很多的业务都是通用的,例如对请求数据的封装、数据的校验、防止表单重复提交等。早期的MVC框架将这些业务功能都写死在核心控制器中了,这直接导致框架的灵活性和可扩展性严重下降。

Struts 2将它的核心功能放到拦截器中实现而不是集中在核心控制器里,并且每个拦截器完成一个业务功能,不同的拦截器还能自由组合,这使得开发人员能够更加高效、灵活的使用Struts 2框架进行开发。

拦截器是动态拦截Action调用的对象,拦截器的方法可以在Action执行之前或之后自动执行,从而将通用的操作动态地插入到Action执行的前后,这跟我们平时组装电脑很类似,业务功能变成了可插拔式,需要哪个功能就“插入”一个拦截器,不需要就“拔出”,非常有利于系统的解耦。

单一的拦截器还可以灵活的组合在一起构成拦截器栈。拦截器是一个类,通过在struts.xml中进行配置来发挥作用。

5.1.1 拦截器工作原理

拦截器围绕着Action和Result的执行而执行,如图5-1-1所示。Action被一系列的拦截器包裹,首先执行Action之前的拦截器,并按照顺序依次执行拦截器1、拦截器2、拦截器3……,在Action和Result执行过之后,拦截器会再一次执行,并按照相反的顺序依次执行,图5-1-2清晰的显示了这种顺序。在这一系列执行过程中,任何一个拦截器都可以直接返回,从而终止余下的拦截器的执行。

图5.1.1  拦截器工作原理


图5.1.2  Struts 2拦截器时序图 

5.1.2 Struts 2自带拦截器

Struts 2框架提供了一系列功能强大的拦截器,它们实现了框架的大部分功能,同时在实际开发中我们也可以灵活应用这些Struts 2自带的拦截器。打开Struts 2源文件中的struts-default.xml文件,如图5.1.3所示,Struts 2自带的拦截器就配置在这个文件里。

 

图5.1.3 Struts 2自带拦截器

单个拦截器由<interceptor>元素配置,name属性设置拦截器的逻辑名,class属性设置拦截器的实现类。

下面对Struts 2自带的拦截器进行简单介绍:

Ø checkbox:添加了对表单中checkbox自动处理的代码,将没有选中的checkbox的内容

设定为false,而HTML默认情况下不提交没有选中的checkbox。

 conversionError:将错误信息从ActionContext中添加到Action的属性字段中。

 createSession:自动创建HttpSession,用来为需要使用到HttpSession的拦截器服务。

 execAndWait:在后台执行Action,同时将用户带到一个中间的等待页面。

 exception:捕获异常并能根据异常类型映射到用户自定义的错误页面。

 fileUpload:提供文件上传功能。

 params:将请求中的参数设置到Action的属性上。

 scope:将Action状态存入session和application的简单方法。

 servletConfig:提供访问HttpServletRequest和HttpServletResponse的方法,以Map的方

式访问。

 token:防止表单重复提交。

 tokenSession:和token一样,不过双击的时候把请求的数据存储在session中。

 validation:执行数据校验。

 workflow:调用Action的validate方法,一旦有错误返回就终止执行流程。

上面列出了Struts 2常用的拦截器,在实际应用中,我们经常需要组合不同的拦截器形成一个拦截器栈,Struts 2框架在struts-default.xml中定义了一个默认的拦截器栈defaultStack,如图5.1.4所示,这个拦截器栈组合了多个拦截器,并且这些拦截器的顺序都是经过精心设计的,能满足大多数Web应用的需求。在struts.xml中,我们自定义的包(package)通常都要继承struts-default包,而此包指定了defaultStack拦截器栈为默认拦截器栈,所以如果用户的自定义包继承了struts-default包,也会自动将defaultStack做为默认拦截器。如果用户没有为Action指定拦截器,系统将会自动把defaultStack拦截器栈作用于此Action。

 

图5.1.4 defaultStack拦截器栈

5.2 配置拦截器

拦截器的使用分为三个步骤:

(1) 实现拦截器类

(2) 在struts.xml中定义拦截器或拦截器栈

(3) 为Action配置拦截器或拦截器栈

如果我们使用的是Struts 2自带的拦截器,那么只需要进行第三步即可;如果我们使用的是自己开发的拦截器,就需要进行以上三步。下面是配置语法。

<struts>
<package name ="admin" extends="struts-default">
<!—定义拦截器 -- >
<interceptors>
<interceptorname="拦截器1" class="拦截器的实现类" />
... ...
<interceptor-stack name="拦截器栈1">
<interceptor-ref name="拦截器1"/>
<interceptor-ref name="拦截器2"/>
... ...
</interceptor-stack>
</interceptors>
<!—使用拦截器 -- >
<action name="checkLogin" class="tmq.action.DefaultAction" >
<result name="success">/success.jsp</result>
<result name="login">/login.jsp</result>
<interceptor-ref name="拦截器1" />
<interceptor-ref name="拦截器栈1"/>
</action>
</package>
</struts>


所有的拦截器或拦截器栈都定义在<interceptors>元素内,单个拦截器由它的子元素<interceptor>s定义,name属性定义拦截器的逻辑名,class属性用来指定拦截器的实现类。

拦截器栈由<interceptor-stack>元素定义,并需要通过子元素<interceptor-ref>来引用已经定义好的拦截器作为栈元素,<interceptor-ref>的name属性用来设置想要引用的拦截器的逻辑名。

定义好拦截器或拦截器栈以后,需要在Action的配置中为<action>元素配置拦截器或拦截器栈,此时使用的也是<interceptor-ref>,name同样设置为想要引用的拦截器的逻辑名,这里可以直接使用Struts的自带的拦截器。

5.3 自定义拦截器

5.3.1 如何使用自定义的拦截器

虽然Struts 2提过了如此丰富的拦截器,但是在实际应用中,我们仍需要自己开发拦截器以满足经常变化的业务需求。

自定义的拦截器类通常需要实现com.opensymphony.xwork2.interceptor.lnterceptor 接口,该接口的源代码如下所示。

public interface Interceptor {
void destroy();
void init();
String intercept (ActionInvocation invocation) throws Exception;
}
}


该接口定义了三个方法:

 init(),该方法执行于拦截器执行拦截之前,且每个拦截器只执行一次。因此,该方法的

主要用于打开某些资源。

 destroy(),该方法与init()方法对应。在拦截器实例被销毁之前,系统将回调此方法,销

毁在init()方法中打开的资源。

 intercept(Actionlnvocationinvocation),该方法是用户需要实现的拦截器动作,返回一个result配置字符串作为逻辑视图。该方法的ActionInvocation参数包含被拦截的Action的引用,可以通过调用该参数的invoke方法,将控制权转给下一个拦截器或者Action。详见表7-1-1所示。

表7-1-1 Actionlnvocation类的常用方法

方法

描述

Object getAction()

获得与拦截器关联的Action,注意进行强制类型转换。

String invoke()throws Exception

继续执行后面的拦截器或Action,可能抛出任何异常。

除此之外,Struts2还提供了一个com.opensymphony.xwork2.interceptor.Abstractlnterceptor类,该类提供了一个init方法和destroy方法的空实现。如果自定义的拦截器不需要申请资源,就无须实现这两个方法。所以,继承自Abstractlnterccptor类来实现自定义拦截器会更加简便。

示例5.1

考虑一般的WEB应用,基本都可分为前台和后台两部分,后台主要是对整个WEB应用进行管理,所以要使用后台必须先登录,后台部分可能包含了很多的Action和JSP视图,我们必须保证用户不能直接访问后台的每一个Action和JSP视图,或者说要想访问就必须先登录,这属于访问控制,这种情况非常适合使用拦截器来解决,接下来我们使用拦截器重构登录案例,把登录验证用拦截器来实现。

(1) 实现拦截器类

public class LoginInterceptor implements Interceptor {
public void destroy() {
}
public void init() {
}
public String intercept(ActionInvocation ai) throws Exception {
HttpSession session = ServletActionContext.getRequest().getSession();
User user = (User)session.getAttribute("loginUser");
 
if(user!=null)
return ai.invoke();   //登录成功则继续执行后面的拦截器或Action
else
return "error";
}
}
(2) 实现Action。
public class LoginAction extends ActionSupport{
private String name;
private String pwd;
//省略getter和setter方法
public String execute()
{
return SUCCESS;
}
}


由于我们把登录业务放在了拦截器中实现,所以Action中就无需编写业务实现代码了,直接在execute方法中返回了SUCCESS。

(3) 登录视图页面login.jsp

<body>
<form action="login.action" method="post">
<table width="397" height="169" border="0" align="center">
<tr>
<td colspan="2" align="center">管理员登录</td>
</tr>
<tr>
<td width="163" align="right">登录名称:</td>
<td width="218"><input name="name" type="text" class="txt"></td>
</tr>
<tr>
<td align="right">登录密码:</td>
<td><input name="pwd" type="password" class="txt"></td>
</tr>
<tr>
<td colspan="2" align="center"><input type="submit" value="提交"></td>
</tr>
</table>
</form>
</body>


(4) 在struts.xml配置文件中配置LoginAction的拦截器。

<struts>
<package name="admin" extends="struts-default">
<interceptors>
<interceptor name="loginInter" class="com.zy.LoginInterceptor"/>
<interceptor-stack name="loginStack">
<interceptor-ref name="defaultStack" />
<interceptor-ref name="loginInter" />
</interceptor-stack>
</interceptors>
<action name="login" class="com.zy.LoginAction">
<result name="success" type="redirect">/index.jsp</result>
<result name="error" type="redirect">/login.jsp</result>
<interceptor-ref name="loginStack" />
</action>
</package>
</struts>


在上述代码中,我们首先使用<interceptor>在配置文件中定义了自己开发的拦截器,然后把该拦截器和Struts 2默认的defaultStack组成了一个拦截器栈,最后为名字是“login”的action指定了这个拦截器栈。

如果其他的Action也需要进行登录访问控制,就只需要为该Action配置实现登录验证的拦截器即可。

5.3.2 默认拦截器

通常情况下,WEB应用的后台部分可能包含了很多的Action和JSP视图,为了实现访问控制,我们要给后台的每个Action都配置拦截器,虽然能够实现,但是过于繁琐,更好的解决方案就是给这些后台Action配置一个默认的拦截器(栈)。

默认拦截器(栈)定义在包(package)中,该包(package)中的所有Action都共享使用该默认拦截器(栈),每个包(package)中只能定义一个默认拦截器(栈)。

在struts.xml文件中使用<default-interceptor-ref>元素来配置默认拦截器(栈),它是包(package)的子元素,该元素的name属性值是一个已经定义好的某个拦截器(栈)的名字。参考代码如下所示。

<struts>
<package name ="admin" extends="struts-default">
<interceptors>
<interceptor name="loginInter" class="com.zy.LoginInterceptor"/>
<interceptor-stack name="loginStack">
<interceptor-ref name="defaultStack" />
<interceptor-ref name="loginInter" />
</interceptor-stack>
</interceptors>


<!-- 为此包配置一个默认拦截器或拦截器栈 -- >

<default-interceptor-ref  name="loginStack"/>
<!-- Action,可以有多个 -- >
<action name="login" class="com.zy.LoginAction">
<result name="success" type="redirect">/index.jsp</result>
<result name="error" type="redirect">/login.jsp</result>
</action>
<action>
……
</action>
……
</package>
</struts>

注意:

如果包中的某些Action没有显式的指定任何拦截器,则默认拦截器将会起作用。如果包中的某个Action显式指定了某个拦截器,则默认的拦截器将不会起作用,如果该Action还必须使用默认拦截器,那么就需要手动的配置该默认拦截器的引用。

5.4 深入拦截器

通过上面的学习,我们掌握了Struts 2中拦截器类的实现、拦截器的定义以及拦截器的使用,但是这些并不能完全满足实际开发的需求,我们还需要深入学习拦截器,包括拦截器方法过滤、拦截器的拦截顺序等知识。

5.4.1 拦截器方法过滤

在默认情况下,如果我们为某个Action指定了拦截器,那么这个拦截器就会拦截Action中的所有方法。但是有时候,实际需求并不希望拦截Action中所有的方法,而是只需要拦截其中的某些方法,这时就需要使用Struts 2提供的拦截器方法过滤功能。例如:在一个Action中我们实现了对商品的增、删、改、查等业务方法,管理员和普通用户都可以进行增、改、查操作,但是只有管理员可以进行删除操作,因此我们可以通过一个拦截器只拦截Action中的删除方法,在拦截时判断当前的用户是否为管理员。

为了实现拦截器方法过滤,Struts 2提供了一个MethodFilterInterceptor抽象类。这个类重写了AbstractInterceptor类中的intercept方法,但是提供了doIntercept(ActionInvocation invocation)的抽象方法。如果开发者要实现拦截器方法过滤,则应该继承MethodFiledIntercepor抽象类,并重写doIntercept(ActionInvocation invocation)方法。

示例5.2

下面我们通过一个示例来演示如何使用拦截器方法过滤,拦截器可以拦截Action中删除管理员的方法,不拦截添加和查询管理员的方法。

(1) 实现拦截器类,参考代码如下所示。

public class AdminInterceptor extends MethodFilterInterceptor {
protected String doIntercept(ActionInvocation ai) throws Exception {
System.out.println("拦截器起作用了");
return ai.invoke();
}
}


此处只是为了演示拦截器方法过滤的使用,所以在doIntercept方法中仅仅进行了控制台输出。

(2) 实现Action,参考代码如下所示。

public class AdminAction {
public String add()
{
System.out.println("添加管理员");
return "success";
}
public String query()
{
System.out.println("查询管理员");
return "success";
}
public String del()
{
System.out.println("删除管理员");
return "success";
}
}


上述代码分别模拟实现了添加、查询和删除管理员的方法。本示例要求拦截器可以拦截删除管理员的方法,不拦截添加和查询管理员的方法。

(3) struts.xml文件的配置代码如下所示。

<struts>
<package name="admin" extends="struts-default">
<interceptors>
<interceptor name="adminInter" class="com.zy.AdminInterceptor"/>
</interceptors>
<action name="admin_*" class="com.zy.AdminAction" method="{1}">
<result name="success" type="redirect">/index.jsp</result>
<interceptor-ref name="adminInter">
<param name="includeMethods">del</param>
<param name="excludeMethods">query</param>
</interceptor-ref>
</action>
</package>
</struts>

从上面的代码可以看出,在struts.xml文件中定义实现方法过滤的拦截器与普通拦截器是一样的,都是使用<interceptor>进行定义。不同的是,在为<action>元素指定拦截器时,方法过滤拦截器可以使用<param>元素设置拦截哪些方法,不拦截哪些方法。

<param>元素的name属性是必须的,主要有两个取值:

 includeMethods:设置需要拦截(过滤)的方法,只需把Action中的方法名罗列出来即可,多个方法之间用逗号隔开

 excludeMethods:设置不需要拦截(过滤)的方法,只需把Action中的方法名罗列出来即可,多个方法之间用逗号隔开

注意

如果一个方法既被指定在excludeMethods中,同时又被指定在includeMethods中,则此方法会被拦截,即includeMethods的优先级高于excludeMethods。

如果一个方法既没有被指定在excludeMethods中,同时又没有被指定在includeMethods中,则此方法不会被拦截。

接下来我们开始测试,直接通过URL访问Action并调用相应的方法。

 访问http://localhost:8080/Struts7-adv/admin_add.action,运行效果如图5.1.5所示。

 

图5.1.5 添加管理员

 访问http://localhost:8080/Struts7-adv/admin_query.action,运行效果如图5.1.6所示。

 

图5.1.6 查询管理员

 访问http://localhost:8080/Struts7-adv/admin_del.action,运行效果如图5.1.7所示。

 

图5.1.7 删除管理员

5.4.2 拦截顺序

前面学习拦截器工作原理时,我们介绍了拦截器的执行时序图,首先执行Action之前的拦截器,并按照顺序依次执行拦截器1、拦截器2、拦截器3 ……,在Action和Result执行过之后,拦截器会再一次执行,并按照相反的顺序依次执行,下面我们通过一个案例来演示拦截器的执行顺序。

示例5.3

public class SortInterceptor1 extends AbstractInterceptor{
public String intercept(ActionInvocation ai) throws Exception {
System.out.println("拦截器1开始执行...");
String result=ai.invoke();
System.out.println("拦截器1执行完毕...");
return result;
}
}
public class SortInterceptor2 extends AbstractInterceptor{
public String intercept(ActionInvocation ai) throws Exception {
System.out.println("拦截器2开始执行...");
String result=ai.invoke();
System.out.println("拦截器2执行完毕...");
return result;
}
}
public class SortInterceptor3 extends AbstractInterceptor{
public String intercept(ActionInvocation ai) throws Exception {
System.out.println("拦截器3开始执行...");
String result=ai.invoke();
System.out.println("拦截器3执行完毕...");
return result;
}
}
上述代码创建了三个拦截器类,代码比较简单,这里不再多述。下面是Action类的参考代码。
public class SortAction extends ActionSupport {
public String execute()
{
System.out.println("Action执行...");
return "success";
}
}
该Action只有一个execute方法,不再多述,重点看下面的struts.xml配置文件,参考代码如下所示。
<struts>
<package name="sort" extends="struts-default">
<interceptors>
<interceptor name="sortInter1" class="com.zy.SortInterceptor1"/>
<interceptor name="sortInter2" class="com.zy.SortInterceptor2"/>
<interceptor name="sortInter3" class="com.zy.SortInterceptor3"/>
</interceptors>
<action name="sort" class="com.zy.SortAction">
<result name="success" type="redirect">/index.jsp</result>
<interceptor-ref name="sortInter1"/>
<interceptor-ref name="sortInter2"/>
<interceptor-ref name="sortInter3"/>
</action>
</package>
</struts>


在配置文件中,我们定义了三个拦截器并为名字是“sort”的action元素指定了这三个拦截器。运行效果如图5.1.8所示。

 

图5.1.8 执行顺序

在Action执行之前,三个拦截器按照配置的顺序依次执行;在Action执行之后;三个拦截器按照相反的顺序依次执行。

本章总结

拦截器是动态拦截Action调用的对象,拦截器的方法可以在Action执行之前或之后自动执行,从而将通用的操作动态地插入到Action执行的前后,这跟我们平时组装电脑很类似,业务功能变成了可插拔式,需要哪个功能就“插入”一个拦截器,不需要就“拔出”,非常有利于系统的解耦。

Ø 系统拦截器。在struts-default.xml中配置了一组拦截器,并组成了默认拦截器栈,自定义Action通过package的extends属性直接或者间接的继承到了拦截器的配置。

Ø 自定义拦截器。

(1)创建拦截器类,实现com.opensymphony.xwork2.interceptor.lnterceptor 接口。

(2)使用<interceptor>在配置文件中定义了自己开发的拦截器,然后把该拦截器和Struts 2默认的defaultStack组成了一个拦截器栈。

(3)在Action的配置中引用该拦截器栈。

Ø 默认拦截器。默认拦截器(栈)定义在包(package)中,该包(package)中的所有Action都共享使用该默认拦截器(栈),每个包(package)中只能定义一个默认拦截器(栈)。在struts.xml文件中使用<default-interceptor-ref>元素来配置默认拦截器(栈)。

Ø 拦截器方法过滤

(1)继承MethodFiledIntercepor抽象类,并重写doIntercept(ActionInvocation invocation方法。

(2)为<action>元素指定拦截器时,方法过滤拦截器可以使用<param>元素设置拦截哪些方法,不拦截哪些方法。

任务实训部分

1:计算器除0拦截器

训练技能点

 动态方法调用

 自定义拦截器

需求说明

在上一章的任务实训部分我们实现了一个简单的计算器,现在要求:当用户进行除法运

算时,如果除数为0则不进行运算并跳转到一个提示“除数不能为0”的页面,必须使

用拦截器实现。

实现步骤

(1) 创建Action类,参考代码如下所示。

public class CalculatorAction {
private double num1;
private double num2;
private double result;
public String jia()
{
result=num1+num2;
return "result";
}
public String jian()
{
result=num1-num2;
return "result";
}
public String cheng()
{
result=num1*num2;
return "result";
}
public String chu()
{
result=num1/num2;
return "result";
}
//省略getter和setter方法
}

(2) 创建与Action对应的视图页面,参考代码如下所示。

<body>
<form name="frm" method="post">
<table width="298" border="0" align="center">
<tr>
<td colspan="2" align="center">简易计算器</td>
</tr>
<tr>
<td width="76" align="center">第一个数</td>
<td width="206"><input type="text" name="num1" value="${num1}"></td>
</tr>
<tr>
<td align="center">第二个数</td>
<td><input type="text" name="num2" value="${num2}"></td>
</tr>
<tr>
<td colspan="2" align="center">
<input type="button"  value="+" οnclick="submitForm('jia')">
<input type="button"  value="-" οnclick="submitForm('jian')">
<input type="button"  value="*" οnclick="submitForm('cheng')">
<input type="button"  value="/" οnclick="submitForm('chu')"></td>
</tr>
<tr>
<td align="center">结果</td>
<td><input type="text" name="result" readonly value="${result}"></td>
</tr>
</table>
</form>
</body>
<script>
function submitForm(op)
{
frm.action="cal_"+op+".action";
frm.submit();
}
</script>
(3) 创建除0拦截器,参考代码如下所示。
public class CalculatorInterceptor extends AbstractInterceptor {
public String intercept(ActionInvocation ai) throws Exception {
CalculatorAction ca=(CalculatorAction)ai.getAction();
if(ai.getProxy().getMethod().equals("chu")&&ca.getNum2()==0)
return "error";
else
return ai.invoke();
}
}


在拦截器类中需要解决的一个问题是:判断此次请求调用的是否是Action中的chu()方法。ActionInvocation类的getProxy()方法可以获得当前Action的代理对象,该对象的getMethod()方法可以获得当前请求调用的方法名。

(4) 下面是struts.xml文件的参考代码

<struts>
<constant name="struts.i18n.encoding" value="utf-8"></constant>
<package name="shangji" extends="struts-default">
<interceptors>
<interceptor name="calInter" class="com.zy.cal.
CalculatorInterceptor"/>
</interceptors>
<action name="cal_*" class="com.zy.cal.CalculatorAction" method="{1}">
<interceptor-ref name="defaultStack"/>
<interceptor-ref name="calInter"/>
<result name="result" type="dispatcher">/calculator.jsp</result>
<result name="error" type="redirect">/error.html</result>
</action>
</package>
</struts>


我们为action指定了两个拦截器,一个是Struts 2默认的defaultStack拦截器栈,另一个是我们自定义的拦截器。运行效果如图5.2.1和图5.2.2所示,当我们进行除0运算时,页面跳转到了error.html。

 

图5.2.1 计算器

 

图5.2.2 提示

 2:脏字过滤

训练技能点

 自定义拦截器

需求说明

很多网站都有评论功能,即用户可以对商品、新闻等进行评论,但是个别用户发表的评论可能带有一些“脏字”,例如“妈的”等等。现在要求当用户发表的评论中带有“妈的”文字时不予执行并要求重新发表评论,必须使用拦截器实现。

实现步骤

(1) 创建Action类,参考代码如下所示。

public class WordAction {
private String title;     //标题
private String context;  //正文
public String pub()
{
//省略将评论插入到数据库中的代码
return "success";
}
//省略getter和setter方法
}

(2) 创建与之对应的视图页面,参考代码如下所示。

<body>
<form  method="post" action="pub.action">
<table border="0" align="center">
<tr>
<td>标题:</td>
<td><input name="title" type="text" size="30"></td>
</tr>
<tr>
<td>正文:</td>
<td><textarea name="context" cols="28" rows="10"></textarea></td>
</tr>
<tr>
<td colspan="2" align="center">
<input type="submit" value="提交"></td>
</tr>
</table>
</form>
</body>
(3) 创建脏字过滤拦截器,参考代码如下所示。
public class WordInterceptor extends AbstractInterceptor {
public String intercept(ActionInvocation ai) throws Exception {
WordAction wa=(WordAction)ai.getAction();
if(wa.getTitle().indexOf("妈的")!=-1||
wa.getContext().indexOf("妈的")!=-1)
return "input";
else
return ai.invoke();
}
}


(4) 下面是struts.xml文件的参考代码

<struts>
<constant name="struts.i18n.encoding" value="utf-8"></constant>
<package name="shangji" extends="struts-default">
<interceptors>
<interceptor name="wordInter" class="com.zy.word.
WordInterceptor"/>
</interceptors>
<action name="pub" class="com.zy.word.WordAction" method="pub">
<interceptor-ref name="defaultStack"/>
<interceptor-ref name="wordInter"/>
<result name="success" type="redirect">/success.html</result>
<result name="input" type="redirect">/pub.html</result>
</action>
</package>
</struts>


运行效果如图5.2.3所示,当我们发表的评论中带有“妈的”文字时会重新回到发表评论的页面。

 

图5.2.3 脏字过滤

3:限时访问

训练技能点

 自定义拦截器

 全局结果

需求说明

很多商业网站或软件都需要经常性的进行数据备份或维护,假如现在某个网站从凌晨1点到凌晨4点要进行维护,这个时间段暂停服务,即所有对本网站的访问都将被重置到一个带有提示信息的网页,如图5.2.4所示,要求用拦截器实现。

实现步骤

public class TimeInterceptor extends AbstractInterceptor {
public String intercept(ActionInvocation ai) throws Exception {
Calendar cale=Calendar.getInstance();
int curr=cale.get(Calendar.HOUR_OF_DAY);
if(curr>1&&curr<3)
return "tishi";
else
return ai.invoke();
}
}


这里我们只给出拦截器类的参考代码,在intercept()方法中最重要的是获得当前的时间,这里使用Calendar类的相关方法获得当前的小时数。

 

图5.2.4 限时访问

 4:为管理员登录增加拦截器

训练技能点

 自定义拦截器

 默认拦截器

需求说明

在第五章我们实现了管理员登录以及对管理员的增删改查等操作,现在要求为登录、增加、删除、修改和查询管理员添加默认拦截器,管理员必须登录成功才能进行增删改查操作,没有登录直接返回到登录页面。

巩固练习

一、选择题

1. 以下关于拦截器的说法错误的是()。

A. 可以在Action执行前后做一些操作

B. Struts自带的拦截器用户无法使用

C. 拦截器是一个特殊的Action

D. 拦截器只在Action之前发挥作用

2.自定义拦截器中的invoke()代码表示()。

A. 不执行目标Action的方法,直接返回

B. 执行目标Action的方法,直接返回结果视图

C. 在自定义拦截器中,该代码是必需的

D. 在自定义拦截器中,该代码是可选的

3.开发自定义拦截器的步骤是()。

A. 在struts.xml文件中定义拦截器

B. 创建拦截器类

C. 在struts.xml文件中为action元素指定拦截器

D. 继承struts-default

4.下面()拦截器用来将请求中的参数设置到Action的属性上。

A. token

E. params

F. workflow

G. validation

5.下面关于<interceptor>元素说法错误的是()。

A. name属性指定拦截器的名称

H. name属性的值必须被某个Action所引用

I. 该元素是<package>的子元素

J. class属性指定拦截器的实现类

 二、上机练习

在实训任务4的基础上扩展功能,管理员admin是超级管理员,只有他登录的时候才

可以进行任何操作,其他管理员登录后只能进行查询操作,用拦截器实现。

  • 3
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论
Struts2 中,可以使用拦截器来实现权限控制。具体来说,可以编写一个自定义拦截器,然后在 struts.xml 配置文件中将其配置为需要进行权限控制的 Action 的拦截器。以下是一个简单的权限拦截器示例: ```java public class AuthInterceptor extends AbstractInterceptor { @Override public String intercept(ActionInvocation invocation) throws Exception { // 获取当前用户 User user = (User) ActionContext.getContext().getSession().get("user"); // 判断用户是否拥有权限 if (user != null && user.hasPermission(invocation.getInvocationContext().getName())) { // 如果有权限,则继续执行 Action return invocation.invoke(); } else { // 如果没有权限,则跳转到错误页面 return "error"; } } } ``` 在上述代码中,我们首先获取了当前用户,然后判断用户是否拥有执行当前 Action 的权限。如果有权限,则继续执行 Action;否则,跳转到错误页面。 接下来,在 struts.xml 配置文件中,我们可以将该拦截器配置为需要进行权限控制的 Action 的拦截器,如下所示: ```xml <action name="myAction" class="com.example.MyAction"> <interceptor-ref name="authInterceptor"/> <result name="success">/myAction.jsp</result> <result name="error">/error.jsp</result> </action> <interceptor-stack name="authStack"> <interceptor-ref name="authInterceptor"/> <interceptor-ref name="defaultStack"/> </interceptor-stack> <interceptors> <interceptor name="authInterceptor" class="com.example.AuthInterceptor"/> </interceptors> ``` 在上述代码中,我们首先定义了一个名为 authStack 的拦截器栈,该拦截器栈包含了 authInterceptor 和 defaultStack 两个拦截器。然后,我们将 myAction Action 配置为使用 authStack 拦截器栈。最后,我们定义了一个名为 authInterceptor 的拦截器,并将其添加到了 interceptors 中。 这样一来,当用户访问 myAction Action 时,就会先执行 authInterceptor 拦截器,进行权限控制,然后再执行 defaultStack 拦截器栈中的其它拦截器。如果 authInterceptor 拦截器返回了 error,则会跳转到 error.jsp 页面;否则,会跳转到 myAction.jsp 页面。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

teayear

读后有收获可以支付宝请作者喝咖

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值