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>