자꾸 까먹는 경향이 있어 기록용으로 저장해 둡니다. JSP에서 간단한 프로그램 로직을 구현하기 위해 JSTL을 사용하는데요 다양한 JSTL용 태그 라이브러리가 제공되지만 이 글에서는 플로우등을 조정하기 위한 core만을 보도록 하겠습니다.

1. JSTL을 사용하기 위한 라이브러리를 다운

[이곳] 에서 다운받을 수 있습니다. 현재 시점에서는 1.1.2가 최신버전이군요.

2. 라이브러리 추가

다운받은 파일을 열어보면 standard.jar 와 jstl.jar 두개의 파일이 존재합니다. 둘 모두를 개발중인 프로젝트에 추가합니다.

3. JSP 페이지의 맨 위에 taglib 정의 추가

프로젝트의 맨 위에 다음을 추가해 줍니다.
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>

4. JSTL 문법을 사용 (몇가지 예시)

<c:forEach>를 사용한 특정 범위의 숫자값을 순환
<table>
<tr><th>Value</th>
   
<th>Square</th></tr>
<c:forEach var="x" begin="0" end="10" step="2">
 
<tr><td><c:out value="${x}"/></td>
     
<td><c:out value="${x * x}"/></td></tr>
</c:forEach>
</table>

위의 코드는 0부터 10까지 2씩 증가하는 순환문을 뜻합니다. 현재의 증가값은 변수 x에 저장됩니다. 결과는 다음과 같이 출력이 됩니다.
사용자 삽입 이미지


<c:forEach>태그를 이용한 Collection형 배열을 처리
forEach는 Collection, Map, Iterator, Enumeration, Array(Object/Primitive), 쉼표로 구분된 String, SQL쿼리 결과값(javax.servlet.jsp.jstl.sql.Result) 등의 순환을 지원합니다.
<table>

 
<c:forEach items="${entryList}" var="blogEntry">
   
<tr><td align="left" class="blogTitle">
     
<c:out value="${blogEntry.title}" escapeXml="false"/>
   
</td></tr>
   
<tr><td align="left" class="blogText">
     
<c:out value="${blogEntry.text}" escapeXml="false"/>
   
</td></tr>
 
</c:forEach>
</table>

위의 모드는 블로그 글을 순환하며 출력하는 예시입니다. ${entryList}는 title, text를 멤버 변수로 갖는 특정 객체의 집합 배열입니다. 현재 순환중인 객체가 blogEntry에 저장되며 .을 사용하여 title과 text를 출력하는 예시입니다.

여기에 새롭게 현재 순환중의 상태를 확인할 수 있는 varStatus라는 값을 사용할 수 있습니다. 말을 길게 할 필요없이 코드로 보여드리겠습니다.
<table>
 
<c:forEach items=
   
"${entryList}" var="blogEntry" varStatus="status">
   
<tr><td align="left" class="blogTitle">
     
<c:out value="${status.count}"/>.
     
<c:out value="${blogEntry.title}" escapeXml="false"/>
   
</td></tr>
   
<tr><td align="left" class="blogText">
     
<c:out value="${blogEntry.text}" escapeXml="false"/>
   
</td></tr>
 
</c:forEach>
</table>

위에 추가된 ${status.count}에서는 현재 몇번째 순환중인지 값을 확인할 수 있습니다.
사용가능한 변수의 종류는 다음과 같습니다.

current : 현재 순환중인 아이템을 가져옵니다.
index : 현재 순환중인 아이템의 인덱스(0베이스)를 가져옵니다.
count : 현재 순환중인 아이템의 인덱스(1베이스)를 가져옵니다.
first : 현재 순환중인 아이템이 첫번째 아이템인지 여부를 확인합니다. (Boolean)
last : 현재 순환중인 아이템이 마지막 아이템인지 여부를 확인합니다. (Boolean)
begin : forEach에서 지정할 수 있는 begin값을 가져옵니다.
end : forEach에서 지정할 수 있는 end값을 가져옵니다.
step : forEach에서 지정할 수 있는 step값을 가져옵니다.

<c:if>를 사용한 조건문 활용
다음의 코드는 첫번째 아이템이 순환중일 경우 블로그글이 언제 작성되었는지 날짜를 출력하도록 수정된 코드입니다. test안에 Boolean형이 반환될 수 있는 어떤 수식을 사용해도 됩니다.
<table>
 
<c:forEach items=
   
"${entryList}" var="blogEntry" varStatus="status">
   
<c:if test="${status.first}">
     
<tr><td align="left" class="blogDate">
           
<c:out value="${blogEntry.created}"/>
     
</td></tr>
   
</c:if>
   
<tr><td align="left" class="blogTitle">
     
<c:out value="${blogEntry.title}" escapeXml="false"/>
   
</td></tr>
   
<tr><td align="left" class="blogText">
     
<c:out value="${blogEntry.text}" escapeXml="false"/>
   
</td></tr>
 
</c:forEach>
</table>

그런데 정말 희안하게도 위의 <c:if>에는 else가 존재하지 않습니다. 그래서 다음의 방법을 사용하곤 합니다.

<c:choose>를 사용한 다중 조건문 활용
다음의 예제는 pageContext라는 컨텍스트 객체에 접근하여 요청의 스킴을 읽어오는 예제입니다. HTTP로 접속했을때와 HTTPS를 통해 접속했을때 다른 메시지를 출력하는 예시입니다. 추가로 둘다 아닐경우 오류 메시지를 출력하도록 하였습니다.
<c:choose>
 
