본문 바로가기

WEB_Programming/Ajax

Ajax in Struts: select 박스를 이용한 Ajax구현

Ajax in Struts: implementing dependent select boxes

이 포스팅에서는, Struts 애플리케이션에서 AJAX의 이용 방법에 대해서 설명한다.

내 현재 프로젝트에서 스트러츠 기반의 웹 애플리케이션을 많은 입력 폼과 함께 개발했다. 이러한 폼에서는 2개 혹은 이상의 html select box를 포함하고 있다. 이 의미는, 2개의 의존성있는 박스를 만들며, 가능한 옵션에 대해서 두번재 선택박스가 첫번째 선택박스내와 관련있는 내용을 보여주는 애플리케이션을 개발할때 다음과 같은 3개의 가능한 해법이 존재한다.

  • 자바 스크립트의 array를 이용하여 첫번째 셀렉트 박스에 대해서 두번째에 세팅하는 방법
  • 첫번째 셀렉트 박스에서 onchange 를 선택했을 때 자동적으로 폼을 서버에 submit하여 새로운 옵션 집합에 해당하는 내용을 다시 화면에 그려주는 것으로 전체 페이지를 갱신하는 것이다.
  • Ajax를 비동기적으로 사용하고 새로운 옵션들을 두번째 select 박스에 설정하는 방법

첫번째 옵션은 우리가 원하는 사항이 아니다. : 그것은 html-page내에서 많은 로직을 구현해야한다는 의미이다. 이것은 자바스크립트 코드를 해독하는데 매우 어렵게 만든다. 두번재 옵션은 더 낫다. 그러나 새로운 옵션을 위해 서버에 완전히 갔다 오는 방식에는 많은 단점이 있다. 이것은 단지 두번재 선택 박스를 위해서 전체 페이지를 위해서 그려야 한다는 의미가 된다.

선택박스를 해결하기 위해서, AJAX를 사용하기로 결정할 것이다.

스트러츠는 아직 AJAX를 지원하지 않기 때문에, 우리가 직접 추가해야한다. 왜냐하면 AJAX는 프레임워크가 아니다. 그러나 Javascript와 DHTML을 이용하여 웹 페이지를 더욱 동적으로 만들 수 있는 기술이다. 이것은 스트러츠와 매우 쉽게 연동된다.

첫번째로 작은 html 폼을 만들것이다.
...
<tr>
  <td><label for="first"><bean:message key="nl.company.first"/></label></td>
  <td>
    <!--On change the function retrieveSecondOptions() is called to populate the second box -->
    <html:select property="first" onchange="retrieveSecondOptions()" styleId="firstBox" styleClass="mandatory">
      <html:options collection="firstOptions" property="value" labelProperty="label"/>
    </html:select>   
  </td>
</tr>
<tr>
  <td><label for="second"><bean:message key="nl.company.second"/></label></td>
  <td>
    <html:select property="second" styleId="secondBox" styleClass="mandatory">
      <html:option value="nothing">-First choose above-</html:option>
    </html:select>
   
  </td>
</tr>
...

이제 java script 파트를 구현할 것이다.

<
script lang="javascript">
var req;
/*
  * Get the second options by calling a Struts action
  */
function retrieveSecondOptions(){
   
   
firstBox =document.getElementById('firstBox');
   
   
//Nothing selected
   
if(firstBox.selectedIndex==0){
     
return;
   
}
   
selectedOption =firstBox.options[firstBox.selectedIndex].value;
   
//get the (form based) params to push up as part of the get request
   
url="retrieveSecondOptionsAjaxAction.do?selectedOption="+selectedOption;
 
   
//Do the Ajax call
   
if(window.XMLHttpRequest){// Non-IE browsers
     
req =newXMLHttpRequest();
     
//A call-back function is define so the browser knows which function to call after the server gives a reponse back
     
req.onreadystatechange =populateSecondBox;
     
try{
     
req.open("GET",url,true);//was get
     
}catch(e) {
       
alert("Cannot connect to server);
      }
      req.send(null);
    } else if (window.ActiveXObject) { // IE     
      req = new ActiveXObject(
"Microsoft.XMLHTTP");
      if (req) {
        req.onreadystatechange = populateSecondBox;
        req.open(
"GET", url, true);
        req.send();
      }
    }
  }
 
  //Callback function
  function populateSecondBox(){
  document.getElementById('secondBox').options.length = 0;

    if (req.readyState == 4) { // Complete
      if (req.status == 200) { // OK response
         textToSplit = req.responseText
         if(textToSplit == '803'){
alert(
"No select option available on the server")
}
          //Split the document
          returnElements=textToSplit.split(
"||")
         
          //Process each of the elements
          for ( var i=0; i<returnelements .length; i++ ){
             valueLabelPair = returnElements[i].split(
"|")
             document.getElementById('secondBox').options[i] = new Option(valueLabelPair[0], valueLabelPair[1]);
          }
        }
      } else { 
            alert(
"Bad response by the server");
        }   
    }
    }
</script>

마지막으로 우리는 Struts Action을 구현한다.

package
nl.company.action;

importorg.apache.log4j.Logger;

importorg.apache.struts.action.Action;
importorg.apache.struts.action.ActionError;
importorg.apache.struts.action.ActionErrors;
importorg.apache.struts.action.ActionForm;
importorg.apache.struts.action.ActionForward;
importorg.apache.struts.action.ActionMapping;

importnl.company.*

importjava.io.*

importjava.util.List;

importjavax.servlet.ServletException;
importjavax.servlet.http.HttpServletRequest;
importjavax.servlet.http.HttpServletResponse;


public classRetrieveSecondOptionsAjaxActionextendsAction
 
{
   
/**
     * This is the main action called from the Struts framework.
     *
@parammapping The ActionMapping used to select this instance.
     *
@paramform The optional ActionForm bean for this request.
     *
@paramrequest The HTTP Request we are processing.
     *
@paramresponse The HTTP Response we are processing.
     *
@throwsjavax.servlet.ServletException
     *
@throwsjava.io.IOException
     *
@return
   
*/
   
publicActionForward execute(ActionMapping mapping,ActionForm form,
       
HttpServletRequest request,HttpServletResponse response)
       
throwsIOException,ServletException
     
{
       
Logger logger =Logger.getLogger(getClass());
       
logger.info(
           
"==========================================================");
       
logger.info("Starting in RetrieveSecondOptionsAjaxAction");

       
String optionSelected =request.getParameter("optionSelected");

       
//Check of het soortId wel correct is
       
if(ValidationSupport.isEmptyString(selectedOption))
          {
           
logger.debug("No selected option supplied");

           
PrintWriter out =response.getWriter();
           
out.print("803");
         
}
       
else
         
{
           
List options =getSecondOptions(selectedOption);
           
//Make a String representation where each option is seperated by '||' and a valua and a label by ';'
           
String outLine =makeOutputString(options);
           
out.print(outLine);    
         
}
      }
     
return null;
 
}

보는바와 같이 Struts에서 AJAX를 이용하는것은 매우 단순한 작업이다. 웹 페이지를 오직 업데이트를 위해서 서버에 갔다 와야하는 경우 매우 큰 이점을 준다. 그러하기 때문에 AJAX는 서버의 자원을 비동기적으로 호출하여 더 거시적인 작업을 할 수 있도록 해준다.