'Language/JSP'에 해당되는 글 49건

  1. 2012.10.31 Spring MVC
  2. 2012.10.31 MyBatis-Spring
  3. 2012.10.29 tiles :: 2.2.2 버전 web.xml 설정 세 가지 방법
  4. 2012.10.23 struts2 튜토리얼
  5. 2012.10.23 태그라이브러리 URI
  6. 2012.10.12 [centOS] apache2.2 + tomcat6 (yum 설치 성공 통합 정리)
  7. 2012.10.11 CentOS(64Bit)에 yum을 이용하여 Apache+Tomcat+JSP 연동
  8. 2012.10.11 Apache+Tomcat 연동
  9. 2012.10.10 [CentOS] 6.2에 아파치 + 톰캣6 연동하기 2

Spring MVC

Language/JSP 2012. 10. 31. 15:56

Spring MVC

비록, Spring이 스트러츠를 비롯하여 다양한 웹 프레임워크와 비교적 잘 연동되는 편이긴 하지만, 서로 다른 두 프레임워크를 연동하기 위해서는 설정의 중복 등 개발 과정에서 불편함이 존재한다. 서로 잘 맞지 않는 단추를 억지로 끼워 맞추는 것 같다.

Spring 자체적으로 제공하는 MVC 프레임워크를 사용하면, Spring이 제공하는 AOP, 트랜잭션 처리, DI 등의 기능을 그대로 사용하면서 MVC 패턴에 기반하여 웹 어플리케이션을 개발할 수 있다. 또한, 스트러츠와 Spring을 연동하기 위해 설정의 중복과 같은 개발 과정상의 불편을 해소할 수도 있다.

본 글에서는 Spring MVC의 구성에 대해서 살펴보고, 실제로 Spring MVC를 사용하여 웹 어플리케이션을 개발하는 기본적인 방법을 살펴보도록 하겠다. 그외 Spring MVC를 이용한 웹 어플리케이션에 대해 좀더 자세한 내용이 알고 싶다면 http://www.springframework.org/documentation 사이트를 참고하기 바란다.

Spring MVC의 구성 및 실행 흐름

다른 MVC 기반의 프레임워크와 마찬가지로 Spring MVC도 컨트롤러를 사용하여 클라이언트의 요청을 처리하게 된다. 이 컨트롤러의 역할을 하는 것이 DispatcherServlet인데, DispatcherServlet을 비롯하여 Spring MVC의 주요 구성 요소는 표 1과 같다.

구성 요소설명
DispatcherServlet클라이언트의 요청을 전달받는다. Controller에게 클라이언트의 요청을 전달하고, Controller가 리턴한 결과값을 View에 전달하여 알맞은 응답을 생성하도록 한다.
HandlerMapping클라이언트의 요청 URL을 어떤 Controller가 처리할지를 결정한다.
Controller클라이언트의 요청을 처리한 뒤, 그 결과를 DispatcherServlet에 알려준다. 스트러츠의 Action과 동일한 역할을 수행한다.
ViewResolverCommander의 처리 결과를 보여줄 View를 결정한다.
ViewCommander의 처리 결과를 보여줄 응답을 생성한다.

이들 주요 구성 요소간의 메시지 흐름은 그림 1과 같다.


각 흐름을 좀더 자세하게 설명하면 다음과 같다.

  1. 클라이언트의 요청이 DispatcherServlet에 전달된다.
  2. DispatcherServlet은 HandlerMapping을 사용하여 클라이언트의 요청이 전달될 Controller 객체를 구한다.
  3. DispatcherServlet은 Controller 객체의 handleRequest() 메소드를 호출하여 클라이언트의 요청을 처리한다.
  4. Controller.handleRequest() 메소드는 처리 결과 정보를 담은 ModelAndView 객체를 리턴한다.
  5. DispatcherServlet은 ViewResolver로부터 처리 결과를 보여줄 View를 구한다
  6. View는 클라이언트에 전송할 응답을 생성한다.
여기서 개발자가 직접 개발해주어야 하는 부분은 클라이언트의 요청을 처리할 Commander 클래스와 클라이언트에 응답 결과 화면을 전송할 JSP나 Velocity 템플릿 등의 View 코드이다. 나머지, DispatcherServlet이나 HandlerMapping, ViewResolver 등은 Spring이 제공하는 기본 구현체를 사용하면 된다.

Spring MVC를 이용한 웹 어플리케이션 개발

Spring MVC를 이용하여 웹 어플리케이션을 개발하는 과정은 다음과 같다.

  1. 클라이언트의 요청을 받을 DispatcherServlet을 web.xml 파일에 설정한다.
  2. 요청 URL과 Controller의 매핑 방식을 설정한다.
  3. Controller의 처리 결과를 어떤 View로 보여줄 지의 여부를 결정하는 ViewResolver를 설정한다.
  4. Controller를 작성한다.
  5. 뷰 영역의 코드를 작성한다.
DispatcherServlet 설정 및 Spring 콘텍스트 설정

Spring MVC를 사용하기 위해서는 가장 먼저 web.xml 파일에 DispatcherServlet 설정을 추가해주어야 한다. DispatcherServlet은 서블릿 클래스로서 다음과 같이 서블릿 설정 및 서블릿 매핑 설정을 web.xml 파일에 추가해주면 된다.

<?xml version="1.0" ?>

<web-app version="2.4"
    xmlns="http://java.sun.com/xml/ns/j2ee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
                        http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
    <servlet>
        <servlet-name>example</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>
    
    <servlet-mapping>
        <servlet-name>example</servlet-name>
        <url-pattern>*.do</url-pattern>
    </servlet-mapping>
</web-app>

위 설정은 모든 *.do로 들어오는 요청을 DispatcherServlet이 처리하도록 하고 있다.

DispatcherServlet은 설정 파일에서 지정한 서블릿 이름을 사용하여 Spring 설정 파일을 로딩한다. 예를 들어, 위 코드의 경우 DispatcherServlet의 이름이 "example"인데, 이 경우 사용되는 Spring 설정 파일은 'WEB-INF/example-servlet.xml' 이다.

만약 기본적으로 사용되는 Spring 콘텍스트 설정 파일이 아닌 다른 이름의 파일을 사용하고 싶다면 다음과 같이 contextConfigLocation 초기화 파라미터에 사용할 설정 파일의 목록을 지정해주면 된다.

    <servlet>
        <servlet-name>multipleConfig</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>
                /WEB-INF/mvc1.xml,
                /WEB-INF/mvc2.xml
            </param-value>
        </init-param>
        <load-on-startup>3</load-on-startup>
    </servlet>

이때 각 설정 파일은 콤마를 사용하여 구분한다. 만약 각 설정 파일에서 동일한 이름의 빈을 지정했다면 더 뒤에 위치한 설정 파일에 명시된 빈이 우선순위를 갖는다.

HandlerMapping 설정

클라이언트의 요청을 Spring의 DispatcherServlet이 처리하도록 설정했다면, 다음으로 해야 할 작업은 어떤 HandlerMapping을 사용할지의 여부를 지정하는 것이다. HandlerMapping은 클라이언트의 요청을 어떤 Commender가 수행할 지의 여부를 결정해주는데, 표 2와 같이 두 개의 구현체가 주로 사용된다.

구현체설명
BeanNameUrlHandlerMapping요청 URI와 동일한 이름을 가진 Controller 빈을 매핑한다.
SimpleUrlHandlerMappingAnt 스타일의 경로 매핑 방식을 사용하여 URI와 Controller 빈을 매핑한다.

BeanNameUrlHandlerMapping

BeanNameUrlHandlerMapping은 요청 URI와 동일한 이름을 갖는 Controller 빈으로 하여금 클라이언트의 요청을 처리하도록 한다. 예를 들어, http://some.com/hello.do 와 같은 요청 URL에 대해 "/hello.do" 라는 이름을 가진 Controller 빈이 해당 요청을 처리하도록 한다. 아래 코드는 BeanNameUrlHandlerMapping를 사용하는 경우의 Spring 설정 파일의 예를 보여주고 있다.

<?xml version="1.0" encoding="UTF-8" ?>

<beans xmlns="http://www.springframework.org/schema/beans"
    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.xsd">
    
    <bean id="beanNameUrlMapping" 
        class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping" />
    
    <bean name="/hello.do"
        class="net.daum.ts.techReport.report2.springmvc.HelloController" />
    
    <bean name="/login.do"
        class="net.daum.ts.techReport.report2.springmvc.LoginController" />
    
    <bean id="viewResolver"
        class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/view/" />
        <property name="suffix" value=".jsp" />
    </bean>
</beans>

만약 요청 URL이 http://some.com/login.do 였다면, 이름이 "/login.do"인 LoginController가 해당 요청을 처리하게 된다. 비슷한 이유로, http://some.com/hello.do 요청은 HelloController가 처리하게 된다.

HandlerMapping 빈을 따로 생성하지 않은 경우 DispatcherServlet은 기본적으로 HandlerMapping의 구현체로 BeanNameUrlHandlerMapping을 사용한다. 따라서, 위 코드에서 HandlerMapping과 관련된 설정은 생략할 수 있다.

SimpleUrlHandlerMapping

SimpleUrlHandlerMapping은 Ant 스타일의 매핑 방식을 사용하여 Controller를 매칭한다. 아래 코드는 SimpelUrlHandlerMapping을 사용하여 클라이언트의 요청 URL과 매핑될 Controller를 지정하는 예를 보여주고 있다.

<?xml version="1.0" encoding="UTF-8" ?>

<beans xmlns="http://www.springframework.org/schema/beans"
    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.xsd">
    
    <bean id="beanNameUrlMapping" 
        class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
        <property name="mappings">
            <value>
                /content/*.html=contentController
                /**/help.html=helpController
            </value>
        </property>
    </bean>
    
    <bean name="contentController" 
        class="net.daum.ts.techReport.report2.springmvc.ContentController" />
    
    <bean name="helpController" 
        class="net.daum.ts.techReport.report2.springmvc.HelpController" />
    
    <bean id="viewResolver" 
        class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/view/" />
        <property name="suffix" value=".jsp" />
    </bean>
</beans>

SimpleUrlHandlerMapping은 mappings 프로퍼티를 통해서 매핑 설정 목록을 입력받는다. 이때 설정의 이름은 Ant 스타일의 URL 경로를 의미하며, 값은 매핑될 Controller 빈의 이름을 의미한다. 예를 들어, 위 예제의 경우 http://some.com/content/1.html 이나 http://some.com/content/mvc.html 요청이 들어오면 contentController가 처리하도록 매핑하였다.

SimpleUrlHandlerMapping에서 사용되는 규칙은 다음과 같다.

  • ? - 한 글자에 매칭된다.
  • * - 0 개 이상의 글자에 매칭된다.
  • ** - 0개 이상의 디렉토리에 매칭된다.
아래는 org.springframework.util.AntPathMatcher API 문서에 예시로 나온 몇 가지 매핑 설정의 예이다.

  • com/t?st.jsp - com/test.jsp, com/tast.jsp 또는 com/txst.jsp 등에 매칭된다.
  • com/*.jsp - com 디렉토리에 있는 모든 .jsp에 매칭된다.
  • com/**/test.jsp - com 경로 아래에 위치한 모든 test.jsp와 매칭된다.
  • org/springframework/**/*.jsp - org/springframework 경로 아래에 위치한 모든 jsp와 매칭된다.
두 HandlerMapping 구현체의 공통 프로퍼티

앞서 살펴본 두 HandlerMapping 구현 클래스는 AbstractUrlHandlerMapping 클래스를 상속받고 있으며, AbstractUrlHandlerMapping 클래스는 AbstractHandlerMapping 클래스를 상속받고 있다. 이 두 클래스는 공통으로 사용되는 몇 가지 프로퍼티를 제공하고 있는데, 먼저 AbstractHandlerMapping 클래스는 다음과 같은 프로퍼티를 제공하고 있다.