<c:when test="${pageContext.request.scheme eq 'http'}">
    This is an insecure Web session.
 
</c:when>
 
<c:when test="${pageContext.request.scheme eq 'https'}">
    This is a secure Web session.
 
</c:when>
 
<c:otherwise>
    You are using an unrecognized Web protocol. How did this happen?!
 
</c:otherwise>
</c:choose>


<c:url>를 사용하여 주소 생성
JSTL에서는 <c:url>을 지원하는데요 이 태그는 현재의 서블릿 컨텍스트 이름을 자동으로 앞에 붙여주고 세션관리와 파라미터의 이름과 값의 인코딩을 자동으로 지원합니다. 기본적인 사용법은 다음과 같습니다.
<a href="<c:url value='/content/sitemap.jsp'/>">View sitemap</a>

간단하죠? 여기서 더 나아가 <c:param>을 사용하여 파라미터를 추가할 수 있습니다.
<c:url value="/content/search.jsp">
 
<c:param name="keyword" value="${searchTerm}"/>
 
<c:param name="month" value="02/2003"/>
</c:url>

위의 코드로써 생성되는 URL은 기본적으로 서블릿컨텍스트가 붙게 되며 세션쿠키를 사용중이라면 추가적으로 파라미터들만 추가되며 다음의 모습을 가지게 됩니다.
/blog/content/search.jsp?keyword=foo+bar&month=02%2F2003

만약에 세션 쿠키가 존재하지 않는다면 다음과 같은 결과를 나타내게 됩니다. 마찬가지로 파라미터들은 URL 인코딩되어 출력됩니다.

/blog/content/search.jsp;jsessionid=233379C7CD2D0ED2E9F3963906DB4290
?keyword=foo+bar&month=02%2F2003


<c:import>를 사용하여 페이지 첨부하기
JSP에는 기본적으로 두가지 방법의 페이지 안에 다른 컨텐츠를 추가하는 방법이 존재합니다. include지시자와 <jsp:include> 액션이 있는데요. 하지만 둘 모두 같은 웹 어플리케이션 또는 서블릿 컨텍스트 안에있는 페이지만을 불어들일 수 있습니다. core라이브러리에 있는 <c:import>액션은 좀더 일반적이고 강력한 기능을 가진 <jsp:include>로 볼 수 있습니다. 사용 문법은<c:url>과 매우 배슷하며 심지어 <c:param>도 그대로 사용할 수 있습니다.
<c:import url="ftp://ftp.example.com/package/README"/>

<c:import>에는 var와 scope 두가지 필수적이지 않은 속성이 존재하는데요. var의 경우에는 불러들인 페이지를 곧바로 출력하지 않고 String형 변수로 담아두기 위해 사용됩니다. scope는 이 변수의 스코프를 지정할 수 있습니다. 기본적으로 page로 되어있습니다.

<c:catch>로 예외처리 하기
길게 설명할 필요가 없을것 같네요. <c:import>는 ftp에도 접속이 가능합니다. 다음에 보여드릴 코드의 경우 만약에 해당 위치에 파일이 존재하지 않거나 네트워크의 문제로 페이지를 불러올 수 없는 상황이라면 예외가 발생할 것입니다. 예외가 발생할 경우 var에 예외가 저장됩니다. <c:if>를 통해 예외가 발생했는지 확인하는 예제입니다
<c:catch var="exception">
 
<c:import url="ftp://ftp.example.com/package/README"/>
</c:catch>
<c:if test="${not empty exception}">
  Sorry, the remote content is not currently available.
</c:if>


<c:redirect>를 이용한 페이지 리다이렉트 하기
이 액션은 <jsp:forward> 액션과도 매우 흡사합니다. 하지만 이 기능의 경우에는 서버사이드에서 구현된 요청형태만을 포워딩 합니다. 이게 무슨 말이냐면 포워딩의 경우에는 사용자 입장에서 보면 페이지의 이동 없이 다른 페이지를 띄워줄 수 있지만 리다이렉트의 경우에는 브라우저에 의해 페이지의 이동이 일어나게 됩니다. 하지만 <c:redirect>액션이 좀 더 유연합니다.<jsp:forward>의 경우에는 현재 같은 서블릿 컨텍스트 내의 다른 페이지로만 이동 할 수 있기 때문입니다.

참고 : http://www.ibm.com/developerworks/java/library/j-jstl0318/




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

 

JSP에서 JSTL과 EL(Expression Language) 사용하기 JAVA


Posted by linuxism
,




Struts에서 Spring으로 ...

당신은 이 글을 통해 Struts애플리케이션에서 Spring MVC애플리케이션으로 변형하는 방법뿐 아니라 두 프레임워크 사이의 논리적인 맵핑과 Struts개념을 Spring MVC개념에 관련시키는 수단을 배울것이다.

 

사실 Struts프레임워크는 기술발전이나 채택이 감소하기 시작하고 있다고 몇몇 사람들이 제기한다.

사실 Struts의 책임 개발자인 Craig McClanahan또한 Struts사용자에게 새로운 웹 프레임워크로의 이전을 권하고 있는 상황이다. (허걱...)

 

반면에 J2EE웹 공간에서, Spring MVC는 꾸준한 채택과 자바 개발자의 주의를 끌고 있다.

가장 인기있는 Spring프레임워크는 잘 디자인되었으며, 잘 만들어졌고, 혁신적이다.

