源代码放在的邮箱的收件箱里用户名:sharesource密码:javafans 希望保留给有用的人谢谢 取这样一个标题太大吸引眼球嘛@_@ 事实是最近读《JEE设计模式》讲述表达层模式的那几章书中有一个前端控制器+command模式的workflow例子就琢磨着可以很简单地扩展成一个MVC框架花了一个下午改写了下对书中所述的理解更为深入我想这也许对于学习和理解设计模式以及初次接触struts等MVC框架的人可能有点帮助因为整个模型类似于struts我把它取名叫strutslet^_^学习性质切勿认真 (一)完整的类图如下 前端控制器(FrontController):前端控制器提供了一个统一的位置来封装公共请求处理它的任务相当简单执行公共的任务然后把请求转交给相应的控制器在strutslet中前端控制器主要作用也在于此它初始化并解析配置文件接受每个请求并简单地把请求委托给调度器(Dispatcher)由调度器执行相应的动作(Action)调度器把action返回的url返回给FrontControllerFrontController负责转发 Action接口command模式很好的例子它是一个命令接口每一个实现了此接口的action都封装了某一个请求新增一条数据记录并更新model或者把某个文件写入磁盘命令解耦了发送者和接受者之间联系发送者调用一个操作接受者接受请求执行相应的动作因为使用Command模式解耦发送者无需知道接受者任何接口 Dispatcher调度器负责流程的转发负责调用action去执行业务逻辑由调度器选择页面和action它去除了应用行为和前端控制器间的耦合调度器服务于前端控制器它把model的更新委托给action又提供页面选择给FrontController ActionForward封装了转向操作所需要信息的一个模型包括name和转向url ActionModel解析配置文件后将每一个Action封装成一个ActionModel对象所有ActionModel构成一个map并存储在ServletContext中供整个框架使用 (二)源代码简单分析 Action接口只有一个execute方法任何一个action都只要实现此接口并实现相应的业务逻辑最后返回一个ActionForward提供给Dispacher调用 publicinterfaceAction{ publicActionForwardexecute(HttpServletRequestrequestServletContextcontext); }
比如我们要实现一个登陆系统(demo的例子)LoginAction验证用户名和密码如果正确返回success页面如果登陆失败返回fail页面 publicclassLoginActionimplementsAction{ privateStringname=; publicActionForwardexecute(HttpServletRequestrequest ServletContextcontext){ StringuserName=requestgetParameter(userName); Stringpassword=requestgetParameter(password); if(userNameequals(dennis)&&passwordequals()){ requestsetAttribute(namename); returnActionForwardSUCCESS;//登陆成功返回success }else returnActionForwardFAIL;//否则返回fail }
还是先来看下两个模型ActionForward和ActionModel没什么东西属性以及相应的gettersetter方法 /** *类说明:转向模型 *@authordennis * **/ publicclassActionForward{ privateStringname;//forward的name privateStringviewUrl;//forward的url publicstaticfinalActionForwardSUCCESS=newActionForward(success); publicstaticfinalActionForwardFAIL=newActionForward(fail); publicActionForward(Stringname){ thisname=name; } publicActionForward(StringnameStringviewUrl){ super(); thisname=name; thisviewUrl=viewUrl; } //name和viewUrl的getter和setter方法 }
我们看到ActionForward预先封装了SUCCESS和FAIL对象 publicclassActionModel{ privateStringpath;//action的path privateStringclassName;//action的class privateMap<StringActionForward>forwards;//action的forward publicActionModel(){} publicActionModel(StringpathStringclassName Map<StringActionForward>forwards){ super(); thispath=path; thisclassName=className; thisforwards=forwards; } //相应的getter和setter方法 }
知道了两个模型是什么样也应该可以猜到我们的配置文件大概是什么样的了与struts的配置文件格式类似 <?xmlversion=encoding=UTF?> <actions> <actionpath=/login class=comstrutsletdemoLoginAction> <forwardname=successurl=hellojsp/> <forwardname=failurl=failjsp/> </action> </actions>
path是在应用中将被调用的路径class指定了调用的哪个actionforward元素指定了转向比如我们这里如果是success就转向hellojsp失败的话转向failjsp这里配置了demo用到的LoginAction Dispacher接口主要是getNextPage方法此方法负责获得下一个页面将导向哪里提供给前端控制器转发 publicinterfaceDispatcher{ publicvoidsetServletContext(ServletContextcontext); publicStringgetNextPage(HttpServletRequestrequestServletContextcontext); }
原先书中实现了一个WorkFlow的Dispatcher按照顺序调用action实现工作流调用而我们所需要的是根据请求的path调用相应的action执行action的execute方法返回一个ActionForward然后得到ActionForward的viewUrl将此viewUrl提供给前端控制器转发看看它的getNextPage方法 publicStringgetNextPage(HttpServletRequestrequestServletContextcontext){ setServletContext(context); Map<StringActionModel>actions=(Map<StringActionModel>)context getAttribute(ConstantACTIONS_ATTR);//从ServletContext得到所有action信息 StringreqPath=(String)requestgetAttribute(ConstantREQUEST_ATTR);//发起请求的path ActionModelactionModel=actionsget(reqPath);//根据path得到相应的action Stringforward_name=; ActionForwardactionForward; try{ Classc=ClassforName(actionModelgetClassName());//每个请求对应一个action实例 Actionaction=(Action)cnewInstance(); actionForward=actionexecute(requestcontext);//执行action的execute方法 forward_name=actionForwardgetName(); }catch(Exceptione){ logerror(cannotfindaction+actionModelgetClassName()); eprintStackTrace(); } actionForward=actionModelgetForwards()get(forward_name); if(actionForward==null){ logerror(cannotfindpageforforward+forward_name); returnnull; }else returnactionForwardgetViewUrl();//返回ActionForward的viewUrl }
前端控制器(FrontController)它的任务我们已经很清楚初始化配置文件存储所有action到ServletContext供整个框架使用得到发起请求的path提供给Dispachter查找相应的action调用Dispatcher执行getNextPage方法得到下一个页面的url并转发 publicvoidinit()throwsServletException{ //初始化配置文件 ServletContextcontext=getServletContext(); Stringconfig_file=getServletConfig()getInitParameter(config); Stringdispatcher_name=getServletConfig()getInitParameter(dispatcher); if(config_file==null||config_fileequals()) config_file=/WEBINF/strutsletconfigxml;//默认是/WEBINF/下面的strutsletconfig if(dispatcher_name==null||dispatcher_nameequals()) dispatcher_name=ConstantDEFAULT_DISPATCHER; try{ Map<StringActionModel>resources=ConfigUtilnewInstance()//工具类解析配置文件 parse(config_filecontext); contextsetAttribute(ConstantACTIONS_ATTRresources);//存储在ServletContext中 (初始化strutslet配置文件成功); }catch(Exceptione){ logerror(初始化strutslet配置文件失败); eprintStackTrace(); } //实例化Dispacher try{ Classc=ClassforName(dispatcher_name); Dispatcherdispatcher=(Dispatcher)cnewInstance(); contextsetAttribute(ConstantDISPATCHER_ATTRdispatcher);//放在ServletContext (初始化Dispatcher成功); }catch(Exceptione){ logerror(初始化Dispatcher失败); eprintStackTrace(); }
doGet()和doPost方法我们都让它调用process方法 protectedvoidprocess(HttpServletRequestrequest HttpServletResponseresponse)throwsServletExceptionIOException{ ServletContextcontext=getServletContext(); //获取action的path StringreqURI=requestgetRequestURI(); inti=reqURIlastIndexOf(); StringcontextPath=requestgetContextPath(); Stringpath=reqURIsubstring(contextPathlength()i); requestsetAttribute(ConstantREQUEST_ATTRpath); Dispatcherdispatcher=(Dispatcher)contextgetAttribute(ConstantDISPATCHER_ATTR); //makesurewedontcachedynamicdata responsesetHeader(CacheControlnocache); responsesetHeader(Pragmanocache); //usethedispatchertofindthenextpage StringnextPage=dispatchergetNextPage(requestcontext);//调用Dispatcher的getNextPage //forwardcontroltotheview RequestDispatcherforwarder=requestgetRequestDispatcher(/ +nextPage); forwarderforward(requestresponse);//转发页面 }
最后webxml的配置就非常简单了配置前端控制器提供启动参数(配置文件所在位置为空就查找/WEBINF/下面的strutsletconfigxml文件)我们把所有以action结尾的请求都交给FrontController处理 <servlet> <servletname>StrutsletController</servletname> <servletclass>reFrontController</servletclass> <! <initparam> <paramname>config</paramname> <paramvalue>/WEBINFstrutsletconfigxml</paramvalue> </initparam> > <loadonstartup></loadonstartup> </servlet> <servletmapping> <servletname>StrutsletController</servletname> <urlpattern>*action</urlpattern> </servletmapping>
最后让我们看看整个框架图 |