레이블이 spring인 게시물을 표시합니다. 모든 게시물 표시
레이블이 spring인 게시물을 표시합니다. 모든 게시물 표시

2010년 6월 6일 일요일

OSGi의 이점

거의 한달만에 포스트를 올리네요 .
한달 동안 정말 개인적으로 너무 힘들 었습니다.
이제 정신이 들어서 다시 블러그를 하려고 합니다.
당분간 Spring DM관련해서 포스팅을 하려고 합니다.

  • OSGi's Advantages
- 전체 시스템을 restart 하지 않고 각 모듈 (class, jar) 단위로
dynamically하게 install,uninstall,update,start,stop 할 수 있음

- 하나의 시스템내에서 각 모듈의 버전 정보를 복수로 install 할 수 있음
시스템 업그레이드에 좋은 대안이 될 수 있음

- OSGi 컨테이너는 모듈관의 의존 관계를 관리 한다.

- 각 모듈 (bundle)은 개별적인 life cycle을 가지고 있음.

- 각 모듈은 SOA 처럼 서비스로 노출하고 , 사용 할수 있음.
즉 느슨한 연결과 Service-Oriented한 설계를 가능 하도록 함.

2010년 4월 7일 수요일

Spring3.0 기반 SSC-MVC 릴리즈!! (개인 오픈소스:실무형 MVC)

개인적으로 Spring3.0 기반 오픈소스 "SpringShowcase"
의 마이너 버전을 release 했습니다.
(최근에 개인적으로 백수인 관계로 놀기도 모하고 해서....ㅋㅋ)
이번 버전 컨셉은 Spring3.0 기반에 실무형 MVC
prototype 입니다.






  • Technologies
(1) JDK 1.6
(2) Tomcat 6.0
(3) Spring 3.0
(4) Tiles2
(5) jQuery
(6) JSR-303 Validation
(7) Json-Lib
(8) Apache Commons Configuration
  • New Feature
(1) Dynamic Tiles2 Layout
Html Layout을 무거운 sitemesh 대신 Tiles2를 적용
와일드 카드 설정으로 인해서 config 최소화


(2) compound configuration
System Properties,Application Properties,DB Code ..
등 실무에서 사용하는 config성 데이터를 한개의
compound형태의 spring bean으로 제공.




(3) trace log
개발기 디버깅을 위해서 각 구간별 (Controller,Facade,Service,Dao..)
수행 시간, binding data의 속성 정보,client 기본 정보
(요청 url,http method,parameter 정보)
등을 로그로 기록한다. 로그레벨 "Info"로 설정시
조회 가능.


(4) Form Type Validation with JSR-303
Form Type(전통적인 submit 방식)기반 Validation을
JSR-303 스펙으로 구현. Annotation 기반 컨트롤러에서
구현 (스타일은 이전 SimpleFormController 방식)


(5) Ajax Type Validation with JSR-303
Clinet에서 jQuery를 통해서 요청시 바인딩
Validation이 발생할 경우 json 형태로 invalid된
field 아이디: 에러메시지를 출력함.


(6) Global Locale
spring 3.0에 추가된"mvc:annotation-driven " 네임스페이스를
적용해서 구현



(7) Ajax View Support with Json-Lib
Spring3.0에서 제공 하는 "jackson" 라이브러리는 톰캣를
제외한 다른 서버에서 Verify Exception을 발생함.
보다 검증되고 다양한 형태의 "json-lib" 뷰로
구현함.



(8) 직관적인 Exception 메세지
exception이 발생 했을 경우 에러 메세지를 직관적으로
지원. 예를 들어서 메세지 번들에 Exception Short 명을
키로 하고 메세지를 입력하면 자동으로 파싱해서
출력함

exception_ko.properties
NullPointException=데이터값이 존재 하지 않습니다.
NotFoundUserException=회원이 존재 하지 않습니다.

(9)
Exception Message Supported Ajax
Ajax 요청시 Exception 메세지를 json 형태로
에러메세지 뿐만 아니라 exception에 관련된
다양한 정보를 클라언트에게 전송 한다.



