November 4, 2011

Servlet Include နှင့် Forward

Web Application များကို ရေးသားရာတွင် Servlet တစ်ခုအတွင်းမှ၊ အခြေအနေအရ အခြားသော Servlet များကို ခေါ်ယူအသုံးချလိုသောအခါမျိုး၊ ဒါမှမဟုတ် လက်ရှိလုပ်ငန်းများကို အခြားသော Servlet ကို လုံးလုံးတာဝန်လွှဲလိုသည့်အခါမျိုး ကြုံလာရတတ်ပါသည်။ ယခင်က Servlet API တွင် ServletContext#getServlet ဒါမှမဟုတ် ServletContext#getServlets ကို အသုံးပြု၍ Servlet များကို ခေါ်ယူ အသုံးပြုနိုင်ခဲ့၏။

သို့ရာတွင် Version 2.1 နောက်ပိုင်းတွင် အထက်ပါနည်းကို အသုံးပြုခြင်းသည် မလိုလားအပ်သော ပြဿနာများဖြစ်ပေါ်တတ်ပါသဖြင့် Support လုပ်ခြင်းမရှိတော့ပါ။ လက်ရှိ API တွင်လည်း အထက်ပါ လုပ်ဆောင်ချက်များပါဝင်သော်လည်း ခေါ်ယူသည့်အခါတိုင်း null ကို သာပြန်ပေးစေပါသည်။ သို့ရာတွင် အထက်ပါ လုပ်ဆောင်ချက်များအစား include နှင့် forward လုပ်ဆောင်ချက်များကို ပြင်ဆင်လာခဲ့ပါသည်။

include သည် Servlet တစ်ခုအတွင်းမှ၊ တစ်စိတ်တစ်ပိုင်ကို အခြားသော Servlet၊ HTML၊ JSP ကို အလုပ်လုပ်စေလိုသောအခါတွင် အသုံးပြုပြီး၊ forward သည် အခြားသောနေရာသို့ လုံးဝတာဝန်လွှဲလိုက်ခြင်း ဖြစ်သည်။ HTTP တွင် Redirect ဟုခေါ်သော Function ပိုင်ဆိုင်သော်လည်း၊ ထိုနည်းမှာ Client ထံသို့အရင် ပြန်ပို့ပြီးမှ အခြားသောနေရာသို့ တဆင့်ပြန်သွားခြင်းဖြစ်ပါသည်။ သို့ရာတွင် Servlet ၏ forward သည် Client ဆီသို့မပြန်တော့ပဲ စေလိုရာသို့ တိုက်ရိုက်သွားရောက်စေခြင်း ဖြစ်ပါသည်။

ယခုဘလောဂ်ဖြင့် Servlet ၏ include နှင့် forward ကို ဖော်ပြပြီး၊ default စာမျက်နှာသတ်မှတ်ချက်များ ဖြစ်သော error-page များ သတ်မှတ်ပုံကို ဖော်ပြသွားပါမည်။


အသုံးချလိုသည်များကို include


include ရော forward ပါ javax.servlet.RequestDispatcher interface မှတဆင့် လုပ်ဆောင်စေသော လုပ်ဆောင်ချက်များ ဖြစ်ကြပါသည်။ အထက်ပါ interface ကို ServletRequest#getRequestDispatcher ၊ ServletContext#getRequestDispatcher နှင့် ServletContext#getNameDispatcher လုပ်ဆောင်ချက်တို့မှ တဆင့် ခေါ်ယူနိုင်ပါသည်။ ကွဲခြားသည်မှာ ခေါ်ယူလိုသည့် HTML, JSP နှင့် Servlet တို့အားခေါ်ယူသည့် ခေါ်ယူနည်းပဲဖြစ်ပါသည်။


