当前位置: 首页 > news >正文

超轻量级MVC框架的设计和实现 (1)

前段时间准备做一个小网站,但是又不想用Spring/Struts/WebWork这样的大块头,因此决定自己写一个MVC框架。花了3天左右时间完成,目前运行良好,整个MVC框架仅21KB,感兴趣的朋友可以从http://code.google.com/p/lightweight-mvc/downloads/list下载完整的源代码和jar包。

设计目标:

一个最简单最小巧的MVC框架,花哨的功能一个不要,越简洁越好,并且不使用XML配置文件,而是完全用Java 5注解配置。

功能列表:

组件必须用IoC配置;

处理HTTP请求的Action,类似WebWork每个请求都生成一个新实例,并自动填充属性;

类似Filter的Interceptor机制,但是在IoC容器中配置;

统一的异常处理;

多视图支持。

由于组件需要用IoC容器配置,因此,第一步就是寻找小巧的IoC容器,Google Guice是一个很不错的选择,并且完全用Java 5注解配置组件。这个MVC框架唯一依赖的也就是Guice和Commons Logging两个jar包,如果使用Velocity作为视图则还需要Velocity的jar包。

下一步,开始设计各主要功能类:

负责处理Http请求的Action类必须实现的Action接口:

package com.javaeedev.lightweight.mvc;

public interface Action {

ModelAndView execute() throws Exception;

}

从WebWork抄过来,不过返回值由String改成了ModelAndView(从Spring抄过来的),好处是不必再次根据String查找视图的绝对路径,直接在ModelAndView中包含了。用Spring的MVC其实可以发现,ModelAndView同时包含一个Model(本质是一个Map)和View的路径,减少了Struts和WebWork需要的一个XML映射文件,而维护XML配置文件是一件相当令人头疼的问题,往往改了代码还要改配置,索性写死在代码中得了,视图路径又不会经常改变,没必要为了额外的灵活性给自己搞一堆XML配置文件。

Action返回的ModelAndView:

package com.javaeedev.lightweight.mvc;

public final class ModelAndView {

private String view;
private Map<String, Object> model;

/**
* Construct a View with empty model.
*
* @param view View's logic name.
*/
public ModelAndView(String view) {
this.view = view;
this.model = Collections.emptyMap();
}

/**
* Construct a View with model.
*
* @param view View's logic name.
* @param model Model as a Map.
*/
public ModelAndView(String view, Map<String, Object> model) {
this.view = view;
this.model = model;
}

/**
* Return View.
*
* @return View's logic name.
*/
public String getView() {
return view;
}

/**
* Return model.
*
* @return Model as a Map.
*/
public Map<String, Object> getModel() {
return model;
}

}

这个完全是从Spring MVC抄过来的,Map改成了泛型,View路径可以以"redirect:"开头表示重定向,这个和Spring MVC一致。虽然直接调用HttpServletResponse也可以重定向,但是遇到事务处理起来会很麻烦,还是让MVC框架自己来处理会好一些。

WebWork的Action设计的好处是大大简化了参数的绑定,不过很多时候也需要在Action中访问HttpSession等对象,因此还需要设计一个ActionContext类,通过ThreadLocal让Action对象能轻易地访问到这些对象:

package com.javaeedev.lightweight.mvc;

public final class ActionContext {

private static ThreadLocal<ActionContext> contextThreadLocal = new ThreadLocal<ActionContext>();

/**
* Get current ActionContext.
*
* @return ActionContext.
*/
public static ActionContext getActionContext() {
return contextThreadLocal.get();
}

private HttpServletRequest request;
private HttpServletResponse response;
private HttpSession session;
private ServletContext context;

/**
* Initiate all servlet objects as thread local.
*
* @param request HttpServletRequest object.
* @param response HttpServletResponse object.
* @param session HttpSession object.
* @param context ServletContext object.
*/
static void setActionContext(HttpServletRequest request, HttpServletResponse response, HttpSession session, ServletContext context) {
ActionContext actionContext = new ActionContext();
actionContext.setRequest(request);
actionContext.setResponse(response);
actionContext.setSession(session);
actionContext.setServletContext(context);
contextThreadLocal.set(actionContext);
}

/**
* Remove all servlet objects from thread local.
*/
static void remove() {
contextThreadLocal.remove();
}

/**
* Get HttpServletRequest object.
*
* @return HttpServletRequest object.
*/
public HttpServletRequest getRequest() {
return request;
}

/**
* Set HttpServletRequest object.
*
* @param request HttpServletRequest object.
*/
void setRequest(HttpServletRequest request) {
this.request = request;
}

/**
* Get HttpServletResponse object.
*
* @return HttpServletResponse object.
*/
public HttpServletResponse getResponse() {
return response;
}

/**
* Set HttpServletResponse object.
*
* @param response HttpServletResponse object.
*/
void setResponse(HttpServletResponse response) {
this.response = response;
}

/**
* Get HttpSession object.
*
* @return HttpSession object.
*/
public HttpSession getSession() {
return session;
}

/**
* Set HttpSession object.
*
* @param session HttpSession object.
*/
void setSession(HttpSession session) {
this.session = session;
}

/**
* Get ServletContext object.
*
* @return ServletContext object.
*/
public ServletContext getServletContext() {
return context;
}

/**
* Set ServletContext object.
*
* @param context ServletContext object.
*/
void setServletContext(ServletContext context) {
this.context = context;
}

}

接下来是定义类似Filter功能的Interceptor接口:

package com.javaeedev.lightweight.mvc;