(10) Exception Log
exception이 발생하면 별도의 로그파일로 관리 합니다.
로그파일은 exception 발생 시 발생시간,trace ID,호출 URL
및 Http Parameter 정보, throw한 클래스들과 발생 line등을
제공 한다.
[로그파일 다운로드]

  • 실행 방법
아래의 동영상을 참고 하시기 바랍니다.
[동영상 보기]


  • 세미나
4월 24일에 ssc-mvc 관련해서 간략하게 세미나를
하려고 합니다.
관심 있으신분은 댓글이나 메일로 보내 주시기 바랍니다.
시간이 날때 기능별 User Guide를 만들려고 합니다.
아무래도 저도 돈받고 하는 사람이 아니라서
언제라고 장담은 못드리 겠네요 ^^

Spring 3.0 다국어 처리

Spring3.0에서 다국어 처리 하는 방법에 대해서
말씀 드리겠습니다.
3.0이라고 해서 크게 변동된 것은 없습니다.
단지 새로 추가된 네임 스페이스 "
<mvc:annotation-driven />
"를 통한 설정이 조금 변경 되었습니다.
먼저 아래와 같이 Message Resource를 등록 합니다.
<bean id="messageSource"
class="org.springframework.context.support.ResourceBundleMessageSource">
<property name="basenames">
<list>
<value>messages.default
</value>
</list>
</property>
</bean>



아래와 같이 localeResolver를 설정 합니다.
실무에서는 다국어 처리를 세션으로 제일 많이
사용하기 때문에 SessionLocale를 설정 했습니다.

<bean id="localeResolver"
class="org.springframework.web.servlet.i18n.SessionLocaleResolver" />



마지막으로 "mvc:annotation-driven" 네임스페이스에
interceptor를 적용 합니다.
<mvc:interceptors>
<bean class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor">
<property name="paramName" value="lang" />
</bean>
</mvc:interceptors>


아래와 같이 "lang"파라미터에 국가 코드를
넘기면 다국어가 변경 됩니다.
국문 : http://....../hello.htm?lang=ko
영문 : http://....../hello.htm?lang=en

2010년 4월 4일 일요일

Spring 3.0 Validation Part3

Part1,Part2는 기본적인 스프링에서 JSR-303
Validation 사용 방법에 대해서 설명 드렸습니다.
이번 Part는 Custom Validation에 대해서
말씀 드리겠습니다.
먼저 User 도메인 클래스 보면 아래와
같습니다.
public class User {

@NotEmail
private String email;

.....
}


"@NotEmail"은 제가 직접 만든 검증
annotation 입니다.
이제 부터 작성 방법에 대해서 말씀 드리겠습니다.

  • NotEmail Annotation 작성 방법
custom validation을 만들려면 2개의 클래스가 필요 합니다.
첫번째는 검증 annotation 클래스 이며 나머지 하나는
annotation을 검증할 validator 클래스 입니다.
이 두클래스의 참조 관계는 서로 의존 하는 관계
입니다.
package org.springshowcase.mvc;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

import javax.validation.Constraint;
import javax.validation.ConstraintPayload;

@Documented
//@Constraint(validatedBy = EmailValidator.class)
@Target( { ElementType.METHOD, ElementType.FIELD, ElementType.ANNOTATION_TYPE })
@Retention(RetentionPolicy.RUNTIME)
public @interface NotEmail {
public abstract String message() default "Not Email Format!";
public abstract Class<?>[] groups() default {};
public abstract Class<? extends ConstraintPayload>[] payload() default {};
}


"@Contraint" 부분을 주석 처리 하고 compile을 합니다.
이유는 아직 "EmailValidator" 클래스가 존재 하지 않기
때문입니다.

  • EmailValidator 클래스 작성 방법

package org.springshowcase.mvc;

import java.util.regex.Pattern;

import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;

public class EmailValidator implements ConstraintValidator<NotEmail, String> {

@Autowired
@Qualifier("emailPattern")
String pattern;

public void initialize(NotEmail constraintAnnotation) {
// nothing to initialize
}

public boolean isValid(String value, ConstraintValidatorContext context) {
Pattern EMAIL_PATTERN = Pattern.compile(this.pattern);
return EMAIL_PATTERN.matcher(value).matches();
}
}
반드시 "ContraintValidator" 인터페이스를 구현 해야 합니다
"@Autowired" 어노테이션을 보면 스프링 annotation 입니다.
이 얘기는 아래와 같이 스프링 빈을 선언 하면
<mvc:annotation-driven />