ServletRequest getRequestDispatcher လက်ရှိ နေရာမှ နိုင်းယှဉ် Path သို့မဟုတ်WWW Application Root မှ အတိအကျ Path ဖြင့် ခေါ်ယူရပါမည်။
ServletContext getRequestDispatcher WWW Application Root မှ အတိအကျ Path ဖြင့် ခေါ်ယူရပါမည်။
getNamedDispatcher Resource ၏ သတ်မှတ်သားသော အမည်ဖြင့် ခေါ်ယူနိုင်မည် ဖြစ်သည်။

လက်တွေ့ include ကို သုံးပြီး နမှုနာ တစ်ခုကိုရေးကြည့်ပါမည်။ နမှုနာအဖြစ် IncludeServlet.java နှင့် ခေါ်ယူအသုံးချမည့် ToBeInclude.java ကို အသုံးပြုသွားပါမည်။ ဤနမှုနာထဲတွင် include လုပ်ပုံကို သိသာစေရန်၊ IncludeServlet အထဲမှနေ၍ ToBeInclude ကို include လုပ်ပြီး၊ HTML စာမျက်နှာတွင် လိုအပ်သောအချက်အလက်များကို ရေးခိုင်ကြည့်ပါမည်။

IncludeServlet#doGet
    protected void doGet(HttpServletRequest request,
            HttpServletResponse response) throws ServletException, IOException {
    
        // response တွင် ယူနီကုဒ် Encoding အဖြစ် သတ်မှတ်ခြင်း
        response.setCharacterEncoding("UTF-8");
        PrintWriter writer = response.getWriter();
        writer.println(getHeaderHtml(EPISODE, "Include ကို စမ်းသပ်ရေးသားခြင်း"));
        
        // RequestDispatcher ကို HttpServletRequest မှ ခေါ်ယူခြင်း
        RequestDispatcher disp = request.getRequestDispatcher("/ToInclude");
        // Dispatcher မှ Servlet ကို ခေါ်ယူ အလုပ်လုပ်စေခြင်း
        disp.include(request, response);
        
        writer.println(getFooterHtml());        
    }

ထုံးစံအတိုင်း HttpServletResponse ၏ Object ဖြစ်သော response ၏ Encoding ကို ယူနီကုဒ် (UTF-8) ဟု သတ်မှတ်ပါသည်။ ပြီးလျှင် PrintWriter ၏ instance ကို ခေါ်ယူပြီး၊ HTML ၏ အထက်ပိုင်းစာသားများကို ရေးသားစေပါသည်။ getHeaderHtml အကြောင်းကိုမှု ယခင်အခန်းတွင် ဖော်ပြခဲ့ပါ၍ ယခုအခန်းတွင် အသေးစိတ် မရှင်းပြတော့ပါ။
အဓိကမှာ include လုပ်ရန်အတွက် RequestDispatcher ၏ instance ကို HttpServletRequset#getRequestDispatcher လုပ်ဆောင်ချက်ဖြင့် ခေါ်ယူနေပါသည်။ HttpServletRequset#getRequestDispatcher ၏ ပါရာမီတာတွင် "/ToInclude" ဟု လမ်းကြောင်းအပြည့်အစုံ(full path) ရေးပြီး ခေါ်ယူနေပါသည်။ ပြီးပါက RequestDispatcher#include ကို ခေါ်ယူ၍ ToBeInclude Servlet အား ခေါ်ယူအလုပ်လုပ်စေခြင်း ဖြစ်သည်။

နောက်ဆုံးတွင် getFooterHtml ဖြင့် HTML ၏ အောက်ပိုင်းစာသားများကို ရယူပြီး ရေးသားနေစေခြင်းဖြစ်ပါသည်။

