August 5, 2012

Custom Tag (Part 2)

အပလီကေးရှင်းကောင်းတစ်ခု အတွက် ပရိုဂရမ်မာက ဒီဇိုင်းရေး၊ ဒီဇိုင်းနာကလော့ဂျစ်ရေး နေလို့ကတော့ ကောင်းမွန်သောအပလီကေးရှင်းများ ဖြစ်မြောက်ရန်မှာခက်ခဲလှပေသည်။ ထို့အတွက် အားလုံးကို လောဘကြီးခြင်းမရှိပဲ ထူးချွံသည့်အပိုင်းအား ထူးချွံသူကို တာဝန်ပေးပြီး အကောင်းဆုံး အပလီကေးရှင်းကို တည်ဆောက်သင့်ပေသည်။ Custom Tag များကို အသုံးပြုခြင်းသည် View နှင့် လော့ဂျစ်အားခွဲထုတ်ရာတွင် လွန်စွာမှ သင့်တော်လှသော နည်းလမ်း တစ်ခု ဖြစ်ပါသည်။

Presentation အပိုင်းတွင် လော့ဂျစ်များအား အသုံးပြုလိုပါက ပရိုဂရမ်မာက Custom Tag များအား ရေးသားပြီး၊ ဒီဇိုင်းနာက လော့ဂျစ်များအား မထိခိုက်စေပဲ ဂရုစိုက်စရာမလိုပဲ HTML စာမျက်နှာများအား ရေးသားစေနိုင်ပါသည်။ ထိုဒီဇိုင်းစာမျက်နှာများအား Auto Generator များအား အသုံးပြုကာ JSP စာမျက်နှာအား ပြုလုပ်ခြင်းအားဖြင့် View ဒီဇိုင်းနှင့် လော့ဂျစ်အပိုင်းကို ခွဲခြားရေးသားနိုင်ပါသည်။

ပြီးခဲ့သော အခန်းဖြင့် Custom Tag များကို ကိုယ်တိုင်ရေး၍ JSP စာမျက်နှာများ တွင် အသုံးပြုနိုင်ကြောင်းကို ဖော်ပြခဲ့၏။ ယခုတစ်ခေါက်တွင်လည်း ဆက်လက်၍ Custon Tag ရေးသားပုံကို ဖော်ပြသွားပါဦးမည်။


IterationTag

လုပ်ဆောင်ချက်များအား အကြိမ်ကြိမ် လုပ်ဆောင်စေရာတွင် အသုံးပြုနိုင်သည်မှာ IterationTag အင်တာဖေစ် ပင်ဖြစ်၏။ IterationTag အင်တာဖေစ် အော့ဘဂျက်၏ Life Cycle မှာ အောက်ပါအတိုင်း ဖြစ်ပါသည်။


ပြီးခဲ့တဲ့ တစ်ခေါက်က ရေးသားခဲ့သော Tag အင်တာဖေစ်နှင့်ကွာခြားသည်မှာ doAfterBody လုပ်ဆောင်ချက်ဖြစ်၏။ Tag အင်တာဖေစ်တွင် Body အပိုင်းကို ဖော်ပြပြီးတဲ့နောက်မှာ doEndTag ကို ဆက်လက် လုပ်ဆောင်စေပါသည်။ သို့ရာတွင် IterationTag တွင် Body အပိုင်းကို ဖော်ပြပြီးပါက doAfterBody ကို ခေါ်ဆိုမည် ဖြစ်၏။ တဖန် doAfterBody ၏ ရလဒ်သည် EVAL_BODY_AGAIN ဖြစ်ပါက ထပ်မံ Body အပိုင်းကို ဖော်ပြမည် ဖြစ်ပါသည်။ doAfterBody ၏ ရလဒ်သည် SKIP_BODY ဖြစ်ပါမှ Body အပိုင်းကို ဆက်မဖော်ပြတော့ပဲ doEndTag ကို ခေါ်ဆိုမည် ဖြစ်ပါသည်။ Message တစ်ခုကို အကြိမ်ကြိမ် ဖော်ပြပေးသည့် နမှုနာတစ်ခုကို ရေးသားကြည့်ပါမည်။

EchoTag.java
apackage com.mmju.jsp.ep8;

import java.io.IOException;