"ContraintValidator" 인터페이스를 구현한 모든 클래스는
스프링 ApplicationContext에서 이러한 클래스들을
스프링 빈으로 생성합니다.
이말은 Validator에 다른 스프링 빈을 injection을 할 수있다는
뜻 입니다.
예제를 통해서 email 정규식을 일부러 스프링 빈으로 설정하고
injection을 시켰습니다.
아래는 injection 당한 빈 입니다.
<bean id="emailPattern" class="java.lang.String">
<constructor-arg index="0" type="java.lang.String"
value=".+@.+\\.[a-z]+" />
</bean>

  • NotEmail Annotation 재컴파일
이제 "EmailValidator"가 생성이 되었기 때문에
"NotEmail" 어노테이션 클래스의 주석을 해제하고
재컴파일 합니다.

package org.springshowcase.mvc;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

import javax.validation.Constraint;
import javax.validation.ConstraintPayload;

@Documented
@Constraint(validatedBy = EmailValidator.class)
@Target( { ElementType.METHOD, ElementType.FIELD, ElementType.ANNOTATION_TYPE })
@Retention(RetentionPolicy.RUNTIME)
public @interface NotEmail {
public abstract String message() default "Not Email Format!";
public abstract Class<?>[] groups() default {};
public abstract Class<? extends ConstraintPayload>[] payload() default {};
}



  • Message Bundle 작성 방법
이제 새로운 custom validator를 작성이 끝났습니다.
새로운 annotation을 적용할 도메인 클래스에
선언 하면 됩니다.
메세지 번들 작성 방법은 아래와 같이 하면 됩니다.
NotEmail.user.email=이메일 형식이 틀립니다.

  • Spring Validation VS JSR-303
JSR-303 스펙에 대해서 확정을 하기 위한 투표를
하려고 했을때 스프링 진영에서는 참석을 하지
않았다고 합니다. 그래서 jboss 진영에서 심기가
좋지 않았다는 얘기가 있습니다.
역시 둘은 앙숙인듯....
아무래도 스프링 입장에서 자기들 validation이
있는데 굳이 JSR-303 스펙을 넣는게 그다지
좋지는 않았을 것 같습니다.
anyway!
JSR-303은 제가 도메인 클래스를 얘를 들었지만
사실 도메인 클래스만 해당 되는 것은 아닙니다.
모든 클래스(Service,DAO,..)에서 적용이 가능
합니다.
직접 써보니 JSR-303은 장점이 상당히 많았습니다.
첫째 검증 로직의 중복이 없습니다.
대부분 스프링 validation은 매요청시 작성 한거에
반해서 JSR-303은 도메인에 설정 하기때문에
검증 로직이 좀더 명확하고 코딩수도 적다는 얘기
입니다. 그리고 메세지 작성 방법도 직관적이기
때문에 관리도 수월 합니다.
반면 단점이 한나 있습니다. 좀 유연하지 않는다는
문제 입니다.
무슨 얘기냐 예를 들어서 id,name,email 이런 3개의
속성이 있다고 하고 모두 NotNull 조건이라고
설정을 합니다.
insert일 경우야 당연히 NotNull이지만
name만 update를 할경우 id,name 두
속성만 있으면 되는데 validation 조건이
모두 NotNull 조건이기 때문에 굳이
필요 없는 email에 기존 값을 채워서
보내야 한다는 것입니다.
즉 케이스별 검증 체크를 선택적으로 할 수
없다는 것입니다.
이런 이유는 예측컨데 jboss 진영에 힘이
있었지 않나 생각 합니다.
hibernate인 경우는 전체 업데이트를
체크 하기 때문이죠..
그래서 제가 개인적으로 시간이 되면 선택적으로
validation을 수행하는 util 클래스를 만드려고 합니다.
(언제가 될지 모르지만..)
그리고 한가지 더 현재 JSR-303 라이브러리와 구현체
라이브러리가 release가 아닌 running 중이기 때문에
라이브러리의 버전 진행도 유심히 모니터링
할 필요가 있습니다.
개인적으로 JSR-303은 실무에서 사용해도
훌륭한 개발 도구가 될 것 같습니다.

  • 소스 다운 로드
