軽量フレームワーク?、アノテーションの練習?

web.xmlにわざわざ1つずつのServletを設定しなくても良くなるフレームワークを試作してみた。コードネームはSylvester。少し長いですけど、興味があったら読んでみてください。

フレームワークの仕組み

まずweb.xmlに簡単な設定。でコントローラ側のパッケージを指定。

<servlet>
    <servlet-name>SylvesterServlet</servlet-name>
    <servlet-class>org.dyndns.coolstyle.sylvester.SylvesterServlet</servlet-class>
    <init-param>
	    <param-name>classpackages</param-name>
	    <param-value>sample.sylvester</param-value>
    </init-param>
</servlet>

<servlet-mapping>
    <servlet-name>SylvesterServlet</servlet-name>
    <url-pattern>*.do</url-pattern>
</servlet-mapping>

リクエストを受け取るフロントコントローラでそれを設定

public void init(ServletConfig conf) throws ServletException {
	super.init(conf);

	this.classPackages = conf.getInitParameter("classpackages");
}

リクエストパラメータを元に、アクションクラスを設定。
setSetterAttributes, setGetterAttributesにてアクションクラスのアノテーションを読み取ってパラメータ関係を設定する。

protected void doGet(HttpServletRequest req, HttpServletResponse res)
		throws ServletException, IOException {

	this.doPost(req, res);
}

protected void doPost(HttpServletRequest req, HttpServletResponse res)
		throws ServletException, IOException {

	String actionName = 
		req.getServletPath().substring(1,req.getServletPath().length() - ".do".length());
	
	Object delegateAction = null;
	
	try {
		delegateAction = 
			Class.forName(this.classPackages + "." + actionName).newInstance();
	} catch (InstantiationException e) {
		e.printStackTrace();
	} catch (IllegalAccessException e) {
		e.printStackTrace();
	} catch (ClassNotFoundException e) {
		e.printStackTrace();
	}
	
	setSetterAttributes(delegateAction, req); // パラメータをアクションクラスに設定する
	setGetterAttributes(delegateAction, req); // アクションクラスのゲッターメソッドをリクエスト変数に設定する
	
	req.getRequestDispatcher(actionName + ".html").forward(req, res);
}

	private void setSetterAttributes(Object obj, HttpServletRequest req) {

		for (Method method : obj.getClass().getDeclaredMethods()) {

			SetAttribute sa = method.getAnnotation(SetAttribute.class);
			if (sa == null) {
				
				continue;
			}
			try {
				Object[] param = new Object[1];
				param[0] = req.getParameter(sa.name());
				method.invoke(obj, param);

			} catch (IllegalArgumentException e) {
				e.printStackTrace();
			} catch (IllegalAccessException e) {
				e.printStackTrace();
			} catch (InvocationTargetException e) {
				e.printStackTrace();
			}
		}
	}
	
	private void setGetterAttributes(Object obj, HttpServletRequest req) {

		for (Method method : obj.getClass().getDeclaredMethods()) {

			GetAttribute sa = method.getAnnotation(GetAttribute.class);
			if (sa == null) {
				
				continue;
			}
			try {
				Object[] param = null;
				Object value = method.invoke(obj, param);
				req.setAttribute(sa.name(), value);

			} catch (IllegalArgumentException e) {
				e.printStackTrace();
			} catch (IllegalAccessException e) {
				e.printStackTrace();
			} catch (InvocationTargetException e) {
				e.printStackTrace();
			}
		}
	}

肝としては生成したアクションクラスのアノテーションを読み取って必要な情報をパラメータに設定するところ。
フレームワーク側は今のところこんな感じ。

フレームワークを使って超超簡単なWebアプリ

アクションクラスの例として簡単に入力フォームに入力をして結果を出力するクラスを作ってみる。

public class Input {

	private String msg;

	@GetAttribute(name="msg")
	public String getMsg() {
		return msg;
	}

	@SetAttribute(name="msg")
	public void setMsg(String msg) {
		this.msg = msg;
	}
}

一応POJO??^^;;
後は、テンプレートとなるHTML(Mayaa)

<html>
	<head>
		<meta http-equiv="content-type" content="text/html">
		<title>Welcome!</title>
	</head>
	<body>
        <Form Action="#" Method="POST">
            
            <Input Type="text" name="msg" value="${msg}" />
            <Input Type="submit" name="button" value="write" />
            
        </Form>
        ${msg}
	</body>
</html>

Webコンテナを起動してhttp://localhost:8080/Input.doと打てば動きます。
と、言いたいところなんだけど、なんかまだちょっと怪しいところがあるので要調整。

まあ、ただのお遊びですけど。

デザイン

ヘッダーに書いてたものをフッターに移動しました。頻繁に必要じゃない情報はちょっと探せば見つかるような位置にあれば十分だと思ったからです。そのために1ページの表示日数も3日にしました。
同じような意味で、サイドバーもつけてません。サイドバーをつければパッと見た感じのまとまり具合は良い感じで、初めて訪れる人にはわかりやすいかもしれませんが、ある程度慣れてくると、それがうざったくなります。
日記の本文を読むためだけに、その横っちょに見飽きたガイド情報がのってるのを毎回見ると、うんざりしてしまうわけです。
万人向けのサイトを目指して一見さんへ親切な情報を記載するのを心がけているならきちんと考えなきゃいけませんけど、この日記ではそんなこと考慮してもあんまり意味がないし。
如何に、自分にとって、そしてアンテナなどを使って日々読んでくれる人に対して、わかりやすいデザインを提供できるか。それを意識しながら色々と調整してます。