/**
* Intercept action's execution like servlet Filter, but interceptors are
* configured and managed by IoC container. Another difference from Filter
* is that Interceptor is executed around Action's execution, but before
* rendering view.
*
* @author Xuefeng
*/
public interface Interceptor {

/**
* Do intercept and invoke chain.doInterceptor() to process next interceptor.
* NOTE that process will not continue if chain.doInterceptor() method is not
* invoked.
*
* @param action Action instance to handle http request.
* @param chain Interceptor chain.
* @throws Exception If any exception is thrown, process will not continued.
*/
void intercept(Action action, InterceptorChain chain) throws Exception;

}

InterceptorChain对象和FilterChain是一样的,它允许一个拦截器是否将请求继续交给下一拦截器处理,还是中断当前请求的处理:

package com.javaeedev.lightweight.mvc;

/**
* Holds all interceptors as a chain.
*
* @author Xuefeng
*/
public interface InterceptorChain {

/**
* Apply next interceptor around the execution of Action.
*
* @param action Target Action to execute.
* @throws Exception Any exception if error occured.
*/
void doInterceptor(Action action) throws Exception;

}

最后是支持多种View的ViewResolver,这个也抄自Spring MVC:

package com.javaeedev.lightweight.mvc;

import java.io.IOException;
import java.util.Map;

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
* To resolve and render a view.
*
* @author Xuefeng
*/
public interface ViewResolver {

/**
* Init this ViewResolver.
*
* @param context ServletContext object that holds information of current
* web application.
* @throws ServletException If init failed.
*/
void init(ServletContext context) throws ServletException;

/**
* To resolve view's name and render view if necessary.
*
* @param view View's logic name.
* @param model Model represent as a generic Map.
* @param request HttpServletRequest object.
* @param response HttpServletResponse object.
* @throws ServletException If any ServletException occur.
* @throws IOException If any IOException occur.
*/
void resolveView(String view, Map<String, Object> model, HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException;

}

第一个版本支持JSP和Velocity两种View,其实支持其他的View完全是可扩展的,只需要参考现有的两种ViewResolver的实现再写一个实现即可,例如支持FreeMarker的ViewResolver。

到此为止,提供给客户端的API准备完毕。下一步是如何实现这些API。虽然概念和结构都来自WebWork和Spring,但是其具体实现却没有参考他们的源代码,因为读大块头的源码本身就是一件非常费力的事情,还不如自己身体力行,写代码往往比读懂代码更快。

后面我们会讲述如何实现该MVC框架。

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • linux nginx discuz安装失败,discuz! and Nginx
  • 夜梦吕布,未知所指
  • 大连理工大学c语言第三次上机作业答案,第一次上机作业参考答案
  • 利用Oracle构建BI信息板
  • 九九乘法表 冒泡排序 c语言,冒泡排序--打印三角形--九九乘法表
  • c语言输出字符串改asck,stm8s的c语言编程例程.doc
  • 超轻量级MVC框架的设计和实现 (2)
  • Java代码混淆器ProGuard
  • ds18b20的c语言程序,DS18B20的C语言程序
  • c语言编译嵌入txt文件,c ++-在本机Windows应用程序的资源中嵌入文本文件
  • 是该好好鄙视一下...!
  • 51c语言中断返回指令,[新人求指教]51C语言编程可否用中断令循环结束提早结束...
  • oracle11gR1JDBC新特性
  • w=a b*c用汇编语言写,汇编语言编写规范.docx
  • 壮壮已经20天了
  • HTTP中的ETag在移动客户端的应用
  • java第三方包学习之lombok
  • JS+CSS实现数字滚动
  • Promise面试题2实现异步串行执行
  • Python学习之路16-使用API
  • QQ浏览器x5内核的兼容性问题
  • React Native移动开发实战-3-实现页面间的数据传递
  • Redis的resp协议
  • SegmentFault 2015 Top Rank
  • Sublime text 3 3103 注册码
  • TypeScript迭代器
  • webpack4 一点通
  • 百度贴吧爬虫node+vue baidu_tieba_crawler
  • 从零开始的无人驾驶 1
  • 番外篇1:在Windows环境下安装JDK
  • - 概述 - 《设计模式(极简c++版)》
  • 给自己的博客网站加上酷炫的初音未来音乐游戏?
  • 简析gRPC client 连接管理
  • 京东美团研发面经
  • 如何胜任知名企业的商业数据分析师?
  • 入手阿里云新服务器的部署NODE
  • 事件委托的小应用
  • 小程序开发中的那些坑
  • 移动端 h5开发相关内容总结(三)
  • 用简单代码看卷积组块发展
  • 正则表达式小结
  • 7行Python代码的人脸识别
  • 我们雇佣了一只大猴子...
  • ​【C语言】长篇详解,字符系列篇3-----strstr,strtok,strerror字符串函数的使用【图文详解​】
  • ​Linux·i2c驱动架构​
  • ​七周四次课(5月9日)iptables filter表案例、iptables nat表应用
  • # 再次尝试 连接失败_无线WiFi无法连接到网络怎么办【解决方法】
  • #C++ 智能指针 std::unique_ptr 、std::shared_ptr 和 std::weak_ptr
  • $ is not function   和JQUERY 命名 冲突的解说 Jquer问题 (
  • $.extend({},旧的,新的);合并对象,后面的覆盖前面的
  • (阿里云在线播放)基于SpringBoot+Vue前后端分离的在线教育平台项目
  • (超简单)使用vuepress搭建自己的博客并部署到github pages上
  • (附源码)ssm本科教学合格评估管理系统 毕业设计 180916
  • (附源码)计算机毕业设计ssm本地美食推荐平台
  • (十八)SpringBoot之发送QQ邮件