微信扫一扫

028-83195727 , 15928970361
business@forhy.com

【电信计费系统项目实战】基础篇---登录检查拦截器

拦截器-struts2016-08-11

上一篇中,我们主要了解了如何用map实现登录界面的验证码,这一次,我们将学习登录检查拦截器,用于对资费等业务模块进行登录校验。

在上一篇的登录验证码中,登录成功后,将登录信息记录到Session(第54行),如下:

package com.tarena.action.login;

import org.omg.CORBA.Request;

import com.tarena.action.BaseAction;
import com.tarena.dao.DAOException;
import com.tarena.dao.DAOFactory;
import com.tarena.dao.login.ILoginDAO;
import com.tarena.entity.Admin;

public class LoginAction extends BaseAction {

    //input
    private String adminCode;
    private String password;
    private String imageCode;
    //output
    private String errorMsg;

    public String execute() {
        //1.校验验证码
        String code = (String) session.get("imageCode");
        if(code == null ||
                !code.equalsIgnoreCase(imageCode)) {
            //验证码不匹配,校验失败
            errorMsg = "验证码错误!";
            return "fail";
        }

        //2.根据账号查询管理员
        ILoginDAO dao = DAOFactory.getLoginDAO();
        Admin admin = null;
        try {
            admin = dao.findByCode(adminCode);
        } catch (DAOException e) {
            e.printStackTrace();
            errorMsg = "查询管理员报错,请联系系统管理员!";
            return "fail"; //异常,返回登录页面
        }

        if(admin == null) {
            //3.如果没有对应的管理员,登录失败,账号不存在
            errorMsg = "账号不存在!";
            return "fail"; //验证失败,回登录页面
        } else {
            //4.如果有对应管理员,看密码,若密码错误,登录失败
            String pwd = admin.getPassword();
            if(!pwd.equals(password)) {
                errorMsg = "密码错误!";
                return "fail"; //验证失败,回登录页面
            }
        }
        //4.登录成功后,将登录信息记录到Session
        session.put("admin", adminCode);
        return "success"; //成功,去index.jsp
    }

    public String getAdminCode() {
        return adminCode;
    }

    public void setAdminCode(String adminCode) {
        this.adminCode = adminCode;
    }

    public String getErrorMsg() {
        return errorMsg;
    }

    public void setErrorMsg(String errorMsg) {
        this.errorMsg = errorMsg;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public String getImageCode() {
        return imageCode;
    }

    public void setImageCode(String imageCode) {
        this.imageCode = imageCode;
    }

}

我们在公共配置包中注册了登录拦截器,这样每个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>

    <!-- 
        定义公共的包,将公共的配置放于此包下,
        如果其他package希望使用此包下的内容,
        则继承与此包即可。 
    -->
    <package name="netctoss" extends="json-default">
        <!-- 注册拦截器 -->
        <interceptors>
            <!-- 注册登录检查拦截器 -->
            <interceptor name="loginInterceptor"
                class="com.tarena.interceptor.LoginInterceptor"></interceptor>
            <!-- 
                为了引用方便,将登录检查拦截器和默认
                拦截器打包成栈 
            -->
            <interceptor-stack name="loginStack">
                <interceptor-ref name="loginInterceptor"></interceptor-ref>
                <interceptor-ref name="defaultStack"></interceptor-ref>
            </interceptor-stack>
        </interceptors>
        <!-- 
            指定当前包下Action默认引用的拦截器,
            其作用相当于是在此包下每个Action中
            都引用了这个拦截器。
        -->
    <!--    <default-interceptor-ref name="loginStack"/>-->
        <!-- 
            定义全局的Result,全局Result可以被当前包下
            所有的Action访问。相当于当前包下每个Action
            中都写了这个全局Result。
         -->
        <global-results>
            <!-- 踢回登录页面Result -->
            <result name="login" type="redirectAction">
                <param name="namespace">/login</param>
                <param name="actionName">toLogin</param>
            </result>
            <!-- 转到错误页面Result -->
            <result name="error">
                /WEB-INF/main/error.jsp
            </result>
        </global-results>
    </package>

</struts>

登录检查拦截器,用于对资费等业务模块进行登录校验

package com.tarena.interceptor;

import java.util.Map;

import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.interceptor.Interceptor;

/**
 *  登录检查拦截器,用于对资费等业务模块进行登录校验
 */
public class LoginInterceptor implements Interceptor {

    public void destroy() {

    }

    public void init() {

    }

    public String intercept(ActionInvocation ai) 
        throws Exception {
        Map<String,Object> session = 
            ai.getInvocationContext().getSession();
        //如果登录过,则从session中可以取到admin,否则取不到
        Object admin = session.get("admin");
        if(admin == null) {
            //session中没取到admin,说明没登录过,踢回登录页
            return "login"; //通过login找Result转到登录页
        } else {
            //session中取到admin,说明登录过,可以访问Action
            return ai.invoke();
        }
    }

}

这里有必要说一下struts2 拦截器和actioninvocation(参考这里):

Interceptor的接口定义没有什么特别的地方,除了init和destory方法以外,intercept方法是实现整个拦截器机制的核心方法。而它所依赖的参数ActionInvocation则是我们之前章节中曾经提到过的著名的Action调度者。

我在这里需要指出的是一个很重要的方法invocation.invoke()。这是ActionInvocation中的方法,而ActionInvocation是Action调度者,所以这个方法具备以下2层含义(详细看DefaultActionInvocation源代码):
1. 如果拦截器堆栈中还有其他的Interceptor,那么invocation.invoke()将调用堆栈中下一个Interceptor的执行。
2. 如果拦截器堆栈中只有Action了,那么invocation.invoke()将调用Action执行。

3.