Gson Sample


Gson 기능 중 Object, List 를 Json 형태로 변환해주는 기능이 있다.


public String getJson (List sampleList) {
    return gson.toJson(sampleList, ArrayList.class);
}


위와 같은 코드를 작성 하면 쉽게 처리가 가능 하다.


Spring MVC Sample


@RequestMapping(value="/sampleJson", method=RequestMethod.GET, produces="text/plain;charset=UTF-8")
public @ResponseBody String sampleJson(HttpServletRequest request, HttpServletResponse response) throws Exception {
    try {
        ModelAndView mav = new ModelAndView();
        mav.setViewName("sample.list");

        return this.gson.toJson(sampleService.selectList(), ArrayList.class);
    } catch (Exception e) {
        throw e;
    }
}


위 소스를 참고 하면 Json String 으로 변환 하여 응답 한다. Encoding 문제로 한글이 물음표로 께지는 현상이 있다.


produces="text/plain;charset=UTF-8"


@RequestMapping 에 해당 값을 추가 하자. 한글이 정상적으로 출력 될 것이다.




Web Application 개발 시 SpringFramework(http://spring.io/) 을 주로 사용하고 있다. 


개발 시 공통으로 필요한 Util 을 개발 하여 사용하지만, 기존에 개발되어 있는 좋은 라이브러리가 이미 존재 한다. 

SpringFramework 에서 org.springframework.util package 에서 제공하는 class 이다. 



3.2.0 RELEASE 기준 javadoc 문서 이다. SpringFramework 기능도 위 유틸을 사용하고 있고, 검증도 되어 있기 때문에 사용하는 경우 개발 시간도 단축하고 안정성도 올라간다고 판단 된다.


SpringFramework 3.2.0 RELEASE API 주소: http://docs.spring.io/spring/docs/3.2.0.RELEASE/javadoc-api/

API 를 참조 하면 제공되는 class의 정보를 활용할 수 있다.


참고 사이트

 ※ Logo Image: http://fr.wikipedia.org/wiki/Fichier:Spring_framework.png

 ※ SpringFramework: http://spring.io/

 ※ SpringFramework 3.2.0 RELEASE API: http://docs.spring.io/spring/docs/3.2.0.RELEASE/javadoc-api/



WEB 개발을 JAVA 로 하는 경우 SpringFramework 를 많이 사용 하고 있다.


※ 공식 사이트: http://spring.io/


가장 많이 사용하게 되고, 빠질 수 없는 DispatcherServlet 의 구조에 대해 알아보자



위 그림은 Spring MVC 의 전체 흐름도 이다. 중요하게 봐야 할 부분은 HandlerExceptionResolver 이다. 



  • HandlerExceptionResolver
    • DispatcherServlet 에 셋팅을 했을 경우 모든 Exception 을 위임 받아 해당 페이지로 이동 한다.

dispatcher-servlet.xml (Spring 2.5 기준)
<bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
    <property name="order" value="1" />
    <property name="exceptionMappings">
        <props>
            <prop key="Exception">error</prop>
        </props>
    </property>
</bean>

HandlerExceptionResolver 에 해당되는 Class 이다. 위에서 설명 한대로 exceptionMappings 에 예외 Class와, 이동할 Page를 설정 한다.

Annotation 지원은 Spring 3.0 이상 부터 된다고 한다. 


SampleController.java

@RequestMapping(value="sample", method=RequestMethod.GET)
public ModelAndView sample(String sample) throws Exception {
    
    ModelAndView mav = new ModelAndView("sample");
    
    try {
        
        // ... logic
        
        return mav;
    } catch(Exception e) {
        e.printStackTrace();
        throw e;
    } 
}

Exception 모두 던질 경우 trace를 할 수 없기 때문에 중요한 부분은 위와 같이 trace 를 하는 부분이 좋다고 생각 한다.


dispatcher-servlet 셋팅 후 아래와 같이 예외를 위임 하는 경우 에러 페이지로 이동하는 것을 확인 할 수 있다.


※ 참고 사이트

  - https://code.google.com/p/developerhaus/wiki/SpringException

  - http://www.cnblogs.com/fangwenyu/archive/2012/10/11/2716665.html




[projectName]-servlet.xml 파일에 추가 하도록 하자.


Resolve 1.  모든 요청에 따른 Interceptor 적용


<!-- Interceptor -->

<bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping">

<property name="interceptors">

<list>

<ref bean="kr.co.whitelife.WhitelifeInterceptor"/>

<ref bean="kr.co.whitelife.BlacklifeInterceptor"/>

</list>

</property>

</bean>



모든 요청에 대한 응답을 해주는 DefaultAnnotationHandlerMapping을 이용 한다. 다 수의 Interceptor를 순차적으로 적용이 가능하다.


Resolve 2.  일부 요청에 따른 Interceptor 적용


<!-- Interceptor -->

<bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">

<property name="mappings">

<props>

<prop key="/test">WhitelifeController</prop>

</props>

</property>

<property name="interceptors">

<ref bean="WhitelifeInterceptor"/>

</property>

</bean>



RequestUri에 따른 Controller 분기가 가능한 SimpleUrlHandlerMapping을 이용 했다. Resolve 1 방법과 같은 방법으로 Interceptor을 적용이 가능하다.


Resolve 3.  mvc 태그를 이용 하는 방법


<mvc:interceptors>

<bean class="kr.co.whitelife.WhitelifeInterceptor"/>

<bean class="kr.co.whitelife.Blacklifenterceptor"/>

<mvc:interceptor>

<mvc:mapping path="/test/*"/>

<bean class="kr.co.whitelife.WhitelifeInterceptor"/>

</mvc:interceptor>

</mvc:interceptors>



Spring 3.x 버전 이후로는 mvc 전용 태그를 지원 한다. 2~3번째 줄에 있는 부분은 Resolve 1 방법, 4~7번째 줄에 있는 부분은 Resolve 2 방법과 같다. 


Interceptor Class Sample


/**

 * Sample Interceptor

 * @author whitelife

 * @since 2013-01-31

 */

@Controller("TestInterceptor")

public class TestInterceptor extends HandlerInterceptorAdapter {


@Override

public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {

System.out.println("TestInterceptor{preHandle}............................................ start");

return true;

}


@Override

public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {

System.out.println("TestInterceptor{postHandle}............................................ end");

}

}




Interceptor도 Controller과 마찬가지로 RequestUri에 따라 분기를 하기 때문에 Controller과 같은 동작을 한다. @Controller도 적용이 가능하다.





Spring 으로 테스트를 하고 싶을 때 Junit4 실행 시 설정 파일을 못 찾는 경우가 발생 할 수도 있다. 그럴 경우 아래와 같이 수정하고 시도 해보도록 하자.



import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"classpath:applicationContext.xml", "file:WebContent/WEB-INF/config/ibatis.properties"})
public class ATest {