import javax.servlet.jsp.JspException;
import javax.servlet.jsp.PageContext;
import javax.servlet.jsp.tagext.IterationTag;
import javax.servlet.jsp.tagext.Tag;

public class EchoTag implements IterationTag {
 
 private PageContext ctx = null;
 private Tag parent = null;
 private String message = null;
 private Integer times = null;
 private Integer var = 0;

 @Override
 public int doEndTag() throws JspException {
  this.out("</table>");
  return EVAL_PAGE;
 }

 @Override
 public int doStartTag() throws JspException {
  this.out("<table><tr><td>");
  return EVAL_BODY_INCLUDE;
 }

 @Override
 public Tag getParent() {
  return this.parent;
 }

 @Override
 public void release() {
 }

 @Override
 public void setPageContext(PageContext arg0) {
  this.ctx = arg0;
 }

 @Override
 public void setParent(Tag arg0) {
  this.parent = arg0;
 }

 @Override
 public int doAfterBody() throws JspException {
  var++;
  out("</td>");
  out("<td>");
  out(message);
  out("</td>");
  out("</tr>");
  if(var < times) {
   out("<tr>");
   out("<td>");
   return EVAL_BODY_AGAIN;
  }
  return SKIP_BODY;
 }

 public String getMessage() {
  return message;
     }

 public void setMessage(String message) {
  this.message = message;
 }

 public Integer getTimes() {
  return times;
 }

 public void setTimes(Integer times) {
  this.times = times;
 }
 
 private void out(String str) {
  try {
   this.ctx.getOut().println(str);
  } catch (IOException e) {
   e.printStackTrace();
  }
 }

}

doStartTag လုပ်ဆောင်ချက်အတွင်းတွင် Table Tag ၏ အဖွင့်ကို ဖော်ပြပြီးရလဒ်အဖြစ် EVAL_BODY_INCLUDE ကို ပြန်ပေးစေပါသည်။ ထို့ကြောင့် Body အပိုင်းကို ဖော်ပြပြီး၊ doAfterBody ကို ခေါ်ဆိုမည် ဖြစ်သည်။ အတွင်းပိုင်းတွင် var သည် အလုပ်လုပ်ခဲ့သည့် အကြိမ်ဖြစ်ပြီး တစ်တိုးပါမည်။ ပြီးပါက TR အပိုင်းနှင့် Message ကို ဖော်ပြပါမည်။

ပြီးပါက ဆက်လက်၍ လက်ရှိအကြိမ် (var) သည် အလုပ်လုပ်ရမည့်အကြိမ် (times)ထက်ငယ်ပါက TR ၏ အဖွင့် Tag ကို ဖော်ပြပြီး၊ EVAL_BODY_AGAIN ကို return လုပ်မည် ဖြစ်ပါသည်။ သို့မဟုတ်ပါက SKIP_BODY ကို return လုပ်မည် ဖြစ်ပါသည်။

episode8.tld
  <tag>
    <name>echo</name>
    <tag-class>com.mmju.jsp.ep8.EchoTag</tag-class>
    <body-content>JSP</body-content>
    <attribute>
        <name>message</name>
        <required>true</required>
        <rtexprvalue>true</rtexprvalue>
        <type>String</type>
    </attribute>
    <attribute>
        <name>times</name>
        <required>true</required>
        <rtexprvalue>true</rtexprvalue>
        <type>Integer</type>
    </attribute>
  </tag>
အထက်တွင် ရေးသားခဲ့သော Tag Handler Class အား Custom Tag အဖြစ်အသုံးပြုနိုင်ရန် TLD အား ရေးသားရန် လိုအပ်ပါသည်။ TLD အတွင်းတွင် echo အမည်ဖြင့် Tag အားသတ်မှတ်ရေးသားပြီး၊ Attribute အနေဖြင့် message နှင့် times အားအသုံးပြုရန် သတ်မှတ်ရေးသားပါသည်။ ပြီးပါက နောက်ဆုံးတွင် JSP အတွင်းမှ ခေါ်ယူ အသုံးပြုရုံသာဖြစ်၏။

echo.jsp
<%@ page language="java" contentType="text/html; charset=utf-8"
    pageEncoding="utf-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<%@ taglib uri='http://java.sun.com/jsp/jstl/core' prefix='c'%>
