`
daibalusu
  • 浏览: 344424 次
文章分类
社区版块
存档分类
最新评论

用注解和pojo支撑起来的轻量级REST框架--T2

 
阅读更多

用注解和pojo支撑起来的轻量级REST框架--T2

Written by Tony@tokyo

1. 前言

T2是以java5注解为支撑的轻量级Web框架。

T2不是简单的form提交,而对Ajax请求,RIA客户端等多种多样的前台技术的支持。

T2的目标:

² 无论什么类型的客户端都可以访问的Web服务器端框架

² 提供尽量简约,轻量级,易于维护和可扩展的架构

² 支持无状态,Rest风格的技术架构

² 提供plugin接口,可轻易扩展业务层架构

T2架构草图

T2homepage: http://code.google.com/p/t-2/

1. T2sample code

T2的运行需要的JREWeb容器

JRE1.6以上

Web容器:实现了Servlet2.5JSP2.0的JavaEE标准

T2运行时必要的jar文件

T2.jar

Commons.jar Apache的共通类库

slf4j-api.jar logging用类库

T2必要的设定

Web.xml中的设定

<?xml version="1.0" encoding="ISO-8859-1"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
    version="2.5">
        <filter>
                <filter-name>t2</filter-name>
                <filter-class>org.t2framework.t2.filter.T2Filter</filter-class>
                <init-param>
                        <param-name>t2.rootpackage</param-name>
                        <param-value>sample.page</param-value>
                </init-param>
        </filter>
        <filter-mapping>
                <filter-name>t2</filter-name>
                <url-pattern>/*</url-pattern>
        </filter-mapping>

</web-app>


http请求由T2Filter接受,这里是T2框架的入口
 [t2.rootpackage]指定了所有后台页面程序的根目录,Web容器启动以后,到这个目录下面,将所有@Page注解的Java程序实例化。
 T2框架本身有自带的IOC管理器—SimpleContainerAdapter
 当然也可以通过以下配置,将instances的管理交由专业框架。
<init-param>
                        <param-name>t2.container.adapter</param-name>
                        <param-value>org.t2framework.t2.adapter.S2Adapter</param-value>
                </init-param>
                <!-- 設定ファイルの読み込み -->
                <init-param>
                        <param-name>t2.config</param-name>
                        <param-value>app.dicon</param-value>
                </init-param>


接受http请求的后台类
@Page("/helloworld")
public class HelloPage {

        @Default
        public Navigation index() {
                String message ="HelloWorld";
                return SimpleText.out(message);
        }
}


以上,@Page用来声明这个后台类对外公开的URL@Default声明默认的http请求的处理函数。
假设,Web工程的contentroot是/sample的话,上面的后台类能够用以下url访问
http://localhost:8080/sample/helloworld
T2框架可执行的SampleCode可以由以下取得
http://code.google.com/p/t-2/wiki/Samples

3. T2的运行原理

T2MVC
 T2的核心在于,一个url对应一个Page类。
 Page类和View分离,达到可以自由更换View层技术。
 Page类中,http request的接受,http response的组装,Token的获得,Session的获得,业务层service的对象的组装都可以由注解来完成。
 比如,拿官方的sample举例
@RequestScope
@Page("login")
public class LoginPage {

	private static Logger logger = Logger.getLogger(LoginPage.class);

	protected LoginService loginService;

	/**
	 * 
	 * {@.en }
	 * 
	 * <br />
	 * 
	 * @param request
	 * @return
	 */
	@Default
	public Navigation index(final HttpServletRequest request) {
		TokenUtil.saveToken(request, Constants.TOKEN_KEY);
		String token = TokenUtil.getToken(request, Constants.TOKEN_KEY);
		request.setAttribute(Constants.TOKEN_KEY, token);
		return Forward.to("WEB-INF/pages/login.jsp");
	}

/**
	 * 
	 * {@.en }
	 * 
	 * @param context
	 * @return
	 * @since 0.5.1
	 */
	@Ajax
	@POST
	@ActionParam
	public Navigation login(WebContext context) {
		final String contextPath = context.getRequest().getContextPath();
		final Map<String, String> map = CollectionsUtil.newHashMap();
		String next;
		if (TokenUtil.isTokenValid(context.getRequest().getNativeResource(),
				Constants.TOKEN_KEY) == false) {
			map.put("errorMessage", Functions.nls("login_token_invalid"));
			next = "/login";
		} else {
			final String user = context.getRequest().getParameter("user");
			final String pass = context.getRequest().getParameter("pass");
			if (StringUtil.isEmpty(user)) {
				map.put("errorMessage", Functions.nls("login_userid_empty"));
				next = "/login";
			} else if (StringUtil.isEmpty(pass)) {
				map.put("errorMessage", Functions.nls("login_password_empty"));
				next = "/login";
			} else {
				final boolean logined = loginService.login(user, pass, 0);
				if (logined == false) {
					logger.debug("Login error");
					map.put("errorMessage", Functions.nls("login_auth_failed"));
					next = "/login";
				} else {
					context.getSession().setAttribute(Constants.AUTH_KEY,
							System.currentTimeMillis());
					next = "/employee/list";
				}
			}
		}
		map.put("url", contextPath + next);
		return Json.convert(map);
	}


整个类最高层有两个注解,@RequestScope@Page
@RequestScope声明本页面所有的变量只能存续在一次请求中
Index方法上的@Default声明了它是初期化函数
HttpServletRequest的变量是由框架组装实例化。
Login方法上的@Ajax@POST@ActionParam。分别声明了该方法支持Ajax请求,接受post方法请求,用来检查本方法和form的名字是否统一
前台JSP中提交的form如下
<form action="${t:url('/login')}" method="post">
		<div class="x">
		<span id="error" class="err">${message}</span>
		<c:if test="${message != null}"><br /></c:if>
		<span id="errorMessage" class="m">${t:nls('login_init_message')}</span>
		<br/>
		<fieldset id="loginFieldset" class="loginfieldset" title="${t:nls('login_init_message')}">
			<legend>Login</legend>
			<table>
				<tr>
					<td class="z">${t:nls('login_userid')}</td>
					<td class="v">
						<input type="text" id="user" name="user" maxlength="32" style="width: 100px;"/>
					</td>
				</tr>
				<tr>
					<td class="z">${t:nls('login_password')}</td>
					<td class="v">
						<input type="password" id="pass" name="pass" style="width: 100px;"/>
					</td>
					<td>
				</tr>
				<tr>
					<td colspan="2" align="right">
						<input type="submit" id="login" name="login" value="${t:nls('login_loginbutton')}" class="submit"/>
					</td>
					<td></td>
				</tr>
			</table>
		</fieldset>
		</div>
	</form>


Form中定义的
t:url('/login')是用到了T2自定义的标签,简单说来就是将请求发给了Login.javalogin函数。
T2的扩展
 作为一个高扩展的框架,T2提供了注解自定义,函数拦截,入口参数封装等等扩展接口。

Navigation

Navigation是用来forward,redirect画面的接口。可以自定义扩展,比如在画面跳转之前,将数据封装成json等等。

ContainerAdapter

用来连接DI容器的适配器,可以自定义到任意到现有的DI框架。

Plugin

XXXPlugin这种class可以用来拦截http请求,封装参数对象等等。具体说起来就是在T2Filter将请求转发给XXXPage之前就加以处理

AnnotationResolverCreator

可以用来生成和解释自定义的标签

FormResolver

用来自定义form参数解释器。
#以上#

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics