Struts2中的cookie拦截器

Struts2中,截取HTTP请求中的Cookie信息是由cookie拦截器(CookieInterceptor)来完成的 — action类可以通过使用cookie拦截器来读取cookie的值。

由于默认情况下不使用cookie拦截器(不在defaultStack中),因此在struts.xml配置文件中需要对其进行声明:

<action name="Index" class="com.lifelaf.blog.action.ExampleAction">  
    <interceptor-ref name="defaultStack" />
    <interceptor-ref name="cookie">
        <param name="cookiesName">exampleKeyName1, exampleKeyName2</param>
        <param name="cookiesValue">*</param>
    </interceptor-ref>
    <result>/exampleResult.jsp</result>
</action>  

如上所示,仅仅声明使用cookie拦截器是不够的,我们还需要对该拦截器的cookiesName参数和cookiesValue参数进行设定。如果不设定cookiesName参数,action类将不会收到任何Cookie:

//CookieInterceptor.java
for (Cookie cookie : cookies) {  
    if (cookiesNameSet.contains("*")) {
        populateCookieValueIntoStack(name, value, cookiesMap, stack);
    } else if (cookiesNameSet.contains(cookie.getName())) {
        populateCookieValueIntoStack(name, value, cookiesMap, stack);
    }
}

在之前的struts.xml配置文件实例中,cookiesName参数设定为exampleKeyName1和exampleKeyName2,因此ExampleAction将会收到键为exampleKeyName1和exampleKeyName2的Cookie。有趣的是,只要cookiesName中出现*(比如:exampleKeyName1, *, exampleKeyName2),那么action类将会收到所有的Cookie。

而对于cookiesValue,我们可以用它来设定可接受的Cookie的值。如果cookiesValue未设定,或者cookiesValue中包含*,那么所有name属性符合cookiesName参数设定的Cookie都会被action收到。

ValueStack声明

除了在struts.xml配置文件中声明cookie拦截器及其参数,cookie拦截器的使用还需要一个条件:ValueStack中必须包含cookiesName参数中所设定的那些属性;否则当截取Cookie的时候Struts2会抛异常(”No object in the CompoundRoot has a publicly accessible property named …”)。这是因为在截取Cookie的时候CookieInterceptor会尝试往ValueStack中写入cookie信息:

protected void populateCookieValueIntoStack(String cookieName, String cookieValue, Map<String, String> cookiesMap, ValueStack stack) {  
    ...
    stack.setValue(cookieName, cookieValue);
}

最简单的满足这一条件的方法就是往action类中添加以cookiesName参数为名称的bean。还是以之前的ExampleAction为例,只要在该类中添加以下两个java bean即可:

private String exampleKeyName1;  
public String getExampleKeyName1() {  
    return exampleKeyName1;
}
public void setExampleKeyName1(String exampleKeyName1) {  
    this.exampleKeyName1 = exampleKeyName1;
}

private String exampleKeyName2;  
public String getExampleKeyName2() {  
    return exampleKeyName2;
}
public void setExampleKeyName2(String exampleKeyName2) {  
    this.exampleKeyName2 = exampleKeyName2;
}

至此,action类可以通过访问这些bean来读取Cookie的信息。

CookiesAware接口与cookiesMap

除了设定ValueStack外,action类还可以通过实现CookiesAware接口来获取目标Cookie键值对的Map对象(cookiesMap):

public class ExampleAction extends ActionSupport implements CookiesAware {  
    private Map<String, String> cookiesMap;
    @Override
    public void setCookiesMap(Map<String, String> cookiesMap) {
        this.cookiesMap = cookiesMap;
    }
}

对于使用cookie拦截器而言,实现CookiesAware接口不是必需的(如果不实现CookiesAware,那么action类中不会含有Cookie键值对的Map对象),而在ValueStack中添加目标Cookie键则是必需的。

结语

与SessionAware等其它拦截器相比,cookie拦截器的使用显得更为复杂 — 既要声明目标Cookie,又要在ValueStack中加入相关支持。个人对此做法的理解是:这么做可以让action通过访问ValueStack来直接读取感兴趣的Cookie的值,相应的代价则是编程复杂度的上升。

Struts2中的cookie拦截器只能用于读取Cookie,如果想向浏览器端发送Cookie则需要使用cookieProvider拦截器。