프로퍼티설명
interceptors사용할 인터셉터의 목록
defaultHandler매칭되는 핸들러를 찾지 못할 때 사용할 기본 핸들러
order하나의 서블릿 콘텍스트에서 다수의 HandlerMapping을 사용할 수 있는데, 이 경우 HandlerMapping 간의 우선순위를 지정한다.

AbstractUrlHandlerMapping 클래스가 제공하는 프로퍼티 목록은 표 4와 같다.

프로퍼티설명
alwaysUseFullPath웹 어플리케이션 콘텍스트의 경로를 포함할 지의 여부를 결정한다. 예를 들어, 콘텍스트 경로가 /main 일때, http://some.com/main/a.html 에 대해, 이 값이 true면 /main/a.html 이 사용된다. 이 값이 false이면 /a.html이 사용된다. 기본값은 false이다.
urlDecodeHandlerMapping에 요청 URL을 전달하기 전에 특정 인코딩을 사용해서 디코딩할지의 여부를 결정한다. 이 값을 true로 지정하면 요청에 명시된 인코딩이나 ISO-8859-1을 사용하여 디코딩한다. 기본값은 false이다.
lazyInitHandlers싱글톤 타입의 핸들러에 대해 lazy initialization을 적용할지의 여부를 지정한다. 기본 값은 false이다.

ViewResolver 설정

HandlerMapping을 설정했다면, 이제 ViewResolver를 설정할 차례이다. ViewResolver는 Controller의 실행 결과를 어떤 뷰를 보여줄지의 여부를 결정하는 기능을 제공한다. 주로 사용되는 ViewResolver에는 다음의 두 가지가 존재한다.

  • InternalResourceViewResolver - JSP를 사용하여 뷰를 생성한다.
  • VelocityViewResolver - Velocity 템플릿 엔진을 사용하여 뷰를 생성한다.
InternalResourceViewResolver

InternalResourceViewResolver는 JSP를 사용하여 Commander의 결과 뷰를 생성할 때 사용된다. 아래 코드는 InternalResourceViewResolver의 설정 예를 보여주고 있다.

<?xml version="1.0" encoding="UTF-8" ?>

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:aop="http://www.springframework.org/schema/aop"
    xmlns:tx="http://www.springframework.org/schema/tx"
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans 
        http://www.springframework.org/schema/beans/spring-beans.xsd">
    
    <bean id="beanNameUrlMapping"
        class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping" />
    
    <bean name="/hello.do"
        class="net.daum.ts.techReport.report2.springmvc.HelloController" />

    <bean id="viewResolver"
        class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/view/" />
        <property name="suffix" value=".jsp" />
    </bean>
</beans>

InternalResourceViewResolver는 다음과 같이 두 개의 프로퍼티를 입력받는다.

  • prefix - Controller가 리턴한 뷰 이름 앞에 붙을 접두어
  • suffix - Controller가 리턴한 뷰 이름 뒤에 붙을 확장자
예를 들어, HelloController가 처리 결과를 보여줄 뷰의 이름으로 "hello"를 리턴했다고 하자. 이 경우 InternalResourceViewResolver에 의해 사용되는 뷰는 "/view/hello.jsp"가 된다. 따라서, /view/hello.jsp가 생성한 응답 결과 화면이 클라이언트에 전달된다.

VelocityViewResolver

VelocityViewResolver는 Velocity 템플릿을 사용하여 뷰를 생성할 때 사용된다. 아래 코드는 VelocityViewResolver의 설정 예를 보여주고 있다.

<?xml version="1.0" encoding="UTF-8" ?>

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:aop="http://www.springframework.org/schema/aop"
    xmlns:tx="http://www.springframework.org/schema/tx"
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans 
        http://www.springframework.org/schema/beans/spring-beans.xsd">
    
    <bean name="/hello.mul"
        class="net.daum.ts.techReport.report2.springmvc.HelloController" />
    
    <bean id="velocityConfig" 
        class="org.springframework.web.servlet.view.velocity.VelocityConfigurer">
        <property name="resourceLoaderPath" value="/view_vm/" />
        <property name="velocityProperties">
            <value>
                input.encoding=UTF-8
                output.encoding=UTF-8
            </value>
        </property>
    </bean>
    
    <bean id="viewResolver"
        class="org.springframework.web.servlet.view.velocity.VelocityViewResolver">
        <property name="contentType" value="text/html; charset=UTF-8" />
        <property name="cache" value="true" />
        <property name="prefix" value="" />
        <property name="suffix" value=".vm" />
    </bean>
</beans>

VelocityViewResolver를 사용하기 위해서는 먼저 Velocity의 설정 정보를 관리해주는 VelocityConfigurer를 생성해주어야 한다. VelocityConfigurer에서 사용가능한 주요 프로퍼티는 다음과 같다.

  • resourceLoaderPath - Velocity 템플릿이 위치하는 경로 (웹 콘텍스트 루트 기준)
  • velocityProperties - Velocity 설정 프로퍼티
예를 들어, 위 코드의 경우는 웹 어플리케이션 루트에 위치한 /view_vm/ 디렉토리에 Velocity 템플릿 파일이 위치한다는 것을 의미한다.

VelocityViewResolver를 설정할 때에는 다음의 프로퍼티를 알맞게 지정해준다.

  • contentType - 응답의 컨텐트 타입을 지정한다.
  • prefix - InternalResourceViewResolver와 동일
  • suffix - InternalResourceViewResolver와 동일
위 설정의 경우, Controller가 선택한 뷰가 "hello"라고 한다면 /view_vm/hello.vm 파일이 템플릿으로 선택된다. 또한 생성되는 뷰의 컨텐트 타입은 "text/html" 이고 캐릭터셋은 UTF-8이 된다.

Controller 구현

지금까지는 환경 설정과 관련된 부분에 대해서 설명했는데, 이제 본격적으로 클라이언트의 요청을 처리하는 데 사용되는 Controller의 구현에 대해서 살펴보도록 하자. Controller를 구현하는 가장 간단한 방법은 Controller 인터페이스를 implements 하는 것이다. 하지만, Controller 인터페이스를 직접적 implements 하기 보다는, Controller 인터페이스를 implements 하고 몇 가지 추가적인 기능을 구현하고 있는 클래스들을 상속받아 Controller를 구현하는 것이 일반적이다.

Controller 인터페이스

org.springframework.web.servlet.mvc.Controller 인터페이스는 다음과 같이 정의되어 있다.

public interface Controller {
    
    ModelAndView handleRequest(HttpServletRequest request,
                               HttpServletResponse response)
                               throws Exception

}

Controller를 구현하는 가장 단순한 방법은 Controller 인터페이스를 구현한 뒤, handleRequest() 메소드를 알맞게 구현하는 것이다. 아래 코드는 구현 예이다.

package net.daum.ts.techReport.report2.springmvc;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.Controller;

public class SimpleController implements Controller {

    public ModelAndView handleRequest(HttpServletRequest request,
            HttpServletResponse response) throws Exception {
        // request를 사용하여 클라이언트 요청 분석 후
        // 클라이언트 요청에 따른 알맞은 처리
        ModelAndView mav = new ModelAndView("hello");
        mav.addObject("greeting", "안녕하세요");
        return mav;
    }

}

handleRequest() 메소드는 파라미터로 전달받은 request 객체와 response 객체를 사용하여 클라이언트가 요청한 기능을 알맞게 구현하면 된다.

handleRequest() 메소드는 ModelAndView 객체를 리턴한다. ModelAndView 객체는 클라이언트의 요청을 처리한 결과를 보여줄 뷰 페이지와 관련해서 다음과 같은 정보를 제공한다.

  • 결과를 보여줄 뷰 이름 지정 : 위 코드의 경우 "hello"를 뷰로 선택
  • 뷰에서 사용할 모델 데이터 : 위 코드의 경우 addObject() 메소드로 추가한 객체, 뷰에서는 "greeting" 이라는 이름을 사용하여 데이터에 접근할 수 있다.
예를 들어, ViewResolver를 다음과 같이 설정했다고 해 보자.

    <bean id="viewResolver"
        class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/view/" />
        <property name="suffix" value=".jsp" />
    </bean>

위 viewResolver는 "/view/" + 뷰이름 + ".jsp"를 뷰로 사용하게 된다. SimpleController는 뷰 이름으로 "hello"를 리턴하므로, "/view/hello.jsp"가 뷰로 사용된다. 또한, 이 뷰에서는 다음과 같이 ModelAndView에 저장된 객체를 사용할 수 있게 된다.

<%@ page contentType="text/html; charset=UTF-8" %>

<strong>${greeting}</strong> ..

AbstractController를 이용한 구현

Controller를 구현할 때에는 Controller 인터페이스를 직접 구현하기보다는, AbstractController 추상 클래스를 상속 받아 구현하는 경우가 더 많다. AbstractController 클래스는 Controller 인터페이스를 implements 하여 추가적인 기능을 제공하고 있다.

AbstractController 클래스는 표 5와 같은 프로퍼티를 제공하고 있으며, 이 프로퍼티를 사용하여 HTTP Session, 캐시 등의 설정을 제어할 수 있다.

프로퍼티설명
supportedMethodsController가 처리할 수 있는 메소드를 지정한다. GET과 POST 등 처리할 수 있는 메소드를 지정할 수 있다. 만약 지원되지 않는 메소드를 사용하여 요청이 들어오면 ServletException 예외를 발생시킨다.
requiresSessionController가 HTTP Session을 필요로 하는 지의 여부를 지정한다. 이 값이 true인 경우, 클라이언트와 관련된 세션이 존재하지 않으면 ServletException 예외를 발생시킨다.
synchronizeSessionHTTP Session을 사용하여 Controller에 대한 처리를 동기화 할지의 여부를 지정한다.
cacheSecondsHTTP 응답에 캐시와 관련된 디렉티브를 생성할지의 여부를 지정한다. 기본 값은 -1이며, 이 경우 캐시 디렉티브가 응답 결과에 포함되지 않는다.
useExpiresHeaderHTTP 1.0에 호환되는 "Expires" 헤더의 사용 여부를 지정한다. 기본값은 true 이다.
useCacheHeaderHTTP 1.1에 호환되는 "Cache-Control' 헤더의 사용 여부를 지정한다. 기본값은 true 이다.

AbstractController 클래스를 상속받아 Controller를 구현하는 클래스는 아래 코드와 같이 handleRequestInternal() 메소드를 구현해주면 된다.

package net.daum.ts.techReport.report2.springmvc;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.AbstractController;

public class HelloController extends AbstractController {

    @Override
    protected ModelAndView handleRequestInternal(HttpServletRequest request,
            HttpServletResponse response) throws Exception {
        ModelAndView view = new ModelAndView("hello");
        view.addObject("greeting", "안녕하세요");
        return view;
    }

}

AbstractController 클래스의 handleRequest() 메소드는 내부적으로 필요한 작업을 수행한 뒤, handleRequestInternal() 메소드를 호출한다. 따라서, AbstractController 클래스를 상속받는 경우에는 handleRequest() 메소드가 아닌 handlerRequestInternal() 메소드를 구현해주어야 한다.

AbstractCommandController를 이용한 파라미터 값 전달

요청 파라미터의 값을 특정한 객체에 저장하고 싶다면 AbstractCommandController 클래스를 사용하면 된다. AbstractCommandController 클래스를 상속받은 클래스는 다음과 같이 handle() 메소드를 알맞게 구현해주면 된다.

package net.daum.ts.techReport.report2.springmvc;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.validation.BindException;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.AbstractCommandController;

public class LoginController extends AbstractCommandController {

    @Override
    protected ModelAndView handle(HttpServletRequest request,
            HttpServletResponse response, Object command, BindException errors)
            throws Exception {
        LoginCommand loginCommand = (LoginCommand) command;
        authService.authenticate(loginCommand.getId(), loginCommand.getPassword());
        return new ModelAndView("loginSuccess", "loginCommand", loginCommand);
    }

}

