본문 바로가기

Java/[Servlet/JSP]

factory 패턴 예제


1. 현행 시스템의 문제점

 

다른 부분은 무시하고 색깔 있는 부분만 보자 

 

현재는 factory 패턴으로 서블릿으로 넘어온 커멘드를 처리하고 있다.

 

 

--------------------UserServlet.java ------------------------------------------

 

package sdwa.src.user.servlet;

 

import java.io.IOException;

import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

 

import sdwa.src.common.action.Action;
import sdwa.src.common.action.ActionForward;

import sdwa.src.user.servlet.UserActionFactory;

 

 

 

public class UserServlet extends HttpServlet {

 

 public void doGet(HttpServletRequest request, HttpServletResponse response)
  throws ServletException, IOException {
  doPost(request, response);
 }

 

 public void doPost(HttpServletRequest request, HttpServletResponse response)
 throws ServletException, IOException {
  
 ActionForward forward = null;
 Action action = null;
  
 try {


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

 

  UserActionFactory saf = UserActionFactory.getInstance();
  action = saf.getAction(command);

 

  forward = action.execute(request, response);


 } catch (Exception e) {
  throw new ServletException(e.getMessage());
 }

 

 /* Action에 의해서 전달된 User, List객체들이 response객체를 통하여 전달된다. */
 if (forward.isRedirect()) {
  response.sendRedirect(forward.getPath());
 } else {
  RequestDispatcher rd = request.getRequestDispatcher(forward.getPath());
  rd.forward(request, response);
 }
}
}

 

------------------------------------------------------------------------------------

 

UserActionFactory class 를 살펴보자~

 

------------------- UserActionFactory.java ---------------------------------------

 

package sdwa.src.user.servlet;

 

import sdwa.src.common.action.IllegalCommandException;
import sdwa.src.common.action.Action;

import sdwa.src.user.action.*;

 

 

public class UserActionFactory {

 

 public static UserActionFactory getInstance() {
  return new UserActionFactory();
 }


 public Action getAction(String command) throws IllegalCommandException {
  Action action = null;

 

  if ("LoginForm".equals(command)) {
   action = new LoginFormAction();
  }else if ("LoginCheck".equals(command)) {
   action = new LoginAction();
  }else if ("Logout".equals(command)) {
   action = new LogoutAction();
  }else if ("GoFindSchoolId".equals(command)) {
   action = new GoFindSchoolIdAction();
  }else if ("GoFindSchoolPw".equals(command)) {
   action = new GoFindSchoolPwAction();
  }else if ("FindSchoolId".equals(command)) {
   action = new FindSchoolIdAction();
  }else if ("FindSchoolPw".equals(command)) {
   action = new FindSchoolPwAction();
  }else{
   throw new IllegalCommandException("");
  }
  
  return action;
 }
}

 

------------------------------------------------------------------

 

 

문제점은 무엇일까?

 

1. if, else로 이어지는 분기문 

-> 효율성 문제, FindSchoolPw 커멘드를 처리하려면 상위의 if else 비교를 다 하고서야 도달한다.


 

2. 리로딩문제 

-> 추가적인 커멘드 추가시 리 컴파일 해야하는 문제가 발생한다.

 

 

 

 

2. 해결방법

 

해결방법은 일단 커멘트와 객체를 매핑하는 부분을 프로퍼티 파일로 따로 분리하여 동적으로 클래스를 로딩하도록 하였다

 

팩토리 클래스는 없다.

 

--------------------UserServlet.java ------------------------------------------

 

package sdwa.src.user.servlet;

 

import java.io.IOException;

import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

 

import sdwa.src.common.action.Action;
import sdwa.src.common.action.ActionForward;

import sdwa.src.common.servlet.ServletMap;;

 

 

 

public class UserServlet extends HttpServlet {

 

 public void doGet(HttpServletRequest request, HttpServletResponse response)
  throws ServletException, IOException {
  doPost(request, response);
 }

 

 public void doPost(HttpServletRequest request, HttpServletResponse response)
 throws ServletException, IOException {
  
 ActionForward forward = null;
 Action action = null;
  
 try {

 

   //command - action mapping
   String command  = request.getParameter("command");
   action   = ServletMap.getInstance().getAction("user", command);
   
   forward = action.execute(request, response, reqBox);



 } catch (Exception e) {
  throw new ServletException(e.getMessage());
 }

 

 /* Action에 의해서 전달된 User, List객체들이 response객체를 통하여 전달된다. */
 if (forward.isRedirect()) {
  response.sendRedirect(forward.getPath());
 } else {
  RequestDispatcher rd = request.getRequestDispatcher(forward.getPath());
  rd.forward(request, response);
 }
}
}

 

