2.4 完整代码
本案例的完整代码如下。
SecondInterceptor完整代码:
package interceptor;
import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.interceptor.Interceptor;
/**
* 第二个拦截器
*/
public class SecondInterceptor implements Interceptor {
@Override
public void destroy() {
}
@Override
public void init() {
}
@Override
public String intercept(ActionInvocationai) throws Exception {
System.out.println("SecondInterceptor拦截前...");
ai.invoke();
System.out.println("SecondInterceptor拦截后...");
return "error";
}
}
struts.xml完整代码:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.1.7//EN"
"http://struts.apache.org/dtds/struts-2.1.7.dtd">
<struts>
<!-- 客户配置信息 -->
<package name="customer"
namespace="/customer" extends="struts-default">
<interceptors>
<!-- 注册拦截器 -->
<interceptor name="first"
class="interceptor.FirstInterceptor"/>
<interceptor name="second"
class="interceptor.SecondInterceptor"/>
<!-- 注册拦截器栈 -->
<interceptor-stack name="myStack">
<interceptor-ref name="first"/>
<interceptor-ref name="second"/>
</interceptor-stack>
</interceptors>
<!-- 设置当前包下所有Action默认引用的拦截器 -->
<default-interceptor-ref name="myStack"/>
<!-- 打开修改页面 -->
<action name="toUpdateCustomer"
class="action.ToUpdateCustomerAction">
<!-- 引用拦截器 -->
<!--<interceptor-ref name="first"/> -->
<result name="success">
/WEB-INF/customer/update_customer.jsp
</result>
</action>
</package>
</struts>
3 NetCTOSS登录检查
3.1 问题
当前NetCTOSS项目中,我们可以直接在地址栏中输入地址访问资费模块的功能,这使得登录功能形同虚设。要求在没登录时不允许直接访问资费模块的任何action,登录后才可以访问。
3.2 方案
需要在访问资费action时进行校验,判断是否已进行了登录。这种判断每一个action都要处理,甚至以后有更多业务模块时也要做这样的事情,因此是action通用的业务逻辑,可以使用拦截器来处理。
我们可以创建拦截器组件,在拦截方法中调用action业务方法之前,判断是否进行过登录,从而确定是否可以继续访问该action,然后给每一个业务模块注册该action即可实现此需求。
3.3 步骤
实现此案例需要按照如下步骤进行。
步骤一:创建登录检查拦截器
创建com.netctoss.interceptor包,在该包下创建登录检查拦截器LoginInterceptor,代码如下:
packagecom.netctoss.interceptor;
importjava.util.Map;
import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.interceptor.Interceptor;
/**
* 登录检查拦截器,用于检查用户是否登录。
*/
public class LoginInterceptor implements Interceptor {
@Override
public void destroy() {
}
@Override
public void init() {
}
@Override
public String intercept(ActionInvocationai) throws Exception {
// 获取session
Map<String, Object> session = ai.getInvocationContext().getSession();
// 从session中读取登录信息
Object admin = session.get("admin");
// 如果登录信息为空,则踢回登录页,而不调用业务Action
if (admin == null) {
return "login";
} else {
// 如果登录信息不为空,则调用业务Action
returnai.invoke();
}
}
}
步骤二:使用登录检查拦截器
在struts.xml中注册该拦截器,然后将其与默认拦截器栈打包成新的拦截器栈loginStack,再通过default-interceptor-ref标记设置action默认使用的拦截器为loginStack。在检查到未登录时,需要找到名为login的result,跳转回登录页面,这个result就需要是所有action公用的,可以在global-results标记下定义这个result,来实现被action复用的目的。代码如下:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.1.7//EN"
"http://struts.apache.org/dtds/struts-2.1.7.dtd">
<struts>
#cold_bold <!--公共的包,封装了通用的拦截器、通用的result -->
#cold_bold <package name="netctoss" extends="json-default">
#cold_bold <interceptors>
#cold_bold <!--登录检查拦截器 -->
#cold_bold <interceptor name="loginInterceptor"
#cold_bold class="com.netctoss.interceptor.LoginInterceptor"/>
#cold_bold <!--登录检查拦截器栈 -->
#cold_bold <interceptor-stack name="loginStack">
#cold_bold <interceptor-ref name="loginInterceptor"/>
#cold_bold <!--不要丢掉默认的拦截器栈,里面有很多Struts2依赖的拦截器 -->
#cold_bold <interceptor-ref name="defaultStack"/>
#cold_bold </interceptor-stack>
#cold_bold </interceptors>
#cold_bold <!--设置action默认引用的拦截器 -->
#cold_bold <default-interceptor-ref name="loginStack"/>
#cold_bold <!--全局的result,包下所有的action都可以共用 -->
#cold_bold <global-results>
#cold_bold <!--跳转到登录页面的result -->
#cold_bold <result name="login" type="redirectAction">
#cold_bold <param name="namespace">/login</param>
#cold_bold <param name="actionName">toLogin</param>
#cold_bold </result>
#cold_bold </global-results>
#cold_bold </package>
<!--
资费模块配置信息:
一般情况下,一个模块的配置单独封装在一个package下,
并且以模块名来命名package的name和namespace。
-->
#cold_bold <package name="cost" namespace="/cost" extends="netctoss">
<!--查询资费数据 -->
<action name="findCost" class="com.netctoss.action.FindCostAction">
<!--
正常情况下跳转到资费列表页面。
一般一个模块的页面要打包在一个文件夹下,并且文件夹以模块名命名。
-->
<result name="success">
/WEB-INF/cost/find_cost.jsp
</result>
<!--
错误情况下,跳转到错误页面。
错误页面可以被所有模块复用,因此放在main下,
该文件夹用于存放公用的页面。
-->
<result name="error">
/WEB-INF/main/error.jsp
</result>
</action>
<!--删除资费 -->
<action name="deleteCost"
class="com.netctoss.action.DeleteCostAction">
<!--删除完之后,重定向到查询action -->
<result name="success" type="redirectAction">
findCost
</result>
<result name="error">
/WEB-INF/main/error.jsp
</result>
</action>
<!--打开资费新增页 -->
<action name="toAddCost">
<result name="success">
/WEB-INF/cost/add_cost.jsp
</result>
</action>
<!--资费名唯一性校验 -->
<action name="checkCostName"
class="com.netctoss.action.CheckCostNameAction">
<!--使用json类型的result把结果输出给回调函数 -->
<result name="success" type="json">
<param name="root">info</param>
</result>
</action>
<!--打开修改页面 -->
<action name="toUpdateCost"
class="com.netctoss.action.ToUpdateCostAction">
<result name="success">
/WEB-INF/cost/update_cost.jsp
</result>
<result name="error">
/WEB-INF/main/error.jsp
</result>
</action>
</package>
<!--登录模块 -->
<package name="login" namespace="/login" extends="struts-default">
<!--
打开登录页面:
1、action的class属性可以省略,省略时Struts2
会自动实例化默认的Action类ActionSupport,
该类中有默认业务方法execute,返回success。
2、action的method属性可以省略,省略时Struts2
会自动调用execute方法。
-->
<action name="toLogin">
<result name="success">
/WEB-INF/main/login.jsp
</result>
</action>
<!--登录校验 -->
<action name="login" class="com.netctoss.action.LoginAction">
<!--校验成功,跳转到系统首页 -->
<result name="success">
/WEB-INF/main/index.jsp
</result>
<!--登录失败,跳转回登录页面 -->
<result name="fail">
/WEB-INF/main/login.jsp
</result>
<!--报错,跳转到错误页面 -->
<result name="error">
/WEB-INF/main/error.jsp
</result>
</action>
<!--生成验证码 -->
<action name="createImage" class="com.netctoss.action.CreateImageAction">
<!--使用stream类型的result -->
<result name="success" type="stream">
<!--指定输出的内容 -->
<param name="inputName">imageStream</param>
</result>
</action>
</package>
</struts>