时间: 2021-07-31 作者:daque
简介: 我看到很多名目中,开拓者实行了本人的mvc框架,并不是由于她们想做同struts基础各别的货色,而是由于她们并没有认识到怎样扩充struts。开拓本人的mvc框架不妨赢得十足的遏制权,然而这也表示着须要很多资源来实行它(人工物力),在重要的议程安置下,有功夫这是不大概的。 struts不只仅是一个宏大的框架,同声它也是可扩充的。你不妨以三种办法来扩充struts。 1、plugin:即使你想在application startup或shutdown的功夫做少许交易论理的话,那就创造你本人的plugin类。 2、requestprocessor:即使你想在乞求被处置的进程中某个功夫做少许交易论理的话,那么创造你本人的requestprocessor类。比方说,在历次乞求实行之前,你不妨扩充requestprocessor来查看用户能否登岸了以及他能否有权力去实行某个一定的action。 3、actionservlet:即使你想在application startup和shutdown的功夫以及乞求被处置的功夫做某些交易论理,你也不妨蔓延actionservlet类。然而你该当在plugin和requestprocessor都不许处置你的需要的功夫来运用actionservlet。 在这篇作品中,咱们将运用一个struts运用的示例来演示怎样运用这三种办法来扩充struts。示例步调的代码不妨从http://www.onjava.com/onjava/2004/11/10/examples/sample1.zip载入。两个扩充struts胜利的典型是struts自己的validation和tiles框架。 咱们假如你仍旧比拟熟习struts框架而且领会怎样运用它创造一个大略的运用。即使你想领会更多对于struts的实质,请参考官方网页。 plugin plugin是一个接口,你不妨创造一个实行该接口的类,当application startup或shutdown的功夫做些工作。 比如说,我创造了一个运用hibernate动作长久层的web运用,我想当运用启用的功夫就初始化hibernate,这格式当我的web运用遭到第一个乞求的功夫,hibernate就仍旧是摆设好的而且可用的。同声咱们想当application封闭的功夫封闭hibernate。咱们不妨用一个hibernate plugin来实行这个需要,经过如次的两步: 1、创造一个类实行了plugin接口: public class hibernateplugin implements plugin{ private string configfile; // this method will be called at application shutdown time public void destroy() { system.out.println("entering hibernateplugin.destroy()"); //put hibernate cleanup code here system.out.println("exiting hibernateplugin.destroy()"); } //this method will be called at application startup time public void init(actionservlet actionservlet, moduleconfig config) throws servletexception { system.out.println("entering hibernateplugin.init()"); system.out.println("value of init parameter " + getconfigfile()); system.out.println("exiting hibernateplugin.init()"); } public string getconfigfile() { return name; } public void setconfigfile(string string) { configfile = string; } } 实行plugin接口的类必需实行两个本领:init()和destroy()。当application startup的功夫init()本领被挪用,当shutdown的功夫destroy()本领被挪用。struts还承诺给你的plugin类传播初始化参数。为了传播参数,你必需在plugin类中为每一个参数创造javabean式的setter本领。在咱们的hibernateplugin类中,我会把configfile的name动作参数字传送进去,而不是硬源代码到步调中。 2、在struts-config.xml中增添如次的代码来公布struts有新的plugin: <struts-config> ... <!-- message resources --> <message-resources parameter= "sample1.resources.applicationresources"/> <!-- declare your plugins --> <plug-in classname="com.sample.util.hibernateplugin"> <set-property property="configfile" value="/hibernate.cfg.xml"/> </plug-in> </struts-config> 属性classname是实行了plugin接口的类的全控制名。对于每一个初始化参数,不妨运用<set-property>元素传播参数。在咱们的例子中,我要把config文献的名字传进去,以是运用了一个带有摆设文献路途的<set-property>。 struts的tiles和validator框架都运用plugin来读取摆设文献举行初始化。其余两件plugin不妨帮你做到的工作是: ·即使你的application依附于某些摆设文献,那么你不妨在plugin类中查看它们能否可用,即使不行用的话抛出一个servletexception,如许就不妨使actionservlet变为不行用。 ·plugin接口的init()本领是你不妨变换moduleconfig的结果时机,moduleconfig是一组静态摆设消息的汇合,用来刻画鉴于struts模块。struts将会在一切plugin处置完后开释moduleconfig。 request是怎样被处置的 actionservlet是struts框架中独一的servlet,它控制处置一切request。不管何时接受到一个request,它城市先试验为暂时的request探求一个sub-application。一旦一个sub-application被找到,actionservlet就会为谁人sub-application创造一个requestprocessor东西,挪用这个东西的process()本领并把httpservletrequest和httpservletresponse东西传入。 requestprocessor.process()即是大局部request被处置的场合。process()本领运用了template method形式实行,个中有很多独力的本领来实行乞求处置的每一办法,那些本领将会在process本领中顺序被挪用。比方,将会有一个独力的本领用来探求暂时request对应的actionform类,一个本领来查看暂时用户能否有实行action mapping所必需的权力。那些给与咱们极大的精巧性。在颁布的struts包中有一个requestprocessor类供给了乞求处置每一办法的默许实行。这就表示着你不妨只是重写你感爱好的本领,其它的运用默许的实行。举例来说,默许地struts挪用request.isuserinrole()来查看用户能否有权力实行暂时的actionmapping;这时候即使你想经过查问数据库来实行,你所要做的即是重写processroles()本领,经过查问出的用户能否具有必需的权力来归来true或false。 开始咱们将会看到缺省情景下,process()本领是怎样实行的,而后我将会精细证明默许的requestprocessor类中的每一个本领,如许你就不妨确定哪一局部是你想要变换的。 public void process(httpservletrequest request,httpservletresponse response) throws ioexception, servletexception { // wrap multipart requests with a special wrapper request = processmultipart(request); // identify the path component we will // use to select a mapping string path = processpath(request, response); if (path == null) { return; } if (log.isdebugenabled()) { log.debug("processing a '" + request.getmethod() + "' for path '" + path + "'"); } // select a locale for the current user if requested processlocale(request, response); // set the content type and no-caching headers // if requested processcontent(request, response); processnocache(request, response); // general purpose preprocessing hook if (!processpreprocess(request, response)) { return; } // identify the mapping for this request actionmapping mapping = processmapping(request, response, path); if (mapping == null) { return; } // check for any role required to perform this action if (!processroles(request, response, mapping)) { return; } // process any actionform bean related to this request actionform form = processactionform(request, response, mapping); processpopulate(request, response, form, mapping); if (!processvalidate(request, response, form, mapping)) { return; } // process a forward or include specified by this mapping if (!processforward(request, response, mapping)) { return; } if (!processinclude(request, response, mapping)) { return; } // create or acquire the action instance to // process this request action action = processactioncreate(request, response, mapping); if (action == null) { return; } // call the action instance itself actionforward forward = processactionperform(request, response,action, form, mapping); // process the returned actionforward instance processforwardconfig(request, response, forward); } 1、processmutipart():在这个本领中,struts将会读取request来查看request的contenttype能否是multipart/form-data。即使是的话,将会领会request而且将之包装到httpservletrequest中。当你创造了一个html form用来提交数据,那么request的contenttype默许即是application/x-www-form-urlencoded。然而即使你的form运用了file典型的input控件承诺用户上传文献的话,你就必需将contenttype改为multipart/form-data。即使是如许的情景,你就不许再经过getparameter()来获得用户提交的数据;你必需将request动作一个inputstream来读取,而且本人领会它来赢得参数值。 2、processpath():在这个本领中,struts将会读取request的uri,来决定路途元素,这个元素是用来获得actionmappint元素。 3、processlocale():在这个本领中,struts将会为暂时request博得locale,即使摆设过的话,还不妨将这个东西动作httpsession中org.apache.struts.action.locale属性的值而生存。动作这个本领的副效率,httpsession将会被创造,即使你不想创造的话,你不妨在controllerconfig中将locale属性设为false,在struts-config.xml中象如次如许: <controller> <set-property property="locale" value="false"/> </controller> 4、processcontent():经过挪用response.setcontenttype()来为response树立contenttype。这个本领开始会试验从struts-config.xml摆设中获得contenttype。缺省情景下运用text/html。即使想掩盖它,不妨象如次如许: <controller> <set-property property="contenttype" value="text/plain"/> </controller> 5、processnocache():即使摆设是no-cache,struts将会为每个response树立底下三个headers: requested in struts config.xml response.setheader("pragma", "no-cache"); response.setheader("cache-control", "no-cache"); response.setdateheader("expires", 1); 即使你想树立no-cache header,在struts-config.xml中介入底下消息: <controller> <set-property property="nocache" value="true"/> </controller> 6、processpreprocess():这个本领为预处置供给一个hook,不妨在子类中掩盖它。它的缺省实行没有作任何工作,老是归来true。归来false的话将会中断暂时乞求的处置。 7、processmapping():这个本领将会用路途消息获得一个actionmapping东西。也即是struts-config.xml文献中的<action>元素: <action path="/newcontact" type="com.sample.newcontactaction" name="newcontactform" scope="request"> <forward name="sucess" path="/sucesspage.do"/> <forward name="failure" path="/failurepage.do"/> </action> actionmapping元素包括了action类的称呼和处置乞求运用的actionform之类消息。它还包括暂时actionmapping摆设的actionforwards消息。 8、processroles():struts web运用供给了一个受权计划。也即是说,一旦一个用户登入了容器,struts的processroles()本领将会经过挪用request.isuserinrole(),来查看他能否有必需的脚色来运转一个给定的actionmapping。 <action path="/adduser" roles="administrator"/> 假如你有一个adduseraction而且你只想让administrator不妨减少新的user。你所要做的即是给你的adduseraction元素减少一个role属性,这个属性的值为administrator。如许,在运转adduseraction之前,这个本领会保证用户具有administraotr的脚色。 9、processactionform():每一个actionmapping都一个相映的actionform类。当struts处置一个actionmapping的功夫,它将会从<action>元素的name属性中找到对应的actionform类的称呼。 <form-bean name="newcontactform" type="org.apache.struts.action.dynaactionform"> <form-property name="firstname" type="java.lang.string"/> <form-property name="lastname" type="java.lang.string"/> </form-bean> 在咱们的例子中,它会先在request scope中查看能否有一个org.apache.struts.action.dynaactionform类的东西生存。即使有它将会运用这个东西,即使没有它将会创造一个新的东西并把它树立在request scope。 10、processpopulate():在这个本领中,struts将会用相配合的request参数安装actionform的范例变量。 11、processvalidate():struts将会挪用你的actionform类的validate本领。即使你从validate()归来actionerrors,它将会将user重定向到<action>元素的input属性指定的页面。 12、processforward()和processinclude():在那些本领中,struts将会查看<action>元素的forward或include属性,即使找到了,将会把forward或include乞求安置到摆设的页面中。 <action forward="/login.jsp" path="/logininput"/> <action include="/login.jsp" path="/logininput"/> 你不妨从那些本领的名字上探求它们的各别:processforward()最后挪用requestdispatcher.forward(),而processinclude()挪用requestdispatcher.include()。即使你同声摆设了forward和include属性,它将会老是挪用forward,由于forward先被处置。 13、processactioncreate():这个本领从<action>元素的type属性中获得赢得action类的名字而且创造归来它的范例。在咱们的例子中,它将会创造一个com.sample.newcontactaction类的范例。 14、processactionperform():这个本领挪用你的action类的excute()本领,你的交易论理也即是在excute本领中。 15、processforwardconfig():你的action类的excute()本领将会归来一个actionforward东西,这个东西将指出哪个页面是表露给用户的页面。所以,struts将会为谁人页面创造一个requestdispatcher,而且挪用requestdispatcher.forward()。 上头的列表说领会默许的requestprocessor实行在处置乞求时每一步作的处事,以及实行的程序。正如你所看到的,requestprocessor利害常精巧的,承诺你经过树立<controller>元素的属性来摆设它。举例来说,即使你的运用筹备天生xml实质来包办html,你就不妨经过树立controller元素的属性来报告struts那些情景。 创造你本人的requestprocessor 经过上头,咱们领会到了requestprocessor的默许实行是怎样处事的。此刻咱们要演练一个例子来证明怎样定制你本人的requestprocessor。为了展现创造用户定制的requestprocessor,咱们将会让咱们的示例实行底下两个交易需要: ·咱们想创造一个contactimageaction类,它将天生图片而不是凡是的html页面。 ·在每个乞求处置之前,咱们都想经过查看session中的username属性来决定用户能否仍旧登岸。即使谁人属性没有找到,咱们会把用户重定向到登岸页面。 咱们将分两步实行那些交易需要。 1、创造你的customrequestprocessor类,它将接受自requestprocessor类,如次: public class customrequestprocessor extends requestprocessor { protected boolean processpreprocess ( httpservletrequest request,httpservletresponse response) { httpsession session = request.getsession(false); //if user is trying to access login page // then don't check if( request.getservletpath().equals("/logininput.do") || request.getservletpath().equals("/login.do") ) return true; //check if username attribute is there is session. //if so, it means user has allready logged in if( session != null && session.getattribute("username") != null) return true; else{ try{ //if no redirect user to login page request.getrequestdispatcher("/login.jsp").forward(request,response); }catch(exception ex){ } } return false; } protected void processcontent(httpservletrequest request, httpservletresponse response) { //check if user is requesting contactimageaction // if yes then set image/gif as content type if( request.getservletpath().equals("/contactimage.do")){ response.setcontenttype("image/gif"); return; } super.processcontent(request, response); } } 在customrequestprocessor类的processpreprocess本领中,咱们查看session的username属性,即使没有找到,就将用户重定向到登岸页面。 对于天生图片动作输入的需要,咱们必需掩盖processcontent本领,开始查看乞求能否是/contactimage路途。即使是的话,咱们就会将contenttype树立为image/gif;要不树立为text/html。 2、在你的struts-config.xml文献的<action-mappint>元素之后介入底下的笔墨,报告struts customrequestprocessor该当被用作requestprocessor类: <controller> <set-property property="processorclass"value="com.sample.util.customrequestprocessor"/> </controller> 请提防,当你惟有很少的action类须要天生非text/html典型的输入时,你覆写processcontent()本领是ok的。即使不是这格式的话,你该当创造一个struts的子运用来处置乞求天生图片的action,并为它们将contenttype树立为image/gif。 struts的tiles框架即是运用它本人的requestprocessor来化妆struts的输入。 actionservlet 即使你察看你的struts web运用的web.xml,你会看到如许的笔墨: <web-app > <servlet> <servlet-name>action=</servlet-name> <servlet-class>org.apache.struts.action.actionservlet</servlet-class> <!-- all your init-params go here--> </servlet> <servlet-mapping> <servlet-name>action</servlet-name> <url-pattern>*.do</url-pattern> </servlet-mapping> </web-app > 这表示着actionservlet控制处置你一切struts的乞求。你不妨创造一个actionservlet的子类,当运用启用,封闭,每个乞求的功夫做少许一定的工作。然而在接受actionservlet类之前,你该当尽管创造一个plugin或requestprocessor去处置你的题目。在servlet1.1之前,tiles框架是鉴于actionservlet来化装天生的相应。然而从1.1之后,它发端运用tilesrequestprocessor类。 归纳 确定开拓你本人的mvc框架是一个特殊大的确定,你必需要商量开拓和保护框架代码所耗费的功夫和资源。struts是一个特殊宏大和宁静的框架,你不妨窜改它来满意你绝大普遍的交易需要。 但另一上面,也不要轻率地做出扩充struts的确定。即使你在requestprocessor中写了少许本能比拟低的代码,它将会在历次乞求时实行,所以贬低你所有运用的功效。并且仍旧有少许情景,开拓本人的mvc框架要比扩充struts好。