    @Test
    public void aTest() {
       
        System.out.println("hello...");
       
    }
   
}



"file:WebContent/WEB-INF/config/ibatis.properties" 과 같은 형태로 추가를 하면 파일을 인식 한다.


'Spring' 카테고리의 다른 글

Spring DispatcherServelt HandlerExceptionResolver 적용하기  (0) 2014.04.30
Spring Web MVC Interceptor 적용 하기  (0) 2013.01.31
Spring DI(Denpendency Injection)  (0) 2012.11.11
Spring Ioc  (0) 2012.11.11
Spring InitBinder  (0) 2012.11.07

 앞의 글에서 Ioc에 대하여 알아 보고, DI(Denpendency Injection), DL(Denpendency Lookup) 에 대하여 간략하게 알아보았다. 이번에는 DI(Denpendency Injection) 을 상세하게 알아보도록 한다.

 DI(Denpendency Injection) 는 크게 3가지로 볼 수 있다. 아래의 그림을 보도록 하자.

 



 

 Spring Ioc 글에서 사용했던 예제를 활용 한다. 아래의 표는 Annotation 기반의 @Autowired 기준으로만 설명 한다. @Autowired는 선언을 한 경우, Constructor, Method에 Instance를 주입 한다. 찾지 못한 경우 예외를 발생 시킨다.

  구분

  설명 

 Setter Injection

 

 @Autowired
 public void setService(Wservice service) {
  this.service = service;
 }

 Setter Method에 직접 선언을 하였다. Container는 Instance를 생성 할 때 @Autowired 가 Setter Method에 선언이 되어 있을 경우, Parameter로 있는 Object(Wservice) 를 target으로 주입하게 된다.

 

 Constructor Injection

 

 @Autowired
 public Wcontroller(Wservice wservice) {
  // TODO Auto-generated constructor stub
  this.service = wservice;
 } 

 Constructor에 직접 선언을 하였다. Container는 Instance를 생성 할 때 @Autowired 가 Constructor에 선언이 되어 있을 경우, Parameter로 있는 Object (Wservice) 를 target으로 주입하게 된다.

 

 Method Injection

 

 Setter Injection과 동일 하다고 볼 수 있다. 결국엔 Setter도 Method에 포함 되기 때문이다.

 

 위의 표를 보고 코드를 변경하여 실행을 하면 같은 결과를 확인 해볼 수 있을 것이다.

 실제로 ApplicationContext Container에 적용을 할 경우에는 2가지 방법으로 적용을 할 수가 있다.

  • XML

  • Annotation

 XML의 경우에는 Container의 Config 파일에 직접 명시를 하는 것이고, Annotation의 경우에는 Java 코드에 직접 명시를 하는 경우이다. 지금 까지 예제로 작성 했던 모든 부분 및 Spring Ioc 글에서 설명 했던 예제는 Annotation 기반 이였다. 예제 코드를 작성하기도 쉽고, 간단했기 때문이다. 이번에는 XML로 설명 하겠다.

 

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
 xmlns:aop="http://www.springframework.org/schema/aop"
 xmlns:tx="http://www.springframework.org/schema/tx"
 xmlns:context="http://www.springframework.org/schema/context"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
    http://www.springframework.org/schema/aop
    http://www.springframework.org/schema/aop/spring-aop-3.1.xsd
    http://www.springframework.org/schema/tx
    http://www.springframework.org/schema/tx/spring-tx-3.1.xsd
    http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context-3.1.xsd">

 <bean class="kr.whitelife.controller.Wcontroller">
  <constructor-arg ref="service"/>
 </bean>

 
 <bean id="service" class="kr.whitelife.service.Wservice">
  <property name="dao" ref="dao"></property>
 </bean>
 
 <bean id="dao" class="kr.whitelife.dao.Wdao"/>
 
