Struts Tip: URLから *.doや/do/* を省く

struts-userメーリングリストで、たびたびあるディスカッションの中にアクションのURLから.doや/do/の部分を省くことはできないか? というのがあります。 個人的に私も.doや/do/はあまり可愛くないという単純な理由で(…スミマセン(^^;)好きではありません。 変わりに/execute/* を使っていますが、それも嫌だをいう方々もいらっしゃるようで…。 もちろん、私のような理由ではないようですが。
少し前のメーリングリストアーカイブから、提案されたソリューションを発見しました。
簡単に訳してまとめると、

  1. /*にマップするRequestFilterを作成する
  2. このフィルターは、request.getServletPath()メソッドがstruts-config.xml内のいずれかのアクションのパスにマッチするかどうかをチェック、もしマッチするアクションがあれば、そのアクションにフォワードする
  3. 追加機能として、このフィルターのinitパラメータにエクステンションのセットを追加した。 今のところ、.jsp, .html, .asp, .cfm(.jspを使うことでユーザが直接jspファイルにアクセスするのを防ぐ - MVCの強制)がある。これでマーケティング部門がどのテクノロジーを使うか選ぶことができる。

例えば下のようにアクションが定義されていたとする:


<action path="/advancedSearch"
type="org.apache.struts.actions.ForwardAction"
parameter=".advancedSearch"/>
この場合、次のURL全てでアクションが実行されることになる。

RequestFilter.doFilter()のコードは次のようになる:


// Strutsのコンフィグをとりだす
ModuleConfig m = getModuleConfig(request);

// アクションのリストをとりだす
ActionConfig[] actions = m.findActionConfigs();

// リクエストされたパスをとりだす
String path = request.getServletPath();

for (int i = 0; i < actions.length; i++) {
ActionConfig action = actions[i];
String actionPath = action.getPath();
String params = RequestUtil.getRequestParameters(request);

// パスが定められたエクステンションで終わるかどうかチェック
for (int j = 0; j < allowedExtensions.length; j++) {
if (path.endsWith(allowedExtensions[j])) {
path = path.substring(0, path.indexOf(allowedExtensions[j]));
break;
}
}
if (StringUtils.equalsIgnoreCase(actionPath, path)) {
StringBuffer url = new StringBuffer();
boolean redirect = false; // redirectの場合は"true"に変更

if (redirect) {
url.append(request.getContextPath());
}

url.append("/do" + actionPath);
url.append((!StringUtils.isEmpty(params)) ? ("?" + params) : "");

if (log.isDebugEnabled()) {
log.debug("forwarding from path '" + path +
"' to action '" + actionPath + "'");
}

// This this until we have issues (this way the URL doesn't change)
RequestDispatcher dispatcher =
request.getRequestDispatcher(url.toString());

dispatcher.forward(request, response);

// もしフォワードが上手く機能しない場合は次のラインを使う
// 希望のURLにページをリダイレクトする //response.sendRedirect(response.encodeRedirectURL(url.toString()));

// リクエストされたリソースにチェーンしないように注意
return;
}
}

protected ModuleConfig getModuleConfig(HttpServletRequest request) {
ModuleConfig mConfig =
(ModuleConfig) request.getAttribute(Globals.MODULE_KEY);

if (mConfig == null) {
mConfig =
(ModuleConfig)
config.getServletContext().getAttribute(Globals.MODULE_KEY);
}

return mConfig;
}