그래서 많은 Struts사용자는 Struts를 위한 대체 프레임워크처럼 Spring을 MVC를 사용할것이다.

이 글은 Struts애플리케이션을 Spring MVC로 이전하길 원하는 개발자들을 도와준다.

그리고 다음의 두가지 핵심부분으로 나누어져있다.

  1. Struts와 Spring MVC프레임워크의 기본 개념사이의 논리적인 맵핑.
  2. 이전 대체물을 위한 기본적인 추천사항들.  

논리적인 맵핑 : 다른 프레임워크간의 유사함.

Struts와 Spring은 MVC패턴 구현에서 본질적으로 유사하다.

둘다 핵심 J2EE컴포넌트인 Servlet과 JSP에 기반한 모델2 타입의 개발방식을 주로 할려는 경향이 있다.

Struts에 친숙한 개발자는 하나의 프레임워크에서 다른것으로 개념적으로 쉽게 이주할수 있다.

두가지 프레임워크 모두 View, Controller, Model의 역활을 제공하는 컴포넌트를 명백하게 서술하고 있다.

유사성은 구현레벨에서 멈춘다.

Struts디자인은 각각의 사용자지정 action이 Struts Action컴포넌트의 구조적인 상속이 된다는것을 의미하는 견고한 상속에 기반을 둔다.

Spring컨트롤러는 인터페이스이기 때문에, 어떠한 컴포넌트도 컨트롤러의 역활을 수행할수 있다.

이것은 애플리케이션 디자이너에게 컴포넌트 디자인의 좀더 나은 유연함을 제공한다.

프레임워크 컴포넌트 레벨에서 Struts는 Form Beans(정적이거나 동적인), Actions, Action Mappings, Action Forwards, 그리고 Request Processors와 같은 Struts 특유의 객체 사용을 요구한다.

Spring MVC는 주요한 컴포넌트가 인터페이스처럼 정의된것처럼 좀더 유연하다.

 

Struts는 오직 웹 프레임워크일 뿐이다.

Struts는 애플리케이션 개발에서 오직 presentation계층에만 할당한다.

반면에 Spring MVC는 비지니스 컴포넌트에다가 Spring 기업용 개발의 다른 부분을 관리하는 Spring 프레임워크의 다른 부분과 완벽하게 통합되는 Spring프레임워크의 주요한 부분일뿐이다.

이제 좀더 상세하게 프레임워크 컴포넌트를 보자.

 

Struts Actions는 대략 Spring Controllers이다.

Struts에서 Action은 프레임워크의 핵심 "processing"객체이다.

그것들은 MVC패턴에서 컨트롤러의 역활을 수행한다.

Struts Actions의 Spring이 가진 대안은 Controller인터페이스이다.

반면에 Controller는 Spring에서 사용자 입력을 처리하고 View컴포넌트로 전달한다.

Struts Actions과 Spring Controller사이의 가장 명백한 차이점은

Actions는 추상 클래스이고 Controllers는 인터페이스라는 것이다.

Spring MVC 컨트롤러처럼 설정되기 위해서, 객체는 오직 다음의 메소드를 구현할 필요가 있을것이다.

ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response)

     throws Exception;

이 디자인(인터페이스에 의한 디자인)은 애플리케이션과 프레임워크간의 커플링을 최소화한다.

또한 이것은 Controllers의 디자인에서 구조적으로 좀더 유연성을 제공한다.

이것을 염두해 두고, Struts에서 Spring으로의 가장 간단한 중계역활을 하는 이전(transition) 단계는 Action을 다시 쓰는 것.

그래서 그것들은 Controller인터페이스를 구현하고 존재하는 코드를 재사용하는것이다.

이것은 애플리케이션 작동을 유지하는 동안 모든 Struts의존성의 제거를 증가시키는것을 허용한다.

Spring은 다른 Action대체물도 제공한다.

많은 수의 프레임워크가 제공하는 Controller구현물은 가장 공통적인 웹애플리케이션 작업에 대응된다.

몇몇 제공되는 Controller는 당신이 친숙한 Struts Action에 좀더 특성화된 것에 대응된다.

예를 들어, 당신이 DispatchActions을 사용한다면, MultiActionControllers와 좀더 잘 다듬어진 AbstractWizardFormControllers가 도움을 줄것이다.

다른 Controller구현문은 Spring MVC에 딸려나온다.

 

Action Forms이 없다.

Spring프레임워크내에서 가장 크고 가장 긍정적인 차이점중에 하나는 특성화된 ActionForm객체가 없다는 것이다.

프레임워크는 HTTP폼 값을 직접적으로 POJO에 바인딩하는것을 지원한다.

이 기능은 생성하고 유지할 클래스의 수를 제한하여 애플리케이션 유지관리를 단순화한다.

이 경우, 이전(migration)은 폼빈즈를 삭제하고 직접적으로 도메인 객체를 사용하는것을 의미한다.

어쨌든, 이것은 당신이 폼입력과 도메인 객체간의 맵핑처럼 Form Bean객체를 사용할수 있다면 필수단계는 아니다.

Spring MVC에서, AbstractFormController구현물을 확장하는 특수한 목적의 Controllers는 폼을 지지하는 빈즈를 지원한다. AbstractFormController의 사용자지정 하위클래스는 폼객체처럼 폼을 지지하는(Command) Beans를 사용한다.

다시 말해, 이러한 빈즈를 정의하는 요구사항은 없다.

Command객체는 java.lang.Object의 어떠한 하위클래스도 될수 있다.

 

ActionForwards vs. ModelAndView