</beans>

 

 위의 XML을 보도록 하자.  Container의 Config 파일인 ApplicationContext.xml 이다. Spring Ioc 글에서 사용 하였던 Class를 설정 하는 부분이다. Class의 설정 태그는 <bean .../> 을 이용 한다. 많이 사용하는 속성은 아래의 표를 보도록 하자.

  속성

  설명 

  constructor-arg

  Class 전체 Package 명 작성 및 bean Id

  property

  Class 전체 Package 명 작성 및 bean Id

 Constructor Injection은 <constructor-arg .../> 을 이용한다. Instance가 생성 되는 시점에서 Container에게 해당 Instance를 참조 하겠다 라고, 전해주지 않을 경우 Constructor가 참조하는 Instance를 찾을 수 없기 때문에 동작 할 수 없다. Setter Injection, Method Injection의 경우에는 <property .../> 를 이용 한다.  Constructor Injection 설명과 마찬가지로 Container에게 참조할 Instance를 전해주지 않는 경우 동작 할 수 없다.

 XML 기반으로 작성 할 경우에는 3가지의 Injection 중 어떤 기법을 사용할지 잘 판단 하고, 작성 하도록 한다. 실행 할 경우 예외가 발생한다고 해서 당황하지 말자. 예외를 잘 읽어보면 Container 에게 정보 전달을 확실하게 하지 않았기 때문에 일어나는 경우가 대부분이다.

 