------------------------------------------------------------------------------------

 

ServletMap 을 살펴보자

 

--------------------ServletMap.java ------------------------------------------
 

package sdwa.src.common.servlet;

 

import java.io.File;
import java.io.FileInputStream;

 

import sdwa.src.common.log.LogCommand;
import sdwa.src.common.action.Action;

 

public class ServletMap {
 
 private static ServletMap instance;
 
 protected static Object lock = new Object();

 

 

//java.util.Properties 관련 게시물 확인해 볼것!
 protected static java.util.Properties props = null; 
 
 //property dir location - 프로퍼티 파일 절대 경로
 private static final String property_dir  = "D:\\src\\WEB-INF\\classes\\src\\conf\\";


 //property servlet file location - 프로퍼티 파일 명
 private static final String property_ServletMap = "servlet.properties";
 
 //real-time update values - 파일 수정 시간을 비교하여 변경시 파일을 다시 읽어온다.
 private static long ServletMap_last_modified = 0;
 private static long last_modified     = 0;
 

 private ServletMap() throws Exception {
  initialize();
 }
 
 public static ServletMap getInstance() throws Exception{
  if(instance == null){
   instance = new ServletMap();
  }
  
  return instance;
 }
 
 protected void initialize() throws Exception{
  synchronized(lock){
   try{

    //파일을 다시 읽을 것인지 아닌지 판단
    boolean needUpdate  = false;
    
    //read property_init
    File ServletMap_file = new File( property_dir+property_ServletMap );
    
    if ( !ServletMap_file.canRead() )
     throw new Exception( 
       this.getClass().getName() + " - Can't open Servlet.properties : " 
       + property_ServletMap 
     );
    if ( (ServletMap_last_modified != ServletMap_file.lastModified()) || props == null ){
     needUpdate = true;
    }
    
    //reload property file
    if ( needUpdate ){
     props = new java.util.Properties();
     
     FileInputStream ServletMap_fin = new FileInputStream( ServletMap_file );
     

    //java.util.Properties 관련 게시물 확인해 볼것!
     props.load( new java.io.BufferedInputStream( ServletMap_fin ) );
     ServletMap_fin.close();
     
     ServletMap_last_modified  = ServletMap_file.lastModified();
     
     last_modified = System.currentTimeMillis();
    } // end if
   }catch( Exception ex ){
    ex.printStackTrace();
    LogCommand.getInstance("error",ex);
    throw new Exception( this.getClass().getName() + " - Can't open properties: " + ex.getMessage() );
   }
  } // end of sunchronized(lock);
 }

 public java.util.Properties getProperties(){
  return props;
 }
 
 public long lastModified(){
  return this.last_modified;
 }
 
 /**
  * 시스템 환경설정 config 파일(servlet.properties)의 설정값을 String type 으로 리턴한다.
  * 
  * @param key
  *            servlet.properties 의 각 옵션별 설정명
  * @return String value 를 반환한다.
  */
 public String getProperty(String key)
 {
  String value = null;
  try
  {
   String tmp = props.getProperty( key );
   if ( tmp == null )
    throw new Exception( "value of key(\"" + key + "\")  is null" );
   value = kfda.src.common.util.StringUtil.korEncode( tmp );
  }
  catch( Exception ex )
  {
   LogCommand.getInstance("error",ex);
   throw new IllegalArgumentException( "Illegal String Key : " + key );
  }
  return value;
 }
 
 /**
  * servlet command 를 받아서 action을 반환한다.
  * @param key
  * @return
  */
 public Action getAction(String servletName, String command)
 {
  Action  action = null;
  String key  = "";
  
  try{
   key  = servletName+"."+command;
   
   //STEP01 command로 class 이름을 가져온다.
   //STEP02 class 이름으로 Class를 생성한다. 


   Class roadClass = Class.forName(this.getProperty(key));
   
   //STEP03 Object 생성
   Object obj  = roadClass.newInstance();
 

  //STEP04 Action 으로 형변환
   action   = (Action)obj; 
   
  }catch( Exception ex ){
   LogCommand.getInstance("error",ex);
  }
  
  return action;
 }


}


 

 

----------------------------------------------------------------------------------

 

마지막으로  servlet.properties 프로퍼티 파일을 보자

 

---------------------------- servlet.properties  -------------------------

user.LoginCheck=sdwa.src.user.action.LoginAction
user.Logout=sdwa.src.user.action.LogoutAction

 

Meal.SchoolInfo=sdwa.src.Meal.action.MealInfoAction

---------------------------------------------------------------------------------

 

[서블릿구분자].[커멘트]=로드할 클래스명


출처 : http://cafe.naver.com/junes81.cafe