Struts ActionMapping에서, 객체는 표현자원(Actions, JSPs, Tiles, HTML 파일들 등등.)을 가리킨다.

Spring MVC에서 ActionMapping에 대해 가장 가까운 의미의 컴포넌트는 ModelAndView인터페이스이다.

Spring Controllers는 사용자에 의해 구현될수 있는것처럼 ModelAndView인터페이스의 구현물을 반환한다.

또는 당신이 원한다면 Spring MVC에 의해 제공되는 ModelAndView구현물을 사용할수도 있다.

내포하는 이름처럼, ModelAndView객체는 Model과 View컴포넌트를 가진다.

Model컴포넌트는 View컴포넌트를 통해 표시되기 위한 비지니스 객체를 포함한다.

시나리오에 따르면, ModelAndView구현물은 포함된 어떠한 Model컴포넌트를 가지지 않는다.

그것들은 아마도 실질적인 View컴포넌트(JSP, XSLT, Tiles, HTML, XML, 등등)의 몇몇 형태로 이끌것이다.

Controller구현물에서 처럼, 나는 Spring MVC가 제공하는 Model의 구현물과 View인터페이스 그리고 View해석자(Resolver)를 조사하는것을 강력히 권한다.

 

사용자지정 JSP 태그들

Spring MVC는 표준 JSP태그 라이브러리의 의미있는 힘을 신뢰한다.

Struts와는 달리, Spring MVC는 HTML, logic, 또는 bean처리를 위한 분리된 태그 라이브러리를 제공하지 않는다.

이것은 Command객체에서 Web form으로의 바인딩을 가능하게 하는 작은 태그라이브러리만을 제공한다.

당신은 다른 모든 작업을 위해 표준적인 템플릿 라이브러리(JSTL)를 사용할것이다.

 

유효성체크(Validation)

만약 당신이 Struts의 Commons Validator을 사용한다면, 당신은 Spring내에서 완벽하게 재사용할수 있을것이다.

Spring 1.2는 Commons기반 유효성체크를 지원하지 않지만 Spring MVC의 "sandbox"버전은 Commons Validator마크업 (validator.xml 과 validation-rules.xml)으로 쓰여진 유효성체크 정의의 재사용을 지원한다.

유효성체크 선언를 가진 당신의 XML파일을 버리지 마라. 그것들은 Spring내에서 재사용가능할것이다.

 

Error 와 Validation Messages

좀더 좋은 소식이 있다. Spring은 동일한 형태로 Struts message번들을 인식한다.

Spring MVC내 존재하는 Message자원들을 재사용하기 위해서, 당신은 Spring MVC 설정파일내 messageSource가 다음처럼 설정한다.

"messageSource"
class="org.springframework.context.support.ResourceBundleMessageSource">
 "basename">
  resources.ApplicationResources
 
 

또한, 당신은 Controller구현물내 messageSource프라퍼티로써 당신의 Controller처럼 이것을 사용할 필요가 있다.

요구되는 변경사항은 없다.

 

Dispatcher Servlet

Spring MVC는 Request Processor/Action Servlet의 자신만의 버전을 가진다.

이것은 URL표시그룹으로 맵핑되는 DispatcherServlet이다.

Dispatcher Servlet의 개념을 이해하기 위해서, Controller를 Spring MVC내 설정하는 방법을 보자.

 

설정파일들

Struts사용자라면, 당신은 모든 forward, action mapping, form definition 그리고 플러그인 선언등을 가지는 적어도 하나의 struts-config.xml파일을 사용한다.

Spring MVC에서, 모든 웹 애플리케이션관련 컨트롤러 선언은 Spring Beans처럼 설정된다.

하나이상의 Dispatcher Controller는 웹자원을 위한 모든 요청을 적당한 Controller로 보낸다.

예를 들면, 만약 당신이 ".do"애플리케이션을 Spring MVC애플리케이션으로 다시 맵핑시키길 원한다면,

당신은 애플리케이션의 web.xml에 다음처럼 서블릿 맵핑을 등록하라.

(나는 당신이 .do 확장자를 사용하는것을 실질적으로 권하지 않는다. Struts만 사용하는 규칙처럼 ".do"를 남겨두라.)


 applicationDispatcher 
 class>
  org.springframework.web.servlet.DispatcherServlet
 class>
 1


        ...


 applicationDispatcher
 *.do
  

지금 당신은 Spring MVC Controller선언을 가진 Spring 설정파일(applicationDispatcher-servlet.xml)을 가진다.

"-servlet.xml"는 applicationDispatcher파일을 위한 접미사이다.

이것은 Spring MVC맵핑파일을 자동 리로드하는 DispatcherServlet을 가능하게 하는 Spring MVC규칙이다.

Spring MVC내에서 웹 action을 적당한 컨트롤러로 맵핑하는것은 매우 쉽다.

이것은 Spring애플리케이션의 일부처럼 같은 "wiring"형태로 수행된다.

다음의 예제는 URL expression /showCatalog.do를 Controller showCatalog로 포워드하는 방법을 보여준다.

"urlMapping"
class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
 "mappings">
  
          "/showCatalog.do">showCatalog
  
 

Controller showCatalog는 Controller인터페이스를 구현하는 클래스에 의해 구현된 다른 빈처럼 설정될것이다.

이 예제에서, showCatalog는 URL요청을 카테고리로 명명된 ModelAndView컴포넌트로 포워드하는 간단한 포워딩 컨트롤러에 지나지 않는다.