public class XapplicationContext {
 
 public static void main(String[] args) {
  
  ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
  Wcontroller wcontroller = applicationContext.getBean(Wcontroller.class);
  wcontroller.showMsg();
  
 }
 
}

 

 Spring Ioc 글에서 사용했던 예제는 Annotation 기반의 Container를 작성 했었다. 이번에는 XML 기반의 Contatiner를 작성 해보았다. 위의 코드를 실행 해보자.

 

Wcontroller.showMsg....
Wservice.showMsg....
Wdao.showMsg....

 

 XML 설정을 확실하게 했다면, 위와 같은 결과를 얻을 수 있을 것이다. Container가 예외를 발생 시킬 경우 Container의 Config 파일인 ApplicationContext.xml을 다시 확인 하도록 하자.

 드디어 간략하게 DI(Denpendency Injection)을 XML, Annotation 기반으로 체험을 해보았다. 상세한 설정이나 고급적인 DI를 할 필요성이 있을 경우 [Spring IN ACTION / 크레이그 월즈 지음], [Spring Recipes / 게리 막 다니엘 루비오, 조시 롱 지음] 등 을 참고 하도록 하자.

 

 Spring의 Ioc에 대하여 설명 한다.

 본 글에 들어가기에 앞서 http://www.springsource.org/download/community 에서 Spring 3.x.x 이상을 다운 받고 라이브러리에 추가 하도록 한다.

 Java라는 언어를 이용하면서 new 라는 키워드를 자주 이용 한다. 이와 같은 행위는 Instance 를 생성 하는 것 이다.

 

public class Wcontroller{
 Wservice service = new Wservice();
 ....
}

public class Wservice {
 Wdao dao = new Wdao();
  ....
}

public class Wdao {
  ....
}

 

 위 Sample을 보도록 하자. Wcontroller Class는 Wservice Instance를 가지고 있고, Wservice Class는 Wdao Instance를 가지고 있다. 이런 경우는 서로 강하게 의존을 하고 있는 Code라고 볼 수 있다.

 Instance는 서로 의존(Dependency) 하는 모습을 보여주고 있다. 이런 상황의 경우에는 "의존 관계의 제어권은 개발자가 가지고 있다." 라고 말할 수 있다. Instance에 대한 LifeCycle을 개발자가 직접 관리하게 된다. 제어권을 Container에게 넘겨주는 행위를 제어권의 역전 Ioc(Inversion Of Control) 이라고 한다. 여기서 말하는 Container는 SpringFramework의 ApplicationContext 라고 봐도 된다.

 

 

 위 그림을 보도록 하자. Ioc(Inversion Of Control) 은 두 종류로 분리가 된다. 개발자가 Container 에게 제어권을 위임하게 되면 new 를 Container가 대신 한다. 첫 번째의 경우 DI(Denpendency Injection)은 Container가 직접 주입해주는 경우 이다. 개발자는 Object 선언만 하고 Container가 Instance를 주입하게 되는데, 첫번째 방법에서 많이 이용한다. 하지만 멀티 쓰레드 환경에서 Instance를 이용할 경우는 서로의 간섭이 없어야 하기 때문에,  두 번째 방법 DL(Denpendency Lookup)을 이용한다. Contaciner가 Instance를 가지고 있고, 개발자는 Instance를 직접 참조하여 이용 하는 방법 이다.  

 

@Controller
public class Wcontroller {
 
