文档章节

【step by step 构建轻量级web框架】MVC功能介绍

Bieber
 Bieber
发布于 2014/06/18 13:58
字数 2133
阅读 215
收藏 0

本系列博文,将会一步一步介绍如何构建一个轻量级的web框架<br/>jbeer git地址:http://git.oschina.net/bieber/jbeer

JBEER的MVC模块采取完全注解的Restful风格。支持Controller的单例和非单例模式,开发人员可以通过配置来选择。

一、启动MVC

关于MVC的配置在Configurate接口的public void configurateWeb(WebConfig config);方法内配置WebConfig类来实现。该类提供的几个设置方法如下:

  1. setViewPrefix(String viewPrefix)设置视图的前缀,比如/WEB-INF/pages
  2. setWebTempFileDir(String webTempFileDir)设置文件上次的临时目录,默认是/temp,即,应用根目录下面的temp目录。
  3. setViewSuffix(String viewSuffix)视图的后缀,例如:.jsp后者.ftl
  4. isSingletonMode(boolean singletonMode)controller是否单例模式,默认是非单例模式,如果是单例模式,框架将不会自动将request中的参数,自动注入到controler的字段中(如果是对象,将会自动封装到对象的字段中,例如user.name,在controller中有user这个User字段,那么将会初始化一个User对象并且复制name到User的name属性上面)

通过上面描述我如下配置了MVC模块 #######1)配置WEB.XML####### <!-- lang: xml --> <context-param> <param-name>basePackageName</param-name> <param-value>org.jbeer.sample</param-value> </context-param> <listener> <listener-class>com.jbeer.framework.startup.JBeerWebContextListener</listener-class> </listener> <servlet> <servlet-name>jbeerDispatcherServlet</servlet-name> <servlet-class>com.jbeer.framework.web.JBeerDispatcherServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>jbeerDispatcherServlet</servlet-name> <url-pattern>*.htm</url-pattern> </servlet-mapping>

1、配置JBeerDispatcherServlet用于拦截MVC的请求,如上是拦截素有.htm的请求<br/> 2、配置JBeerWebContextListener用于启动框架,加载应用相关信息<br/> 3、配置basePackageName是告知框架,需要扫描类的基础包,该包下面的所有类都会进行扫描 #######2)配置应用的MVC####### <!-- lang: java --> public class AppConfig implements Configurate { @Override public void configurateWeb(WebConfig config) { config.setViewPrefix("/WEB-INF/pages"); config.setViewSuffix(".jsp"); config.isSingletonMode(true); } } 由于上面配置了basePackageName,并且AppConfig是在配置的包(子包)下,那么框架将会扫描到AppConfig类,并执行configurateWeb方法,对MVC进行配置。这里的配置告知了框架视图模板是WEB-INF/pages下面的.jsp文件,同时告知框架MVC里面的Controller是单例模式,那么需要手动在Controller中获取请求参数。下面便是一个单例模式下面的Controller实现 #######3)实现FirstController####### <!-- lang: java --> @Controller(urlPattern="/first") public class FirstController extends BaseController{

@RefBean
private UserService userService;

@Action(urlPatterns="post.htm",requestType=RequestType.POST)
public ModelAndView post() throws JBeerException{
	System.out.println(this);
	PageModelAndView mav = ModelAndView.createModelAndView();
	List<User> user = getList("user", User.class);
	List<File> file = getFiles("file");
	Short test = getShort("test");
	User[] users = getArray(User.class, "user");
	int a = getInteger("a");
	mav.setDataMap("test", test);
	mav.setDataMap("user", users[0]);
	mav.setDataMap("file", file.get(0).getName());
	mav.setView("view");
	return mav;
}

@Action(urlPatterns="index.htm",requestType=RequestType.ANY)
public String index() throws IOException, ScanClassException{
	return "index";
}
}

从上往下看,分析该类的实现。<br/> 1、通过注解@Controller告知框架FirstController是一个控制器,并且匹配的路径是以${ctx}/first开始<br> 2、FirstController继承了BaseController,在BaseController中,有获取HttpServletRequest中的参数方法,例如getList,getFiles,getShort,getObject等等,继承了该类,那么不用再去手动从HttpServletRequest获取请求参数。当然,也可以不用继承该类,通过RequestParameterUtil里面的静态方法一样可以达到同样的效果,具体可以自己选择。<br/> 3、方法post通过注解@Action进行了修饰,表示该方法将会响应来自路径${ctx}/first/post.htm,并且是POST方式的请求,通过注解@Action注解进行修饰的方法,框架都没当作是一个Action来进行解析。<br/> 4、action方法返回的是ModelAndView,该类是Action返回的一个抽象,该类不能直接实体化,需要通过ModelAndView下面的静态方法构造对应的视图和数据模型对象。如果是需要返回一个页面到前端,则是通过createModelAndView()来构造一个PageModelAndView对象,如果是需要返回一个JSON对象返回到前端,那么通过createJsonModel来构造一个JSONModelAndView等等....根据具体需求可以生成对应的视图和数据模型<br>