handle() 메소드의 세 번째 파라미터는 파라미터의 값을 저장한 command 객체이다. 이 command 객체의 타입을 지정하기 위해서는 다음과 같이 Spring 설정 파일에서 commandClass 프로퍼티의 값으로 클래스의 이름을 지정해주면 된다.

    <bean name="/login.do"
        class="net.daum.ts.techReport.report2.springmvc.LoginController">
        <property name="commandClass" 
            value="net.daum.ts.techReport.report2.springmvc.LoginCommand" />
    </bean>

handle() 메소드에 전달되는 command 파라미터는 commandClass 프로퍼티에 지정한 타입의 객체가 된다. 이때 파라미터와 생성할 command 객체의 프로퍼티 사이의 매핑은 자바빈 스타일을 따른다. 예를 들어, 파라미터 이름이 id 인 경우 setId() 메소드를 통해 파라미터 값이 전달되며, 파라미터 이름이 address 인 경우 setAddress() 메소드를 통해 파라미터 값이 전달된다.

SimpleFormController를 이용한 폼 전송 처리

SimpleFormController는 AbstractCommandController와 마찬가지로 파라미터의 값을 객체에 저장할 때 사용된다. 차이점이 있다면, SimpleFormController는 폼 전송 개념이 적용되어 있다는 것이다. SimpleFormController는 POST 방식으로 요청이 들어올 경우 doSubmitAction() 메소드를 통해 요청을 처리하는 반면에, GET 방식으로 요청이 들어오면 "formView" 프로퍼티로 지정한 뷰를 출력한다.

SimpleFormController는 클라이언트가 POST로 전송한 데이터는 commandClass 프로퍼티로 지정한 타입의 객체에 저장되어 doSubmitAction() 메소드에 전달된다. 아래 코드는 SimpleFormController의 구현 예를 보여주고 있다.

package net.daum.ts.techReport.report2.springmvc;

import org.springframework.web.servlet.mvc.SimpleFormController;

public class LoginFormController extends SimpleFormController {

    @Override
    protected void doSubmitAction(Object command) throws Exception {
        LoginCommand loginCommand = (LoginCommand) command;
        if (!loginCommand.getId().equals("madvirus")) {
            throw new LoginFailException("invalid id: "+loginCommand.getId());
        }
    }

}

클라이언트가 요청한 작업을 성공적으로 수행하지 못한 경우, doSubmitAction() 메소드는 예외를 발생시켜서 올바르게 처리하지 못했음을 알리게 된다. 이 경우, 예외 타입에 따라 알맞게 예외 처리를 해 주어야 한다.

GET 방식으로 데이터를 전송하는 경우에는 doSubmitAction() 메소드가 호출되지 않는다. 대신, formView 프로퍼티로 지정한 뷰를 보여준다. 아래 코드는 SimpleFormController 클래스를 상속받은 클래스의 구현 예를 보여주고 있다.

    <bean name="/loginUsingForm.do"
        class="net.daum.ts.techReport.report2.springmvc.LoginFormController">
        <property name="commandClass" 
            value="net.daum.ts.techReport.report2.springmvc.LoginCommand" />
        <property name="formView" value="loginForm" />
        <property name="successView" value="loginSuccess" />
    </bean>

뷰 영역에 데이터를 전달하고 싶다면 다음과 같이 onSubmit() 메소드를 추가적으로 구현해주면 된다.

package net.daum.ts.techReport.report2.springmvc;

import org.springframework.validation.BindException;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.SimpleFormController;

public class LoginFormController extends SimpleFormController {

    @Override
    protected void doSubmitAction(Object command) throws Exception {
        LoginCommand loginCommand = (LoginCommand) command;
        if (!loginCommand.getId().equals("madvirus")) {
            throw new LoginFailException("invalid id: "+loginCommand.getId());
        }
    }
    
    @Override
    protected ModelAndView onSubmit(Object command, BindException errors) 
    throws Exception {
        try {
            ModelAndView mav = super.onSubmit(command, errors);
            mav.addObject("loginCommand", command);
            return mav;
        } catch(Exception e) {
            throw e;
        }
    }
}

위 코드에서 super.doSubmit() 메소드를 호출하면 doSubmitAction() 메소드가 호출된다. 따라서, doSubmitAction() 메소드가 성공적으로 수행되면 ModelAndView.addObject() 메소드를 사용하여 뷰에 데이터를 전달할 수 있게 된다.

뷰의 구현

뷰에서는 ModelAndView 객체에 저장한 객체를 사용할 수 있다. 예를 들어, Controller에서 다음과 같이 ModelAndView에 데이터를 저장했다고 해 보자.

    protected ModelAndView handle(HttpServletRequest request,
            HttpServletResponse response, Object command, BindException errors)
            throws Exception {
        LoginCommand loginCommand = (LoginCommand) command;
        ModelAndView mav = new ModelAndView("loginSuccess");
        mav.addObject("loginCommand", loginCommand);
        return mav;
    }

이 경우 "loginSuccess" 뷰에 해당되는 JSP는 다음과 같이 EL(Expression Language)이나 request.getAttribute() 등의 메소드를 사용하여 ModelAndView 객체에 저장된 값을 사용할 수 있다.

로그인 정보: ${loginCommand.id}
<%
    LoginCommand cmd = (LoginCommand) request.getAttribute("loginCommand");
%>

Velocity 템플릿에서도 다음과 같이 Velocity의 템플릿 언어를 사용하여 ModelAndView 객체에 저장된 값을 사용할 수 있다.

<body>
인사말: ${greeting}
</body>


'Language > JSP' 카테고리의 다른 글

스프링 MVC - 뷰 영역 구현  (0) 2012.10.31
web.xml (servlet)  (0) 2012.10.31
MyBatis-Spring  (0) 2012.10.31
tiles :: 2.2.2 버전 web.xml 설정 세 가지 방법  (0) 2012.10.29
struts2 튜토리얼  (0) 2012.10.23
:

MyBatis-Spring

Language/JSP 2012. 10. 31. 15:10

MyBatis-Spring




********************************************************************************
Getting Started
********************************************************************************


- 설치

MyBatis-Spring 을 이용하기 위해서는 mybatis-spring-x.x.x.jar 과 그 dependency들을 클래스 패스에 추가해야 한다. Maven을 사용중이라면 pom.xml 에 다음 dependency 를 추가한다.

<dependency>
  <groupId>org.mybatis</groupId>
  <artifactId>mybatis-spring</artifactId>
  <version>x.x.x</version>
</dependency>

- Quick Setup

스프링 어플리케에션 컨텍스트에는 기본적으로 다음 2가지가 필요하다.

1. SqlSessionFactory
2. 최소 하나이상의 mapper interface

SqlSessionFactory를 생성하기 위해 SqlSessionFactoryBean 이 사용된다. 즉 다음처럼 스프링 설정파일에 선언해야 한다.

<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
  <property name="dataSource" ref="dataSource" />
</bean>

데이터 소스가 필요한것을 잊지 말것. 그 다음 Mapper Interface 가 필요하다.

public interface UserMapper {
  // mapper XML 파일 대신 annotation 사용가능!
  @Select("SELECT * FROM users WHERE id = #{userId}")
  User getUser(@Param("userId") String userId);
}


이 인터페이스는 다음처럼 MapperFactoryBean 를 사용해서 스프링에 추가된다.

<bean id="userMapper" class="org.mybatis.spring.mapper.MapperFactoryBean">
  <property name="mapperInterface" value="org.mybatis.spring.sample.mapper.UserMapper" />
  <property name="sqlSessionFactory" ref="sqlSessionFactory" />
</bean>

맵퍼 클래스는 반드시 인터페이스여야 한다. 실제 구현 파일이면 안된다.
위처럼 annotation 을 이용해서 SQL을 지정할수도 있지만, MyBatis mapper XML 파일또한 사용가능하다.

일단 설정이 완료되면, 기존 스프링 빈과 동일하게 비즈니스/서비스 객체들에게 mapper들을 inject할수 있다.
MapperFactoryBean 은 SqlSession을 생성하고, 닫는 역활을 수행한다. 또한 스프링 트랜잭션이 진행중이라면 그것이 완료될때, 세션 또한 커밋과 롤백 처리된다. 그리고 모든 예외들을 스프링의 DataAccessException 로 전환시키는 역활도 수행한다.

이제 MyBatis 데이터 메서드들은 코드 한줄 이면 된다.

public class FooServiceImpl implements FooService
{
    private UserMapper userMapper;

    public void setUserMapper(UserMapper userMapper)
   {
       this.userMapper = userMapper;
    }

    public User doSomeBusinessStuff(String userId)
    {
   return this.userMapper.getUser(userId);
    }
}


다음부터는 앞서의 내용에 대한 좀더 상세한 설명들이다. 


********************************************************************************
SqlSessionFactoryBean
********************************************************************************

기본적으로 MyBatis에서 SqlSessionFactory는 SqlSessionFactoryBuilder를 이용해서 만들어진다. MyBatis-Spring 에서는 대신, SqlSessionFactoryBean 가 사용된다.

- 설정

팩토리빈을 생성하기 위한 스프링 설정 파일 내용은 다음과 같다.

<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
  <property name="dataSource" ref="dataSource" />
</bean>

SqlSessionFactoryBean 은 스프링의 FactoryBean interface 를 구현하고 있다는것을 알 필요가 있다 (section 3.8 of the Spring documentation 참조). 이 말은 스프링이 생성하는 빈은 SqlSessionFactoryBean 그자체가 아니며, 팩토리가 리턴해주는 객체는 그 팩토리의 getObject()를 호출한 결과라는 뜻이다. 이 경우 스프링은 어플리케이션 시작시에 SqlSessionFactory 를 생성하고 그이름은 sqlSessionFactory 으로 저장하게 된다. 자바 코드로 나타내면 다음과 같을것이다.

SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();
SqlSessionFactory sessionFactory = factoryBean.getObject();
//팩토리의 getObject()를 호출한 결과가 빈으로 생성된다.

일반적인 MyBatis-Spring 사용시에는 SqlSessionFactoryBean 혹은 상응하는 SqlSessionFactory 를 직접 사용할일은 없을것이다. 대신 세션 팩토리는 MapperFactoryBeans나 다른 DAO들(SqlSessionDaoSupport을 상속받은)에게 인젝트 될것이다.

- 속성들

SqlSessionFactory 는 필요로 하는 하나의 속성을 가지는데, 바로 JDBC DataSource 이다. 이것은 다른 스프링 데이터 연결과 마찬가지로 어떤것이든 설정될 수 있다. 또하나 일반적인 속성이 있는데 MyBatis XML 설정 파일의 위치를 설정하는 configLocation 이다. 이것이 필요한 이유는 MyBatis 설정이 변경될 필요가 있는 경우이다. 또한 만약 동일한 클래스 패스상에 맵퍼 XML파일과 맵퍼 클래스가 존재하지 않는 경우에도 이 설정파일이 필요하다. 이런 경우라면 2가지의 옵션이 존재하는데 첫째는 <mapper> 섹션지정으로 수동으로 MyBatis XML 맵퍼 파일들을 지정하는것이고, 두번째 옵션은 팩토리 빈의 속성인 mapperLocations 을 사용하는것이다.

mapperLocations 는 리소스 위치들의 리스트를 필요로 한다. 이 속성은 MyBatis XML 맵퍼 파일의 위치를 지정하기 위해 사용될수 있다. 값은 디렉토리의 모든 파일을 로드하거나, 기본 위치로부터 재귀적으로 모든 경로를 찾게끔 Ant스타일의 패턴을 포함할수 있는데, 예를 들면 다음과 같다.