"showCatalog" name="showCatalog"
class="org.springframework.web.servlet.mvc.ParameterizableViewController">
 "viewName" value="catalog"/> 
 
 

Struts에서 Spring MVC로의 이전 경로.

Struts애플리케이션을 Spring MVC로 이전하기 위해서는 3가지 접근법이 있다.

 

몇몇은 애플리케이션을 점차적으로 이전할것이다.

다른것들은 Struts프레임워크를 완벽하게 포기하고 완전히 다시 쓰는 작업을 수행할것이다.

접근법들은 아래에서 개요를 말하고, 이전의 완벽함 순서대로 정렬된다.

 

1. Spring은 Struts컴포넌트를 가능하게 한다.

천천히 이전하길 원하는 사람들을 위해, 첫번째이고 완벽하게 이전에 따른 무리가 없는것은.?

Spring Beans처럼 Struts Actions를 가능하게 하는것이다.

이것은 간단한 작업이고, Spring문서에 잘 설명되어 있다.

이것은 Struts코드에 대한 변경을 요구하지 않지만, 이것은 Spring Beans처럼 처리되기 위해 Struts Controller컴포넌트, Actions를 가능하게 한다.

이 처리로, Actions은 Spring Beans의 상태를 상속한다.

그러므로, Spring Controller처럼 많은 것을 보기 시작하라.

늦으면서 단계별로 현명한 이전은 이 처리로 가능하다.

각각의 Action은 애플리케이션 재작성과 현재 웹 연속물의 중단없이 Spring Controller에 의해 한번에 대체될수 있다.

 

2. Tiles를 사용하는 Spring프레임워크에 의해 완전히 제공되는 다른 대체물은 순수한 "view" 프레임워크처럼 Tiles를 유지하는 동안 Spring MVC컴포넌트로 Struts Controller과 관련 컴포넌트(Actions, Form Beans, 등등)를 대체하는것이다.

Spring MVC는 Tiles에 대한 특정 대안을 가지지 않는다.

그래서 구조는 Tiles에 대한 것을 유지하기로 결정하고 Spring MVC를 통해 그 작업을 하도록 만든다.

이 접근법의 심각한 단점은 당신이 웹애플리케이션 내 두개의 다양한 웹 프레임워크를 효과적으로 유지관리하기 위해 유지관리를 위한 많은 노력과 두가지 프레임워크를 위한 추가적인 학습이 필요하다는 것이다.

 

3. 완전한 이전 완전한 이전은 Struts프레임워크의 모든 컴포넌트를 Spring MVC로 교체하는것을 의미한다.

이 처리의 마지막에는 Struts특성의 컴포넌트는 애플리케이션에 남지않는다.


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

Posted by linuxism
,

 

이클립스를 실행합니다.

퍼스펙티브는 Java 를 기준으로 설명합니다.

 

새로운 자바 프로젝트를 만듭니다.

프로젝트 이름은 MyBatis로 하겠습니다.

 

퍼스펙티브는 Java 로 하고 새로운 프로젝트를 만들면 프로젝트 이름의 폴더 아래 서브 폴더 bin 폴더와 src 폴더가 만들어지게 되죠.

MyBatis 실습을 위해서 저는 lib 폴더를 하나 더 만들겠습니다.

lib 롤더에는 MyBatis와 MySQL용 JDBC 드라이버 파일을 복사해 넣습니다.

 

MyBatis는 http://www.mybatis.org/ 에서 Java 메뉴에서 찾습니다.

MySQL용 JDBC 드라이버는 http://www.mysql.com/ 에서 찾을 수 있습니다.

 

이클립스에서 Package뷰에서 MyBatis 프로젝트에 마우스로 활성화 한 후,

마우스 오른쪽 키를 이용해서 컨텍스트 메뉴를 보이게 한 후 Build Path , Configure Build Path 를 차례로 선택합니다.

이어 나온 다이얼로그 박스에서 Libraries 탭을 선택하고 Add External JARs를 클릭하여 MyBatis팩키지와 MySQL JDBC 드라이버 팩키지를 추가합니다.

 

다음으로

src폴더에서 db.properties 와 Configuration.xml 를 아래와 같이 작성합니다.

 

db.properties 파일 내용

driver=com.mysql.jdbc.Driver

url=jdbc:mysql://localhost:3306/javaschool

username=javaschool

password=1234

 

Configuration.xml 파일 내용

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

<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd">

<configuration>

<properties resource="db.properties" />

<environments default="development">

<environment id="development">

<transactionManager type="JDBC" />

<dataSource type="POOLED">

<property name="driver" value="${driver}" />

<property name="url" value="${url}" />

<property name="username" value="${username}" />

<property name="password" value="${password}" />

</dataSource>

</environment>

</environments>

<mappers>

<mapper resource="User.xml" />

</mappers>

</configuration>

 

다음으로 User.java를 아래와 같이 작성합니다.

 

package net.java_school.mybatis.example;

public class User {

private String email;

private String name;

private String passwd;

 

public String getEmail() {

return email;

}

 

public void setEmail(String email) {

this.email = email;

}

 

public String getName() {

return name;

}

 

public void setName(String name) {

this.name = name;

}

 

public String getPasswd() {

return passwd;

}

 

public void setPasswd(String passwd) {

this.passwd = passwd;

}

 

public String toString() {

String result = null;

result = String.format("[User:Email=%s,Password=%s,Name=%s]", email,passwd,name);

return result;

}

}

 