通过上面几个步骤,JBeer的MVC就可以正常执行了,可以处理前端发起的请求。下面对JBeer里面视图渲染的思想进行描述一下。 #二、JBeer里面的视图渲染#

渲染视图,包括三个核心组件:数据,渲染器,视图。 数据和视图,是具体的请求在Action的方法中告知框架的,而渲染器,则需要框架根据对应的数据模型来匹配对应的渲染器。所以JBEER中,为每个ModelAndView匹配了视图。 ######1)数据模型和视图的抽象######

<!-- lang: java -->
public class ModelAndView {

protected String view;

protected String callback;

protected Map<String,Object> datas = new HashMap<String,Object>();

protected ViewType type = ViewType.PAGE;

protected Object data = null;

protected String content;


protected ModelAndView(){
    
}
public static JSONModelAndView createJsonModel(){
    return new JSONModelAndView();
}

public static JSONPModelAndView createJsonpModel(){
    return new JSONPModelAndView();
}

public static PageModelAndView createModelAndView(){
    return new PageModelAndView();
}

public static AJAXModelAdnView createAJAXModelAdnView(){
	return new AJAXModelAdnView();
}

protected ModelAndView setContent(String content){
	this.content = content;
	return this;
}
protected ModelAndView setView(String view){
    this.view = view.startsWith("/")?view:("/"+view);
    return this;
}
protected ModelAndView setCallback(String callback){
    this.callback = callback;
    return this;
}
protected ModelAndView setViewType(ViewType type){
   this.type = type;
   return this;
}
protected ModelAndView setDataMap(String key,Object data){
    datas.put(key, data);
    return this;
}
protected ModelAndView setData(Object data){
    this.data = data;
    return this;
}
public String getContent(){
	return content;
}
public String getView(){
    return view;
}

public Map<String,Object> getDatas(){
    return datas;
}

public Object getData(){
    return data;
}

public String getCallback(){
    return callback;
}
public ViewType getViewType(){
    return type;
}

public static class JSONModelAndView extends ModelAndView{

    public JSONModelAndView(){
        this.type = ViewType.JSON;
    }
    @Override
    public JSONModelAndView setData(Object data) {
         this.data = data;
         return this;
    }
    
}

public static class JSONPModelAndView extends JSONModelAndView{
    public JSONPModelAndView(){
        this.type = ViewType.JSONP;
    }
    @Override
    public JSONPModelAndView setCallback(String callback) {
        this.callback = callback;
        return this;
    }

}

public static class AJAXModelAdnView extends ModelAndView{
	public AJAXModelAdnView(){
		this.type = ViewType.AJAX;
	}
	@Override
	public ModelAndView setContent(String content) {
		this.content = content;
		 return this;
	}
	
	
}

public static class PageModelAndView extends ModelAndView{
    public PageModelAndView(){
        this.type = ViewType.PAGE;
    }

    @Override
    public PageModelAndView setView(String view) {
        this.view = view;
        return this;
    }

    @Override
    public PageModelAndView setDataMap(String key, Object data) {
        this.datas.put(key, data);
        return this;
    }
    
}

public static enum ViewType{
    
    JSON("json"),PAGE("page"),FILE("file"),JSONP("jsonp"),AJAX("ajax");
    
    private String name;
    private ViewType(String name){
        this.name = name;
    }
    
    public String getName(){
        return name;
    }
    
}

}

在类ModelAndView中抽象出了描述数据和视图之间关系公共属性,并且相关的set方法是protected,那么在外部直接通过ModelAndView是无法进行设置值的,而ModelAndView有几个子类,分别是:JSONModelAndView,JSONPModelAndView,PageModelAndView,AJAXModelAdnView,那么各个子类,则对应了一种类型的视图了,并且在各个子类中通过基础父类相关set方法,并调整为public,以达到ModelAndView中的各个属性的set方法按需分配到了各个子类中,并且各个子类根据具体需求,对外暴露相关的set方法。这样就达到了绑定数据和相应视图关系。 ######2)视图渲染器###### 通过抽象一个渲染器的公共接口,Render来规范各种渲染器。 <!-- lang: java --> public interface Render {

/**
 * 
* <p>函数功能说明:当一个容器中有多个render的时候,order的值高的,将会优先调用其来进行渲染</p>
* <p>Bieber  2014年6月17日</p>
* <p>修改者名字 修改日期</p>
* <p>修改内容</a>  
* @return int
 */
public int order();
/**
 * 
* <p>函数功能说明:是否支持当前数据模型和视图渲染</p>
* <p>Bieber  2014年6月13日</p>
* <p>修改者名字 修改日期</p>
* <p>修改内容</a>  
* @return boolean
 */
public boolean isSupport(ModelAndView modelView);

/**
 * 
* <p>函数功能说明:进行渲染操作</p>
* <p>Bieber  2014年6月13日</p>
* <p>修改者名字 修改日期</p>
* <p>修改内容</a>  
* @return void
 */