본 예제는 제가 진행하는 오픈 소스 "ssc-mvc"를 체크아웃
받으시면 됩니다.
자세한 내용은 오픈 소스 사이트를 참고 하시기 바랍니다.

Spring 3.0 Validation Part2

"Spring 3.0 Validation Part1"에 이어서 설명 드리도록 하겠습니다.
먼저 이전에 작성한 User 도메인 클래스 입니다.
package org.springshowcase.mvc;

import javax.validation.constraints.Pattern;
import javax.validation.constraints.Size;
import org.hibernate.validation.constraints.NotEmpty;


public class User {

@NotEmpty()
@Size(min=1,max = 5)
@Pattern(regexp="[0-9a-zA-Z]")
private String id;

@NotEmpty()
private String name;

@NotEmail
private String email;

private Integer age;

...setter & getter method
}


  • Controller에서 Validation 사용 하는 방법
Controller 에서 사용 하는 방법은 의외로 간단 합니다.
@RequestMapping(method = RequestMethod.POST)
public ModelAndView processSubmit(@Valid @ModelAttribute("user") User user,
BindingResult result, SessionStatus status) {
ModelAndView mav = new ModelAndView();
if (result.hasErrors()) {
System.out.println(".....invalid");
}
return mav;
}

위의 소스를 보면 검증을 위해서 파라미터 부분에
"@Valid" 어노테이션을 설정하면 끝입니다.
즉 저말은 User 도메인에 검증 로직을 실행 하라
는 뜻입니다. 이미 검증이 끝났기 때문에
"result.hasErrors"를 통해서 validation
분기 로직을 적절하게 작성 하면 됩니다.

  • JSP 설정 방법
<form:input path="id" /> <br />
<font color="yellow"><form:errors path="id" /></font><br />
<label for="contact_email">Enter user name: </label> <br />
<form:input path="name" /><br />
<font color="yellow"><form:errors path="name" /></font><br />
<label for="contact_email">Enter email: </label> <br />
<form:input path="email" /><br />
<font color="yellow"><form:errors path="email" /></font><br />
<label for="contact_subject">Enter Age: </label> <br />
<form:input path="age" /> <br /><br />
<input type="button" value="Save Changes" onclick="doSave();" class="button" />
</form:form>

JSP 소스는 이전 버전과 동일 하게 위와 같이 코드를
작성 합니다.

  • Invalid시 Message 리소스 적용 하기
이 부분은 SpringSource 팀 블러그와 JSR-303 스펙을
보면서 알아낸 방법 입니다.매우 중요한 부분이니
잘 이해하시기 바랍니다.

먼저 아래와 같이 메세지 번들을 설정 합니다.
<bean id="messageSource"
class="org.springframework.context.support.ResourceBundleMessageSource">
<property name="basenames">
<list>
<value>messages.default</value>
</list>
</property>
</bean>


default_ko.properties
메세지 expression은 "검증 annotation명+도메인명+속성명"
으로 하며 key 작성 규칙은 java method 형식으로
합니다.
NotEmpty.user.id=아이디를 입력 하세요.
Size.user.id=아이디는 5자 이하 입니다.
Pattern.user.id=아이디는 반드시 영문 또는 숫자만 입력 가능 합니다.
NotEmpty.user.name=이름을 입력 하세요.
NotEmail.user.email=이메일 형식이 틀립니다.
public class User {

@NotEmpty()
@Size(min=1,max = 5)
@Pattern(regexp="[0-9a-zA-Z]")
private String id;

.....
}

예를 들어서 "@NotEmpty"의 경우 메세지 키는
NotEmpty(annotation 명) + "." + user(도메인 클래스명)
+"." + id(속성명) 그래서 전체 메세지 키는
"NotEmpty.user.id"가 되는 것입니다.