<%@ taglib uri="/WEB-INF/tld/episode8.tld"  prefix="ep8"%>
<title>Insert title here</title>
</head>
<body>
 <c:import url="/jsp/header.jsp"></c:import>
 <div style="width: 100%; text-align: right">
     <a href="javascript:history.back();">ယခင် စာမျက်နှာသို့</a>
 </div>
<h3>8.1 Iterator Tag</h3>
<div>
<ep8:echo message="Hello" times="4">Message : </ep8:echo>
</div>
<br/>
<div>
IterationTag အား အသုံးပြုသော Custom Tag တစ်ခု၏ နမှုနာတစ်ခုဖြစ်ပါသည်။<br/>
message နှင့် times အား Attribute အနေဖြင့် ရယူပြီး၊ ရယူထားသော message အား times အကြိမ် ဖော်ပြစေပါသည်။<br/>
Attribute အနေဖြင့် List များကို ရယူပြီး၊ List အတွင်းမှ အချက်အလက်များအား တစ်ခုချင်း ဖော်ပြရာတွင် အသုံးဝင်ပါသည်။<br/>
</div>
</body>
</html>
ဤ နေရာတွင် အထက်ပါ custom tag echo အား အသုံးပြုထားသည်မှာ စာကြောင်း ၁၈ တွင် ဖြစ်၏။ message အား Hello ဖြင့် times အား 4 ဟု သတ်မှတ်ရေးသားထားပါသည်။ အထက်ပါ JSP အား စမ်းသပ်ကြည့်သော အခါ အောက်ပါအတိုင်း တွေ့မြင်ရမည် ဖြစ်ပါသည်။




TagSupport

ပြီးခဲ့သော အခန်းတွင် Tag ဖြင့်၎င်း၊ ယခုတစ်ခေါက် IterationTag ဖြင့်၎င်း အင်တာဖေစ်အား အသုံးပြုကာ Tag Handler ကလပ်စ်များအား ရေးသားခဲ့ပြီဖြစ်သည်။ doStartTag, doAfterBody နှင့် doEndTag များသည်သာ Tag ရေးသူက လက်တွေ့ ရေးသားရန် လိုအပ်သော အပိုင်းများ ဖြစ်၏။ မလိုအပ်ပဲ အများကြီး ရေးနေရသည်ဟု ခံစားရမည် ဖြစ်၏။ ထိုအခါမျိုးအတွက် ပြင်ဆင်လာသည်မှာ TagSupport ကလပ်စ်ပင် ဖြစ်၏။

TagSupport ကလပ်စ်သည် Tagအင်တာဖေစ်အား ပံ့ပိုးထားသော အခြေခံ ကလပ်စ် တစ်ခုဖြစ်ပါသည်။ Tag Handler ကလပ်စ်ကို ရေးသားလိုသူသည် TagSupport အား Extends လုပ်ကာ ရေးသားလိုသည့် လုပ်ဆောင်ချက်ကိုသာ Override လုပ်ရုံဖြစ်၏။ ယခင် Tag အင်တာဖေစ် အား Implement လုပ်တုန်းကလို Tag ၏ လုပ်ဆောင်ချက်များ အားလုံးအား Override လုပ်ရန် မလိုအပ်ပေ။ ကျွှန်တော်တို့ အထက်ပါ နမှုနာအား TagSupport အား Extends လုပ်ပြီး ရေးကြည့်ပါဦးမည်။

EchoTagSupport.java
apackage com.mmju.jsp.ep8;

import java.io.IOException;

import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.TagSupport;

public class EchoTagSupport extends TagSupport {

 private static final long serialVersionUID = -8556986664817835060L;

 private String message = null;
 private Integer times = null;
 private Integer var = 0;
 
 public void setMessage(String message) {
  this.message = message;
 }
 public void setTimes(Integer times) {
  this.times = times;
 }
 
 @Override
 public int doAfterBody() throws JspException {
  var++;
  out("</td>");
  out("<td>");
  out(message);
  out("</td>");
  out("</tr>");
  if(var < times) {
   out("<tr>");
   out("<td>");
   return EVAL_BODY_AGAIN;
  }
  return SKIP_BODY;
 }
 @Override
 public int doEndTag() throws JspException {
  this.out("</table>");
  return EVAL_PAGE;
 }