다음으로 src폴더에서 User.xml 파일을 아래와 같이 작성합니다.

 

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

<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="User">

<!-- 리절트 맵 정의 -->

<resultMap id="UserResult" type="net.java_school.mybatis.example.User">

<result property="email" column="email" />

<result property="name" column="name" />

<result property="passwd" column="passwd" />

</resultMap>

 

<!-- select 쿼리문 정의 -->

<select id="selectAllUsers" resultMap="UserResult">

select * from user

</select>

 

</mapper>

 

마지막으로 main메소드가 있는 UserTest.java 파일을 아래와 같이 작성합니다.

 

package net.java_school.mybatis.example;

 

import java.io.*;

import org.apache.ibatis.io.*;

import org.apache.ibatis.session.*;

import java.util.*;

 

public class UserTest {

@SuppressWarnings("unchecked")

public static void main(String[] args) {

String resource = "Configuration.xml";

Reader reader;

 

try {

reader = Resources.getResourceAsReader(resource);

SqlSessionFactory sqlMapper = new SqlSessionFactoryBuilder().build(reader);

SqlSession session = sqlMapper.openSession();

try {

List<User> list = (List<User>)session.selectList("selectAllUsers");

for(User user : list) {

System.out.println(user);

}

} finally {

session.close();

}

} catch (IOException e) {

e.printStackTrace();

}

}

}

 

이클립스에서 실행합니다.

명령프롬프트에서 실행할 때는 bin 디렉토리로 이동 후 아래와 같이 classpath 옵션을 적절히 추가해 주어야 합니다.

 

kim@kim-android:~/java/MyBatis/bin$ java -classpath /home/kim/java/MyBatis/lib/mybatis-3.0.5.jar:/home/kim/java/MyBatis/lib/mysql-connector-java-5.1.17-bin.jar:. net.java_school.mybatis.example.UserTest

참고문서

스트럿츠2 프로그래밍 입문 -대림출판사,성윤정,이명숙 저 - Chapter13

 

출처 - http://cafe.naver.com/webprogramguide.cafe?iframe_url=/ArticleRead.nhn%3Farticleid=438&


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


mybatis 3.0 에서 resultMap 활용 ◈ Framework/mybatis 3.x2011/12/01 20:37

1. 하나의 테이블에 대한 결과 조회

 

         <resultMap id="bbsDataResult" type="kr.xboard.dao.bbsdata.BbsDataBean">

                  <id property="bbsId" column="S_BBS_ID" javaType="java.lang.String"/>

                  <id property="bbsIdx" column="I_BBS_IDX" javaType="int"/>

                  <result property="parentIdx" column="I_PARENT_IDX" javaType="int"/>

                  <result property="idxLeft" column="I_IDX_LEFT" javaType="int"/>

                  <result property="idxRight" column="I_IDX_RIGHT" javaType="int"/>

                  <result property="bbsTitle" column="S_BBS_TITLE" javaType="java.lang.String"/>

                  <result property="bbsDesc" column="S_BBS_DESC" javaType="java.lang.String"/>

         </resultMap>

 

         <select id="getBbsDataList" parameterType="BbsDataBean" resultMap="bbsDataResult">

         <!-- bbs_data 의 목록 -->

                  SELECT S_BBS_ID,

                              I_BBS_IDX,

                              I_PARENT_IDX,

                              I_IDX_LEFT,

                              I_IDX_RIGHT,

                              S_BBS_TITLE,

                              S_BBS_DESC

                    FROM bbs_data

                  <where>

                           <if test="bbsId != null and bbsId != ''">

                                   AND S_BBS_ID = #{bbsId}

                           </if>

                           <if test="bbsIdx != null and bbsIdx != ''">

                                   AND I_BBS_IDX = #{bbsIdx}

                           </if>

                  </where>

         </select>

 

getBbsDataList 쿼리에서 결과가 bbsDataResult 로 맵핑이 된다.

resultmap  id 는 pk 여부를 나타내며이후 설명할 association, collection 에서 중요하게 사용된다.

 

게시판 내용을 보기를 하기 위해서는

게시판에 대한 기본 정보 (bbs_info) 와 게시글 (bbs_data), 게시글에 첨부 파일(bbs_file), 게시글에 대한 덧글 (bbs_comment)가 있을 수 있다.

이와 같이 4개의 테이블에 대해 각각 쿼리를 작성하지 않고,

하나의 resultmap 에서 처리 가능하도록 해보자

 

 

Entity Generator 로 생성된 BbsDataBean 파일에 다음과 같이

게시판 정보 (BbsInfoBean), 첨부파일 (BbsFileBean), 덧글 (BbsCommentBean) 을 각각 등록한다.

BbsInfoBean 은 게시글에 대해 1개의 row 를 가지고

BbsFileBean 과 BbsCommentBean  n개의 row 를 가질 수 있다.

 

kr.xboard.dao.bbsdata.BbsDataBean.java

 

public class BbsDataBean {

        

 

         /**

          * 게시판 정보

          */

         public BbsInfoBean bbsInfoBean;

        

         /**

          * 게시물 파일 목록

          */

         public List<BbsFileBean> bbsFileBeans;

        

         /**

          * 게시물 덧글 목록

          */

         public List<BbsCommentBean> bbsCommentBeans;

        

 

    /**

     * bbs_data.S_BBS_ID

     * defaultValue = ''

     *

     * 게시판 코드

     */