public void render(HttpServletRequest request, HttpServletResponse response,
                          ModelAndView modelView) throws RenderingViewException;
}

该接口中只定义了三个方法,order方法用于当支持某一类型的视图有多个渲染器,那么会调用该值最高的渲染器渲染视图。isSupport用于判断当前渲染器是否支持当前数据模型的渲染,render方法则是进入到渲染具体方法,该方法执行完毕后,则将渲染完毕的视图,返回到前端。基于这个接口,框架默认提供了:AJAXRender用于渲染AJAXModelAdnView的数据模型和视图,JSONPRender则对一个了渲染JSONPModelAndView等等,这里就不再赘述,具体可以查看JBEER框架具体实现。<br/> 基于Render的接口,以及JBeer插件接口,可以提供freemark(具体见 http://git.oschina.net/bieber/jbeer/tree/dev/jbeer_freemarker_viewer模块)和velocity(具体见 http://git.oschina.net/bieber/jbeer/tree/dev/jbeer_velocity_viewer模块)的支持,以及对文件下载的支持,文件下载也可以理解为是一种试图渲染器,只是返回前端的是字节流(具体见 http://git.oschina.net/bieber/jbeer/tree/dev/jbeer_file_viewer模块)。通过这种方式可以更加灵活的扩展JBeer的视图类型以及渲染器。

后续会对MVC部分细节的实现,进行详细描述,有什么问题欢迎大家积极提问。

© 著作权归作者所有

Bieber

Bieber

粉丝 211
博文 36
码字总数 83312
作品 1
杭州
高级程序员
私信 提问
加载中

评论(0)

【step by step构建轻量级web框架】-何为轻量级web框架

本系列博文,将会一步一步介绍如何构建一个轻量级的web框架jbeer git地址:http://git.oschina.net/bieber/jbeer 在SSH/SSI充实着我们每个项目的开发过程中,我们所做的事情就是将他们一次组...

Bieber
2014/06/14
650
4
【step by step构建轻量级web框架】轻量级框架jbeer预览

本系列博文,将会一步一步介绍如何构建一个轻量级的web框架jbeer git地址:http://git.oschina.net/bieber/jbeer 经过本人差不多半年的纠结,今天终于把JBeer的0.1版本完成了。Jbeer具备MVC...

Bieber
2014/06/17
287
2
对于新手学习PHP的规划建议

关于自学PHP,这方面的很多资料,我几乎没有看到过一个满意的答案,我该构建一个什么样的体系,如何构建,从哪开始?下面就是小编总结的学习网站开发(使用PHP)的过程,如果你有基础或已经了解...

丶辉
2016/08/18
272
4
对于新手学习PHP的规划建议

关于自学PHP,这方面的很多资料,我几乎没有看到过一个满意的答案,我该构建一个什么样的体系,如何构建,从哪开始?下面就是小编总结的学习网站开发(使用PHP)的过程,如果你有基础或已经了解...

xdl刘涛
2016/08/17
15
0
Spring-Batch批处理框架

官方地址:http://spring.io/guides/gs/batch-processing/ Spring Batch是一个轻量级的,完全面向Spring的批处理框架,可以应用于企业级大量的数据处理系统。Spring Batch以POJO和大家熟知的...

boonya
2016/08/19
603
0

没有更多内容

加载失败,请刷新页面

加载更多

Flume概述及组成

Flume是Cloudera提供的一个高可用的,高可靠的,分布式的海量日志采集、聚合和传输的系统,Flume支持在日志系统中定制各类数据发送方,用于收集数据;同时,Flume提供对数据进行简单处理,并...

长臂猿猴
16分钟前
64
0
将较小的显示器切换到较大的显示器时,有没有办法重新绘制tmux窗口?

假设您使用Terminal.app通过ssh连接到远程服务器。 当您使用较大的分辨率监视器“tmux attach”时,您之前启动了tmux,它会在控制台周围绘制点。 它不适合新的窗口大小。 有没有办法重绘和清...

技术盛宴
23分钟前
34
0
在两个日期之间查找对象MongoDB

我一直在围绕在mongodb中存储推文,每个对象看起来像这样: {"_id" : ObjectId("4c02c58de500fe1be1000005"),"contributors" : null,"text" : "Hello world","user" : { "following......

javail
39分钟前
59
0
《aelf经济和治理白皮书》重磅发布:为DAPP提供治理高效、价值驱动的生态环境

2020年2月17日,aelf正式发布《aelf经济和治理白皮书》,这是aelf继项目白皮书后,在aelf网络经济模型和治理模式方面的权威论述。 《aelf经济和治理白皮书》描述了aelf生态中各个角色及利益的...

AELF开发者社区
50分钟前
53
0
战疫 | 高德工程师如何在3天上线“医护专车”

新冠状病毒肺炎疫情突袭,无数医护人员放弃与家人团聚,明知凶险,仍然奋战在一线。但因为武汉公交、地铁、网约车停运,医护人员上下班很难。白衣天使疾呼打车难。 (截图摘自《财经国家周刊...

amap_tech
今天
55
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部