需求:设计一个MVC框架

(以下可能摘要不全,后期整理)

架构图:

* 核心控制器:MVC框架入口,负责接收和反馈HTTP请求

* 过滤器:Servlet容器内的过滤器,实现对数据的过滤处理

* 拦截器:对进出模型的数据进行过滤,不依赖系统容器,只过滤MVC框架内的业务数据

* 模型管理器:提供一个模型框架,内部所有业务操作应该无状态,不关心容器对象

* 视图管理器:管理所有的视图

* 辅助工具:比如文件管理、对象管理

【核心控制器】

public class FilterDispatcher implements Filter {
//定义一个值栈辅助类
private ValueStackHelper valueStackHelper = new ValueStackHelper();
//应用IActionDispatcher
IActionDispather actionDispatcher = new ActionDispatcher(); //servlet销毁时要做的事情
public void destroy() {
} //过滤器必须实现的方法
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
//转换为HttpServletRequest
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse res = (HttpServletResponse) response;
//传递到其他过滤器处理
chain.doFilter(req, res);
//获得从HTTP请求的ACTION名称
String actionName = getActionNameFromURI(req);
//对ViewManager的应用
ViewManager viewManager = new ViewManager(actionName);
//所有参数放入值栈
ValueStack valueStack = valueStackHelper.putIntoStack(req);
//把所有的请求传递给ActionDispatcher处理
String result = actionDispatcher.actionInvoke(actionName);
String viewPath = viewManager.getViewPath(result);
//直接转向
RequestDispatcher rd = req.getRequestDispatcher(viewPath);
rd.forward(req, res);
} public void init(FilterConfig arg0) throws ServletException {
/*
* 1、检查XML配置文件是否正确
* 2、启动监控程序,观察配置文件是否正确
*/
} //通过url获得actionName
private String getActionNameFromURI(HttpServletRequest req) {
String path = (String) req.getRequestURI();
String actionName = path.substring(path.lastIndexOf("/") + 1,
path.lastIndexOf("."));
return actionName;
}
}

核心控制器的配置

<?xml version="1.0" encoding="UTF-8"?>
<web-app>
  <filter>
    <display-name>FilterDispatcher</display-name>
    <filter-name>FilterDispatcher</filter-name>
    <filter-class>{包名}.FilterDispatcher</filter-class>
  </filter>
  <filter-mapping>
    <filter-name>FilterDispatcher</filter-name>
    <url-pattern>*.do</url-pattern>
  </filter-mapping>
</web-app>
<?xml version="1.0" encoding="UTF-8"?>
<mvc>
<action name="loginAction" class="{类名全路径}" method="execute">
<result name="success">/index2.jsp</result>
<result name="fail">/index.jsp</result>
</action>
</mvc>

框架逻辑校验

public class LogicXmlValidate implements IXmlValidate {
//检查xmlPath是否符合逻辑,比如不会出现一个类中没有的方法
public boolean validate(String xmlPath) {
return false;
}
}

逻辑校验流程:

1)读取XML文件

2)使用反射技术初始化一个对象(配置文件中的class属性值)

3)检查是否存在配置文件中配置的方法

4)检查方法的返回值是否是String,并且无输入参数,同时必须继承指定类或接口

策略场景类

public class Checker {
//使用哪一个策略
private IXmlValidate validate;
//xml配置文件的路径
String xmlPath; //构造函数传递
public Checker(IXmlValidate _validate) {
this.validate = _validate;
} public void setXmlPath(String _xmlPath) {
this.xmlPath = _xmlPath;
} //检查
public boolean check() {
return validate.validate(xmlPath);
}
}

监听接口

public interface Watchable {
//监听
public void watch();
}

文件监听者

public class FileWatcher extends Observable implements Watchable {
//是否要重新加载XML文件
private boolean isReload = false; //启动监视
public void watch() {
//启动一个线程,每隔15秒扫描一下文件,发现文件日期被修改,立刻通知观察者
super.addObserver(new Checker());
super.setChanged();
super.notifyObservers(isReload);
}
}

修正后的检查者

public class Checker implements Observer {
public void update(Observable arg0, Object arg1) {
//检查是否符合条件
arg1 = check();
}
}

【模型管理器】

