Home > Tags > Servlet

Servlet

HttpServletRequestWrapperを使って、HTTPリクエストを改変する

OpenAMは、認証済のユーザー情報をHTTPリクエストヘッダーに載せてくれるんですが、Servletでそれってどうやって実現してるのかなーと思って、調べたら HttpServletRequestWrapper クラスを使うようです。

使い方ですが、HttpServletRequestWrapper は、HttpServletRequestインタフェースを実装しているので、HttpServletRequestインタフェースのメソッドをオーバーライドして独自の実装を定義します。
http://mergedoc.sourceforge.jp/tomcat-servletapi-5-ja/javax/servlet/http/HttpServletRequestWrapper.html

今は、すべてのリクエストのヘッダーに情報を付与しようとしているので、getHeader辺りをオーバーライドします。

package org.sample;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;

public class HeaderAddedHttpServletRequest extends HttpServletRequestWrapper {

    private Map<String, String> addHeaders;

    public HeaderAddedHttpServletRequest(HttpServletRequest request, Map<String, String> addHeaders) {
        super(request);

        if (addHeaders == null) {
            this.addHeaders = new HashMap<String, String>();
        } else {
            this.addHeaders = addHeaders;
        }
    }

    @Override
    public String getHeader(String name) {
        String header = super.getHeader(name);
        if (header != null) {
            return header;
        }

        header = addHeaders.get(name);
        if (header != null) {
            return header;
        }

        return null;
    }

    @Override
    public Enumeration<String> getHeaderNames() {
        List<String> newHeaderNames = new ArrayList<String>();

        Enumeration<String> currentHeaderNames = super.getHeaderNames();
        while (currentHeaderNames.hasMoreElements()) {
            newHeaderNames.add(currentHeaderNames.nextElement());
        }

        for (Entry<String, String> e : addHeaders.entrySet()) {
            newHeaderNames.add(e.getKey());
        }

        return Collections.enumeration(newHeaderNames);
    }
}

で、すべてのリクエストがこのWrapperクラスを使うようにFilterを定義します。

package org.sample;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;

@WebFilter("/*")
public class AddHeaderFilter implements Filter {

    @Override
    public void init(FilterConfig fConfig) throws ServletException {
    }

    @Override
    public void destroy() {
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {

        Map<String, String> addHeaders = new HashMap<String, String>();
        addHeaders.put("X-USER-ID", "HIJIKATA");
        addHeaders.put("X-USER-NAME", "土方歳三");

        chain.doFilter(new HeaderAddedHttpServletRequest((HttpServletRequest) request, addHeaders), response);
    }
}

これで、HTTPリクエストが飛んできたら自動でヘッダーが付与サれてます。

package org.sample;

import java.io.IOException;
import java.util.Enumeration;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@WebServlet("/SampleServlet")
public class SampleServlet extends HttpServlet {

    private static final long serialVersionUID = 1L;

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        Enumeration<String> headerNames = request.getHeaderNames();
        while (headerNames.hasMoreElements()) {
            String headerName = headerNames.nextElement();
            String headerValue = request.getHeader(headerName);

            System.out.println(headerName + "=" + headerValue);
        }
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
    }
}
host=localhost:8080
connection=keep-alive
user-agent=Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.152 Safari/535.19
accept=text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
accept-encoding=gzip,deflate,sdch
accept-language=ja,en-US;q=0.8,en;q=0.6
accept-charset=Shift_JIS,utf-8;q=0.7,*;q=0.3
X-USER-ID=HIJIKATA
X-USER-NAME=土方歳三

同様の事はレスポンスでもできます。

Servlet 3.0 のアノテーションでは Filter の順番を指定できない?

Servlet 3.0 になってから HttpServlet クラスの @WebServlet 同様に、Filter クラスも @WebFilter というアノテーションが指定できるようになっていて、やたら便利です。

@WebFilter(dispatcherTypes = { DispatcherType.REQUEST }, urlPatterns = { "/*" },
        initParams = { @WebInitParam(name = "encoding", value = "UTF-8") })
public class EncodingFilter implements Filter {

    private String encoding = null;

    @Override
    public void init(FilterConfig fConfig) throws ServletException {
        encoding = fConfig.getInitParameter("encoding");
    }

    @Override
    public void destroy() {
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {
        request.setCharacterEncoding(encoding);
        response.setCharacterEncoding(encoding);
        chain.doFilter(request, response);
    }
}

が、どうもアノテーションだけでは、Filter クラスの順番を定義することはできないようです。
なので、結局、web.xml に Filter を上から順番に書いていくしかないようです、残念。
(指定する方法があったら教えて欲しいです)

ちなみに @WebFilter に指定するアノテーション定義はこちら
http://docs.oracle.com/javaee/6/api/javax/servlet/annotation/WebFilter.html

やはり、順番を指定する指定は無いっぽい。

Home > Tags > Servlet

Search
Feeds
Meta

Return to page top