<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
  <property name="dataSource" ref="dataSource" />
  <property name="mapperLocations" value="classpath*:sample/config/mappers/**/*.xml" />
</bean>

이것은 클래스 패스로부터 sample.config.mappers 패키지와 그 서브 패키지들에 있는 모든 MyBatis 맵퍼 XML 파일들을  로드 할 것이다.

********************************************************************************
트랜잭션
********************************************************************************
MyBatis-Spring 을 사용하는 주된 이유중의 하나는 MyBatis를 스프링 트랜잭션에 참여하게 해주기 때문이다. MyBatis를 위한 특별한 트랜잭션 매니져를 만들기 보다는, MyBatis-Spring는 기존 스프링의 DataSourceTransactionManager 를 활용하고 있다. 스프링 트랜잭션 매니져가 설정이 되면, 일반적으로 하던것처럼 스프링에서의 트랜잭션을 설정할수 있다. @Transactional 어노테이션들과 AOP 스타일의 설정들 모두 지원된다. 트랜잭션 기간동안 하나의 SqlSession 객체가 생성되어 사용된다. 이 세션은 트랜잭션이 완료될때 적절하게, 커밋 혹은 롤백처리 될것이다. MyBatis-Spring 은 일단 설정이 되면 트랜잭션들을 투명하게 관리할것이다. 사용자의 DAO 클래스들에게 추가적인 코드는 불필요하다.

- Standard Configuration

스프링 트랜잭션 처리를 활성화 시키기 위해서는, 간단하게 DataSourceTransactionManager 를 스프링 설정 파일에 생성하면 된다.

<bean id="transactionManager"  class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
  <property name="dataSource" ref="dataSource" />
</bean>

트랜잭션 매니져에 설정된 DataSource는 SqlSessionFactoryBean 생성시에 설정했던 것과 동일해야만 한다. 만약 틀리다면 트랜잭션 관리는 작동하지 않을것이다.

- 컨테이너 관리 트랜잭션들

만약 JEE container 를 사용중이고 스프링이 컨테이너 관리 트랜잭션들(CMT) 에 참가하게 하려면,JtaTransactionManager 혹은 특정 컨테이너에 대한 그것의 서브 클래스중의 하나로 스프링 설정을 해줘야 한다. 이것을 하기 위한 가장 쉬운 방법은 스프링 트랜잭션 네임스페이스를 사용하는 것이다.

<tx:jta-transaction-manager />

이 설정으로,  MyBatis 는 CMT로 설정된 여타 다른 스프링 트랜잭션 처리되는 리소스들과 같이 동작할것이다. 스프링은 자동으로, 존재하는 컨테이너 트랜잭션을 사용할것이고  SqlSession을 그것에 덧붙일것이다.  만약 트랜잭션이 시작 안된 상태에서 트랜잭션 설정을 기본으로 그것(트랜잭션)이 필요한 경우면, 스프링은 새로운 컨테이너 관리 트랜잭션을 시작할것이다.
만약 CMT를 원하고 스프링 트랜잭션 관리를 원하지 않는다면, 어떠한 스프링 트랜잭션 설정도 해서는 안된다.  또한 기본MyBatis 관리 트랜잭션 팩토리를 사용하기 위해 SqlSessionFactoryBean을 설정해야한다.

<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
  <property name="dataSource" ref="dataSource" />
  <property name="transactionFactory">
    <bean class="org.apache.ibatis.transaction.managed.ManagedTransactionFactory" />
  </property>
</bean>

- 코드를 통한 트랜잭션 관리

MyBatis SqlSession 은 특정 메서드를 통해서 트랜잭션들을 프로그래밍적으로 다룰수 있다. 하지만 MyBatis-Spring를 사용할때는 당신의 bean들에게는 스프링이 관리하는 SqlSession이나 스프링이 관리하는 맵퍼가 인젝트 될것이다. 즉, 스프링이 언제나 당신의 트랜잭션을 다룬다는 의미이다. 이러한 스프링 관리하의 SqlSession에서는 SqlSession.commit(), SqlSession.rollback() 혹은 SqlSession.close()을 호출할수 없다. 만약 호출한다면 UnsupportedOperationException 예외가 발생 할 것이다. 이러한 메서드들은 인젝트된 맵퍼 클래스안에서 노출이 안된다는것을 알기 바란다. 당신의 JDBC connection's autocommit 설정에 상관없이, SqlSession 데이터 메서드 실행 혹은 스프링 트랜잭션 외부에서의 mapper 메서드 호출은 모두 자동적으로 커밋 될 것이다.

만약 당신이 트랜잭션을 프로그램적으로 제어하길 원한다면,  스프링 레퍼런스 매뉴얼 10.6 장을 참고하기 바란다. 다음 코드는 10.6.2 section에 기술된 부분인데, PlatformTransactionManager 를  사용해서 수동으로 트랜잭션을 다루고 있다.

DefaultTransactionDefinition def = new DefaultTransactionDefinition();
def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
TransactionStatus status = txManager.getTransaction(def);

try {
    userMapper.insertUser(user);
}
catch (MyException ex) {
    txManager.rollback(status);
    throw ex;
}
txManager.commit(status);

이코드는 mapper를 사용하고 있지만,  SqlSession을 이용해서도 동작할것이다.


********************************************************************************
SqlSession 사용
********************************************************************************
MyBatis 에서는 (기본적인 MyBatis를 사용한다면, 즉 MyBatis-Spring을 사용하는것이 아님!) SqlSession 을 생성하기 위해 SqlSessionFactory 를 사용한다. 그리고 일단 세션을 얻게되면, 그것을 이용해서 당신의 맵핑된 구문들을 실행하고 연결들을 커밋하고 롤백하며, 더이상 필요하지 않다면 최종적으로 세션을 닫게 된다.

MyBatis-Spring에서는 SqlSessionFactory를 직접 사용할 필요가 없다. 스프링의 트랜잭션 설정에 근거해서 자동으로 커밋, 롤백, 세션종료가 이루어지며 쓰레드에도 안전한 SqlSession 이 당신의 빈들에게 인젝트 될수있기 때문이다.

또한, 일반적으로 SqlSession 을 직접 사용할 필요가 없다는것도 알아둘 필요가 있다. 대부분의 경우, 단지 필요한 것은 당신의 빈들에게 맵퍼들을 인젝트 할 MapperFactoryBean 일 것이다(이것은 다음 장에 설명된다).


- SqlSessionTemplate

이것은 MyBatis-Spring의 심장이다. 이 클래스는 MyBatis SQL method들을 호출하면서 예외들을 전환하면서 MyBatis SqlSession 들을 관리하는 책임이 있다. SqlSessionTemplate 은 쓰레드 안전하고 여러 DAO들 사이에서 공유 가능하다.

getMapper() 호출로 얻은 맵퍼의 SQL 메서드들을 호출할때, SqlSessionTemplate 은 SqlSession 이 현재 스프링 트랜잭션에 연관된 것임을 보장할것이다. 또한, 필요에 따라 세션의 종료, 커밋, 롤벡을 포함하는 세션 생명주기를 관리한다.

SqlSessionTemplate 은 SqlSession을 구현하고 있는데, 코드에 존재하는 기존 SqlSession 사용에 대해 간단히 교체 된다. 기본 MyBatis 구현인 DefaultSqlSession 대신 SqlSessionTemplate이 항상 사용되어져야 하는데 스프링 트랜잭션에 템플릿이 참가 가능하고 여러개의 인젝트 되어진 맵퍼 클래스에 의해 사용될때 쓰레드 안전하기 때문이다. 동일 어플리케이션에서 이 두가지 클래스(DefaultSqlSession 과 SqlSessionTemplate)를 혼용하는것은 데이터 무결성 문제를 야기할수 있다.

SqlSessionTemplate 은 생성자 인자로 SqlSessionFactory 를 사용해서 생성될수 있다.

<bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
  <constructor-arg index="0" ref="sqlSessionFactory" />
</bean>

이 bean은 이제 당신의 DAO 빈들에게 직접 인젝트될수 있다. 당신의 bean에 SqlSession 프러퍼티가 다음처럼 필요하다.

(다음 코드는 직접 SqlSession를 사용하는 경우이다. Mapper를 이용 한다면 달라질것이다)
public class UserDaoImpl implements UserDao
{
private SqlSession sqlSession;

    public void setSqlSession(SqlSession sqlSession)
   {
        this.sqlSession = sqlSession;
    }

    public User getUser(String userId)
    {
        return
        (User) sqlSession.selectOne("org.mybatis.spring.sample.mapper.UserMapper.getUser",
         userId);
    }
}

그리고 다음처럼 SqlSessionTemplate 을 인젝트 한다.

<bean id="userDao" class="org.mybatis.spring.sample.dao.UserDaoImpl">
  <property name="sqlSession" ref="sqlSession" />
</bean>

SqlSessionTemplate 은 또한 ExecutorType을 입력인자로 가지는 생성자를 가지고 있다. 다음처럼 batch SqlSession 을 생성할수 있게 해준다.

<bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
  <constructor-arg index="0" ref="sqlSessionFactory" />
  <constructor-arg index="1" value="BATCH" />
</bean>

이제 모든 당신의 구문들은 배치로 동작할것이고 DAO에서 다음처럼 코딩될수 있다.

public void insertUsers(User[] users) {
    for (User user : users) {
     sqlSession.insert("org.mybatis.spring.sample.mapper.UserMapper.insertUser", user);
    }
}

이런 설정 스타일은 SqlSessionFactory를 위한 기본 설정과 상이한 실행 메서드가 요구되는 경우만 필요 하다는 것을 알 필요가 있다. 이러한 방식에서 잊지 말아야 할것은 이 메서드가 호출될때 서로다른 ExecutorType에 진행중인 기존 트랜잭션이 존재하면 안된다는 점이다.  별도 트랜잭션에서 동작하는 다른 ExecutorType으로 SqlSessionTemplate들을 호출 하던지 (즉, PROPAGATION_REQUIRES_NEW 사용으로) 아니면 완전히 트랜잭션 밖에서 동작하게 해야 한다.

- SqlSessionDaoSupport

SqlSession을 제공해주는 추상 클래스이다. 다음 예 처럼 getSqlSession() 을 호출해서 SqlSessionTemplate 을 얻을수 있고, SQL 메서드들을 수행할수 있다.

public class UserDaoImpl extends SqlSessionDaoSupport implements UserDao {
    public User getUser(String userId) {
        return (User) getSqlSession().
            selectOne("org.mybatis.spring.sample.mapper.UserMapper.getUser", userId);
    }
}

일반적으로 이 클래스보다 MapperFactoryBean 이 선호된다(추가 코드가 불필요하기 때문). 하지만, 당신의 DAO 에서 다른 비-MyBatis 작업을 수행할 필요가 있을때나, concrete 클래스들이 필요할때 유용하다.

SqlSessionDaoSupport 는 sqlSessionFactory 와 sqlSessionTemplate 속성중 하나만 필요로 한다. Spring에 의해 autowired 되거나, 명시적으로 설정 가능하다. 만약 두 속성이 모두 설정이 된 경우라면, sqlSessionFactory 는 무시된다.
다음 예에서 UserDaoImpl 가 만약 SqlSessionDaoSupport의 자식 클래스라고 하면, 스프링에서 다음처럼 설정 되어질 수 있다.

<bean id="userMapper" class="org.mybatis.spring.sample.mapper.UserDaoImpl">
    <property name="sqlSessionFactory" ref="sqlSessionFactory" />
</bean>