ToBeInclude#doGet
    protected void doGet(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException {

        // Class ၏အမည်ကို ရယူခြင်း
        String className = this.getClass().getSimpleName();
        // response တွင် ယူနီကုဒ် Encoding အဖြစ် သတ်မှတ်ခြင်း
        resp.setCharacterEncoding("UTF-8");
        PrintWriter writer = resp.getWriter();

        writer.println("<p>");
        writer.println("ဤစာကြောင်းသည် " + className + " Class အတွင်းမှရေးသားထားခြင်း ဖြစ်ပါသည်။<br />");
        writer.println("</p>");

        @SuppressWarnings("unchecked")
        Enumeration<String> attrNames = req.getAttributeNames();
        
        if(null != attrNames) {
            writer.println("<h3>Servlet များအကြားတွင် လက်ဆင့်ကမ်း လာသော အချက်အလက်များ</h3>");
            writer.println("<p>");
            
            // လက်ဆင့်ကမ်းလာသော Attribute မကုန်မချင်း
            while(attrNames.hasMoreElements()) {
                // Attribute အမည်
                String name = attrNames.nextElement();
                writer.print(name);
                writer.print(" : ");
                // Attribute တန်ဖိုး
                writer.print(req.getAttribute(name));
                writer.print("<br />");
            }
            writer.println("</p>");
        } 

    }

IncludeServlet အထဲမှ ခေါ်ယူသောအခါ ရေးသားမည့် လုပ်ဆောင်ချက်ဖြစ်၏။ မည်သည့် Class အတွင်းမှ ရေးသားသွားသည် ဆိုသည်ကို ဖော်ပြနိုင်ရန် Class ၏ အမည်ကို ရယူပါသည်။ ပြီးလျှင် Encoding သတ်မှတ်ပြီး PrintWriter ကို ခေါ်ယူပြီး၊ "ဤစာကြောင်းသည် " + className + " Class အတွင်းမှရေးသားထားခြင်း ဖြစ်ပါသည်။" ဟု ရေးသားစေပါသည်။

တဖန် Servlet တစ်ခုမှ အခြားသော Servlet များကို ခေါ်ယူရာတွင် အချက်အလက်များကို လက်ဆင့်ကမ်းပေးပို့နိုင်ပါသည်။ အသုံးပြုကြသည့် လုပ်ဆောင်ချက်များမှာ HttpServletRequest#setAttribute ဖြင့် ပေးပို့လိုသည့် အချက်အလက်များကို ရေးသားပြီး၊ HttpServletRequest#getAttribute ဖြင့် ပေးပို့လိုက်သော အချက်အလက်များကို ရယူနိုင်ပါသည်။ တဖန် HttpServletRequest#getAttributeNames ဖြင့် ပေးပို့လိုက်သော အချက်အလက်၏ အမည်များကို ရယူနိုင်ပါသည်။

ဤနမှုနာတွင် IncludeServlet အတွင်းမှ အချက်အလက်များကို မပေးပို့လိုက်ပါသော်လည်း include လုပ်သောအခါတွင် ServletContainer က ပေးပို့လိုက်သော အချက်အလက်များကို ကြည့်ရှုလိုပါသဖြင့် getAttributeNames ဖြင့် အမည်များကို ရယူကာ၊ while ဝါကျကို အသုံးပြုပြီး အမည်များမကုန်မချင်း အမည်တစ်ခုစီနှင့် တန်ဖိုးများကို ဖော်ပြနေစေခြင်း ဖြစ်ပါသည်။



IncludeServlet ကို ခေါ်ယူကြည့်သောအခါ အထက်ပါအတိုင်း တွေ့မြင်ရမည် ဖြစ်သည်။ IncludeServlet အတွင်းမှ setAttribute နှင့် အချက်အလက်များကို မရေးသားထားပါ သော်လည်း include ကို အသုံးပြုပါက အထက်ပါ အချက်အလက်များကို ServletContainer မှ ဖြည့်စွက်ရေးသား သွားသည်ကိုသိရှိနိုင်ပါသည်။


မျက်နှာလွှဲခဲပစ် forward

Servlet တစ်ခုအတွင်းမှ အခြားသော Servlet တစ်ခုဆီသို့ လုံးဝတာဝန်လွှဲပြောင်းလိုသော အခါမျိုးတွင် forward ကို အသုံးပြုရပါသည်။ include ကဲ့သို့ပင် forward သည်လည်း RequestDispatcher interface ၏ လုပ်ဆောင်ချက်တစ်ခုဖြစ်သည်။ include နှင့် forward ၏ကွဲခြားချက်ကို သိရှိနိုင်စေရန် IncludeServlet တွင်အသုံးပြုခဲ့သော ToBeInclude ကို ပြန်လည်အသုံးပြုပါမည်။

ဤနမှုနာတွင် ForwardServlet အထဲမှ ToBeInclude ဆီသို့ forward လုပ်ကြည့်ပါမည်။

ForwardServlet#doGet
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException {

        req.setAttribute("param1", "အခန်း၄ မှ ပါရာမီတာ ၁ ဖြစ်၏။");
        req.setAttribute("param2", "အခန်း၄ မှ ပါရာမီတာ ၂ ဖြစ်၏။");
        req.setAttribute("param3", "အခန်း၄ မှ ပါရာမီတာ ၃ ဖြစ်၏။");

        //  Dispatcher ကို အမည်ဖြင့် ခေါ်ယူ၍ တာဝန်လွှဲ ခိုင်းစေခြင်း
        getServletContext().getNamedDispatcher("ToInclude").forward(req, resp);

    }

ဤ Servlet အတွင်းတွင် HttpServletRequest#setAttribute ကို အသုံးပြု၍ လက်ဆင့်ကမ်းလိုသော အချက်အလက်များကို သတ်မှတ်နေပါသည်။ နောက်ဆုံးတွင် getServletContext ဖြစ် ServletContext ကို ခေါ်ယူပြီး၊ ServletContext#getNamedDispatcher ဖြင့် ToBeInclude ၏ RequestDispatcher ကို ခေါ်ယူပါသည်။ ရရှိလာသော RequestDispatcher မှတဆင့် forward လုပ်လိုက်ခြင်းအားဖြင့် ToBeInclude ကို အလုပ်လက်ဆင့်ကမ်းလိုက်ခြင်းဖြစ်သည်။


အထက်ပါအတိုင်း setAttribute ဖြင့် လက်ဆင့်ကမ်းလိုက်သော အချက်အလက်များကို ToBeInclude ထဲမှ ခေါ်ယူနိုင်ကြောင်းကို တွေ့မြင်နိုင်မည် ဖြစ်သည်။ forward ကို အသုံးပြုရာတွင် include ကို အသုံးပြုစဉ်ကကဲ့သို့ javax.servlet.include အချက်အလက်များ မပါဝင်သည်ကို သတိပြုမိမည် ဖြစ်သည်။

ဤအခန်းတွင် include နှင့် forward ကို အသုံးပြု၍ Servlet တစ်ခုနှင့်တစ်ခု ဆက်သွယ်ပြီး အလုပ်လုပ်နိုင်ပုံနှင့် Servlet တစ်ခုနှင့် တစ်ခုအကြား အချက်အလက်များကို လက်ဆင့်ကမ်းလိုသည့်အခါများတွင် setAttribute, getAttribute နှင့် getAttributeNames လုပ်ဆောင်ချက်များကို အသုံးပြုနိုင်ပုံတို့ကို လေ့လာခဲ့ပါသည်။


Error Page များကို အသုံးပြုခြင်း

နောက်ဆုံးတွင် Java EE Web Application များတွင် Error Page များကိုအသုံးပြုပုံကို ဖော်ပြပါမည်။ Error Page ဆိုသည်မှာ HTTP Error သို့မဟုတ် Servlet Container အတွင်း Exception များဖြစ်ပေါ်သောအခါ ဖော်ပြပေးမည့် Web စာမျက်နှာများဖြစ်ပါသည်။ Java EE Application များတွင် Application အတွင်း၌ အမှားများပေါ်ပေါက်သောအခါမျိုးတွင် သင့်တော်သလို စာများနှာများကို ဖော်ပြပေးနိုင်ရန် Error Page များကို အသုံးပြု၍ စီစဉ်ထားနိုင်ပါသည်။

Application အတွင်းတွင် အမှားအဖြစ် သတ်မှတ်မှတ်လိုသောအခါ forward ကို အသုံးပြု၍ Error Page များကို လမ်းညွှန်နိုင်သလို၊ Exception အဖြစ် Throw လုပ်ပြီး၊ သတ်မှတ်ထားသော Error Page များကို ဖော်ပြနိုင်ပါသည်။ Error Page များ၏ သတ်မှတ်ချက်ကို web.xml တွင် ရေးသားရပေမည်။

web.xml
  <error-page>
    <error-code>404</error-code>
    <location>/error/error.html</location>
  </error-page>
  <error-page>
    <exception-type>java.lang.Exception</exception-type>
    <location>/error/error.html</location>
  </error-page>

အထက်ပါအတိုင်း error-page tag အတွင်းတွင် Error Page ၏ သတ်မှတ်ချက်ကို ရေးသားရပါမည်။ HTML Error Code များကို သတ်မှတ်ရေးသားလိုပါက error-code tag အတွင်းတွင် ဖြစ်ပွားနိုင်သော error code ကို ရေးသားပြီး၊ ထို error code ဖြစ်ပေါ်ပါက ဖော်ပြပေးရမည့် စာမျက်နှာကို location အတွင်းတွင် ဖော်ပြရပါမည်။ ဤကဲ့သို့ရေးသားထားပါက HTML Error 404 ဖြစ်ပေါ်ပါက /error/error.html စာမျက်နှာကို ဖော်ပြပေးမည်ဖြစ်သည်။

ထို့နည်းတူ Java Exception များကိုလည်း exception-type တွင်သတ်မှတ်နိုင်ပါသည်။ ဤကဲ့သို့ Exception အမျိုးမျိုးကို သင့်တော်ရာ Error Page များကို ဖော်ပြပေးခြင်းအားဖြင့် အသုံးပြုသူကို သင့်တော်မည့် လမ်းညွှန်မှု့များကို ပေးနိုင်မည်ဖြစ်သည်။



အထက်ပါအတိုင်း Application အတွင်းတွင်မရှိသော HTML စာမျက်နှာကို Request လုပ်ကြည့်သောအခါ ပြင်ဆင်ထားသော အမှားစာမျက်နှာကို ဖော်ပြပေးနိုင်မည်ဖြစ်သည်။

Application များတွင် အမှားမှာ မကင်းပေ။ အကြောင်းအမျိုးမျိုးကြောင့် အမှားဆိုသည်မှာ ပေါ်ပေါက်လာနိုင်ပါသည်။ အမှားတစ်ခုပေါ်ပေါက်လာပါက ရှေ့ဘာဆက်လုပ်ရမှန်းမသိသော Application များသည် Application ကောင်းဟု မသတ်မှတ်နိုင်ပေ။ နောက်ဆုံးအခါမျိုးအထိ အသုံးပြုသူကို မျက်စေ့မလယ်စေအောင် လမ်းညွှန်ပေးနိုင်သော Application မျိုးကို Application ကောင်းဟု သတ်မှတ်နိုင်မည် ဖြစ်သည်။

လက်တွေ့စမ်းသပ်ရန်
http://mmitp-servlet-tutorial.appspot.com/


ကိုးကား
http://download.oracle.com/javaee/5/api/javax/servlet/http/HttpServ...
http://download.oracle.com/javaee/5/api/javax/servlet/ServletContex...
http://download.oracle.com/javaee/5/api/javax/servlet/RequestDispat...
http://legacy.techscore.com/tech/J2EE/Servlet/5.html


လေးစားစွာဖြင့်
မင်းလွင်

No comments:

Post a Comment