Part3에서는 Custom Validation 작성 방법에
대해서 말씀을 드리겠습니다.

2010년 4월 2일 금요일

Spring 3.0 Validation Part1

Spring3.0 에서 Validation 기능을 보면 이전 버전
에서 사용했던 Validation 방법 뿐만 아니라
새로운 기능들이 추가가 되었습니다.
그중에서 단연 꽃은 JSR-303 스펙 입니다.
혹자는 이것을 Spring 3.0 Validation이라고 합니다.
JSR-303스펙은 쉽게 말해서 자바의 모든 클래스 자체에
검증 로직을 annotation으로 설정 해서 검증이
필요한 어느 곳이든 해당 검증을 수행 할 수 있도록
하는 J2EE Spec 입니다.
ㅋㅋ 저 답지 않게 유식한 척을 했군요
아래 코드를 보면서 간략 하게 설명 드리겠습니다.
public class PersonForm {

@NotNull
@Size(max=64)
private String name;

@Min(0)
private int age;

}

위에 코드를 보면 name 속성은 반드시 값이 존재 해야 하고,
length는 64자를 넘어서는 안된 다는 것입니다.
이렇게 클래스에 검증 로직을 넣고 검증이 필요한 곳
에서 실행을 하면 됩니다.


  • Library 설정
먼저 Spring 3.0 에서 JSR-303 스펙을 구현 하기 위해서는
아래의 라이브러리가 필요 합니다.
(1) jax-validation.jar (JSR-303 스펙 라이브러리)
(2) hibernate-validation.jar (JSR-303 구현체 라이브러리)
위 의 두개의 라이브러리를 다운 받아서 이클립스 classpath
를 설정 합니다.
만약 Maven을 사용 하시는 분들은 아래의 pom.xml을
추가 합니다.
<repositories>
<repository>
<id>jboss</id>
<url>http://repository.jboss.com/maven2</url>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
</repositories>

<dependencies>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>4.0.0.Beta2</version>
</dependency>
</dependencies>


스프링 3.0 full pom.xml 설정을 원하 시는 분들은
제 블러그 "Spring3.0 관련 라이브러리 (pom.xml)"
을 참조 하시면 됩니다.

  • 검증 클래스 작성

package org.springshowcase.mvc;

import javax.validation.constraints.Pattern;
import javax.validation.constraints.Size;
import org.hibernate.validation.constraints.NotEmpty;


public class User {

@NotEmpty()
@Size(min=1,max = 5)
@Pattern(regexp="[0-9a-zA-Z]")
private String id;

@NotEmpty()
private String name;

@NotEmail
private String email;

private Integer age;

...setter & getter method
}

위의 소스를 보면 전형적인 일반 자바 빈즈
클래스 형태 입니다.
"id" 속성의 검증 로직은 아래와 같습니다.
- 반드시 값이 존재 해야함
- 반드시 길이는 1이상 5이하여야 함 (byte 기준 아님)
- 반드시 영문 또는 숫자 형태여야함
"email" 속성에서 "@NotEmail"은 제가 직접
만든 annotation입니다. 이부분은 뒤에서
설명 하도록 하겠습니다.

  • Spring 빈 설정
스프링에서 JSR-303 스펙을 적용 하기 위해서는
다소 복잡한 과정을 거쳐야 합니다.
"LocalValidatorFactoryBean" 빈을 설정 하고 또 이 빈을
"AnnotationMethodHandlerAdapter" 선언된 빈에
injection 해야 하고...
이런거 필요 없이 spring3.0 에서 아주 간단한
네임스페이스를 제공 합니다.
<mvc:annotation-driven />

위와 같이 선언 하면 스프링에서 JSR-303 적용은
끝입니다.

Comming Up Next...

- Controller에서 Validation 사용 하는 방법
- JSR-303 기반 Message 번들 적용 방법
- JSP 설정 방법
- 커스컴 Validation Annotation 작성 방법
- Spring Validation VS JSR 303

너무 졸려서 다음에 포스팅 하도록 하겠습니다.

2010년 3월 28일 일요일

Spring3.0 + Tiles2 Intergration Part3

