タグに指定するアクションパスと拡張子マッピング

Struts1で私が勘違いしていたこと。

 URLパターンはすべて〜.doとなる。

ある意味正解、ある意味不正解。

Strutsといえども、基本はWebアプリケーション

web.xmlに様々な設定がしてあるのです。

Strutsフレームワークの基盤部分の設定がきちんとあります。
普段、開発者(プログラマ)はあまり意識しなくてすむ部分。

<servlet>
  <servlet-name>action</servlet-name>
  <servlet-class>org.apache.struts.action.servlet.ActionServlet</servlet-class>
   <init-param>
      <param-name>config</param-name>
      <param-value>struts-config.xml</param-value>
   <init-param>
</servlet>
<servlet-mapping>
  <servlet-name>action</servlet-name>
  <url-pattern>*.do</url-pattern>
</servlet-mapping>

ざっくり読むと、以下の3つが書いてある。
①末尾.doと付いているURLに対して、ActionServletが起動する。
②ActionServletが生成された時に、ServletContext内にconfigという名前でパラメータをもつ。
(余談:Servletは一番最初に呼び出されたときに生成され、以後消滅するまで同じインスタンスを使いまわす)
③configパラメータに、strutsの設定ファイルへのパスを定義しておき、ActionServletから利用できるようにしておく。

以下は想像

ActionServletは呼ばれたらstrutsの設定ファイルを取得する。(ServletContext#getInitParameter)
ActionFormや処理するActionクラスを取得する。
よしなにする。
ActionクラスにActionFormやHttpRequest等を渡して起動させる。

さて、ここで、url-patternタグを変更してみる。

もちろん可能。
例えば/do/*とかにしてみる。
http://〜/do/test というURLでアクセスするとActionServletが呼ばれる。
http://〜/do/test.doでも同様。

.do指定は拡張子マッピングといい、
/do/*指定はパスマッピングという。
ついでに/sample指定は特定のファイルへのマッピング
/指定はデフォルトマッピング(何も指定しなくてもURL全パターンに引っかかる)という。

つまり、拡張子はあってもなくても本当は良かったわけです。
デフォルトがそうなっているというだけの理由です。

本題

<html:form action="/sample/actionPath">
  <%-- 省略 --%>
</html:form>

ここに注目。

 action="/sample/actionPath"

ここは、struts-configで指定したアクションパスを指定する必要がある。

ちなみに、上記のタグはJSPに出力されるときは

<form action="http://〜/sample/actionPath.do">
</form>

というような感じで出力される。

どうやら.doという拡張子を勝手に付けてくれているらしい。

ちなみに

action="/sample/actionPath.do"

と指定しても、

<form action="http://〜/sample/actionPath.do">
</form>

というような感じで出力される。

絶対URLになるだけじゃなく、
どうも、最後の拡張子は変換時に読み捨てられるらしいですよ。
つまり内部で、ActionServletが呼ばれるように拡張子がある場合は読み捨てて拡張子を新たに付与、
拡張子がない場合は何もせず拡張子を付与するということをしているように見える。

かしこい。

action="/sample/actionPath.do.abc"

と指定すると、

<form action="http://〜/sample/actionPath.do.do">
</form>

というような感じで出力されるので、推測はただしそう。

ということでソースを見てみた

String actionMapping = getActionMappingName(action);
if (servletMapping.startsWith("*.")) {
     value.append(actionMapping);
     value.append(servletMapping.substring(1)); //.doを付与(url-patternが.doの場合)
} else if (servletMapping.endsWith("/*")) {
     value.append(servletMapping.substring(0,
          servletMapping.length() - 2));
     value.append(actionMapping);
} else if (servletMapping.equals("/")) {
     value.append(actionMapping);
}

ビンゴでしたね。