サーブレット & JSP で Web アプリケーションを開発している人にとっては常識的なことかもしれませんが、この手の問題は初期の段階で対策を打ってしまえばあとはあまり意識することのないものなので、再び同じ問題にぶち当たったときのために備忘録としてまとめておきます。
サーブレットで日本語のリクエストパラメータを受け取った際、それを適切に処理するには以下のような方法が考えられます。
1.getBytees()を利用してリクエストパラメータの文字コード変換を行う。
サーブレットでは、リクエストパラメータをデコードする際の文字コードがデフォルトで ISO8859-1 と決められていますので、その他の文字コードでデコードする場合は、取得したリクエストパラメータを getBytes() を利用して一旦 ISO8859-1 のバイト列に変換し、改めて文字コードを指定してデコードします。サーブレットクラス
. (省略) . public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // パラメータの取得 String keyword = request.getParameter("keyword"); // 文字コードを変換 keyword = new String(keyword.getBytes("8859_1"),"utf-8"); request.getParameter("keyword"); . (省略) . } . (省略) .
2.setCharactorEncoding()を利用して文字コードを指定する。
リクエストパラメータを取得する前に setCharactorEncoding() を利用してデコードする際の文字コードを指定します。こうすることによって、getParameter() した時に指定した文字コードで自動的にデコードされるようになります。
※setCharactorEncoding()は必ずgetParameter()の前に実行する必要があります。
サーブレットクラス
. (省略) . public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // エンコードの指定 request.setCharactorEncoding("utf-8"); // パラメータの取得 String keyword = request.getParameter("keyword"); . (省略) . }
3.フィルタクラスで setCharactorEncoding() を利用して文字コードを指定する。
2.と同じことをフィルタクラスの中で実行します。フィルタクラス
. (省略) . public class CharacterEncodingFilter implements Filter { protected String encoding; public void init(FilterConfig config) throws ServletException { encoding = config.getInitParameter("encoding"); if (encoding == null || encoding.length() == 0) { encoding = "8859_1"; } } public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { request.setCharacterEncoding(encoding); } public void destroy() {} }
web.xml
. (省略) . <filter> <filter-name>SetCharacterEncodingFilter</filter-name> <filter-class>CharacterEncodingFilter</filter-class> <init-param> <param-name>encoding</param-name> <param-value>utf-8</param-value> </init-param> </filter> . (省略) .
上記3つの方法のうち、1.は個々のパラメータごとに対応しなければならない、2.は個々のサーブレットごとに対応しなければならない、ということで、3.の方法がベターかと思います。
なお、上記の方法は文字コードが固定であることを前提にしていますが、呼び出し元によって文字コードが異なるようなケースでは、
- 1.の場合、文字コードを示すパラメータを追加し、その値に応じたデコードを行う。(または文字コードごとにサーブレットを分ける)
- 2.の場合、文字コードごとにサーブレットを分ける。
- 3.の場合、文字コードごとにサーブレットもしくはそのURLを分け、適用するフィルタクラスを分ける。