Part2 까지는 tiles2가 구동하기 위한 스프링 환경 설정
이였다면 이번 Part는 tiles 설정 및 활용 방안에
대해서 말씀 드리겠습니다.

  • Tiles Definition

Paste your text here.<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE tiles-definitions PUBLIC
"-//Apache Software Foundation//DTD Tiles Configuration 2.1//EN"
"http://tiles.apache.org/dtds/tiles-config_2_1.dtd">

<tiles-definitions>

<!-- = Abstract root definition ============ -->
<!-- default -->
<definition name=".default"
template="/WEB-INF/views/jsp/layout/defaultLayout.jsp">
<put-attribute name="title" value="CHANGE-ME" />
<put-attribute name="meta" value="/WEB-INF/views/jsp/layout/meta.jsp" />
<put-attribute name="left" value="/WEB-INF/views/jsp/layout/left.jsp" />
<put-attribute name="footer"
value="/WEB-INF/views/jsp/layout/footer.jsp" />
</definition>

<!-- empty -->
<definition name=".empty" template="/WEB-INF/views/jsp/layout/emptyLayout.jsp">
<put-attribute name="meta" value="/WEB-INF/views/jsp/layout/meta.jsp" />
</definition>


<!-- = implement definition ============ -->
<!-- default depth3 -->
<definition name="*/*/*" extends=".default">
<put-attribute name="title" value="Tiles2 Test" />
<put-attribute name="body" value="/WEB-INF/views/jsp/{1}/{2}/{3}.jsp" />
</definition>
<!-- default depth2 -->
<definition name="*/*" extends=".default">
<put-attribute name="title" value="Tiles2 Test" />
<put-attribute name="body" value="/WEB-INF/views/jsp/{1}/{2}.jsp" />
</definition>
<!-- default depth1 -->
<definition name="*" extends=".default">
<put-attribute name="title" value="Tiles2 Test" />
<put-attribute name="body" value="/WEB-INF/views/jsp/{1}.jsp" />
</definition>

<!-- empty -->
<definition name="dummy/empty" extends=".empty">
<put-attribute name="body"
value="/WEB-INF/views/jsp/dummy/empty.jsp" />
</definition>


</tiles-definitions>


definition name이 ".default"는 전체 layout을
선언하는 부분 입니다.

definition name이 ".empty" 부분은 web application에서
보면 기본 Layout을 적용이 되지 않고 싶을때 (팝업,iframe 등)
에서 사용할때 필요한 말 그대로 빈 페이지를 위한 레이 아웃입니다.

위에 설명한 2개의 설정은 layout 템플릿 설정이고 이제부터는
실제로 요청시 body 부분을 설정 하도록 해보겠습니다.

원래는 tiles는 매번 요청 마다 definition name를 설정해야
하는 엄청난 노가다를 해야 했습니다. 물론 spring examples
같은 곳에서 만든 라이브러리를 사용하면 일정부분
해결이 되긴 하지만 tiles2 부터는 와이들 카드로
설정 할수가 있습니다.

definition name이 "*/*/*"인 경우 위에서 extends=".default"
를 통해서 속성을 상속 받습니다.
그리고 호출 URL이 3 depth일 경우 해당 definition이
적용 됩니다.
예를 들어서
http://localhost:8080/dummy/depth1/depth2.ssc
라고 호출하면 스프링은 자동으로 view name을
"dummy/depth1/depth2.ssc" 변환 해서
해당 ViewResolver를 찾습니다.
"UrlBasedViewResolver"에 해당하기 때문에 tiles2 뷰로
포워딩 됩니다.
Tiles2 View에 도착한 View는 해당 definition을 찾습니다.
위의 view name은 "*/*/*" 패턴에 해당 하기 때문에
이 definition을 사용합니다.
요청 URL을 순서별로 body로 선언된 jsp를 찾습니다.

{1}:dummy,{2}:depth1,{3}:depth2.ssc
결국 /WEB-INF/views/jsp/dummy/depth1/depth2.jsp
로 포워딩이 됩니다.