public interface IActionDispather {
//根据Action的名字,返回处理结果
public String actionInvoke(String actionName);
}
public class ActionDispather implements IActionDispather {
//需要执行的Action
private ActionManager actionManager = new ActionManager();
//拦截器链
private ArrayList<Interceptors> listInterceptors = InterceptorFactory.createInterceptors(); public String actionInvoke(String actionName) {
//前置拦截器
return actionManager.execAction(actionName);
//后置拦截器
}
}
public abstract class ActionSupport {
public final static String SUCCESS = "success";
public final static String FAIL = "fail"; //默认的执行方法
public String execute() {
return SUCCESS;
}
}

public class ActionManager {
//执行Action的指定方法
public String execAction(String actionName) {
return null;
}
}
public abstract class AbstractInterceptor {
//获得当前的值栈
private ValueStack valueStack = ValueStackHelper.getValueStack();
//拦截器类型:前置、后置、环绕
private int type = 0; //当前的值栈
protected ValueStack getValueStack() {
return valueStack;
} //拦截处理
public final void exec() {
//根据type不同,处理方式也不同
} //拦截器类型
protected abstract void setType(int type); //子类实现的拦截器
protected abstract void intercept();
}
public class Interceptors implements Iterable<AbstractInterceptor> {
//根据拦截器列表建立一个拦截器链
public Interceptors(ArrayList<AbstractInterceptor> list) {
} //列出所有的拦截器
public Iterator<AbstractInterceptor> iterator() {
return null;
} //拦截器链的执行方法
public void intercept() {
//委托拦截器执行
}
}
public class InterceptorFactory {
public static ArrayList<Interceptors> createInterceptors() {
//根据配置文件创建出所有的拦截器链
return null;
}
}

【视图管理器】

public class GBLangData extends AbsLangData {
@Override
public Map<String, String> getItems() {
/*
* Map 的结构为:
* key='title', value='标题'
* key='menu', value='菜单'
*/
return null;
}
} public class ENLangData extends AbsLangData {
@Override
public Map<String, String> getItems() {
/*
* Map结构为:
* key='title',value='title';
* key='menu', value='menu'
*/
return null;
}
}
public abstract class AbsView {
private AbsLangData langData; //必须有一个语言文件
public AbsView(AbsLangData _langData) {
this.langData = _langData;
} //获得当前的语言
public AbsLangData getLangData() {
return langData;
} //页面的URL路径
public String getURI() {
return null;
} //组装一个页面
public abstract void assemble();
}
public class JspView extends AbsView {
//传递语言配置
public JspView(AbsLangData _langData) {
super(_langData);
} @Override
public void assemble() {
Map<String, String> langMap = getLangData().getItems();
for (String key : langMap.keySet()) {
/*
* 直接替换文件中的语言条目
*
*/
}
}
}
public class SwfView extends AbsView {
public SwfView(AbsLangData _langData) {
super(_langData);
} @Override
public void assemble() {
Map<String, String> langMap = getLangData().getItems();
for (String key : langMap.keySet()) {
/*
* 组装一个HTTP的请求格式:
* http://abc.com/xxx.swf?key1=value&key2=value
*/
}
}
}
public class ViewManager {
//Action的名称
private String actionName;
//当前的值栈
private ValueStack valueStack = ValueStackHelper.getValueStack(); //接收一个ActionName
public ViewManager(String _actionName) {
this.actionName = _actionName;
} //根据模型的返回结果提供视图
public String getViewPath(String result) {
//根据值栈查找到需要提供的语言
AbsLangData langData = new GBLangData();
//根据action和result查找到指定的视图,并加载语言
AbsView view = new JspView(langData);
//返回视图的地址
return view.getURI();
}
}

【工具类】

<action name="loginAction" class="{类名全路径}" method="execute">
  <result name="success">/index2.jsp</result>
  <result name="fail">/index.jsp</result>
