需求:设计一个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的唯一入口,避免外部模块深入到模型模块内部。
● 代理模式:大量使用动态代理,确保了框架的智能化。