********************************************************************************
Mappers 인젝팅
********************************************************************************
SqlSessionDaoSupport 나 SqlSessionTemplate 사용해서 data access objects (DAOs)를 수동으로 코딩하는 것보다, Mybatis-Spring 는 MapperFactoryBean 이라는 프록시 팩토리를 제공하고 있다. 이클래스는 data mapper 인터페이스들을 다른 빈들에게 직접 인젝트 할수 있게 해준다. 맵퍼들을 이용할때는 DAO들을 호출했던것과 동일하게 호출하지만, Mybatis-Spring이 프록시를 생성할것이기 때문에, DAO 구현을 위해서 어떠한 코딩도 필요하지 않다.
인젝트되어진 맵퍼들 인해 당신의 코드는 MyBatis, 스프링 혹은 MyBatis-Spring과 직접적인 의존관계를 갖지 않게 될것이다.

MapperFactoryBean 가 생성하는 프록시는 세션을 열고 닫는 것을 다루며 또한 예외들을 스프링의 DataAccessException 로 변환한다. 더 나아가 만약 필요한경우 그 프록시는 새로운 Spring 트랜잭션을 시작하거나, 트랜잭션이 활성화 되어 있는 경우, 기존 트랜잭션에 참가 할것이다.

- MapperFactoryBean

데이터 맵퍼는 스프링에 다음과 같이 추가된다.

<bean id="userMapper" class="org.mybatis.spring.mapper.MapperFactoryBean">
  <property name="mapperInterface" value="org.mybatis.spring.sample.mapper.UserMapper" />
  <property name="sqlSessionFactory" ref="sqlSessionFactory" />
</bean>

MapperFactoryBean 는 UserMapper 를 구현하는 프록시 클래스를 생성하고, 그것을 어플리케이션에 인젝트 한다. 프록시는 런타임시에 생성되므로, 지정된 맵퍼는 실제 구현 클래스가 아닌, 인터페이스여야만 한다.
만약 UserMapper 가 상응하는 MyBatis XML mapper 파일을 가지고 있고, mapper interface 와 동일한 클래스 패스에 존재한다면, 자동적으로 MapperFactoryBean 에 의해 해석될것이다. 만약 mapper XML 파일이 다른 클래스 패스 위치상에 있는 경우만 아니면 MyBatis 설정 파일에 맵퍼를 지정할 필요는 없다.( SqlSessionFactoryBean 의 configLocation 속성 참조)

MapperFactoryBean 는 SqlSessionFactory 나 SqlSessionTemplate를 필요로 하는것에 유의하기 바란다. 이것들은 각각의 sqlSessionFactory  나 sqlSessionTemplate  속성이나 스프링에 의해 autowired 에 의해 설정되어질수 있다.만약 둘다 설정이 된다면 SqlSessionFactory 가 무시된다. SqlSessionTemplate 가 session factory 설정을 필요로 하므로, 그 팩토리는
MapperFactoryBean에 의해 사용된다.

이제 맵퍼들을 당신의 비즈니스/서비스 객체들에게 직접 인젝트 가능하다.
<bean id="fooService" class="org.mybatis.spring.sample.mapper.FooServiceImpl">
  <property name="userMapper" ref="userMapper" />
</bean>

이 bean은 어플리케이션 로직에서 직접 사용가능하다.
public class FooServiceImpl implements FooService
{
   private UserMapper userMapper;

   public void setUserMapper(UserMapper userMapper) {
        this.userMapper = userMapper;
    }

    public User doSomeBusinessStuff(String userId) {
        return this.userMapper.getUser(userId);
    }
}

이 코드에는 어떠한 SqlSession 나 MyBatis 참조도 없다는것을 주목하기 바란다. 또한 세션을 생성하고, 열고 닫을 필요도 없다. MyBatis-Spring가 그 일들을 해줄 것이다.

- MapperScannerConfigurer

모든 맵퍼들을 스프링 XML파일에 등록할 필요없이, MapperScannerConfigurer 를 이용해서 MapperFactoryBean 처럼 당신의 맵퍼들을 위해 클래스 패스를 검색하고 자동적으로 그것들을 설정하게 할 수 있다. 다음처럼 스프링 설정에 추가하면 된다.

<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
  <property name="basePackage" value="org.mybatis.spring.sample.mapper" />
</bean>

basePackage 속성은 맵퍼 인터페이스 파일들의 기본 패키지를 설정하는것이다. 세미콜론이나 콤마 구분자를 이용해서 하나이상의 패키지를 설정할수 있다. 그러면 지정된 패키지부터 시작해서 재귀적으로 mapper가 검색된다.

SqlSessionFactory 나 SqlSessionTemplate 를 지정할 필요가 없는것에 주목하기 바란다. 왜냐하면 MapperScannerConfigurer 가 autowired될수 있는 MapperFactoryBean들을 생성할 것이기 때문이다.
그런데 만약 하나 이상의 데이터 소스를 사용중이라면, autowire 는 작동하지 않을 수 있다. 이 경우에는 sqlSessionFactoryBeanName 나 sqlSessionTemplateBeanName 속성들을 사용해서 사용할 올바른 bean 이름을 지정 할 수 있다. 주의할것은 bean의 참조가 아니라 이름이 필요하다는 것이다. 그 때문에 일반적인 ref 대신 value 어트리뷰트가 사용된다.

  <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory" />

알아둘것 : sqlSessionFactoryBean 과 sqlSessionTemplateBean 속성은 MyBatis-Spring 1.0.2 버전까지 가능했던 그냥 옵션일 뿐이었다. 하지만 MapperScannerConfigurer가 기동 프로세스의 초기에 구동된다고 할때 PropertyPlaceholderConfigurer 에 빈번한 에러가 발생했다. 그래서 이 속성들은 deprecated 되었고 새로운 속성, 즉 sqlSessionFactoryBeanName과 sqlSessionTemplateBeanName 사용이 권장된다.

MapperScannerConfigurer 는 marker interface 지정 혹은 annotation 에 의해 생성된 맵퍼들을 필터링하는것을 지원한다.
annotationClass 속성은 찾고자 하는 annotation 을 지정한다. markerInterface 속성은 찾고자 하는 부모 인터페이스 를 지정한다. 만약 두 속성이 모두 지정되면 한쪽 조건에 일치하는 멥퍼들이 추가된다. 디폴트로 이속성들은 null이다. 따라서 기본 패키지에 있는 모든 인터페이스들이 맵퍼들로 로드 될것이다.

발견된 맵퍼들은 스프링의 자동 감지된 컴퍼넌트들을 위한 기본 네이밍 전략에 의해 이름이 정해진다(section 3.14.4 of the Spring manual). 즉, 어노테이션이 발견 안된 경우, 소문자로 구성된 맵퍼의 클래스(non-qualified 클래스명,즉 패키지 제외한 단순 클래스명만)를 이름으로 사용할것이다. 하지만 @Component 혹은 JSR-330 @Named 어노테이션이 발견된다면 그것으부터 이름이 결정된다.annotationClass 속성에 org.springframework.stereotype.Component, javax.inject.Named (JSE 6 경우만) 혹은 사용자 고유의 annotation 을 설정할수 도 있는데 이러면 annotation 이 마커와 네임 프로바이더로 모두 동작하게 된다.

********************************************************************************
MyBatis API 사용하기
********************************************************************************
MyBatis-Spring 에서 MyBatis API를 직접 사용하는 방법이다. 스프링에서 SqlSessionFactoryBean  을 이용해서 SqlSessionFactory 를 생성하고, 코드상에서 factory 를 사용한다.

public class UserMapperSqlSessionImpl implements UserMapper {
    // SqlSessionFactory would normally be set by SqlSessionDaoSupport
    private SqlSessionFactory sqlSessionFactory;

    public void setSqlSessionFactory(SqlSessionFactory sqlSessionFactory) {
        this.sqlSessionFactory = sqlSessionFactory;
    }

    public User getUser(String userId) {
        // note standard MyBatis API usage - opening and closing the session manually
        SqlSession session = sqlSessionFactory.openSession();

        try {
            return
            (User) session.selectOne("org.mybatis.spring.sample.mapper.UserMapper.getUser",
                                    userId);
        } finally {
            session.close();
        }
    }
}

이 방법을 사용할때는 주의를 기울여야 한다. 잘못된 사용으로 인해 런타임 에러가 발생하거나, 심하면 데이터 무결성에 문제를 일으킬수도 있다. 직접 API를 사용하기 위해서는 다음을 명심해야 한다.

 - 이것은 어떠한 스프링 트랜잭션들에게도 참가하지 않는다

 - 만약 SqlSession 사용중인 DataSource 를 Spring transaction manager 도 사용중이고,
   현재 진행중인 트랜잭션이 존재한다면 이 코드는 예외를 던질것이다.

 - MyBatis의 DefaultSqlSession 은 쓰레드에 안전하지 않다. 만약 그것을 당신의 bean들에게
   인젝트 한다면 에러가 발생할것이다.

 - DefaultSqlSession 를 사용해서 만들어진 mapper들도 쓰레드에 안전하지 않다.
   만약 그것을 당신의 bean들에게 인젝트 한다면 에러가 발생할것이다.

 - SqlSessions 이 finally 블럭에서 항상 닫혀지는지 확인해야 한다.

간단한 게시판 예제를 참고하기 바란다.

'Language > JSP' 카테고리의 다른 글

web.xml (servlet)  (0) 2012.10.31
Spring MVC  (0) 2012.10.31
tiles :: 2.2.2 버전 web.xml 설정 세 가지 방법  (0) 2012.10.29
struts2 튜토리얼  (0) 2012.10.23
태그라이브러리 URI  (0) 2012.10.23
:

tiles :: 2.2.2 버전 web.xml 설정 세 가지 방법

Language/JSP 2012. 10. 29. 11:18

1. web.xml 의 <servlet> 태그 활용

아래는 web.xml 에 추가되야 하는 부분의 예제 코드이다.

 

 <servlet>
        <servlet-name>tiles</servlet-name>
        <servlet-class>org.apache.tiles.web.startup.TilesServlet</servlet-class>
        <init-param>
            <param-name>
                  org.apache.tiles.definition.DefinitionsFactory.DEFINITIONS_CONFIG
            </param-name>
            <param-value>
                  /WEB-INF/tiles-hello.xml
            </param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
 </servlet>

 

 

물론 여기서 태그 설정 파일(여기서는 tiles-hello.xml) 이 WEB-INF 폴더 밑에 있어야 한다.

그러므로 이 방법을 선택할 분은 <param-value> 이 부분을 자신이 설정한 이름에 맞게

바꿔 주면 된다.

 

 

 

 

 

2. web.xml 의 <listener> 와 <context-param> 사용하기

 

 <listener>
        <listener-class>org.apache.tiles.web.startup.TilesListener</listener-class>
 </listener>
 
 <context-param>
        <param-name>
               org.apache.tiles.impl.BasicTilesContainer.DEFINITIONS_CONFIG
        </param-name>
        <param-value>
               /WEB-INF/tiles-hello.xml
        </param-value>
 </context-param>

 

1번 방법과 큰 차이는 없으며 여기서도 역시 <param-value> 의 몸체에 해당하는 부분만

자신이 설정한 tiles 설정 파일의 이름에 맞게 바꿔 주면 된다.

 

 

 

 

 

3. 이제 마지막 .. 세 번째 방법.. 이거 때문에 삽질 좀 했다.

먼저 여기서는 두 개의 자바 파일이 필요하다. 아래 두 개의 자바 파일 중 첫 번째 꺼를 먼저

컴파일 한 후 두 번째꺼를 컴파일 해줘야 한다.

 

첫 번째 자바 파일(TestTilesContainerFactory.java)

첫 번째 자바 파일에서 사용자가 설정한 태그 파일(여기서는 /WEB-INF/tiles-hello.xml) 를

추가 해주는 것을 확인할 수 있다.

 

package tiles;

import java.io.IOException;
import java.util.List;
import java.util.ArrayList;
import java.net.URL;
import org.apache.tiles.factory.BasicTilesContainerFactory;
import org.apache.tiles.TilesApplicationContext;
import org.apache.tiles.context.TilesRequestContextFactory;
import org.apache.tiles.definition.DefinitionsFactoryException;