 @Override
 public int doStartTag() throws JspException {
  this.out("<table><tr><td>");
  return EVAL_BODY_INCLUDE;
 }
 
 private void out(String str) {
  try {
   super.pageContext.getOut().println(str);
  } catch (IOException e) {
   e.printStackTrace();
  }
 }


}
EchoTag အားရေးသားထားသည်နှင့် အတူတူ ရေးသားထားခြင်း ဖြစ်သည်။ ကိုယ်တိုင်အသုံးပြုလိုသည့် private လုပ်ဆောင်ချက်အချို့၊ Attribute များအတွက် setter လုပ်ဆောင်ချက်နှင့်၊ doStartTag, doAfterBody နှင့် doEndTag အား Override လုပ်ရန်သာ လိုအပ်ပါသည်။ EchoTag နှင့် စာလျှင် များစွာ ရေးရလွယ်ပြီး ရှင်းလင်းသွားသည်ကိုတွေ့ရပါလိမ့်မည်။

သို့ရာတွင်စစချင်း TagSupport မှ စ၍ ရေးသားမည် ဆိုပါက ကောင်းကောင်းနားမလည်ပဲ၊ ဘယ်လုပ်ဆောင်ချက်ကို ဘကြောင့် Override လုပ်သင့်သည်ကို နားလည်ရ ခက်ခဲပေလိမ့်မည်။ Tag အင်တာဖေစ် ၏ လုပ်ဆောင်ချက် များအား ကြည့်ပြီး Servlet Container နှင့် Application တို့တွင် မည်ကဲ့သို့ ပူးပေါင်းဆောင်ရွက်ကြသည်ကို နားလည်လာလိမ့်မည် ဖြစ်ပါသည်။


BodyTag နှင့် BodyTagSupport

ကျွှန်တော်တို့ အထက်တွင် အသုံးပြုခဲ့သော Tag နှင့် IterationTag များသည် Body အပိုင်းအား ဝင်ရောက် လုပ်ဆောင်ခဲ့ခြင်း မရှိပေ။ အစပိုင်း အဆုံးပိုင်းကိုသာ လုပ်ဆောင်ပြီး၊ Body အပိုင်းအား JSP ကွန်တိန်နာ မှ ဖော်ပြပြီးနောက်တွင် လုပ်ဆောင်ချက်များအား လုပ်ဆောင်စေခဲ့၏။ Body အပိုင်းအား ဝင်ရောက် လုပ်ဆောင်နိုင်စေရန် BodyTag အင်တာဖေစ် အား သီးခြား ပြင်ဆင်ထားပါသည်။ BodyTag အား ပံ့ပိုးထားသော အခြေခံ ကလပ်စ်မှာ BodyTagSupport ကလပ်စ် ဖြစ်ပါသည်။


doStartTag ၏ ရလဒ်တွင် EVAL_BODY_BUFFERED ကို အသစ်ဖြည့်စွက်ပြီး၊ အဆိုပါ ရလဒ်ဆိုပါက setBodyContext နှင့် doInitBody အား လုပ်ဆောင်စေပြီးမှ Body အပိုင်းကို Evaluate လုပ်မည် ဖြစ်ပါသည်။ ဤနည်းအားဖြင့် bodyContext အော့ဘဂျက်အား ခေါ်ယူ အသုံးပြုနိုင်မည် ဖြစ်ပါသည်။


လေ့ကျင့်ခန်း

အထက်တွင် အသုံးပြုခဲ့သော Echo Message ပရိုဂရမ်အား BodyTagSupport ကလပ်စ်အား Extends လုပ်၍ ပြုပြင် ရေးသားပါ။

အဖြေ
https://github.com/minlwin/mmju/blob/master/jsp-tutorials/src/com/mmju/jsp/ep8/EchoBodyTagSupport.java


ကိုးကား
http://www.techscore.com/tech/Java/JavaEE/JSP/7/
http://www.techscore.com/tech/Java/JavaEE/JSP/8/

Project Source
https://github.com/minlwin/mmju/tree/master/jsp-tutorials

နမှုနာ အပလီကေးရှင်းများ
http://jsp-tutorials.minlwin.cloudbees.net/

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

No comments:

Post a Comment