    private String bbsId = "";

 

sqlmap.xml 파일에 수정된 BbsDataBean 파일에 대응하는 resultMap 을 생성한다.

 

kr.xboard.dao.bbsdata.BbsData-sqlmap.xml

 

         <resultMap id="bbsDataExResult" extends="bbsDataResult" type="BbsDataBean">

                  <association property="bbsInfoBean" column="{bbsId=S_BBS_ID}"select="kr.xboard.dao.bbsinfo.BbsInfoDao.getBbsInfoItem"/>

                  <collection property="bbsFileBeans" ofType="BbsFileBean" column="{bbsId=S_BBS_ID,bbsIdx=I_BBS_IDX}" select="kr.xboard.dao.bbsfile.BbsFileDao.getBbsFileList"/>

                  <collection property="bbsCommentBeans" ofType="BbsCommentBean" column="{bbsId=S_BBS_ID,bbsIdx=I_BBS_IDX}"select="kr.xboard.dao.bbscomment.BbsCommentDao.getBbsCommentList"/>

         </resultMap>     

 

select="kr.xboard.dao.bbsinfo.BbsInfoDao.getBbsInfoItem"

 getBbsInfoItem 은 kr.xboard.dao.bbsInfo.BbsInfo-sqlmap.xml 파일에 존재한다.

column="{bbsId=S_BBS_ID}"

의 bbsId  pk 값을 나타내며, getBbsInfoItem select query  resultMap 

 

         <resultMap id="bbsInfoResult" type="kr.xboard.dao.bbsinfo.BbsInfoBean">

                  <id property="bbsId" column="S_BBS_ID" javaType="java.lang.String"/>

 

에서 id 로 등록되어 있다.

column 의 값에 따라 select 에서 수행되는 쿼리의 #{bbsId} 값이 맵핑이 된다.

 

이제 getBbsDataItem  resultMap 을 새로 추가한 bbsDataExResult 로 변경한 후

 

         <select id="getBbsDataItem" parameterType="BbsDataBean" resultMap="bbsDataExResult">

         <!-- bbs_data 의 상세 내역 -->

                  SELECT S_BBS_ID,

                              I_BBS_IDX,

                              I_PARENT_IDX,

                              I_IDX_LEFT,

                              I_IDX_RIGHT,

                              S_BBS_TITLE,

                              S_BBS_DESC

                    FROM bbs_data

                  <where>

                           <if test="bbsId != null and bbsId != ''">

                                   AND S_BBS_ID = #{bbsId}

                           </if>

                           <if test="bbsIdx != null and bbsIdx != ''">

                                   AND I_BBS_IDX = #{bbsIdx}

                           </if>

                  </where>

         </select>

 

테이블에 몇개의 데이터를 추가하자.

그리고 test.xboard.BbsDataControllerTest.java 파일을 열어

 

@Test

    public void getBbsDataItemTest () {

                  BbsDataBean bean = new BbsDataBean();

                  bean.setBbsId("1");                // 테스트용

                  bean.setBbsIdx(1);                 // 테스트용

                  bbsDataController.getBbsDataItem(bean);

    }   

 

bbsid, bbsidx 를 입력한 후

 

JUnit Test 를 수행하면 오류 없이 정상적으로 동작된다.

 

P6Spy 로그를 보면

 

bbs_data 쿼리가 수행되기 이전에

bbs_info, bbs_file, bbs_comment 에 각각 쿼리가 수행되는 것을 확인할 수 있다.

 

 

 

복잡한 join 쿼리에 대한 resultMap

복잡한 join 쿼리의 경우 쿼리를 하나씩 수행하기 보다는 한 쿼리에서 결과를 각각 가지고 올 수 도 있다.

 

        

         <resultMap id="bbsDataEx2Result" extends="bbsDataResult" type="BbsDataBean">

                  <association property="bbsInfoBean" column="{bbsId=S_BBS_ID}"select="kr.xboard.dao.bbsinfo.BbsInfoDao.getBbsInfoItem"/>

                  <collection property="bbsFileBeans" ofType="BbsFileBean" column="{bbsId=S_BBS_ID,bbsIdx=I_BBS_IDX}" resultMap="kr.xboard.dao.bbsfile.BbsFileDao.bbsFileResult"/>

                  <collection property="bbsCommentBeans" ofType="BbsCommentBean" column="{bbsId=S_BBS_ID,bbsIdx=I_BBS_IDX}"resultMap="kr.xboard.dao.bbscomment.BbsCommentDao.bbsCommentResult"/>          

         </resultMap>

 

         <select id="getBbsDataItem2" parameterType="BbsDataBean" resultMap="bbsDataEx2Result">

                  SELECT *

                    FROM bbs_data a, bbs_file c, bbs_comment d

                   WHERE a.S_BBS_ID = c.S_BBS_ID

                     AND a.I_BBS_IDX = c.I_BBS_IDX

                     AND a.S_BBS_ID = d.S_BBS_ID

                     AND a.I_BBS_IDX = d.I_BBS_IDX

                           <if test="bbsId != null and bbsId != ''">

                                   AND a.S_BBS_ID = #{bbsId}

                           </if>

                           <if test="bbsIdx != null and bbsIdx != ''">

                                   AND a.I_BBS_IDX = #{bbsIdx}

                           </if>              