"*/*" 이것도 위와 동일한 메커니즘 입니다.
마지막으로 "dummy/empty"로 선언된 것은 빈 페이지
layout template를 타기 위해서 선언된 것으로
이렇게 명시적으로 선언하면 wild card로 선언된
것은 무시하고 명시된 body를 찾습니다.

  • 샘플 다운로드 받기
해당 소스를 받기 위해서 아래와 같이
svn 주소로 full checkout 받으시면 됩니다.
소스 다운로드 : (https://springshowcase.googlecode.com/svn/trunk/ssc-webtemplate)
실행 하기 앞서서 참고로 JDK1.6 과 tomcat 6.0 에서 개발했습니다.
실행 방법은 "http://localhost:8080/" 치면 화면이 열리고
왼쪽 메뉴에 케이스별로 링크를 걸어 놓았습니다.
앞으로 spring best practice를 위한 오픈 소스를 개인적으로
하려고 합니다. 관심있는 분들은 springorg@gmail.com
로 주시면 감사 하겠습니다.
앞으로 되도록 샘플 소스를 이런식으로 배포 하고자 합니다.





Spring3.0 + Tiles2 Intergration Part2

Part2에서는 Spring3.0 기반에서 Tiles2 연동에
대해서 말씀 드리겠습니다.

  • 필요한 라이브러리
tiles2를 연동하기 위해서 필요한 라이브러리는 아래와 같습니다.
<dependency>
<groupId>org.apache.tiles</groupId>
<artifactId>tiles-api</artifactId>
<version>2.1.4</version>
</dependency>
<dependency>
<groupId>org.apache.tiles</groupId>
<artifactId>tiles-compat</artifactId>
<version>2.1.4</version>
</dependency>
<dependency>
<groupId>org.apache.tiles</groupId>
<artifactId>tiles-core</artifactId>
<version>2.1.4</version>
</dependency>

제 블러그 "Spring3.0 관련 라이브러리 (pom.xml)" pom.xml을
참고 하시면 됩니다.
※여기서 중요한 부분이 tiles2 버전 2.1.4로 하셔야 합니다.
새로 나온 2.2.1 버전은 아직 spring3.0과
호환성 문제가 있습니다.구글링을 통해서 알아보니
외국애들도 이 문제에 대해서 이슈화 하고 있습니다.

  • Controller 설정

@Controller
@RequestMapping("/dummy")
public class DummyController {

// ---------------------------------------------------------------------
// Class Variable Declaration
// ---------------------------------------------------------------------
/** The Constant logger. */
private static final Logger logger = LoggerFactory
.getLogger(DummyController.class);

// ---------------------------------------------------------------------
// Constructor Method Declaration
// ---------------------------------------------------------------------
/**
* Instantiates a new config controller.
*/

public DummyController(){}

// ---------------------------------------------------------------------
// DI Method (setter,getter) Declaration
// ---------------------------------------------------------------------
// ---------------------------------------------------------------------
// this Method (public/private) Declaration
// ---------------------------------------------------------------------
/**
* Gets the config.
*
* @param model the model
* @param request the request
*
* @return the config
*/

@RequestMapping(value = "/index")
public ModelAndView getMain() {
logger.info("========= DummyController.getMain");
return new ModelAndView();
}

/**
* Gets the show case tiles.
*
* @param model the model
* @param request the request
*
* @return the show case tiles
*/

@RequestMapping(value = "/list")
public ModelAndView getList() {
logger.info("========= DummyController.getList");
return new ModelAndView();
}

/**
* Gets the empty.
*
* @param model the model
* @param request the request
*
* @return the empty
*/

@RequestMapping(value = "/form")
public ModelAndView getForm() {
logger.info("==TilesController.getForm");
return new ModelAndView();
}

/**
* Handler empty.
*
* @return the model and view
*/

@RequestMapping(value = "/empty")
public ModelAndView getEmpty() {
logger.info("==TilesController.getEmpty");
return new ModelAndView();
}

// ---------------------------------------------------------------------
// interface implement Method (public/private) Declaration
// ---------------------------------------------------------------------
// ---------------------------------------------------------------------
// abstract implement Method (public/private) Declaration
// ---------------------------------------------------------------------
// ---------------------------------------------------------------------
// abstract Method (public/private) Declaration
// ---------------------------------------------------------------------


}


각각의 메서드들은 아래와 같은 요청시 처리 됩니다.

※참고로 호출 URL 확장자명은 "ssc" 입니다.
getMain : http://localhost:8080/dummy/index.ssc
getList :http://localhost:8080/dummy/list.ssc
getForm :http://localhost:8080/dummy/form.ssc
getEmpty : http://localhost:8080/dummy/empty.ssc
컨트롤러는 기본적인 annotation 기반 컨트롤러 입니다.

  • spring XML


<?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:util="http://www.springframework.org/schema/util"
xmlns:context="http://www.springframework.org/schema/context" xmlns:p="http://www.springframework.org/schema/p"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd">

<!-- annotation config & scan -->
<context:annotation-config />
<context:component-scan base-package="org.ssc">
<context:include-filter type="annotation"
expression="org.springframework.stereotype.Controller" />
</context:component-scan>

<!--
JSR-303 support will be detected on classpath and enabled
automatically
-->

<mvc:annotation-driven />

<!-- convert request data -->
<bean
class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
<property name="cacheSeconds" value="0" />
</bean>

<!-- tiles2 layout config -->
<bean id="tilesConfigurer"
class="org.springframework.web.servlet.view.tiles2.TilesConfigurer">
<property name="definitions">
<list>
<value>classpath:/tiles2/tiles2.cfg.xml</value>
</list>
</property>
</bean>

<!-- view name tanslator -->
<bean id="viewNameTranslator"
class="org.springframework.web.servlet.view.DefaultRequestToViewNameTranslator" />

<!-- view resolver -->
<bean
class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver">
<property name="mediaTypes">
<map>
<entry key="atom" value="application/atom+xml" />
<entry key="ssc" value="text/html" />
<entry key="json" value="application/json" />
</map>
</property>
<property name="viewResolvers">
<list>
<bean class="org.springframework.web.servlet.view.BeanNameViewResolver" />
<bean class="org.springframework.web.servlet.view.UrlBasedViewResolver">
<property name="viewClass"
value="org.springframework.web.servlet.view.tiles2.TilesView" />
</bean>
<bean
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/views/jsp/" />
<property name="suffix" value=".jsp" />
</bean>
</list>
</property>
<property name="defaultViews">
<list>
<bean
class="org.springframework.web.servlet.view.json.MappingJacksonJsonView">
<property name="prefixJson" value="true" />
</bean>
</list>
</property>
</bean>
</beans>


빈 아이디 "viewNameTranslator"는 요청 URL과 같은 형태로
View Name을 변환해 주는 빈입니다.
즉 "http://localhost:8080/dummy/index.ssc"로
호출하면 View Name은 "dummy/index"로 변환 됩니다.

빈 아이디 "tilesConfigurer"는 tiles2 초기화 하는
빈입니다. 파라미터로 초기화에 필요한 tiles2 설정
파일을 입력 합니다.

"ContentNegotiatingViewResolver" 빈이 제일
중요 합니다.
Spring3.0 부터 지원 합니다. 이 Resolver는 스스로
View를 resolving 할 수 있는 능력이 없습니다.
단 이름에서 알수 있듯이 여러 ViewResolver를
중에서 케이스별로 처리 할 수 있도록 resolving
logic을 해주는 resolver 입니다.
"mediaTypes"를 보면 "ssc"되는 부분이 있습니다.
전 뷰 형태의 호출 URL을 ".do" 또는 ".action"
이아닌 ".ssc"로 하고 있습니다.
저 말은 ".ssc"로 오는 요청은 "text/html"
타입을 처리 할 수 있는 "UrlBasedViewResolver"
또는 "InternalResourceViewResolver" 으로
포워딩 하라는 뜻 입니다.
".json" 형태로 오면 "MappingJacksonJsonView"
처리하게 되어 있습니다.
"viewResolvers" properties를 보면 "list" 형태로
되어 있습니다. 이것은 2.5.6의 "order" 태그와
같습니다. 컨트롤러에서 리턴된 view name을
위의 순서되로 찾아 갑니다.

tiles2 설정은 Part3에서 설명 드리겠습니다.