 @Autowired
 Wservice service;

 
 public void showMsg() {
  System.out.println("Wcontroller.showMsg....");
  service.showMsg();
 }
 
}

@Service
public class Wservice {
 
 @Autowired
 Wdao dao = new Wdao();
 

 public void showMsg() {
  System.out.println("Wservice.showMsg....");
  dao.showMsg();
 }
 
}

@Repository
public class Wdao {
 
 public void showMsg() {
  System.out.println("Wdao.showMsg....");
 }
 
}

 

위 Sample를 보도록 하자. Annotation으로 작성 되었고, Spring Web 환경에서 사용한다. 제일 위에 있던 Sample 과 달리 new 라는 키워드가 사라진 점을 발견할 수 있다. 개발자가 직접 Instance를 관리하지 않는다. @Autowired는 DI(Denpendency Injection)을 해주는 기준이라고 보면 된다. 여기서 끝이 아니다. 위와 같이 작성만 했다고 해서 동작하지는 않는다. Container에 대한 작업을 해야 한다.

 

public class WapplicationContext {
 
 public static void main(String[] args) {
  
  AnnotationConfigApplicationContext annotationConfigApplicationContext
  = new AnnotationConfigApplicationContext();
  
  annotationConfigApplicationContext.register(Wdao.class);
  annotationConfigApplicationContext.register(Wservice.class);
  annotationConfigApplicationContext.register(Wcontroller.class);
  
  annotationConfigApplicationContext.refresh();
  
  Wcontroller wcontroller = annotationConfigApplicationContext.getBean(Wcontroller.class);
  
  wcontroller.showMsg();
  
 }
 

 

 위 Sample를 보도록 하자. 쉽게 이해를 돕기 위하여 코드 기준으로 작성 하였다. Container는 Wdao, Wservice, Wcontroller Class를 등록함 으로써, 각각 Instance 들을 가지고 있다. getBean(Wcontroller.class)는 DL(Denpendency Lookup)을 해주는 기준이라고 보면 된다.

 

Wcontroller.showMsg....
Wservice.showMsg....
Wdao.showMsg....

 

 실행 할 경우 위와 같은 메시지가 출력 된다. 정상적으로 DI(Denpendency Injection), DL(Denpendency Lookup)이 된 것을 확인 할 수 있다.

 실제로 사용할 경우에는 SpringFramework의 AppcationContext Instance가 위의 역활을 대신해 줄 것이다. XML로 설정을 하게 된다.

 Spring을 사용하여 개발을 할 경우, Ioc에 대해서는 꼭 기억 하고 있도록 하자. DI(Denpendency Injection)에 대한 자세한 내용은 다음 글을 참고 하도록 한다.

 Spring Web 환경에서는 기존 Servlet을 이용했을 때의 상황과는 달리, Java의 reflection 기법을 이용하여 parameter 들을 POJO 기반의 Class로 setter 주입을 하여 제공을 하게 된다.

 기본 자료형 변수들이 setter 될때 Type이 일치 하지 않는 경우, 예외가 발생하게 된다. 이런 상황을 방지하기 위하여 initBinder라는 애노테이션을 이용하게 된다.

 

 @InitBinder
public void initBinder(WebDataBinder binder) throws Exception {
    SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy. MM. dd.");

    binder.registerCustomEditor(Date.class, new CustomDateEditor(simpleDateFormat, true));
}

 

Controller 코드 중 일부 이다. Spring은 initBinder라는 애노테이션을 제공 한다. POJO 객체로 setter 하기 전에 해당 애노테이션이 있는 경우 참고를 하게 된다. 위 샘플 코드는 Date Type이 불일치 하는경우를 해결하기 위하여 작성 되었다.

 Spring의 Web parameter 제공은 좋은 기술이지만, 단점으로 Type 불일치가 존재 한다. 앞으로 이런 상황이 발생할 경우 위의 애노테이션을 활용 하자.

+ Recent posts