public class TestTilesContainerFactory extends BasicTilesContainerFactory {

protected List<URL> getSourceURLs(TilesApplicationContext applicationContext,   TilesRequestContextFactory contextFactory) {
        List<URL> urls = new ArrayList<URL>();
        try {
            urls.add(applicationContext.getResource("/WEB-INF/tiles-hello.xml"));
        } catch (IOException e) {
            throw new DefinitionsFactoryException("Cannot load definition URLs", e);
        }
        return urls;
    }
}

 

 

두 번째 자바 파일(TestTilesListener.java)

 

package tiles;

import tiles.TestTilesContainerFactory;
import org.apache.tiles.TilesApplicationContext;
import org.apache.tiles.web.startup.AbstractTilesListener;
import org.apache.tiles.startup.TilesInitializer;
import org.apache.tiles.startup.AbstractTilesInitializer;
import org.apache.tiles.factory.AbstractTilesContainerFactory;

 

public class TestTilesListener extends AbstractTilesListener {

    @Override
    protected TilesInitializer createTilesInitializer() {
        return new TestTilesListenerInitializer();
    }

    private static class TestTilesListenerInitializer extends AbstractTilesInitializer {

        @Override
        protected AbstractTilesContainerFactory createContainerFactory(TilesApplicationContext  context) {
            return new TestTilesContainerFactory();
        }
    }
}

 

이 두 자바 파일을 컴파일 하는데 필요한 라이브러리는 아래와 같다. 나는 이 라이브러리를

WEB-INF\lib 밑에 놔뒀다.

 

tiles-servlet-2.2.2.jar
tiles-api-2.2.2.jar
tiles-core-2.2.2.jar

servlet-api.jar

 

그래서 내가 cmd 창에서 했던 명령어는 아래와 같다.


C:\Tomcat 6.0\webapps\JSP2\WEB-INF>javac -classpath lib\tiles-servlet-2.2.2.jar -d classes src\tiles\TestTilesContainerFactory.java


C:\Tomcat 6.0\webapps\JSP2\WEB-INF>javac -classpath classes;lib\servlet-api.jar;lib\tiles-servlet-2.2.2.jar;lib\tiles-api-2.2.2.jar;lib\tiles-core-2.2.2.jar -d classes src\tiles\TestTilesListener.java

 

참고로 두 자바 파일 모두 WEB-INF/src/tiles/ 밑에 존재하고 첫번째 자바 파일을 컴파일 하면

클래스 파일은

 

WEB-INF/classes/tiles/TestTilesContainerFactory.class

 

에 생성된다.

그러므로 두 번째 컴파일 할 때

 

classpath classes;

 

라고 되 있는 것은 첫 번째 컴파일된 클래스 파일을 두 번째 자바 파일이 import 하기 때문에

추가하고 있는 것이다.

 

이렇게 두 자바 파일 모두

 

WEB-INF/classes/tiles/

 

밑에 생성되고

 

이제 web.xml 은 아래와 같이 추가 해주면 된다.

 

 <listener>
         <listener-class>tiles.TestTilesListener</listener-class>
 </listener>

 

tiles.TestTilesListener 여기서 tiles 는 패키지 명이고 TestTilesListener 가

우리가 작성한 두번째 클래스 이름이다.

 

가장 중요한 것이 web.xml  이므로 이 부분을 잘 확인해 보기 바란다.


출처 - http://blog.naver.com/myca11?Redirect=Log&logNo=80127196294

'Language > JSP' 카테고리의 다른 글

Spring MVC  (0) 2012.10.31
MyBatis-Spring  (0) 2012.10.31
struts2 튜토리얼  (0) 2012.10.23
태그라이브러리 URI  (0) 2012.10.23
[centOS] apache2.2 + tomcat6 (yum 설치 성공 통합 정리)  (0) 2012.10.12
:

struts2 튜토리얼

Language/JSP 2012. 10. 23. 15:51

http://www.dzone.com/tutorials/java/struts-2/

:

태그라이브러리 URI

Language/JSP 2012. 10. 23. 14:40

TLD 등록 방법

1. TLD 파일 경로를 지정해 준다.

1.<%@ taglib uri="/WEB-INF/tlds/elf.tld" prefix="elf" %>

2. 라이브러리 경로를 지정해 준다.
1.<%@ taglib uri="/WEB-INF/lib/elf.jar" prefix="elf" %>
META-INF/elf.tld 가 있어야 한다.

3. 
web.xml
1.<taglib>
2.<taglib-uri>http://elf.com/taglibs/elf<;/taglib-uri>
3.<taglib-location>/WEB-INF/tlds/elf.tld</taglib-location>
4.</taglib>
JSP
1.<%@ taglib uri="http://elf.com/taglibs/elf" prefix="elf" %>
2....
3.<elf:magic/>
TLD의 uri도 맞추라고 함.

4. JSTL 사용시 web.xml에 등록하지 않아도 되는 이유
1.<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
/WEB-INF/lib/stardartd.jar/META-INF/c.tld
- 참고 문서

:

[centOS] apache2.2 + tomcat6 (yum 설치 성공 통합 정리)

Language/JSP 2012. 10. 12. 14:26

1. 아파치 설치

#yum install httpd

#yum install httpd-devel

- httpd-devel 을 설치하는 이유는 커넥터 설치시 apxs를 사용해야 하기 때문


2. Tomcat 설치

#yum install tomcat6

#yum install tomcat6-webapps

#yum install tomcat6-admin-webapps


- servlet invoker 관련내용의 주석 제거

#vim /usr/share/tomcat6/conf/web.xml

// 풀어줘야 할 주석

가. 121줄 ~ 131줄

 <servlet>

   <servlet-name>invoker </servlet-name>

         .... 중략 ....

 </servlet>