</action>
public abstract class ActionNode {
//Action的名称
private String actionName;
//Action的类名
private String actionClass;
//方法名,默认是execute
private String methodName = "excuete";
//视图路径
private String view; public String getActionName() {
return actionName;
} public String getActionClass() {
return actionClass;
} public String getMethodName() {
return methodName;
} public abstract String getView(String Result);
}
public class XmlActionNode extends ActionNode {
//需要转换的element
private Element el; //通过构造函数传递
public XmlActionNode(Element _el) {
this.el = _el;
} @Override
public String getActionName() {
return getAttValue("name");
} @Override
public String getActionClass() {
return getAttValue("class");
} @Override
public String getMethodName() {
return getAttValue("method");
} public String getView(String result) {
ViewPathVisitor visitor = new ViewPathVisitor("success");
el.accept(visitor);
return visitor.getViewPath();
} //获得指定属性值
private String getAttValue(String attName) {
Attribute att = el.attribute(attName);
return att.getText();
}
}
public class ViewPathVisitor extends VisitorSupport {
//获得指定的路径
private String viewPath;
private String result; //传递模型结果
public ViewPathVisitor(String _result) {
result = _result;
} @Override
public void visit(Element el) {
Attribute att = el.attribute("name");
if (att != null) {
if (att.getName().equals("name") && att.getText().equals(result)) {
viewPath = el.getText();
}
}
} public String getViewPath() {
return viewPath;
}
}

MVC用到了哪些框架:

● 工厂方法模式:通过工厂方法模式把所有的拦截器链实现出来,方便在系统初始化时直接处理。

● 单例模式:Action的默认配置都是单例模式,在一般的应用中单例已经足够了,在复杂情况下可以使用享元模式提供应用性能,减少单例模式的性能隐患。

● 责任链模式:建立拦截器链以及过滤器链,实现任务的链条化处理。

● 迭代器模式:非常方便地遍历拦截器链内的拦截器,而不用再自己写遍历拦截器链的方法。

● 中介者模式:以核心控制器为核心,其他同事类都负责为核心控制器“打工”,保证核心控制器瘦小、稳定。

● 观察者模式:配置文件修改时,不用重启应用可以即刻生效,提供使用者的体验。

● 桥梁模式:使不同的视图配合不同的语言文件,为终端用户展示不同的界面。

● 策略模式:对XML文件的检查可以使用两种不同的策略,而且可以在测试机和开发机中使用不同的检查策略,方便系统间自由切换。

● 访问者模式:在解析XML文件时,使用访问者非常方便地访问到需要的对象。

● 适配器模式:把一个开发者不熟悉的对象转换为熟悉的对象,避免工具或框架对开发者的影响。

● 门面模式:Action分发器负责所有的Action的分发工作,它提供了一个调用Action的唯一入口,避免外部模块深入到模型模块内部。

● 代理模式:大量使用动态代理,确保了框架的智能化。

《设计模式之禅》--MVC框架的更多相关文章

  1. 开源:Taurus.MVC 框架

    为什么要创造Taurus.MVC: 记得被上一家公司忽悠去负责公司电商平台的时候,情况是这样的: 项目原版是外包给第三方的,使用:WebForm+NHibernate,代码不堪入目,Bug无限,经常点 ...

  2. 编写自己的PHP MVC框架笔记

    1.MVC MVC模式(Model-View-Controller)是软件工程中的一种软件架构模式,把软件系统分为三个基本部分:模型(Model).视图(View)和控制器(Controller). ...

  3. 转 10 个最佳的 Node.js 的 MVC 框架

    10 个最佳的 Node.js 的 MVC 框架 oschina 发布于: 2014年02月24日 (33评) 分享到:    收藏 +322 Node.js 是一个基于Chrome JavaScri ...

  4. 制作自己的MVC框架(一)——简单粗暴的实现

    现在市面上有很多成熟的MVC框架,可以拿来直接用,但自己造一下轮子其实也挺有意思的. 下面先来看个最简单粗暴的MVC实现. 5个文件就能实现最简单的MVC,在Apache中设置一个虚拟目录,配置个简单 ...

  5. 分享一实战性开源MVC框架<Linux、Windows跨平台开发so easy>

    一.引子   开源地址 https://github.com/564064202/Moon.Mvc 欢迎加入开发 .NET Core微软还在发力,但作为商用还有一段距离,很多开发库尚不能用于.NET ...

  6. 产品前端重构(TypeScript、MVC框架设计)

    最近两周完成了对公司某一产品的前端重构,本文记录重构的主要思路及相关的设计内容. 公司期望把某一管理类信息系统从项目代码中抽取.重构为一个可复用的产品.该系统的前端是基于 ExtJs 5 进行构造的, ...

  7. 请求如何进入ASP.NET MVC框架

    一.前言 对于WebForm开发,请求通常是一个以.aspx结尾的url,对应一个物理文件,从代码的角度来说它其实是一个控件(Page).而在MVC中,一个请求对应的是一个Controller里的Ac ...

  8. MVC系列——MVC源码学习:打造自己的MVC框架(四:了解神奇的视图引擎)

    前言:通过之前的三篇介绍,我们基本上完成了从请求发出到路由匹配.再到控制器的激活,再到Action的执行这些个过程.今天还是趁热打铁,将我们的View也来完善下,也让整个系列相对完整,博主不希望烂尾. ...

  9. MVC系列——MVC源码学习:打造自己的MVC框架(三:自定义路由规则)

    前言:上篇介绍了下自己的MVC框架前两个版本,经过两天的整理,版本三基本已经完成,今天还是发出来供大家参考和学习.虽然微软的Routing功能已经非常强大,完全没有必要再“重复造轮子”了,但博主还是觉 ...

  10. MVC系列——MVC源码学习:打造自己的MVC框架(二:附源码)

    前言:上篇介绍了下 MVC5 的核心原理,整篇文章比较偏理论,所以相对比较枯燥.今天就来根据上篇的理论一步一步进行实践,通过自己写的一个简易MVC框架逐步理解,相信通过这一篇的实践,你会对MVC有一个 ...

