<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    隨筆 - 6  文章 - 0  trackbacks - 0
    <2025年5月>
    27282930123
    45678910
    11121314151617
    18192021222324
    25262728293031
    1234567

    常用鏈接

    留言簿(2)

    隨筆分類

    文章分類

    好友

    搜索

    •  

    最新評(píng)論

    閱讀排行榜

    評(píng)論排行榜

    作者:Sunil Patil

    簡介

    我見過許多項(xiàng)目開發(fā)者實(shí)現(xiàn)自己專有的MVC框架。這些開發(fā)者并不是因?yàn)橄雽?shí)現(xiàn)不同于Struts的某些功能,而是還沒有意識(shí)到怎么去擴(kuò)展Struts。通過開發(fā)自己的MVC框架,你可以掌控全局,但同時(shí)這也意味著你必須付出很大的代價(jià);在項(xiàng)目計(jì)劃很緊的情況下也許根本就不可能實(shí)現(xiàn)。

    Struts不但功能強(qiáng)大也易于擴(kuò)展。你可以通過三種方式來擴(kuò)展Struts:

    1.PlugIn:在應(yīng)用啟動(dòng)或關(guān)閉時(shí)須執(zhí)行某業(yè)務(wù)邏輯,創(chuàng)建你自己的PlugIn類

    2.RequestProcessor:在請(qǐng)求處理階段一個(gè)特定點(diǎn)欲執(zhí)行某業(yè)務(wù)邏輯,創(chuàng)建你自己的RequestProcessor。例如:你想繼承RequestProcessor來檢查用戶登錄及在執(zhí)行每個(gè)請(qǐng)求時(shí)他是否有權(quán)限執(zhí)行某個(gè)動(dòng)作。

    3.ActionServlet:在應(yīng)用啟動(dòng)或關(guān)閉或在請(qǐng)求處理階段欲執(zhí)行某業(yè)務(wù)邏輯,繼承ActionServlet類。但是必須且只能在PligIn和RequestProcessor都不能滿足你的需求時(shí)候用。

    本文會(huì)列舉一個(gè)簡單的Struts應(yīng)用來示范如何使用以上三種方式擴(kuò)展Struts。在本文末尾資源區(qū)有每種方式的可下載樣例源代碼。Struts Validation 框架和 Tiles 框架是最成功兩個(gè)的Struts擴(kuò)展例子。

    我是假設(shè)讀者已經(jīng)熟悉Struts框架并知道怎樣使用它創(chuàng)建簡單的應(yīng)用。如想了解更多有關(guān)Struts的資料請(qǐng)參見資源區(qū)。

    PlugIn

    根據(jù)Struts文檔,“PlugIn是一個(gè)須在應(yīng)用啟動(dòng)和關(guān)閉時(shí)需被通知的模塊定制資源或服務(wù)配置包”。這就是說,你可以創(chuàng)建一個(gè)類,它實(shí)現(xiàn)PlugIn的接口以便在應(yīng)用啟動(dòng)和關(guān)閉時(shí)做你想要的事。

    假如創(chuàng)建了一個(gè)web應(yīng)用,其中使用Hibernate做為持久化機(jī)制;當(dāng)應(yīng)用一啟動(dòng),就需初始化Hinernate,這樣在web應(yīng)用接收到第一個(gè)請(qǐng)求時(shí),Hibernate已被配置完畢并待命。同時(shí)在應(yīng)用關(guān)閉時(shí)要關(guān)閉Hibernate。跟著以下兩步可以實(shí)現(xiàn)Hibernate PlugIn的需求。

    1.創(chuàng)建一個(gè)實(shí)現(xiàn)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;
    ????????}
    }


    實(shí)現(xiàn)PlugIn接口的類必須是實(shí)現(xiàn)以下兩個(gè)方法:
    init() 和destroy().。在應(yīng)用啟動(dòng)時(shí)init()被調(diào)用,關(guān)閉destroy()被調(diào)用。Struts允許你傳入初始參數(shù)給你的PlugIn類;為了傳入?yún)?shù)你必須在PlugIn類里為每個(gè)參數(shù)創(chuàng)建一個(gè)類似JavaBean形式的setter方法。在HibernatePlugIn類里,欲傳入configFile的名字而不是在應(yīng)用里將它硬編碼進(jìn)去

    2.在struts-condig.xml里面加入以下幾行告知Struts這個(gè)新的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屬性是實(shí)現(xiàn)PlugIn接口類的全名。為每一個(gè)初始化傳入PlugIn類的初始化參數(shù)增加一個(gè)<set-property>元素。在這個(gè)例子里,傳入config文檔的名稱,所以增加了一個(gè)config文檔路徑的<set-property>元素。

    Tiles和Validator框架都是利用PlugIn給初始化讀入配置文件。另外兩個(gè)你還可以在PlugIn類里做的事情是:

    假如應(yīng)用依賴于某配置文件,那么可以在PlugIn類里檢查其可用性,假如配置文件不可用則拋出ServletException。這將導(dǎo)致ActionServlet不可用。

    PlugIn接口的init()方法是你改變ModuleConfig方法的最后機(jī)會(huì),ModuleConfig方法是描述基于Struts模型靜態(tài)配置信息的集合。一旦PlugIn被處理完畢,Struts就會(huì)將ModuleCOnfig凍結(jié)起來。

    請(qǐng)求是如何被處理的

    ActionServlet是Struts框架里唯一一個(gè)Servlet,它負(fù)責(zé)處理所有請(qǐng)求。它無論何時(shí)收到一個(gè)請(qǐng)求,都會(huì)首先試著為現(xiàn)有請(qǐng)求找到一個(gè)子應(yīng)用。一旦子應(yīng)用被找到,它會(huì)為其生成一個(gè)RequestProcessor對(duì)象,并調(diào)用傳入HttpServletRequest和HttpServletResponse為參數(shù)的process()方法。

    大部分請(qǐng)?zhí)幚矶际窃赗equestProcessor.process()發(fā)生的。Process()方法是以模板方法(Template Method)的設(shè)計(jì)模式來實(shí)現(xiàn)的,其中有完成request處理的每個(gè)步驟的方法;所有這些方法都從process()方法順序調(diào)用。例如,尋找當(dāng)前請(qǐng)求的ActionForm類和檢查當(dāng)前用戶是否有權(quán)限執(zhí)行action mapping都有幾個(gè)單獨(dú)的方法。這給我們提供了極大的彈性空間。Struts的RequestProcessor對(duì)每個(gè)請(qǐng)求處理步驟都提供了默認(rèn)的實(shí)現(xiàn)方法。這意味著,你可以重寫你感興趣的方法,而其余剩下的保留默認(rèn)實(shí)現(xiàn)。例如,Struts默認(rèn)調(diào)用request.isUserInRole()檢查用戶是否有權(quán)限執(zhí)行當(dāng)前的ActionMapping,但如果你需要從數(shù)據(jù)庫中查找,那么你要做的就是重寫processRoles()方法,并根據(jù)用戶角色返回true 或 false。

    首先我們看一下process()方法的默認(rèn)實(shí)現(xiàn)方式,然后我將解釋RequestProcessor類里的每個(gè)默認(rèn)的方法,以便你決定要修改請(qǐng)求處理的哪一部分。

    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、processMultipart(): 在這個(gè)方法中,Struts讀取request以找出contentType是否為multipart/form-data。假如是,則解析并將其打包成一個(gè)實(shí)現(xiàn)HttpServletRequest的包。當(dāng)你成生一個(gè)放置數(shù)據(jù)的HTML FORM時(shí),request的contentType默認(rèn)是application/x-www-form-urlencoded。但是如果你的form的input類型是FILE-type允許用戶上載文件,那么你必須把form的contentType改為multipart/form-data。如這樣做,你永遠(yuǎn)不能通過HttpServletRequest的getParameter()來讀取用戶提交的form值;你必須以InputStream的形式讀取request,然后解析它得到值。

    2、processPath(): 在這個(gè)方法中,Struts將讀取request的URI以判斷用來得到ActionMapping元素的路徑。

    3、processLocale(): 在這個(gè)方法中,Struts將得到當(dāng)前request的Locale;Locale假如被配置,將作為org.apache.struts.action.LOCALE屬性的值被存入HttpSession。這個(gè)方法的附作用是HttpSession會(huì)被創(chuàng)建。假如你不想此事發(fā)生,可將在struts-config.xml 文件里ControllerConfig的local屬性設(shè)置為false,如下:
    <controller>
    ????????<set-property property="locale" value="false"/>
    </controller>


    4、processContent():通過調(diào)用response.setContentType()設(shè)置response的contentType。這個(gè)方法首先會(huì)試著的得到配置在struts-config.xml里的contentType。默認(rèn)為text/html,重寫方法如下:
    <controller>
    ????????<set-property property="contentType" value="text/plain"/>
    </controller>


    5、processNoCache():Struts將為每個(gè)response的設(shè)置以下三個(gè)header,假如已在struts 的config.xml將配置為no-cache。
    response.setHeader("Pragma", "No-cache");
    response.setHeader("Cache-Control", "no-cache");
    response.setDateHeader("Expires", 1);


    假如你想設(shè)置為no-cache header,在struts-config.xml中加如以下幾行
    <controller>
    ????????<set-property property="noCache" value="true"/>
    </controller>


    6、processPreprocess():這是一個(gè)一般意義的預(yù)處理hook,其可被子類重寫。在RequestProcessor里的實(shí)現(xiàn)什么都沒有做,總是返回true。如此方法返回false會(huì)中斷請(qǐng)求處理。

    7、processMapping():這個(gè)方法會(huì)利用path信息找到ActionMapping對(duì)象。ActionMapping對(duì)象在struts-config.xml file文件里表示為<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類的名稱及在請(qǐng)求中用到的ActionForm的信息,另外還有配置在當(dāng)前ActionMapping的里的ActionForwards信息。

    8、processRoles(): Struts的web 應(yīng)用安全提供了一個(gè)認(rèn)證機(jī)制。這就是說,一旦用戶登錄到容器,Struts的processRoles()方法通過調(diào)用request.isUserInRole()可以檢查他是否有權(quán)限執(zhí)行給定的ActionMapping。
    ????????<action path="/addUser" roles="administrator"/>

    假如你有一個(gè)AddUserAction,限制只有administrator權(quán)限的用戶才能新添加用戶。你所要做的就是在AddUserAction 的action元素里添加一個(gè)值為administrator的role屬性。

    9、processActionForm():每個(gè)ActionMapping都有一個(gè)與它關(guān)聯(lián)的ActionForm類。struts在處理ActionMapping時(shí),他會(huì)從<action>里name屬性找到相關(guān)的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>


    在這個(gè)例子里,首先會(huì)檢查org.apache.struts.action.DynaActionForm類的對(duì)象是否在request 范圍內(nèi)。如是,則使用它,否則創(chuàng)建一個(gè)新的對(duì)象并在request范圍內(nèi)設(shè)置它。

    10、processPopulate()::在這個(gè)方法里,Struts將匹配的request parameters值填入ActionForm類的實(shí)例變量中。

    11、processValidate():Struts將調(diào)用ActionForm的validate()方法。假如validate()返回ActionErrors,Struts將用戶轉(zhuǎn)到由<action>里的input屬性標(biāo)示的頁面。

    12、processForward() and processInclude():在這兩個(gè)方法里,Struts檢查<action>元素的forward和include屬性的值,假如有配置,則把forward和include 請(qǐng)求放在配置的頁面內(nèi)。
    <action forward="/Login.jsp" path="/loginInput"/>
    ????????<action include="/Login.jsp" path="/loginInput"/>


    你可以從他們的名字看出其不同之處。processForward()調(diào)用RequestDispatcher.forward(),,processInclude()調(diào)用RequestDispatcher.include()。假如你同時(shí)配置了orward 和include 屬性,Struts總會(huì)調(diào)用forward,因?yàn)閒orward,是首先被處理的。

    13、processActionCreate():這個(gè)方法從<action>的type屬性得到Action類名,并創(chuàng)建返回它的實(shí)例。在這里例子中struts將創(chuàng)建一個(gè)com.sample.NewContactAction類的實(shí)例。

    14、processActionPerform():這個(gè)方法調(diào)用Action 類的execute()方法,其中有你寫入的業(yè)務(wù)邏輯。

    15、processForwardConfig():Action類的execute()將會(huì)返回一個(gè)ActionForward類型的對(duì)象,指出哪一頁面將展示給用戶。因此Struts將為這個(gè)頁面創(chuàng)建RequestDispatchet,然后再調(diào)用RequestDispatcher.forward()方法。

    以上列出的方法解釋了RequestProcessor在請(qǐng)求處理的每步默認(rèn)實(shí)現(xiàn)及各個(gè)步驟執(zhí)行的順序。正如你所見,RequestProcessor很有彈性,它允許你通過設(shè)置<controller>里的屬性來配置它。例如,假如你的應(yīng)用將生成XML內(nèi)容而不是HTML,你可以通過設(shè)置controller的某個(gè)屬性來通知Struts。

    創(chuàng)建你自己的RequestProcessor

    從以上內(nèi)容我們已經(jīng)明白了RequestProcessor的默認(rèn)實(shí)現(xiàn)是怎樣工作的,現(xiàn)在我將通過創(chuàng)建你自己的RequestProcessor.展示一個(gè)怎樣自定義RequestProcessor的例子。為了演示創(chuàng)建一個(gè)自定義RequestProcessor,我將修改例子實(shí)現(xiàn)以下連個(gè)業(yè)務(wù)需求:

    我們要?jiǎng)?chuàng)建一個(gè)ContactImageAction類,它將生成images而不是一般的HTMl頁面

    在處理這個(gè)請(qǐng)求之前,將通過檢查session里的userName屬性來確認(rèn)用戶是否登錄。假如此屬性沒有被找到,則將用戶轉(zhuǎn)到登錄頁面。


    分兩步來實(shí)現(xiàn)以上連個(gè)業(yè)務(wù)需求。
    創(chuàng)建你自己的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屬性,假如沒有找到,將用戶轉(zhuǎn)到登錄頁面。

    對(duì)于產(chǎn)生images作為ContactImageAction類的輸出,必須要重寫processContent方法。首先檢查其request是否請(qǐng)求/contactimage路徑,如是則設(shè)置contentType為image/gif;否則為text/html。

    加入以下幾行代碼到sruts-config.xml文件里的<action-mapping>后面,告知Struts ,CustomRequestProcessor應(yīng)該被用作RequestProcessor類

    <controller>
    ????????<set-property??property="processorClass"
    ????????value="com.sample.util.CustomRequestProcessor"/>
    </controller>


    請(qǐng)注意,假如你只是很少生成contentType不是text/html輸出的Action類,重寫processContent()就沒有問題。如不是這種情況,你必須創(chuàng)建一個(gè)Struts子系統(tǒng)來處理生成image??Action的請(qǐng)求并設(shè)置contentType為image/gif

    Title框架使用自己的RequestProcessor來裝飾Struts生成的輸出。

    ActionServlet

    假如你仔細(xì)研究Struts web應(yīng)用的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負(fù)責(zé)處理所有發(fā)向Struts的請(qǐng)求。你可以創(chuàng)建ActionServlet的一個(gè)子類,假如你想在應(yīng)用啟動(dòng)和關(guān)閉時(shí)或每次請(qǐng)求時(shí)做某些事情。但是你必須在繼承ActionServlet類前創(chuàng)建PlugIn 或 RequestProcessor。在Servlet 1.1前,Title框架是基于繼承ActionServlet類來裝飾一個(gè)生成的response。但從1.1開始,就使用TilesRequestProcessor類。

    結(jié)論

    開發(fā)你自己的MVC模型是一個(gè)很大的決心——你必須考慮開發(fā)和維護(hù)代碼的時(shí)間和資源。Struts是一個(gè)功能強(qiáng)大且穩(wěn)定的框架,你可以修改它以使其滿足你大部分的業(yè)務(wù)需求。

    另一方面,也不要輕易地決定擴(kuò)展Struts。假如你在RequestProcessor里放入一些低效率的代碼,這些代碼將在每次請(qǐng)求時(shí)執(zhí)行并大大地降低整個(gè)應(yīng)用的效率。當(dāng)然總有創(chuàng)建你自己的MVC框架比擴(kuò)展Struts更好的情況。
    posted on 2006-05-12 15:21 badboy 閱讀(180) 評(píng)論(0)  編輯  收藏 所屬分類: Framework
    主站蜘蛛池模板: 永久免费无码网站在线观看个| 99999久久久久久亚洲| 国产成人精品无码免费看| 国产成人无码区免费内射一片色欲| 久久久久久久岛国免费播放| 国产亚洲综合久久系列| 精精国产www视频在线观看免费| 亚洲国产a级视频| 激情内射亚洲一区二区三区| 亚洲av无码不卡久久| 国产高清视频免费在线观看 | 精品国产日韩亚洲一区| 亚洲免费黄色网址| 又大又硬又粗又黄的视频免费看| 波多野结衣一区二区免费视频| 亚洲黄色免费观看| 国产免费不卡v片在线观看| 亚洲AV无码资源在线观看| 国产青草视频在线观看免费影院| 美女黄频免费网站| 久久精品国产69国产精品亚洲| 久久免费看少妇高潮V片特黄| 久久亚洲AV成人无码软件| 永久免费AV无码国产网站| 国产亚洲漂亮白嫩美女在线 | 亚洲精品第一国产综合精品| 精品一区二区三区免费观看| 亚洲人成无码网站| 亚洲免费观看在线视频| 亚洲七久久之综合七久久| 四虎永久在线观看免费网站网址| 亚洲色大成网站WWW国产| 99久久免费精品国产72精品九九| 久久精品国产精品亚洲艾 | 99re6在线视频精品免费| 国产成人青青热久免费精品| 中国内地毛片免费高清| 亚洲AV无码乱码在线观看性色扶| 久久精品免费网站网| 亚洲综合亚洲国产尤物| 免费在线观看中文字幕|