[Java,Struts2]ウェブサイトのスマートフォン対応(マルチスクリーン対応)

前回の記事の続きで『2.クライアント端末の種類で画面を振り分け』の実装方法についての記事になります。

環境は大雑把に以下
言語:Java
フレームワーク:Struts2

Struts2での実装を図に表すと下のようになります。

Struts2

処理の要となるクラスはActionで、通常は各画面毎にActionクラスを作成し、その画面特有のロジックを組み込みます。例えば掲示板の画面を開く時はそれ用に作成したBbsActionクラスが実行される等。
そして、Actionの前後にInterceptorというクラスが呼び出されるようになっており、その処理の中ではStruts2が提供するデフォルトの機能群(例外処理や2重押下防止に使えるToken、クッキー制御用のクラスなど)が動いています。

スマホ対応の処理切り分けロジックを埋め込むのは、このインターセプタ群にスマホ用のインターセプタを新規作成して追加するのが妥当でしょう。
スマホ用のインターセプタを作成して追加したイメージは下記

Struts2_2

アクションクラスの処理結果が正常である場合、通常は”SUCCESS”を文字列として返却します。そしてその文字列によってコントローラで処理が分かれ、JSPの処理へ移行したり、別のアクションにチェインしたりします。

ここでは、新規追加したスマホ用インターセプタがアクション処理後に動くようにし、クライアントがスマホである場合は、処理結果の文字列”SUCCESS”の頭に固定で”S_”を連結するようにしています。
インターセプタの処理結果として”S_SUCCESS”が返ってきた場合は、スマホ用のJSPへと処理が流れるようにして対応しています。

スマホ用のインターセプタでは、クライアントのリクエストのヘッダ情報”User-Agent”(ユーザエージェント、通称UA)を見て、スマホかどうか判定を行います。
このインターセプタクラスの参考ソースは以下

package xxx.interceptor;

import org.apache.struts2.ServletActionContext;
import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.interceptor.AbstractInterceptor;
import com.opensymphony.xwork2.interceptor.PreResultListener;

/**
 * クライアント端末がスマートフォンの場合、アクションresult文字列の先頭に"S_"を付与するインターセプタークラス
 */
public class SmartphoneInterceptor extends AbstractInterceptor {

	private static final long serialVersionUID = 1L;
	
	/**
	 * インターセプト
	 */
	@Override
	public String intercept(ActionInvocation invocation) throws Exception {
		//アクション実行後のインターセプト処理
	    invocation.addPreResultListener(
	            new PreResultListener() {
	                public void beforeResult(ActionInvocation actioninvocation, String resultCode) {
	            		// User-Agent(ユーザエージェント、通称UA)文字列取得
	            		String ua = ServletActionContext.getRequest().getHeader("User-Agent");
	            		
	            		// [iPhone][iPod][Android][Windows Phone][BlackBerry]が含まれている場合のみ、スマホ用JSPを呼び出すように対応する。
	            		// ※Androidの場合は[Mobile]が含まれている場合のみ。
	            		
	            		int iphone = ua.indexOf("iPhone");
	            		int ipod = ua.indexOf("iPod");
	            		int win = ua.indexOf("Windows Phone");
	            		int bb = ua.indexOf("BlackBerry");
	            		int android = ua.indexOf("Android");
	            		if(-1 < android) {
	            			android = ua.indexOf("Mobile");
	            		}
						
	            		if(-1 < iphone || -1 < ipod || -1 < win || -1 < bb || -1 < android) {
							// スマホは"S_"付与
	            			actioninvocation.setResultCode("S_" + actioninvocation.getResultCode());
	            		}
	               }
	           }
	        );
		//次のインターセプタ処理
		String result_code = invocation.invoke();
		return result_code;
	}
}

ゼロコンフィグレーションでアクションクラス内にアノテーション付与で実装している場合は別ですが、アクション結果文字列の処理振り分け設定はstruts.xmlに記述します。
個人的にstruts.xmlを記述するのが好みです。この1ファイルを見れば全てのアクション処理が網羅されており、システムの全体マップとなりますので。
 (※ゼロコンフィグレーションの思想でアクション内に設定を記述してしまっては、システム全体像の把握が困難になります。開発から数か月も経ってしまえば忘れてしまうでしょう。それを把握する為にstruts.xmlに相当するドキュメントを作成すればいいのかもしれませんが、実装とドキュメントを完全に同期させておかなければ意味がなく、1つでも反映漏れが有ればそこからバグが生まれます。そうなるとグダグダになるので、結局はドキュメントを信用できなくなり、ソース(アクションクラス)を覗かなければ確証が持てないとなり、ドキュメントは混乱を招くために存在している物のようになり、現場はカオスに。)

	<!-- トップページ -->
    <package name="top" namespace="/" extends="struts-default">
    	<interceptors>
		    <!-- interceptorの定義 -->
		    <interceptor name="smartphone" class="xxx.interceptor.SmartphoneInterceptor"/><!-- スマートフォンインターセプタ -->
		    <!-- interceptorをグルーピング -->
		    <interceptor-stack name="myInterceptorStack" >
		        <interceptor-ref name="smartphone" />
		        <interceptor-ref name="defaultStack"/>
		    </interceptor-stack>
		</interceptors>
    	<default-action-ref name="top"/>
        <action name="top" class="xxx.TopAction">
        	<interceptor-ref name="myInterceptorStack"/>
            <result name="success">/WEB-INF/jsp/top.jsp</result> <!--スマホでない場合は通常JSPへ。-->
            <result name="S_success">/WEB-INF/jsp/smartPhone/smp_top.jsp</result> <!--スマホの場合は専用JSPへ。-->
        </action>
    </package>

以上でスマホのルート切り分けとJSPの定義まで完了しています。
あとはスマホ用のJSPを実装し、CSSも必要により作ればよいでしょう。元々のJSPやCSSには影響が無いのが嬉しい実装です。


コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

*

次のHTML タグと属性が使えます: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>