随机推荐

  1. 搞个小项目吧,做一个ppt播放器

    先来两个参考链接,接下来再进行实战 http://www.geek-workshop.com/forum.php?mod=viewthread&tid=1137 http://www.geek ...

  2. java面向对象的三大特性——封装

    封装 封装从字面上来理解就是包装的意思,专业点就是信息隐藏,是指利用抽象数据类型将数据和基于数据的操作封装在一起,使其构成一个不可分割的独立实体,数据被保护在抽象数据类型的内部,尽可能地隐藏内部的细节 ...

  3. Windows核心编程&进程

    1. 进程的定义 说白了进程就是一个正在运行的执行程序,包含内核对象和独立的地址空间,内核对象负责统计和管理进程信息,地址空间包括所有可执行文件或DLL 模块的代码和数据.动态内存分配(线程堆和栈的分 ...

  4. AMS的适用场景

    AMS适用于网络音视频应用的各种场合,可以独立作为直播点播平台应用,也可以嵌入到用户的各种应用平台中,为客户提供音视频核心支撑,不同于其它提供云服务租给客户使用的产品,AMS是一套安装在企业内部服务器 ...

  5. centos7创建新用户

    创建新用户 创建一个叫xiaoming的用户: [root@192 ~]# adduser xiaoming 为这个用户初始化密码,linux会判断密码复杂度,不过可以强行忽略: [root@192 ...

  6. C#高性能大容量SOCKET并发(八):通讯协议

    协议种类 开发Socket程序有两种协议类型,一种是用文本描述的,类似HTTP协议,定义字符集,好处是兼容性和调试方便,缺点是解析文本会损耗一些性能:一种是用Code加结构体,定义字节顺序,好处是性能 ...

  7. PHP date函数详解

    在页面的最前页加上date_default_timezone_set(PRC);   /*把时间调到北京时间,php5默认为格林威治标准时间*/date ()a:   "am"或是 ...

  8. 小白的.Net Core 2.0 ConsoleApp入门(keng)指南(一)

    一.准备工作 准备工作很简单,甚至可以不用Visual Studio,一只.NET CORE和Runtime即可(你有考虑过世界第一IDE的感受吗) 下载:https://www.microsoft. ...

  9. svn基本操作和图标介绍

    注意事项:    .svn这个隐藏目录记录着两项关键信息:工作文件的基准版本和一个本地副本最后更新的时间戳,千万不要手动修改或者删除这个.svn隐藏目录和里面的文件!!,否则将会导致你本地的工作拷贝( ...

  10. Ubuntu16.04下伪分布式环境搭建之hadoop、jdk、Hbase、phoenix的安装与配置

    一.准备工作 安装包链接: https://pan.baidu.com/s/1i6oNmOd 密码: i6nc 环境准备 修改hostname: $ sudo vi /etc/hostname why ...