         </select>        

 

getBbsDataItem2  bbs_data, bbs_file, bbs_comment 를 각각 join 을 해서 결과를 가지고 온다.

resultMap 에서의 차이점은 collection  select attribute  resultMap 으로 변경되었다.


출처 - http://devx.tistory.com/386


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

아 .. 정말 

Mybatis 기똥 찼다.. 


필자는 

어떠한 사이트를 처음 혼자 개발 하고 있다. 

HTML, CSS, Controller, DB, Scirpt, 웹디 까지전부.. 

좀 사이즈가 크다 보니 ..  

쿨럭 .. 

게다가 처음인지라 

점점 복잡해 져가는 로직 에 

DB가 문제가 되었다.  

단일 테이블 조회는 상관이 없었지만

여러 테이블 동시에 4개 조인( 너무 정규화를 시켜도 문제다.. 조인이 너무 많아진다. ) 

을 하다보니 

1 : N : M : 1 : 1 연결 에서 

결과값이 List로 불러 오니. 

Controller 단에서 어떻게 처리를 해야 할지. 

괜히 메모리만 잡아 먹는 느낌이 들었다 .

그리고 무분별한 조인으로 DB에 영향이 갈가 걱정되기도 했다 

예를 들어 난 

Object  를 불러 오고 싶었는데 조인을 하다보니 Object가 아닌 Object List가 불러 오는 경우였다..  

무슨 말이냐면 

project {
   private String value1 
   private String value2 
   private Process value3 
}

porcess {
   private String proc1 
   private String proc2 
   private String proc3 
   private Step proc4 
}
Step {
  private String step1
  private String step2 


이런식에 DTO가 있을시 
DB에조인을 해서 이러한 연관 관계를 어떻게 

잘 ~ 이쁘게 넣느냐 가 나의 관점이었다.  

결국 뻘짓과 삽질에 반복으로 해결할 수 있었다. 
바로 ResultMap 과 association , collection 의 조화 였다. 아.. 

아름다워라 

이제 서로 닥치고 본론으로 가겠다. 

<select id="getProject" resultMap="ProjectMaxAll" parameterType="string">
  select 
   prj_name, prj_desc, prj_start, 
   proc_idx, max(proc_step) as proc_step, proc_memo, proc_expire, proc_regdate
  from 
   project
  left join process on prj_name = proc_prj_name
  where
   prj_name = #{prj_name} 
 </select>


 <!-- 프로세스 , 속한 고객정보 가져오기 -->
 <select id ="getProcess" resultMap="ProcessAll" parameterType="string">
  select 
   proc_idx, proc_step, proc_memo, proc_expire, proc_regdate
  from 
   process
  where
   proc_idx = #{proc_idx} 
 </select>
<!--  프로젝트의 프로세스 단계 리스트  -->
 <select id="procStepList"  resultType="Step" >
  select 
   step_idx, step_cust_idx, cust_name, comp_name, cust_cellphone
  from 
   step_company 
  left join customer 
   on step_cust_idx = cust_idx 
  left join company 
   on cust_comp_idx = comp_idx
  where
   step_proc_idx = #{proc_idx}
 </select>
 
 <!--  프로세스의 고객 정보 리스트 -->
 <select id="StepList"  resultType="StepLevel" >
  select 
   proc_idx as step_proc_idx, step_title 
  from process
   left join step on step_value = proc_step
  where 
   proc_prj_name = #{proc_prj_name}
 </select>


 <resultMap id="ProjectMaxAll" type="Project" >
  <id property="prj_name" column="prj_name"/>
  <result property="prj_desc" column="prj_desc"/>
  <result property="prj_start" column="prj_start"/>
  <!-- 프로세스 목록 조회 ProcessAll -->
  <association property="proc" column ="proc_idx" javaType="PrjProcess" resultMap="ProcessAll"/>
 
  <!-- 프로젝트 프로세스 목록 조회 -->
  <association property="stepLevel" column ="prj_name" javaType="ArrayList"
  select="StepList">
   <id property="step_proc_idx" column="step_proc_idx" />
   <result property="step_title" column="step_title" />
  </association>
 </resultMap>
 
 <!-- 프로세스 조회  시작 -->
 <resultMap id="ProcessAll" type="PrjProcess" >
   <id property="proc_idx" column="proc_idx"/>
   <result property="proc_step" column="proc_step"/>
   <result property="proc_memo" column="proc_memo"/>
   <result property="proc_expire" column="proc_expire" />
   <result property="proc_regdate" column="proc_regdate" /> 
   <!-- Step Company 조회 -->
   <association property="prj_proc_stepList"  column="proc_idx" javaType="ArrayList"
    select="procStepList">
    <id property="step_idx" column="step_idx" />
    <result property="step_cust_idx" column="step_cust_idx" />
    <result property="cust_name" column="cust_name" />
    <result property="comp_name" column="comp_name" />
    <result property="cust_cellphone" column="cust_cellphone" /> 
    
   </association> 
 </resultMap>


복잡한가? 실로 그러치 않더라. 

정말 이번걸 보면서 DTO가 얼마나 중요한지 깨달았다.  

처음에 하나에 DTO다 때려 넣었다가. 

이렇게도 된다는 점이 너무 행복했다. 

그리고 이렇게 가지고 온 값을 

쉽게 뿌릴 수 있는 Spring Form 태그에 감사한다.


출처 - http://pikasoo.egloos.com/502488




'Framework & Platform > mybatis' 카테고리의 다른 글

mybatis 3 settings 예제  (0) 2012.04.30
mybatis password 암호화/복호화  (0) 2012.04.28
mybatis 설치 예제  (0) 2012.03.18
ibatis vs MyBatis  (0) 2012.03.15
ibatis 문법 정리  (0) 2012.03.14
Posted by linuxism
,