본문 바로가기

Dev.BackEnd/Servlet&JSP

#미니 MVC FrameWork 만들기 세번째 단계, 프런트 컨트롤러 자동화

미니 MVC Framework 만들기 세번째 단계,

리플랙션 API를 이용하여 프런트 컨트롤러를 자동화 하자.

문제점 착안,
프런트 컨트롤러에서 VO 객체를 생성하는 부분이 상당히 지저분하다.
각 요청에 따른 Member 객체를 생성해야하기 때문이다.
나중에 요청이 개수가 더 많아질 경우에, 그에 맞는 VO를 또 생성하는 코드를 작성하는 것은
유지보수성을 떨어뜨린다.


해결방안,
DataBinding을 이용하자.
getBinder라는 메소드를 선언하는 DataBinding Interface를 만들고,
각각의 페이지 컨트롤러들이 DataBinding Interface를 구현한다.
페이지 컨트롤러는 이 getBinder라는 메소드를 통해 
프런트 컨트롤러에게 요청에 필요한 DataName과 DataType을 전달한다.

구체화,
프런트 컨트롤러에서는 요청에 맞는 Data를 준비하기 위한 메소드를 구현한다.
prepareRequestData(req, model, (DataBinding)pageController)
그리고 요청에 맞는 VO를 생성하기 위한 bind 메소드를 구현하기 위해
ServletRequestDataBinder 클래스를 생성한다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public static Object bind(ServletRequest req, Class<?> dataType, String dataName) throws Exception{
  if(isPrimitiveType(dataType)){
    return createValueObject(dataType, req.getParameter(dataName));
  }
  Set<String> paramNames = req.getParameterMap().keySet();
  Object dataObject = dataType.newInstance();
  Method method = null;
  
  for(String paramName : paramNames){
    method = findSetter(dataType, paramName);
    if(method != null){
      method.invoke(dataObject, createValueObject(method.getParameterTypes()[0],
          req.getParameter(paramName)));
      
    }
  }
  return dataObject;
}
cs
이 클래스에서는 .bind(req, dataName, dataType)를 통해 필요한 DataName과 DataType을 분석한다.
code>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
private static boolean isPrimitiveType(Class<?> type) {
  if(type.getName().equals("int"|| type == Integer.class ||
    type.getName().equals("long"|| type == Long.class ||
    type.getName().equals("float"|| type == Float.class ||
    type.getName().equals("double"|| type == Double.class ||
    type.getName().equals("boolean"|| type == Boolean.class ||
    type == Data.class || type == String.class){
    return true;
  }
  return false;
}
 
private static Object createValueObject(Class<?> type, String value) {
  if(type.getName().equals("int"|| type == Integer.class){
    return new Integer(value);
  } else if(type.getName().equals("long"|| type == Long.class){
    return new Float(value);
  } else if(type.getName().equals("float"|| type == Float.class){
    return new Double(value);
  } else if(type.getName().equals("double"|| type == Double.class){
    return new Long(value);
  } else if(type.getName().equals("boolean"|| type == Boolean.class){
    return new Boolean(value);
  } else if(type == Data.class){
    return java.sql.Date.valueOf(value);
  } else {
    return value;
  }
}
cs

원시 타입 Data이면 바로 생성을 하고, 
그게 아니면 dataType에 맞는 인스턴스를 생성한다.
그리고나서, 프런트 컨트롤러는 ServletRequestDataBinder에서 생성한 인스턴스를
페이지 컨트롤러에게 전달하기 위해 Map에 넣어둔다..
1
2
3
4
5
6
7
8
9
10
11
12
13
14
private void prepareRequestData(HttpServletRequest req, HashMap<String, Object> model, DataBinding dataBinding) throws Exception {
  Object[] dataBinders = dataBinding.getDataBinders();
  
  String dataName = null;
  Class<?> dataType = null;
  Object dataObj = null;
  
  for (int i = 0; i < dataBinders.length; i+=2) {
    dataName = (String)dataBinders[i];
    dataType = (Class<?>)dataBinders[i+1];
    dataObj = ServletRequestDataBinder.bind(req, dataType, dataName);
    model.put(dataName, dataObj);
  }
}
cs


End