나. 369줄 ~ 372줄

   <servlet-mapping>

     <servlet-name>invoker</servlet-name>

     <url-pattern>/servlet/*</url-pattern>

   </servlet-mapping>

   

-  ROOT 폴더를 통합

#cd /usr/share/tomcat6/webapps

#ln -s /var/www/html /usr/share/tomcat6/webapps/ROOT


- context.xml 수정

#vim /usr/share/tomcat6/conf/context.xml

// 태그를 아래와 같이 수정

<Context reloadable="true" privileged="true" >


3. Connector 설치

설치하기 전, 브라우저로 해당디렉토리를 찾아가서 다운 받을 버전을 찾는다. 여기서는 tomcat-connectors-1.2.37-src.tar.gz 파일을 쓸 것이다.

#wget http://www.apache.org/dist/tomcat/tomcat-connectors/jk/tomcat-connenctors-1.2.37-src.tar.gz

# tar xvzf tomcat*

# cd tomcat*

# cd native

# ./configure -with-apxs=/usr/sbin/apxs

#make

#make install

이렇게 설치가 끝나고 나면, /etc/httpd/modules 에 mod_jk.so파일이 생성되었나 확인한다.


4. 연동하기


- mod_jk.so 로드 추가


#vim /etc/httpd/conf/httpd.conf


LoadModule jk_module modules/mod_jk.so


<IfModule jk_module>

JkWorkersFile /etc/httpd/conf/workers.properties

JkLogFile /etc/httpd/logs/mod_jk.log

JkShmFile /usr/share/tomcat6/logs/jk.shm

JkMount /*.jsp worker2

JkMount /ExpertGrid_Exam/* worker2

</IfModule>


- index 추가

DirectoryIndex index.jsp


- workers.properties 생성


#vim  /etc/httpd/conf/workers.properties


worker.list=worker2

worker.worker2.type=ajp13

worker.worker2.host=localhost

worker.worker2.port=8009

worker.worker2.lbfactor=1

worker.worker2.connection_pool_timeout=600

worker.worker2.socket_keepalive=1

worker.worker2.socket_timeout=60



4. 재시작

#service httpd restart

#service tomcat6 restart


[참고]

자바홈 : /usr/lib/jvm/jre-1.6.0-openjdk.x86_64

'Language > JSP' 카테고리의 다른 글

struts2 튜토리얼  (0) 2012.10.23
태그라이브러리 URI  (0) 2012.10.23
CentOS(64Bit)에 yum을 이용하여 Apache+Tomcat+JSP 연동  (0) 2012.10.11
Apache+Tomcat 연동  (0) 2012.10.11
[CentOS] 6.2에 아파치 + 톰캣6 연동하기  (2) 2012.10.10
:

CentOS(64Bit)에 yum을 이용하여 Apache+Tomcat+JSP 연동

Language/JSP 2012. 10. 11. 16:03

OS : CentOS 5.5 64bit

Apache : 2.2.3-43 64bit

Tomcat 5.5 : 5.5.23 64bit

Java : 1.6.0_17 64bit

Connector : 1.2.31 64bit

 

 

I. Apache 설치

1, 먼저 root로 로그인 합니다.

2. yum list | grep httpd 를 입력하여 결과를 확인합니다.

 

[root@www ~]# yum list | grep httpd
httpd.x86_64                               2.2.3-43.el5.centos.3       updates  
httpd-devel.i386                           2.2.3-43.el5.centos.3       updates  
httpd-devel.x86_64                         2.2.3-43.el5.centos.3       updates  
httpd-manual.x86_64                        2.2.3-43.el5.centos.3       updates  
system-config-httpd.noarch                 5:1.3.3.3-1.el5             base    

 

저는 OS가 64bit 이므로ㅛ

 

yum -y install httpd.x86_64

 

라고 입력하시면 설치됩니다.

 

3. 설치가 완료되면 vi /etc/httpd/conf/httpd.conf 하여 일부 내용을 편집합니다.

 

먼저 언어 우선순위를 정합니다. 아래와 같이 ko를 맨 앞으로 옮겨 주시면 됩니다.

 

LanguagePriority ko en ca cs da de el eo es et fr he hr it ja ltz nl nn no pl pt
 pt-BR ru sv zh-CN zh-TW

 

다음으로 인코딩 방식입니다. 기본은 UTF-8로 되어 있습니다.

 

AddDefaultCharset UTF-8


만약 한글 전용으로 하실 경우에는

 

AddDefaultCharset EUC-KR

 

로 고쳐주세요.
이제 저장하고 나갑니다.

 

4. 다음으로 방화벽에서 80번 포트를 열어줍니다. vi /etc/sysconfig/iptables 라고 입력합니다. 아래는 제 장비의 설정입니다.

 

=========================================================================================

# Firewall configuration written by system-config-securitylevel
# Manual customization of this file is not recommended.
*filter
:INPUT ACCEPT [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
:RH-Firewall-1-INPUT - [0:0]
-A INPUT -j RH-Firewall-1-INPUT
-A FORWARD -j RH-Firewall-1-INPUT
-A RH-Firewall-1-INPUT -i lo -j ACCEPT
-A RH-Firewall-1-INPUT -p icmp --icmp-type any -j ACCEPT
-A RH-Firewall-1-INPUT -p 50 -j ACCEPT
-A RH-Firewall-1-INPUT -p 51 -j ACCEPT
-A RH-Firewall-1-INPUT -p udp --dport 5353 -d 224.0.0.251 -j ACCEPT
-A RH-Firewall-1-INPUT -p udp -m udp --dport 631 -j ACCEPT
-A RH-Firewall-1-INPUT -p tcp -m tcp --dport 631 -j ACCEPT
-A RH-Firewall-1-INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
-A RH-Firewall-1-INPUT -m state --state NEW -m tcp -p tcp --dport 22 -j ACCEPT
-A RH-Firewall-1-INPUT -j REJECT --reject-with icmp-host-prohibited
COMMIT
==============================================================================================


-A RH-Firewall-1-INPUT -m state --state NEW -m tcp -p tcp --dport 22 -j ACCEPT 다음에

-A RH-Firewall-1-INPUT -m state --state NEW -m tcp -p tcp --dport 80 -j ACCEPT

라고 입력합니다. (복사해서 넣으셔도 됩니다.)

저장하고 나갑니다.

 

[root@www ~]# service iptables restart

 

하여 방화벽을 재시작 합니다.

 

 

5. 이제 Apache 데몬을 올립니다.

[root@www ~]# service httpd start
httpd (을)를 시작 중:                                      [  OK  ]

안되는 분은

[root@www ~]# /sbin/service httpd start  하시면 됩니다.

(일반 계정으로 로그인 후 su로 root 변경 하신분은 위 방법을 사용하세요. 그런분들은 계정 디렉토리에서 .bash_profile(bash 일경우입니다)를 열어서 PATH=/usr/sbin:$PATH; export PATH 추가해서 패스를 추가해주시기 바랍니다.)

 

6. 이제 서비스를 확인합니다. 웹브라우저에서 http://xxx.xxx.xxx.xxx/주소 를 입력하여 아래와 같이 정상적으로 화면이 나오면 됩니다.

 

II. JDK 설치

1. 이번에는 Java를 설치합니다.  yum list | grep java 라고 칩니다.

[root@www ~]# yum list | grep java
adaptx-javadoc.x86_64                      0.9.13-3jpp.1               base     
ant-javadoc.x86_64                         1.6.5-2jpp.2                base     
ant-javamail.x86_64                        1.6.5-2jpp.2                base     
antlr-javadoc.x86_64                       2.7.6-4jpp.2                base     
....

java-1.4.2-gcj-compat-src.x86_64           1.4.2.0-40jpp.115           base     
java-1.6.0-openjdk.x86_64                  1:1.6.0.0-1.16.b17.el5      updates  
java-1.6.0-openjdk-demo.x86_64             1:1.6.0.0-1.16.b17.el5      updates  
java-1.6.0-openjdk-devel.x86_64            1:1.6.0.0-1.16.b17.el5      updates  
java-1.6.0-openjdk-javadoc.x86_64          1:1.6.0.0-1.16.b17.el5      updates  
java-1.6.0-openjdk-src.x86_64              1:1.6.0.0-1.16.b17.el5      updates 


저의 경우에는  java-1.6.0-openjdk.x86_64를 설치하면 됩니다. 

 

2. java를 설치합니다.

[root@www ~]# yum -y install java-1.6.0-openjdk.x86_64

라고 입력하여 설치합니다. 의존성에 의해 필요한 몇개의 패키지가 설치됩니다.

 

3. 설치가 완료되면  아래와 같이 java -version 을 입력하여 내용을 확인합니다.

 

[root@www ~]# java -version
java version "1.6.0_17"
OpenJDK Runtime Environment (IcedTea6 1.7.5) (rhel-1.16.b17.el5-x86_64)
OpenJDK 64-Bit Server VM (build 14.0-b16, mixed mode)

 

III. Tomcat 설치

1. 이제 Tomcat을 설치해 보겠습니다. yum list | grep tomcat 을 입력하여 설치여부를 확인합니다.

[root@www ~]# yum list | grep tomcat
jakarta-commons-collections-tomcat5.x86_64 3.2-2jpp.3                  base     
struts-webapps-tomcat5.x86_64              1.2.9-4jpp.5                base     
tomcat5.x86_64                             5.5.23-0jpp.11.el5_5        updates  
tomcat5-admin-webapps.x86_64               5.5.23-0jpp.11.el5_5        updates  
tomcat5-common-lib.x86_64                  5.5.23-0jpp.11.el5_5        updates  
tomcat5-jasper.x86_64                      5.5.23-0jpp.11.el5_5        updates  
tomcat5-jasper-javadoc.x86_64              5.5.23-0jpp.11.el5_5        updates  
tomcat5-jsp-2.0-api.x86_64                 5.5.23-0jpp.11.el5_5        updates  
tomcat5-jsp-2.0-api-javadoc.x86_64         5.5.23-0jpp.11.el5_5        updates  
tomcat5-server-lib.x86_64                  5.5.23-0jpp.11.el5_5        updates  
tomcat5-servlet-2.4-api.x86_64             5.5.23-0jpp.11.el5_5        updates  
tomcat5-servlet-2.4-api-javadoc.x86_64     5.5.23-0jpp.11.el5_5        updates  
tomcat5-webapps.x86_64                     5.5.23-0jpp.11.el5_5        updates 

 

2. 저의 경우는 tomcat5.x86_64를 설치하면 됩니다.

 

[root@www ~]# yum -y install tomcat5.x86_64
라고 입력하여 설치합니다. 의존성에 의해 필요한 패키지는 자동으로 설치됩니다.

 

3. 방화벽에서 8080포트를 열어줍니다. 앞에 Apache 설치때와 같습니다.

[root@www ~]# vi /etc/sysconfig/iptables
-A RH-Firewall-1-INPUT -m state --state NEW -m tcp -p tcp --dport 22 -j ACCEPT
-A RH-Firewall-1-INPUT -m state --state NEW -m tcp -p tcp --dport 80 -j ACCEPT
-A RH-Firewall-1-INPUT -m state --state NEW -m tcp -p tcp --dport 8080 -j ACCEPT
-A RH-Firewall-1-INPUT -j REJECT --reject-with icmp-host-prohibited

저장하고 나가서 서비스를 재시작합니다.

[root@www ~]# service iptables restart

4. 설정 파일을 확인합니다. 아래와 같이 입력하여 파일을 오픈한 후 파란색으로 표시된 부분과 같이 설정되어 있는지 확인합니다.

 

[root@www ~]# vi /usr/share/tomcat5/bin/relink

 

for webapp in $(find $CATALINA_HOME/webapps -mindepth 1 -maxdepth 2 -type d) ; do
    [ -d "$webapp/WEB-INF/lib" ] && rebuild-jar-repository $webapp/WEB-INF/lib
done

만약 설정되어 있지 않다면 똑같이 수정해 줍니다.

저장 후 나갑니다.

 

5. 아래와 같이 파일을 열어서 파란색 부분과 같이 설정해 줍니다.

[root@www ~]# vi /usr/share/tomcat5/conf/workers.properties

 

#workers.tomcat_home=/var/tomcat3
workers.tomcat_home=/usr/share/tomcat5

 

#workers.java_home=/opt/IBMJava2-13
workers.java_home=/usr/lib/jvm/java

 

위 2부분을 수정한 후 저장하고 나갑니다.

 

6. 이번에는 web.xml을 수정합니다.

아래 기술된 부분이 주석처리 되어 있습니다. 주석을 풀어주시면 됩니다.

 

[root@www ~]# vi /usr/share/tomcat5/conf/web.xml

    <servlet>
        <servlet-name>invoker</servlet-name>
        <servlet-class>
          org.apache.catalina.servlets.InvokerServlet
        </servlet-class>
        <init-param>
            <param-name>debug</param-name>
            <param-value>0</param-value>
        </init-param>
        <load-on-startup>2</load-on-startup>
    </servlet>

그리고 아래 부분도 주석을 풀어줍니다.


    <servlet-mapping>
        <servlet-name>invoker</servlet-name>
        <url-pattern>/servlet/*</url-pattern>
    </servlet-mapping>

완료 되었으면 저장하고 나갑니다.

 

6. 이번에는 server.xml을 편집합니다.

[root@www ~]# vi /usr/share/tomcat5/conf/server.xml
    <!-- Define an AJP 1.3 Connector on port 8009 -->
    <!--<Connector port="8009"
               enableLookups="false" redirectPort="8443" protocol="AJP/1.3" />-->

    위 부분이 주석처리 되어 있지 않습니다. 이 부분을 주석처리 합니다. 그리고 아래와 같이 입력합니다.

 

<Connector port="8009" maxHttpHeaderSize="8192" tomcatAuthentication="false"
maxThreads="150" minSpareThreads="25" maxSpareThreads="75"
enableLookups="false" redirectPort="8443" acceptCount="100"
connectionTimeout="20000" disableUploadTimeout="true" protocol="AJP/1.3" />

 

저장하고 나갑니다.

 

7. 이제 서비스를 시작합니다.

[root@www ~]# service tomcat5 start
Starting tomcat5:                                          [  OK  ]

 

IV. Connector 설치

1. 아래 사이트로 가서 필요한 connector를 설치합니다.

http://www.apache.org/dist/tomcat/tomcat-connectors/jk/binaries/

저는 linux 폴더로 들어가서 현재까지 최신 버전인 jk-1.2.31를 설치하도록 하겠습니다.

OS가 64Bit 이므로 x86_64 폴더 내에서 받습니다.

 

저의 경우 전체 주소는 http://www.apache.org/dist/tomcat/tomcat-connectors/jk/binaries/linux/jk-1.2.31/x86_64/

위치에 있는 mod_jk-1.2.31-httpd-2.2.x.so  를 다운받아 사용합니다.

 

다운받은 뒤 리눅스장비의 아래 위치로 복사합니다.(다운 받은 파일명과 다른 파일명이므로 주의합니다.)

복사위치 /etc/httpd/modules

파일명 mod_jk.so

 

[root@www ~]# cp mod_jk-1.2.31-httpd-2.2.x.so /etc/httpd/modules/mod_jk.so

권한을 변경합니다.

[root@www ~]# chmod 755 /etc/httpd/modules/mod_jk.so

원래는 workers.properties를 수정해줘야 하지만 기본설정 값만으로도 사용 가능하니 작업하지 않겠습니다.

대신 그대로 복사하여 사용하도록 하겠습니다.

[root@www ~]# cp /usr/share/tomcat5/conf/workers.properties /etc/httpd/conf/workers.properties

 

2. 다음으로 Apache 설정파일을 수정합니다.

[root@www ~]# vi /etc/httpd/conf/httpd.conf

후 아래와 같이 내용을 추가합니다.

 

LoadModule cgi_module modules/mod_cgi.so
LoadModule version_module modules/mod_version.so
LoadModule jk_module modules/mod_jk.so

 

다음으로 아래 내용을 추가합니다.

DirectoryIndex index.html index.html.var
부분에 index.jsp를 추가합니다.

DirectoryIndex index.jsp index.html index.html.var

 

다음으로 아래 내용을 추가합니다.

단, 아래 내용은 파일로 만든 후 추가하셔도 되고 바로 입력하셔도 됩니다.

저의 경우는 파알로 만든 후 추가하는 방법을 사용하겠습니다.

(바로 입력하시려면 제가 파일로 만든 내용을 httpd.conf에 그대로 입력하시면 됩니다.)

 

httpd.conf파일에 보면 아래와 같은 내용이 있습니다.

#
# Load config files from the config directory "/etc/httpd/conf.d".
#
Include conf.d/*.conf

즉, /etc/httpd/conf.d 폴더안에 conf파일을 만들어 두면 자동으로 include 되죠..

따라서 jkmodule.conf 파일을 하나 만들어 /etc/httpd/conf.d/에 넣도록 하겠습니다.

우선 jkmodule.conf 파일의 내용은 아래와 같습니다.

 

먼저 파일을 생성합니다.

[root@www ~]# vi /etc/httpd/conf.d/jkmodule.conf

다음으로 내용을 입력합니다.

 

JkWorkersFile /etc/httpd/conf/workers.properties
JkLogFile /etc/httpd/logs/mod_jk.log
JkShmFile /usr/tomcat/logs/jk.shm
JkMount /*.jsp ajp13
JkMount /*.do ajp13
JkMount /article/* ajp13
JkMount /uploadManager ajp13
JkMount /downManager ajp13
JkMount /alice-upload ajp13
JkMount /servlet/* ajp13

 

완료되면 저장하고 나갑니다.

 

3. Tomcat5의 홈디렉토리를 /var/www 로 변경합니다.

 

[root@www webapps]# cd /usr/share/tomcat5/webapps/
[root@www webapps]# ln -s /var/www/html /usr/share/tomcat5/webapps/ROOT

이제 모든 설정이 끝났습니다.

tomcat 재지삭, apache 재시작 후 테스트 해보시면 됩니다.

 

4. 먼저 현재  /usr/share/tomcat5/webapps/ROOT/ 에는 아무것도 없습니다. 그래서 파일을 하나 만들겠습니다.

[root@www /]# vi /usr/share/tomcat5/webapps/ROOT/index.jsp
빈 페이지가 나타나면 아래 내용을 입력합니다.

 

<%@ page contentType="text/html;" %>
<html>
<body>
<%
 String strVar="jsp start";
%>
JSP Start : <%= strVar %>
</body>
</html>

저장하고 나갑니다.

이제 서비스를 재시작합니다.

 

[root@www /]# service tomcat5 restart
Stopping tomcat5:                                          [  OK  ]
Starting tomcat5:                                          [  OK  ]
[root@www /]# service httpd restart
httpd 를 정지 중:                                          [  OK  ]
httpd (을)를 시작 중:                                      [  OK  ]

이제 웹브라우저에서 http://xxx.xxx.xxx.xxx/ 를 입력합니다. 아래 내용이 나타나면 성공입니다.

 

JSP Start : jsp start 

이제 연동이 끝났습니다.



출처 - http://blog.naver.com/PostView.nhn?blogId=gkdrhd93&logNo=10096875525&viewDate=&currentPage=1&listtype=0

'Language > JSP' 카테고리의 다른 글

struts2 튜토리얼  (0) 2012.10.23
태그라이브러리 URI  (0) 2012.10.23
[centOS] apache2.2 + tomcat6 (yum 설치 성공 통합 정리)  (0) 2012.10.12
Apache+Tomcat 연동  (0) 2012.10.11
[CentOS] 6.2에 아파치 + 톰캣6 연동하기  (2) 2012.10.10
:

Apache+Tomcat 연동

Language/JSP 2012. 10. 11. 15:59

일단 process가 어떻게 돌아가는지 부터 알도록 하죠


아파치 -> mod_jk -> 톰캣 


연동 과정을 아는 분들은 이것만 보고도 아실 것이고 


모르는 분들은 설명을 들어주세요


아파치는 기본적으로 html 이나 그림 파일 같은 것을 읽습니다.


tomcat 은 그 외에도 jsp 파일을 컴파일 해서 읽을 수 있죠.


그래서 부하를 줄이기 위해 html 파일들은 아파치에서 jsp 파일은 톰캣에서


읽도록 분산을 시켜놓는데요...


원리는 간단합니다. 아파치와 톰캣이 각각 다른 Port  를 쓰게 하고


아파치 port 로 들어온 jsp 파일 요청 내용을 톰캣 port 로 링크를 걸어주는 것입니다.


그렇게 연결 해주는게 mod_jk 라는 것이구요.


(결국 모든 요청은 아파치 포트로 통일 된다는 것이군요 - 아파치 기본 포트가 80 포트니까요


80포트는 포트를 url 에 안써도 되는건 다들 아실 거라고 생각합니다.)


그럼 설치와 연동에 대해서 살펴보죠


설치 버전

아파치 2.2

톰캣 5.0

jdk 1.6

mod jk 1.2(커넥터 - 앞으로 이쪽 버전 밖에 안나오므로 이걸로 하면 되겠다)

받는것은 가이드 안해드립니다. 아파치 톰캣 사이트 가서 받으시고요

커넥터인 mod jk 는 톰캣 사이트에 connector 인가로 있습니다.


준비 단계

아파치 설치

아파치를 인터넷에서 받아서 압축을 푼 다음

./configure --prefix=/home/apache2 \

--enable-module=so \

--enable-rewrite \

--enable-so

한후 make

make install 로 설치 함


톰캣 설치

tar -zxvf jakarta-tomcat-5.0.28.tar.gz

mv jakarta-tomcat-5.0.28 /usr/local/tomcat-5.0.28


커넥터 설치

tar xvzf tomcat-connectors-1.2.30-src.tar.gz

./buildconf.sh

./configure --with-apxs=/usr/local/apache/bin/apxs

make

make install

mod_jk.so 가 아파치의 modules 폴더에 있는지 확인함

이렇게 하여 설치


연동 설정

 /usr/local/apache2/conf/httpd.conf 아래와 같이 추가

LoadModule jk_module modules/mod_jk.so

JkWorkersFile conf/workers.properties


JkMountFile conf/uriworkermap.properties


JkLogFile logs/mod_jk.log 

JkLogLevel error 

JkLogStampFormat "[%a %b %d %H:%M:%S %Y] " 

JkOptions +ForwardKeySize +ForwardURICompat -ForwardDirectories 

JkRequestLogFormat "%w %V %T"


JkMount /*.jsp default 

JkMount /*.do default

#여기서 default 는 workers.properties 의 default


Alias /jsp-examples "/usr/local/tomcat/webapps/jsp-examples/" 

<Directory "/jsp-examples">

    AllowOverride None

    Options None

    Order allow,deny

    Allow from all

</Directory>

#이건 임의로 연결 시켜주는 것이므로 이런식으로 프로젝트를 연결 시켜주면 됩니다.

Alias /servlets-examples "/usr/local/tomcat/webapps/servlets-examples/"

JkMount /jsp-examples/*.jsp default

JkMount /servlets-examples/* default

또한 


<IfModule dir_module>

    DirectoryIndex index.html index.jsp index.htm

</IfModule>


이부분이 원래 index.html 만 되어 있는데 뒤의 두개 붙여주면 편합니다.



/usr/local/apache2/conf/workers.properties 추가(간단하니까 vi 로 만드세요)

workers.tomcat_home=/usr/local/tomcat5.0.28-dcd2

workers.java_home=/usr/java/jdk1.6.0_17

ps=/

worker.list=default

worker.default.port=8009

worker.default.host=localhost

worker.default.type=ajp13

worker.default.lbfactor=1




/usr/local/apache2/conf/uriworkermap.properties 추가(간단하니까 vi 로 만드세요)

/*.do = default

/*.jsp = default



이게 잘 이해가 안가실 겁니다. worker.properties 에 8009 port 라는 부분을 주목해 볼 필요가


있습니다. tomcat 의 conf 폴더에 server.xml 을 보면


기본 port 는 8080 이고 ajp13 프로토콜은 8009 포트로 들어간다는 내용이 있습니다.


결국 아파치 포트로 들어가는 jsp 요청은 ajp13 프로토콜을 이용해서 8009 포트로 tomcat에


보내진다는 얘기지요.


확인을 하려면 


->아파치설치 경로 /bin/apachectl start 

->톰캣 설치 경로 /bin/startup.sh  

(아파치 먼저 올리고 톰캣 올려야 합니다.)



http://ip:port/jsp-examples/ 해보면 됩니다.

(ip,port 는 아파치 ip와 port 입니다.)


출처 - http://shonm.tistory.com/208

:

[CentOS] 6.2에 아파치 + 톰캣6 연동하기

Language/JSP 2012. 10. 10. 14:21

[CentOS] 6.2에 아파치 + 톰캣6 연동하기

아파치, 톰캣 연동하니 너무 새삼스럽지만, 아직도 이렇게 쓰는 사람들이 있을까 궁금하기도 하다.

톰캣에 웹서버가 내장되어 있어 간단한 웹페이지라면 그냥 톰캣 하나만 써도 되지만, 톰캣의 웹서버는 관리자 + 부하들 용임을 잊지 말자.

트래픽이 발생하는 컨텐츠라면 아파치 연동이 매우 중요하다는 사실.
이 글에서 설명할 순서는 이렇다.

물론 yum으로 지원하는 애들은 전부 yum으로 설치한다. ㅋㅋ
CentOS 버전이 5.x라면, 톰캣이 tomcat5만 지원하므로 다른 문서를 찾아보는게 좋다. ㅋㅋ

1. 아파치 설치

#yum install httpd
#yum install httpd-devel

httpd-devel 을 설치하는 이유는 커넥터 설치시 apxs를 사용해야 하기 때문. 바이너리 형태의 커넥터를 구하기란 하늘의 별따기. -_-;

테스트야 뭐..문제될게 하나도 없으므로 패스~
의심많은 분들은 http://localhost 또는 http://127.0.0.1 또는 http://domain 해보시길. 

2. Tomcat 설치

#yum install tomcat6
#yum install tomcat6-webapps
#yum install tomcat6-admin-webapps

필요한 관련패키지들은 알아서 다 설치되니 요거 세줄로 끝내자. ㅋ

Tomcat을 설치한 후에는 몇가지 설정을 변경해 줘야 한다.
먼저, web.xml 을 열어서 servlet invoker 관련내용의 주석을 풀어준다.

#vim /usr/share/tomcat6/conf/web.xml

// 풀어줘야 할 주석
가. 121줄 ~ 131줄

 <servlet>
   <servlet-name>invoker </servlet-name>
         .... 중략 ....
 </servlet>

나. 369줄 ~ 372줄

   <servlet-mapping>
     <servlet-name>invoker</servlet-name>
     <url-pattern>/servlet/*</url-pattern>
   </servlet-mapping>

변경이 끝났으면 연동을 위해 ROOT 폴더를 통합하자. 왜? jsp페이지 따로, html페이지 따로 구분해서 넣어두고 관리하면 복잡해지니까. ㅋㅋ
사실은, 귀찮더라도 이렇게 관리하는게 좋다. 

#cd /usr/share/tomcat6/webapps
#ln -s /var/www/html /usr/share/tomcat6/webapps/ROOT

Tomcat6 부터는 context 관리를 context.xml에서 따로 관리하므로 한가지 더 수정해주어야 한다.

#vim /usr/share/tomcat6/conf/context.xml
// 태그를 아래와 같이 수정

<Context reloadable="true" privileged="true" >

#/etc/init.d/tomcat6 start

3. Connector 설치
설치하기 전, 브라우저로 해당디렉토리를 찾아가서 다운 받을 버전을 찾는다. 여기서는 tomcat-connectors-1.2.37-src.tar.gz 파일을 쓸 것이다.

#wget http://www.apache.org/dist/tomcat/tomcat-connectors/jk/tomcat-connenctors-1.2.37-src.tar.gz
# tar xvzf tomcat*
# cd tomcat*
# cd native
# ./configure –with-apxs=/usr/sbin/apxs
#make
#make install

이렇게 설치가 끝나고 나면, /etc/httpd/modules 에 mod_jk.so파일이 생성되었나 확인한다.
설치가 되었다면, 이제 workers.properties 파일을 생성한다.

4. 연동하기
# cd /etc/httpd/conf.d/
# vim workers.properties

workers.properties 내용

jkWorkersFile  /etc/httpd/conf.d/workers.properties
jkLogFile  /etc/httpd/logs/mod_jk.log
jkShmFile /usr/tomcat/logs/jk.shm
jkMount /*.jsp ajp13
jkMount /*.do ajp13
jkMount /article/* ajp13
jkMount /uploadManager ajp13
jkMount /downManager ajp13
jkMount /alice-upload ajp13
jkMount /servlet/* ajp13

# vim /etc/httpd/conf/httpd.conf
– DirectoryIndex 항목에 index.jsp 추가
– LoadModule jk_module modules/mod_jk.so 항목 추가

이렇게 연동은 끝! 테스트는 알아서들~ ^_^/


출처 - http://www.gdo.kr/post/4237/



[[ 연동 테스트 ]]


아파치의 기본 작업폴더(한마디로 루트폴더라는 말임)를 톰캣 root 폴더로 변경

 

vim /etc/httpd/conf/httpd.conf 수정


DocumentRoot "/var/lib/tomcat6/webapps/ROOT"

<Directory "/var/lib/tomcat6/webapps/ROOT">

 

<IfModule dir_module>

    DirectoryIndex index.html index.jsp
</IfModule>

 

http://localhost

http://localhost/index.jsp

http://localhost/test.php

: