Whiteship's Note


오랜만에 스프링 MVC 다시 정리

Spring/Chapter 13 : 2008.10.19 13:19


오늘 오후 네 시에 스터디가 있어서 오랜만에 13장을 다시 정리해봤습니다. 그 중 몇 개만 정리해둡니다.

MultiActionController 사용 방법은 두 가지
- 상속
- 위임

WebApplicationContext가 관리하는 빈
- 컨트롤러(controller)
- 핸들러 맵핑(handler mappings)
- 뷰 리졸버(view resolver)
- 로케일 리졸버(locale resolver)
- 테마 리졸버(theme resolver)
- 멀티파트 파일 리졸버(multipart file resolver)
- 예외 처리 리졸버(Handler exception resolver)

애노테이션 기반 컨트롤러 설정시 필요한 빈(자동 등록해줌)
- DefaultAnnotaionHandlerMapping
- AnnotationMethodHandlerAdapter

@RequestMapping 사용 방법
- 클래스 레벨
- 메소드 레벨(MAC와 비슷한 효과)
- 클래스 + 메소드 레벨 혼합(클레스 레벨에 Ant 패턴 사용해서 거르고, 메소드 레벨로 세부적으로.)

요청 처리 메소드 인자
- Servlet API(Session 사용시 Thread-safety 문제가 생기면, AnnotationMethodHandlerAdapter의 synchronizeOnSession 속성을 true로 설정.)
- WebRequest, NativeWebRequest
- Locale
- InputStream/Reader, OutputStream/Writer
- @RequestParam
- Map, Model, ModelMap
- Command/form objects
- Errors/BindingResult
- SessionStatus

요청 처리 메소드 반환 타입
- ModelAndView
- Model (뷰 이름은 CoC 사용)
- Map (위와 동일)
- View (모델은 커맨드 객체와 @ModelAttribute를 사용한 메소드가 반환하는 객체)
- String (위와 동일)
- void (응답을 response 객체를 사용해서 직접 처리하거나, CoC 사용)
- Other return type (해당 객체를 model attribute로 뷰에서 사용가능)

@RequestParam
- 요청 매개변수 바인딩

@ModelAttribute
- 메서드 매개변수 레벨: 모델 속성을 특정 메서드 매개변수로 맵핑할 때 사용.
- 메서드 레벨: 화면에서 사용할 implicite object를 제공할 때 사용.

@SessionAttributes
- @ModelAttribute의 이름 목록을 지니고 있다. 해당 모델 객체들을 세션에 저장하여 여러 요청에서 공통으로 사용.

@InitBinder
- 커스텀 프로퍼티 에디터 등록.
top

Write a comment.


Spring Faces 소개하기, 파트 1

JSF/article : 2008.09.18 10:15


참조, 요약, 번역: http://www.jsfcentral.com/articles/intro_spring_faces_1.html

JavaServer Faces와 스프링의 연동을 돕는 Spring Faces라는 모듈이 있는데, 이 모듈을 Spring Web Flow 2에 도입했다. 본 기사는 Spring Faces에 대한 첫 번째 기사로, JSF 기준과 Spring 기준으로 각각 두 프레임워크를 통합하는 방법을 살펴볼것이다.

스프링은 예전부터 기본적인 JSF 연동을 자체 웹 모듈에서 지원해왔다. 기존 JSF 웹 계층과 스프링이 관리하는 비즈니스 계층 사이를 연결해주는 형태였다. 이 방법을 'JSF-기준 연동'이라고 한다. 이 방법으로도 잘 사용해왔지만, 스프링 웹 팀은 그 둘 사이에 뭔가 잘 안 맞는 것.. 너무 많은 구성물과 너무 많은 개념적인 오버헤드가 생겨서 관리하기 쉽지 않다는 것을 느꼈다.

스프링 Faces는 시야를 바꿔서 통합에 대한 접근 방법을 전환했다. 즉 스프링 기반 웹 애플리케이션에 JSF의 장점을 끌어오는 것을 목표로 했다. 이것은 '스프링-기준 연동'이라는 접근 방법으로 JSF UI 컴포넌트 모델을 사용하여 웹 애플리케이션 개발을 하는 것이다. 본 기사에서는 이 접근 방법의 장점과 왜 이것을 JSF과 스프링 개발자에게 권하는지 살펴보자.

JSF와 스프링 - 완벽한 조화인가?

JSF는 그 자체로 rich 웹 애플리케이션을 개발할 때 매우 많은 장점을 제공한다. 특히 복잡한 UI를 가지고 상태를 유지하는(stateful) 프로그래밍 모델을 필요한 곳에서 말이다. 이 UI 컴포넌트 모델들은 견고하며 강력하다. 제대로 적용하면, 웹 브라우져서에서 복잡한 컨트롤을 만들어야 하는 복잡도를 낮출 수 있다. 풍족한 UI를 선언적으로 만들 수 있고, 통합 EL을 사용하여 개별 컨트롤을 직접 도메인 모델에 유연하게 바인딩할 수 있기 때문에, 보다 빠르게 복잡한 웹 UI를 개발할 수 있다. 이 모든 것을 간단한 POJO 프로그래밍 모델로 달성할 수 있다.

스프링을 JSF를 앞단에 둔 애플리케이션의 도메인 계층에 적용하는 것이 자연스럽고 이상적이다. POJO 프로그래밍 모델을 이용할 수 있기 때문이다. JSF의 풍부하고 잘 정의된 확장 포인트를 사용하면, 스프링이 관리하는 비즈니스 계층을 JSF 앞단에 간단하게 연결할 수 있다.

EL을 사용한 JSF-기준 연동

JSF-기준 연동은, JSF 컨트롤러 모델이 애플리케이션을 주고하고 JSF가 관리하는 빈을 스프링 비즈니스 계층과 연결한다. 스프링은 몇몇 연동 클래스를 제공하여 faces-config.xml에서 스프링 빈을 참조할 수 있게 하는 것이다. 가장 흔한 방법으로는 DelegatingVariableResolver 를 사용하면, EL을 사용하여 스프링 빈을 참조할 수 있다. EL을 사용해서 스프링 빈을 JSF가 관리하는 빈에 주입하는 것이다. 예를 들어, WebApplicationContext에 다음과 같은 빈이 있다고 치자.

<bean id="mySpringService" class="com.foo.MySpringServiceImpl">

EL을 사용해서 faces-config.xml에 정의한 <managed-bean>에서 이 빈을 JSF가 관리하는 빈에 주입할 수 있다.

<managed-bean>
  <managed-bean-name>myJsfManagedBean</managed-bean-name>
  <managed-bean-class>com.foo.MyJsfManagedBean</managed-bean-class>
  <managed-bean-scope>request</managed-bean-scope>
  <managed-property>
    <property-name>mySpringService</property-name>
    <value>#{mySpringService}</value>
  </managed-property>
</managed-bean>

즉 이렇게 하면, 스프링이 관리하는 싱글톤 서비스를 JSF가 매번 생성하는 객체에 주입할 수 있다. 스프링 2.0부터, request와 session 스콥을 사용할 수 있기 때문에, JSF 관리하는 빈을 모두 없애고, EL로 스프링 컨트롤러를 사용할 수도 있다.

JSF-기준 접근방법으로 충분한가?


스프링의 간단한 JSF 연동 클래스로, 부드럽게 스프링이 관리하는 서비스를 JSF 기반 앞 단과 통합할 수 있었다. 하지만, 이것으로 충분한가? 나는 그렇지 않다고 확신한다. 이 방법은 JSF 컨트롤러 모델을 사용하고 있는데, 여기에 몇 가지 단점들이 존재한다.
  • 순수-MVC 접근방법에 따라, 모든 것이 뷰를 렌더링하는것으로 주도된다. 랜더링 전에 모델을 초기화 하는 편리한 포인트가 없다.
  • 성가신 네비게이션 모델은 여러분이 실수를 해도 거의 피드백이 없다.(오타가 있어도 말이다.) 그리고 규칙이 추가되거나 변경될 때마다 애플리케이션을 다시 시작해야 한다.
  • 검증 모델이 충분하지 않다. 서버쪽에서의 필드 수준 검증을 중심으로 하고 있다. 컴포넌트 트리를 순회하지 않고도 클라이언트쪽 필드 검증과 서버쪽 모델 검증을 수행할 수 있는 편리한 방법이 필요하다.
  • URL 맵핑이 좀 유연하지 않고, 리다이렉트 지원이 충분치 않다.
  • request와 session 사이의 보다 세밀한 스콥프가 필요하다. 특히 페이지 내에서 여러번 이벤트를 발생시키는 Ajax 기반 뷰의 경우에 그렇다.
  • 예외 처리 기능이 매우 제한적이다. 특히 뷰 랜더링할 때 그렇다.
  • 컨트롤러 로직이 JSF 빈으로 분산되어 있다. 단위 테스트하기가 힘들고 변경할 때마다 애플리케이션을 다시 시작해야 한다.
JSF의 UI 컴포넌트 모델은 견고하다. 그 행위 들은 잘 정의되어 있는 JSF 컴포넌트 라이프사이클 경계 내에서 실행되고 캡슐화되어 있다. 하지만 컨트롤러 모델은 다소 제한적이다. 특히 스프링, 스프링 MVC, 스프링 Web Flow의 유연함과 막강함을 사용하고자 하는 사람들에게 더 제한적으로 느껴진다. 또한 이 접근 방법은 개념적인 오버헤드를 발생시킨다. faces-config.xml, JSF가 관리하는 빈, JSF 뷰 템플릿 그리고 스프링 기반 비즈니스 계층의 모든 컴포넌트를 계속해서 관리해야 한다.

처음에는, 스프링 Web Flow 1.x도 JSF-기준 방법으로 연동을 시도했었다. 하지만, 이 방법이 너무 제한적었다. 여전히 많은 JSF 구성요소를 사용했고 제대로 동작하려면 faces-config.xml에 뭔가를 추가해야 했다. agile이라고 할 수 없었다.

만약에 JSF의 UI 컴포넌트 모델을 스프링 환경에 연동할 수 있으면 어떨까 고민을 했다. 스프링 프로그래밍 모델을 사용하고 보다 스프링을 기준으로 한 접근 방법으로 말이다. 만약 스프링이 전체 요청을 관리하면, 여러분은 보다 편리하게 전체 애프리케이션 설정을 관리할 수 있고 편하게 프로그래밍을 할 수 있을 것이다. 또한 스프링 MVC의 유연한 라우팅 기반 시설과 스프링 Web Flow 2.x의 agile statefule 컨트롤러 모델을 사용할 수 있겠다. 이는 stateful JSF 뷰와 잘 어울린다. 바로 이러한 동기로 인해 스프링 Faces가 생겼고 스프링 포트폴리오에 추가됐다.

스프링 Faces의 스프링-기준 JSF


스프링 Faces는 JSF와 스프링 연동에 있어서 훨씬 규범적인(prescriptive)-미리 무언가를 예상하고 마련해 두는- 접근방법을 채택했다. JSF의 막강함은 그가 제공하는 여러 확장 포인트인데, 스프링 Faces는 이 모든 장점을 수용하여 JSF를 보다 자연스럽게 스프링에 녹아들게 했다. 환경에 대해 몇가지 가정을 세웠다. 일단 스프링 MVC DispatcherServlet을 사용하여 요청 처리를 라우팅하고, 스프링 Web Flow 2.x의 기초 컨트롤러 모델을 사용한다. 또, 스프링 JavaScript 모듈을 사용하여 경량 JSF Ajax 컴포넌트를 제공한다고 가정했다. (스프링 Faces는 어떠한 JSF 컴포넌트 라이브러리도 사용할 수 있도록 설계했기 대문에, 이들 컴포넌트는 전부 옵션이기 필수가 아니다.)

사용자 삽입 이미지
그림 1. 스프링 Faces 아키텍처에 대한 하이 레벨 뷰

본 기사 남은 부분에서, 스프링 Web Flow 2 배포에 포함되어 있는 Spring Travel에 스프링 Faces를 적용해볼 것이다.

전체 스프링 Faces 예제 소스는 /project/spring-webflow-samples/booking-faces/에 있다.

이미 동작하고 있는 예제가 필요하다면, 여기를 클릭하라.

스프링 Faces 예제의 구조

먼저 살펴볼 것은  /src/main/webapp/WEB-INF/faces-config.xml 다. 이 안에 설정한 것은 오직 FaceletViewHandler 뿐이고, 스프링 Faces가 보다 미리 마련해두는 방식을 채택했기 때문에, 모든 JSF 연동에 필요한 구성물들은 자동으로 클래스패스에 있는 spring-faces.jar에 포함되어 있다.

또한 다음 파일들을 살펴보고 라우팅에 대한 기본 설정에 익숙해져야 할 것이다.

  • /src/main/webapp/WEB-INF/web.xml
  • /src/main/webapp/WEB-INF/config/webmvc-config.xml
  • /src/main/webapp/WEB-INF/config/webflow-config.xml
이 설정에 대해선느 스프링 Web Flow 2 레퍼런스 가이드에 나와있으니 자세히 설명하진 않겠다. 다만 이 설정의 결과만 설명하겠다.

/spring 이하의 모든 요청은 스프링 DispatcherServlet이 처리하도록 되어 있다. DispatcherServlet은 나머지 URL을 보고 stateless JSF 뷰를 보여줘야 하는지, SWF를 사용해서 stateful JSF 뷰를 보여줘야 하는지 판단하다.

예를 들어,

/spring/intro -> renders the stateless Facelets template at /WEB-INF/intro.xhtml

/spring/main -> hands control over to the flow defined at /WEB-INF/flows/main/main.xml

/spring/booking?hotelId=5 -> hands control over to the flow defined at /WEB-INF/flows/booking/booking.xml, passing the hotelId parameter as input to the flow

그림 2에 있는 /flows 디렉토리 구조를 보면, 스프링 Faces 컨틀롤러와 뷰 구성물을 논리적으로 재사용 가능한 모듈로 조직화 하도록 한 것을 볼 수 있다.

사용자 삽입 이미지
그림 2. 모듈들의 논리적인 조직화

스프링 Web Flow와 Agile JSF 컨트롤러

스프링 Faces의 핵심은 스프링 Web Flow 연동에서 온다. 그리고 고수준의 flow DSL을 사용할 수 있으며, 이것으로 정확하고 엘레강트한 구조로 이벤트 처리, 모델 조화, 뷰 네비게이션을 제공할 수 있다. 플로우 정의는 동적이며 애플리케이션 재실행 없이 핫-릴로딩이 가능하다. 웹 컨테이너에 배포할 필요가 없기 때문에 완전한 단위 테스트도 가능하다. 보다 기민한 JSF 개발이 가능하다. 세밀한 스콥(flash, view, flow 스콥)을 사용하여 여러 요청을 넘나들며 도메인 모델을 직접 사용할 수 있다. 따라서 여러분은 도메인 모델에 보다 많은 가치를 부여하는데 힘을 쓸 수 있고, 모델을 매 요청에 저장해두고 가져오는 등의 기반 시설에 대해 걱정하는 시간을 줄일 수 있다. 이런 stateful 특징은 풍부한 JSF 뷰와 잘 어울리며 여러 이벤트로 뷰가 자주 변경되는 상황에 적당하다.

스프링 Faces를 사용하면, JSF postback 라이프사이클은 SWF 제어 하에 실행된다.
PhaseListener를 통해 JSF 라이프사이클에 플로우를 실행하는 SWF 1.x의 제한적인 연동에 비하면, 스프링 Faces JSF 확장 포인트는 SWF 구조를 기반으로 만들었다. 이로인한 아키텍처 적인 장점은 다음과 같다.

  • JSF 뷰는 SWF의 자동 POST + Redirect + GET 행위와 자연스럽게 동작하며, step-behind-URL을 없앴고, 일반적인 JSF 애플리케이션에 있던 브라우저 리프래시 경고 문제를 제거했다.
  • FacesMessage는 스프링의 MessageContext로 바인딩되어 스프링의 강력한 i18n 기능을 사용할 수 있다. 메시지들은 flash 스콥으로 저장되며 따라서 리다이렉트를 해도 보존된다.
  • 컴포넌트 트리 상태는 자동적으로 플로우 실행 상태와 동기화한다. pluggable storage 매키니즘을 적용하여 다양한 클러스터링 시나리오를 다룰 수 있다.
끝. 다음 기사에는 예제를 좀 더 자세히 살펴보겠다.

저자에 대하여

Jeremy Grelle는 SpringSource의 수석 소프트웨어 엔지니어이며 스프링 Faces 프로젝트 기술 리더다.


'JSF > article' 카테고리의 다른 글

Spring Faces 소개하기, 파트 1  (2) 2008.09.18
JavaServer Faces 시작하기 Part 1 Building basic applications  (0) 2008.09.15
top

  1. 2008.09.19 14:07 PERM. MOD/DEL REPLY

    비밀댓글입니다

    Favicon of https://whiteship.tistory.com BlogIcon 기선 2008.09.19 16:00 신고 PERM MOD/DEL

    넵ㅋㅋ :)

Write a comment.


Spring 2.5 @Controller 사용시 BindingResult 주의 할 것.

모하니?/Coding : 2008.05.14 18:13


스프링 레퍼런스에 BindingResult에 대한 언급은 단 한 줄.
org.springframework.validation.Errors / org.springframework.validation.BindingResult  validation results for a preceding command/form object (the immediate preceding argument).

이게 끝입니다. 한 줄이라고 무시하면 안 됩니다. 진짜 중요한 한 줄입니다.

public String update(@ModelAttribute("model") Foo model, BindingResult result, Bar bar)

public String update(@ModelAttribute("model") Foo model, Bar bar, BindingResult result)

이 두 줄의 코드는 어쩌면 아무런 차이가 없을 수도 있지만 Validator를 만들어 보시면 그 차이를 알 수 있습니다. 무슨 차이인지는 비밀입니다. ㅋㅋ 이미 스프링 레퍼런스에 다 설명이 나와있어서 비밀이랄 것도 없지만 말이죠.ㅋ

힌트 1.
validator.validate(model, result);

힌트 2.
public void validate(Object obj, Errors errors) {
    ...
}


top

Write a comment.


ControllerClassNameHandlerMapping 잘 되네~

모하니?/Coding : 2008.04.08 14:54


@Controller
public class MemberController {

    @Autowired
    private MemberService memberService;

    @RequestMapping
    public ModelAndView list(){
        return new ModelAndView("member/list")
            .addObject("members", memberService.getAll());
    }
}

요렇게만 해두면, /member/list.xxx 라는 요청이 오면 알아서(Conversion) 저 메소드가 처리하도록 합니다. ㄴXxx-servlet.xml에는 XML에는

<bean class="org.springframework.web.servlet.mvc.support.ControllerClassNameHandlerMapping" />

애만 등록해주면 됩니다. 저 한 줄의 XML로 URL 맵핑을 손수 적는 수고를 덜 수 있습니다.

계속해서 진화하는 Spring MVC 어디까지 갈텐가~~ 멋있어 멋있어 끝까지 가는거야~~

2008/04/08 - [모하니?/Coding] - ControllerClassNameHandlerMapping가 찾아 준댔는데...
ps : 새벽에 괜히 삽질만 하고... 잠이나 계속 잘껄..
top

  1. 2008.04.08 18:23 PERM. MOD/DEL REPLY

    비밀댓글입니다

    Favicon of https://whiteship.tistory.com BlogIcon 기선 2008.04.08 20:04 신고 PERM MOD/DEL

    저두 그러고 싶은데요. 아직 모르겠어요.
    온라인을 보면 조만간 할 것 같기도 한데 아직 전달받은 이야기가 없습니다.

  2. Favicon of https://iamnotokay.tistory.com BlogIcon jeeyong 2008.04.10 12:47 신고 PERM. MOD/DEL REPLY

    /member/list.xxx 라고 요청을 날리면 ListController 가 받는게 아닌가요?

    Favicon of http://whiteship.tistory.com BlogIcon 기선 2008.04.10 13:03 PERM MOD/DEL

    아니여. MemberController가 받습니다.
    자세한 내용은 http://whiteship.tistory.com/933 이 글을 참조하세요.

Write a comment.


Spring 2.5 MVC 요약

Spring/KSUG : 2007.12.23 00:30


토비님 발표를 들으며 요약한 내용입니다. 많은 걸 적을 순 없었습니다. 어차피 PPT가 KSUG 사이트에 올라올테니 그걸 기다려봅니다.

@Controller

@RequestMapping
    method level에서 narrowing.
        value, method, params
    파라미터와 리턴타입의 자동인식

    리턴값
    파라미터

@RequestParam
    이름이 다를 경우에만 사용
    URL 파라미터 받아오기

@ModelAttribute : 커맨드 객체, 레퍼런스 데이터

@SessionAttribute : 세션폼
    SessionStatus.setComplete();

@InitBinder : 커스텀 프로퍼티 에디터
    WebDataBinder

POJO 컨트롤러 테스트 가능
FlowContext를 이용한 flow control 가능
@PathElement REST 스타일... good! 빨리 나와주길 바래.

실습해볼 것
Spring MVC 예제 만들기(실습 과정을 동영상으로 찍어볼까~ 흠..)
    1. 컨트롤러 하나로 MultiAction + SimpleForm 역할하기
    2. 프로퍼티 에디터 사용하기
    3. 파라미터에서 값 가져오기
    4. 세션 객체 사용하기

이전에 공부했던 내용
2007/11/28 - [Spring/Chapter 13] - Annotation-based controller configuration

top

  1. joker 2008.02.27 22:53 PERM. MOD/DEL REPLY

    spring에 이제 막 입문했습니다.
    님의 블로그에서 항상 많은 도움을 받고 있습니다. 감사합니다.^^

    Favicon of http://whiteship.tistory.com BlogIcon 기선 2008.02.28 20:03 PERM MOD/DEL

    넹 그런가요. 헤헷 감사합니다. ^^

Write a comment.


Annotation-based controller configuration

Spring/Chapter 13 : 2007.11.28 23:51


0. 컴포넌트 스캐너 등록하기

우선, 컴포넌트 스캔 기능을 사용해서 @Controller 애노테이션이 붙어있는 클래스들을 bean으로 인식하도록 해야합니다. 따라서 context:component-scan 엘리먼트로 컨트롤러들이 위치한 패키지를 명시해 줍니다.

<context:component-scan base-package="org.springframework.samples.petclinic.web" />

1. 컨트롤러 작성하기

완전 POJO로 컨트롤러를 작성할 수 있습니다. 획기적이네요. 일단 컨트롤러로 사용할 클래스는 이제 더이상 아무런 클래스도 상속받지 않아도 됩니다. 정말 그야말로 POJO입니다. 이 POJO에다가 @Controller 애노테이션을 붙여주면 컨트롤러가 됩니다.

2. Request Mapping 하기

원래는 Handler Mapper가 하던 일인데, 이제는 이것도 애노테이션이 해줍니다. @RequestMapping 애노테이션으로 해당 클래스 또는 메소드가 처리할 요청을 명시해주면 됩니다.

3. Form Controller로 사용하기

클래스 선언부에 @RequestMapping 애노테이션으로 폼을 요청할 Request를 설정해줍니다. 이 애노테이션이 붙어있는 클래스 안의 메소드 위에 같은 애노테이션을 사용하여 Request의 method에 따라 호출될 메소드를 설정할 수 있습니다.

@SessionAttributes 엘리먼트는 Session에 담을 attribute 를 나타냅니다. 주로 여러 폼에 걸쳐서 보여줄 데이터를 명시합니다.

@ModelAttribute는 두 가지 경우에 사용할 수 있는데, 메소드 위에 사용하면 폼에서 참조할 객체(Reference Data)를 나타낼 때 사용합니다. 아래의 예제에서 populatePetTypes() 메소드가 그 예에 해당합니다. 또 다른 경우는 메소드의 매개변수 앞에 이 애노테이션을 사용할 경우 인데, 이 때는 폼에 입력된 정보를 해당 애노테이션이 붙어있는 객체로 맵핑해 줍니다. processSubmit() 메소드의 인자를 보시면 됩니다.

@RequestParam은 Request의 특정 파라미터의 값을 가져옵니다. 물론 자동으로 해당 값을 이 애노테이션이 붙어있는 타입으로 변환해 줍니다. 기본타입만 가능하겠죠.

@Controller
@RequestMapping("/editPet.do")
@SessionAttributes("pet")
public class EditPetForm {

    private final Clinic clinic;

    @Autowired
    public EditPetForm(Clinic clinic) {
        this.clinic = clinic;
    }

    @ModelAttribute("types")
    public Collection<PetType> populatePetTypes() {
        return this.clinic.getPetTypes();
    }

    @RequestMapping(method = RequestMethod.GET)
    public String setupForm(@RequestParam("petId") int petId, ModelMap model) {
        Pet pet = this.clinic.loadPet(petId);
        model.addAttribute("pet", pet);
        return "petForm";
    }

    @RequestMapping(method = RequestMethod.POST)
    public String processSubmit(@ModelAttribute("pet") Pet pet, BindingResult result,
            SessionStatus status) {
        new PetValidator().validate(pet, result);
        if (result.hasErrors()) {
            return "petForm";
        }
        else {
            this.clinic.storePet(pet);
            status.setComplete();
            return "redirect:owner.do?ownerId=" + pet.getOwner().getId();
        }
    }

}

4. MultiActionController로 사용하기

@RequestMapping 애노테이션으로 처리할 URL을 메소드 위에 표기해 줍니다. 물론 class위에는 적을 필요가없겠죠. 메소드 단위니까요.

뷰는 CoC에 따라 요청 URL을 보고 판단합니다.
뷰를 명시할 수 있는 다른 방법이 있는지 궁금해지네요. 이 부분은 살펴봐야겠습니다.
ModelAndView 객체를 리턴타입으로 사용할 수 있다면 간단해 지겠지만 말이죠.

@Controller
public class ClinicController {

    private final Clinic clinic;

    @Autowired
    public ClinicController(Clinic clinic) {
        this.clinic = clinic;
    }

    @RequestMapping("/welcome.do")
    public void welcomeHandler() {
    }

    @RequestMapping("/vets.do")
    public ModelMap vetsHandler() {
        return new ModelMap(this.clinic.getVets());
    }

    @RequestMapping("/owner.do")
    public ModelMap ownerHandler(@RequestParam("ownerId") int ownerId) {
        return new ModelMap(this.clinic.loadOwner(ownerId));
    }

}

5. 커스텀 프로퍼티 에디터 등록하기.

다음과 같이 @InitBinder를 사용하여 바인딩 하는 녀석을 등록할 수 있습니다.

@Controller
public class MyFormController {

    @InitBinder
    public void initBinder(WebDataBinder binder) {
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
        dateFormat.setLenient(false);
        binder.registerCustomEditor(Date.class, new CustomDateEditor(dateFormat, false));
    }

    // ...
}

해당 바인더는 커맨드나 폼 객체 그리고 그에 따른 에러 객체를 제외한 @RequestMapping이 지원하는 모든 아규먼트에 적용됩니다. 흠.. 폼에서 사용자가 입력한 값은 이걸로 바인딩 하지 않는다는 건가?? -_-?? 이상하네.. 이 부분도 공부나 추가 정보가 필요함.

커스텀 프로퍼티 에디터 등록을 xml에서 하기

WebBindingInitializer 인터페이스 구현체에 프로퍼티 에디터를 등록해서 다음과 같이 설정해주는 듯 합니다. 이 것 역시 어떻게 구현하는지 공부가 필요함.

<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
    <property name="cacheSeconds" value="0" />
    <property name="webBindingInitializer">
        <bean class="org.springframework.samples.petclinic.web.ClinicBindingInitializer" />
    </property>
</bean>

top

Write a comment.


MultiactionController



AbstractController를 상속받아서 간단하게 구현하는 Controller들이 많이 있습니다. 그러한 것들 중에는 서로 관련이 있는 컨트롤러들도 있습니다. 예를 들어 검색결과 리스트를 가져오는 컨트롤러, 전체 목록을 가져오는 컨트롤러, 목록에서 한 개의 아이템에 대한 정보를 가져오는 컨트롤러가 있을 수 있습니다. 이러한 것들을 하나의 컨트롤러에서 처리할 수 있습니다.

MultiactionController의 장점
- 컨트롤러의 갯수가 줄어듭니다.
- 여러 처리를 논리적인 그룹으로 묶어서 하나의 클래스에 담을 수 있습니다.
- 액션 메소드의 유동적인 맵핑이 가능합니다.

MultiactionController의 단점
- 바인딩과 Valitor를 사용할 수 있지만 폼 처리 work flow가 정의되어 있지 않습니다.
    - 따라서 바인딩과 Validation을 요청을 처리할 메소드 내부에서 하기(?)를 권하고 있습니다.
- 쉽게 커질 우려가 있습니다.
- 리플렉션을 사용하기 때문에 컴파일 에러를 확인할 수 없습니다.

사용하는 방법
1. MultiActionController  상속받기
public class IssueController extends MultiActionController {

}

2. 요청을 처리할 액션 메소드 구현
- ModelAndView 객체를 반환해야 합니다.
- HttpServletRequest와 HttpServletResponse 파라미터를 가지고 있어야 합니다.
- 옵션으로 HttpSession 또는 Command 객체를 파라미터로 가질 수 있습니다.
    public ModelAndView list(HttpServletRequest request, HttpServletResponse response){
       return new ModelAndView("issue/list");
   }

3. 등록하기
- MethodNameResolver bean 등록합니다. 참조
    - InternalPathMethodNameResolver를 default로 사용합니다. 따라서 이 녀석을 사용할 때는 굳이 등록하거나 DI하지 않아도 됩니다.
- 위에서 구현한 컨트롤러 baen 등록하기
    <bean name="/issue/*"  class="net.agilejava.nayoung.controller.IssueController" />
- 이 때 *을 사용하여 /issue/list.html, /issue/find.html 과 같은 요청들을 모두 위의 컨트롤러에서 처리하도록 합니다.

궁금한 점
- Binding과 Validation을 할 수는 있는데 화면에 바인딩 하거나 Validation할 때 발생한 Error를 못 보여 주는 것이 단점인 것 같은데 이 걸 어떻게 해결 할 수 있을지...




'Spring MVC > 6장 Controller' 카테고리의 다른 글

AbstractController  (0) 2007.06.21
Non-String DataBinding 테스트하기  (0) 2007.06.21
간단한 DataBinding 테스트하기  (0) 2007.06.20
MultiactionController  (0) 2007.06.19
SimpleFormController's onSubmit()  (0) 2007.04.11
SimpleFormController  (0) 2007.02.28
Controller  (0) 2007.02.28
top

Write a comment.


Vlidator - ValidationUtils 사용하기



Spring에서 Validator를 구현하는 방법은 두 가지가 있습니다.
1. Programmatic
2. Declarative

그 중에서 첫 번째 Programmatic 방법을 사용하여 구현할 때 ValidationUtils를 사용하면 매우 간단하게 구현할 수 있습니다.
사용자 삽입 이미지
인터페이스 중에 인자가 네개인 녀석을 사용하여 defaultMessage를 주면 프로퍼티 파일을 만들지 않아도 메시지를 출력할 수 있습니다.

1. Validator 만들기
public class MemberInfoValidator implements Validator{

    public boolean supports(Class clazz) {
        return MemberInfo.class.isAssignableFrom(clazz);
    }

    public void validate(Object object, Errors errors) {
        ValidationUtils.rejectIfEmptyOrWhitespace(errors, "email", "required", "Enter your email");
        ValidationUtils.rejectIfEmptyOrWhitespace(errors, "password", "required", "Enter your password");
        ValidationUtils.rejectIfEmptyOrWhitespace(errors, "confirmPassword", "required", "Enter the same password for confirmation");
        ValidationUtils.rejectIfEmptyOrWhitespace(errors, "confirmMember", "required", "Enter ajn member code");
        ValidationUtils.rejectIfEmptyOrWhitespace(errors, "name", "required", "Enter your name");
    }

}

Validator 인터페이스를 구현하고 ValidationUtils를 사용하여 간단하게 구현할 수 있습니다.

2. Controller에 등록하기
  public CreateMemberInfoController() {
        setCommandClass(MemberInfo.class);
        setCommandName("memberInfo");
        setFormView("createMemberInfo");
        setSuccessView("viewMemberList");
        setValidator(new MemberInfoValidator());
    }

setValidator 메소드를 사용하여 위에서 만든 Validator를 등록해 줍니다.

3. 화면에 보여주기
<form:errors path="속성 이름" />

이런식으로 속성 이름을 적어주면 그 이름에 해당하는 에러 메시지를 고자리에 출력해 줍니다.

사용자 삽입 이미지

<form:errors path="*" />

이렇게 써주면 저 태그가 들어간 위치에 모든 에러 메시지를 모아서 출력할 수 있습니다. 좋군요~
사용자 삽입 이미지

top

Write a comment.


SimpleFormController's onSubmit()



오버로딩을 사용해서 같은 이름의 메소드가 세 개 있었습니다.

보통은 onSubmit(Object command) 이 녀석만 사용했었는데요. 세션에 객체 하나를 담고 싶어서 아래와 같은 코드가 onSubmit() 메소드 안에 추가 되어야 했습니다.

request.getSession().setAttribute("user", member);

그러나... request 인자가 onSubmit() 메소드에 없는 것입니다. 그래서 이를 어쩌나..했는데 찬욱군이 onSubmit() 메소드가 세 개가 있는데 그중에 request 객체를 받아오는 녀석이 있다고 알려줘서 찾아봤습니다.

Spring MVC 155쪽에 나와있는 그림을 보니 어떤 메소드 들이 있고 어떻게 동작하는지 명확히 알 수 있었습니다.
사용자 삽입 이미지
인자가 제일 많은 녀석 부터 시작해서 하나 인 녀석 순으로 내부에서 호출하게 되는 것 같습니다. 이 걸 코드로 표현하면 아래 처럼 될 것입니다.

protected ModelAndView onSubmit(HttpServletRequest request, HttpServletResponse response, Object command, BindException errors) throws Exception {
    //할 일
    onSubmit(command, errors);
}

protected ModelAndView onSubmit(Object command, BindException errors) throws Exception {
    //할 일
    onSubmit(command);
}

protected ModelAndView onSubmit(Object command) throws Exception {
    //할 일
    doSubmitAction(formBean);
}

이 중에서 필요한 인자에 따라 필요한 녀석을 오버라이딩해서 사용하면 될 것 같습니다. 사용자(개발자) 편의를 위한 계층화라고 생각되네요.


'Spring MVC > 6장 Controller' 카테고리의 다른 글

AbstractController  (0) 2007.06.21
Non-String DataBinding 테스트하기  (0) 2007.06.21
간단한 DataBinding 테스트하기  (0) 2007.06.20
MultiactionController  (0) 2007.06.19
SimpleFormController's onSubmit()  (0) 2007.04.11
SimpleFormController  (0) 2007.02.28
Controller  (0) 2007.02.28
top

Write a comment.


SimpleFormController



참조 : org.springframework.web.portlet.mvc.SimpleFormController

주로 새로운 정보를 입력 또는 수정할 때 사용하는 컨트롤러라고 합니다. 그런데 저는 간단한 검색을 할 때 사용해 봤던 적이 있지요. ㅎㅎㅎ;; 사용하면 안되는건 아니지만 권총으로 맞출 과녁을 대포로 쏴서 맞춘격에 비유할 수 있는 것 같습니다.

이녀석을 사용할 때 설정 해 줄 것이 몇 개 있는데요. form에서 정보 받아올 command 객체(이름과 class)랑 form이 있는 view, 그리고 에러 없이 command 객체를 받아서 전해 줄 successView 이름을 줄 수 있습니다. form이 있는 view는 생략이 가능합니다. 그리고 부가적으로 command 객체에 정보를 검증할 수 있는 validation을 만들어서 사용할 수 있습니다.

사용자 삽입 이미지
이런식으로 동작하게 됩니다. sequence diagram보다 이게 더 보기 좋군요.
Controller와의 관계를 보기 위해 클래스 다이어그램을 보겠습니다.
사용자 삽입 이미지
와.. 기네요~ 이렇게 계층화가 잘 되어 있기 때문에 확장성이 좋다고 하는 것 같습니다. 계층화가 잘 되어 있으면 원하는 지점에서 상속 받아서 사용하면 되기 때문이겠죠?

'Spring MVC > 6장 Controller' 카테고리의 다른 글

AbstractController  (0) 2007.06.21
Non-String DataBinding 테스트하기  (0) 2007.06.21
간단한 DataBinding 테스트하기  (0) 2007.06.20
MultiactionController  (0) 2007.06.19
SimpleFormController's onSubmit()  (0) 2007.04.11
SimpleFormController  (0) 2007.02.28
Controller  (0) 2007.02.28
top

Write a comment.


Controller



참조 : org.springframework.web.servlet.mvc.Controller

MVC 모델에서 C에 해당하는 녀석으로 주로 Servlet이 이 역할을 담당하고 있었고 Struts에서는 Action이라는 것이 역할을 하고 있었는데 Spring MVC를 사용하면 Servlet = Controller or Action = Controller 라고 외우지 않아도 "Controller는 Controller다." 라고 그냥 받아 들이면 되서 편하네요.

Controller API를 보면 책임이 딱 한 개 있는 것이 보입니다.
ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception
HttpServletRequest와 HttpServletResponse 객체를 받아서 ModelAndView 객체를 반환합니다.
사용자 삽입 이미지
이렇게 그리면 되는건지.. 흠..시퀀스 다이어그램은 익숙치가 않아서 많이 보고 그려봐야겠네요.

'Spring MVC > 6장 Controller' 카테고리의 다른 글

AbstractController  (0) 2007.06.21
Non-String DataBinding 테스트하기  (0) 2007.06.21
간단한 DataBinding 테스트하기  (0) 2007.06.20
MultiactionController  (0) 2007.06.19
SimpleFormController's onSubmit()  (0) 2007.04.11
SimpleFormController  (0) 2007.02.28
Controller  (0) 2007.02.28
top

Write a comment.


SimpleFormController 에피소드1



이녀석을 공부하는 어제부터 현재까지 여러 가지 에피소드들이 있었습니다. 발생한 의문들에 자문 자답을 해봅니다.

1. SimpleFormController가 어떻게 흘러가는 건지 이해가 되지 않았습니다.

AbstractController는 ModelAndView 객체에 요청을 처리할 view이름과 그 view에서 사용할 객체를 전달해 주었습니다. 그런데 이녀석은 그렇게 처리하기엔 뭔가.. 허전하다고 느껴지거든요. 자신에게 어떤 요청이 들어왔다는 것은 무엇을 입력할 곳을 찾아 왔다는 것이고[각주:1] 그럼 일단 그 화면으로 이동을 해줘야 하고 그 때 사용자가 입력할 데이타를 받아들일 객체가 있어야겠습니다. 아마도 그녀석을 Command 객체라고 부르는 것 같습니다. 일단 여기까지는 AbstractController와 비슷합니다. 하지만 여기서 끝나면 안되겠죠. 사용자가 입력을 마치고 엔터를 쳤을 때 또 다시 요청이 날아오게 됩니다. 이것도 역시 처리를 해줘야겠죠. 이 요청도 처리를 합니다. 생성자에 setSuccessView("결과를 보여줄 view 이름") 을 생성자에 추가해주면 그쪽 페이지로 이동하게 됩니다.

1.1. Command 객체는 뭔가?

도메인 객체인가? 아닌것 같다는 생각이 듭니다. 물론 도메인 객체를 써도 되겠지만 Command 객체는 사용자가 입력한 값을 받아 오는 역할을 하는 객체이고 만약 사용자가 입력하는 정보다 여러개의 객체에 걸쳐있는 값들이라면 그 때는 도메인 객체만으로는 처리할 수 없겠죠. 아마 그럴 땐 Command 객체를 하나 만들어서 그 안에서 해당 객체에 정보가 들어가도록 처리를 해야될 것 같습니다.

1.2. ModelAndView 객체에는 여러 객체가 들어갈 수 있는 건가?

add("이름", 객체) 형태의 메소드로 여러 객체를 ModelAndView에 붙여 줄 수 있습니다. 그리고 여기서 붙인 객체들은 "첫번째 요청에 의해 보여지는 페이지"와 "두번째 요청에 의해 보여지는 페이지"[각주:2]에서 모두 사용이 가능합니다.
  1. 검색을 하기 위한 링크를 클릭 했다든가 회원 가입, 글 쓰기등의 버튼을 클릭했을 것입니다. [본문으로]
  2. success view에서 요청한 페이지 [본문으로]

'Spring > 주소록 만들기' 카테고리의 다른 글

DisplayTag 링크 기능  (0) 2007.02.08
Validator 사용하기  (0) 2007.02.07
검색창 하나로 모든 필드에서 검색하기.  (4) 2007.02.07
SimpleFormController 에피소드2  (0) 2007.02.02
SimpleFormController 에피소드1  (2) 2007.02.02
Spring's form tag  (0) 2007.02.01
DisplayTag과 SpringMVC  (0) 2007.01.31
DisplayTag 배끼기  (2) 2007.01.31
주소록 개발 카탈로그  (4) 2006.12.30
JSP 화면 작성  (0) 2006.12.29
Spring MVC configuration 파일들 설정 하기  (0) 2006.12.26
top

  1. joshua 2007.03.27 18:16 PERM. MOD/DEL REPLY

    감사합니다

    Favicon of https://whiteship.tistory.com BlogIcon 기선 2007.03.27 18:37 신고 PERM MOD/DEL

    넵..1.2 질문에 요즘에 알게된 방법으로는...
    Map 객체를 넘겨주는 건데요. add("이름", 객체) 이렇게 계속 붙이는 거 보다 더 깔끔한거 같습니다.

    ModelAndView("뷰이름", Map객체);

    이렇게 주는거죠.

Write a comment.


Web Application Context 작성



참조 : Spring MVC 어플리케이션 개발 <3> Web Application Context 파일 작성

Spring Reference에 Dispatcher와 WebApplicationContex와의 관계를 나타낸 그림이 있어서 퍼왔습니다.
사용자 삽입 이미지
앞에서 addressBook-servlet.xml로 .do로 끝나느 요청을 넘기기로 했고 지금 이 글에서 작성해야할 addressBook-servlet.xml을 예전에는 hanlderMapping이라고 머릿속으로 단순화 시켜서 인식하고 있었는데 그게 아닌 것 같습니다. addressBook-sevlet.xml은 WebApplicationContext이고 이 안에 Handler Mapping, View Resolver, Controller들을 등록해 둘 수 있는 것 같습니다.

web/WEB-INF 폴더 안에 addressBook-servlet.xml 이라는 파일을 생성합니다.
Spring 2.0에서 XML 기반의 configuration metadata의 기본 포맷은 다음과 같습니다.

<?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-2.0.xsd">
  <bean id="..." class="...">
    <!-- collaborators and configuration for this bean go here -->
  </bean>
  <bean id="..." class="...">
    <!-- collaborators and configuration for this bean go here -->
  </bean>
</beans>

이제 여기에 Handler Mapping, View Resolver, Controller들을 넣어 봅시다.

Handler Mapping은 요청이 들어온 URL에 따라 어떤 컨트롤러가 사용되어야 하는지 매핑시키는 것으로 이해를 했는데 아무것도 지정해 두지 않으면 bean이름으로 매핑 시킨다고 하는데 흠~ 공부가 필요한 부분입니다.

View Resolver는 view를 실제 파일 이름으로 변환해주는 변환기 역할을 한다고 합니다.

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

위와 같이 등록해 둡니다. view앞에는 /WEB-INF/jsp/ 를 붙이고 뒤에는 .jsp를 붙여서 실제 파일을 찾을 수 있도록 합니다. viewClass 속성은 jsp가 JSTL을 사용할 때 적어주는 것 같습니다.

Controller차례인데요. 먼저 Handler는 요청을 처리하는 Controller의 메소드 단위 라고 합니다. 역시 이 부분도 공부가 필요할 것 같습니다. 이것을 다음과 같이 설정합시다.

<bean name="/index.do"
  class="org.springframework.web.servlet.mvc.ParameterizableViewController">
  <property name="viewName" value="index" />
 </bean>

index.do 요청이 발생하면 ParameterizableViewController로 요청이 넘어가고 이 녀석은 view 이름으로 index를 반환해 줍니다. 그럼 이것이 View Resolver를 타고 /WEB-INF/jsp/index.jsp 를 찾게 됩니다.

이제 addressBook-servlet.xml 파일은 다 만든것 같습니다.

실제 web/WEB-INF 폴더 밑에 jsp라는 폴더를 만들고 그 안에 index.jsp 파일을 만듭니다. index.jsp파일은 제대로 돌아가는지 확인하기 위해 "오~케이!!!"가 출력 되도록 간단히 만들어 봤습니다.

그리고 서버를 가동 시키면....
사용자 삽입 이미지
헉... 이렇게 나오네요;; 음~ 각본에 없던 것이 발생했습니다.

원래대로면 Jstl.jar파일이 없어서 에러가 발생해야 하는데..왜 404가 뜨는지 모르겠군요. 분명히 addressBook-servlet.xml파일은 존재하는데;; 일단은 문제가 발생했으니 여기서 STOP해야겠습니다.

=> 문제 해결 됨. 서버 에서 실행(Run on Server)를 할 때 Alt + Shift + x -> R 단축키를 사용하지 말고 프로젝트 이름 우클릭 -> Run as -> Run on Server 클릭하면 됩니다.

'Spring > 주소록 만들기' 카테고리의 다른 글

JSP 화면 작성  (0) 2006.12.29
Spring MVC configuration 파일들 설정 하기  (0) 2006.12.26
MVC 컨트롤러 작성  (0) 2006.12.26
화면 작성  (0) 2006.12.26
Alt + Shift + X, R 주의  (2) 2006.12.25
Web Application Context 작성  (3) 2006.12.25
Spring MVC 구동을 위한 web.xml 작성  (0) 2006.12.25
이클립스에서 웹 프로젝트 생성하기  (0) 2006.12.25
Spring MVC 공부 중  (10) 2006.12.23
CSS 공부 중  (2) 2006.12.21
주소록 화면 완성  (3) 2006.12.19
top

  1. Favicon of http://chanwook.tistory.com BlogIcon 찬욱 2006.12.25 21:20 신고 PERM. MOD/DEL REPLY

    log4j 등록하고 로그 확인해 보세요.
    404 error가 아닌 다른 설정 에러가 발생해도 404로 나오는 경우가 만더라구요~^^

    Favicon of http://whiteship.tistory.com/ BlogIcon 기선 2006.12.25 22:51 PERM MOD/DEL

    그렇군..제사도 끝났으니 다시 해봐야겠어. 영회형이 정리를 매우 잘 해 놓으셨더라고. 역시 대단하셔.

    Favicon of http://chanwook.tistory.com BlogIcon 찬욱 2006.12.25 23:18 신고 PERM MOD/DEL

    인정!ㅎ

Write a comment.


Spring MVC 공부 중



Spring MVC가 작동하는 전체적인 그림은 Spring Reference에 있는 그림을 참고 하면 다음과 같습니다.
사용자 삽입 이미지
그림에 순서가 적혀있지 않아서 번호를 붙여 봤는데 아무래도 저렇게 동작할 것 같습니다. Spring In Action에도 이와 비슷한 그림을 본 것 같아서 찾아 봤습니다.
사용자 삽입 이미지

Spring Reference에 있는 그림보다 깔끔한것 같습니다.

Dispatcher Sevlet은 흔히 web.xml 파일을 말하며에 <servlet>태그로 설정하며  이것이 Spring Reference에 있는 front controller에 해당합니다.

Handler Mapping은 요청에 따라 어떤 controller 객체가 사용될지에 대한 정보를 가지고 있으며 web.xml에 bean 설정파일에 하나 이상의 Handler Mappling들이 등록되어 있습니다.을 등록할 수 있습니다.

Controller는 Handler Mapping에 전부 등록이 되어있고 POJO 형태이고 DI를 사용합니다. ModleAndView 객체를 반환하는 메소드들이 있습니다.

ViewResolver는 반환된 ModelAndView 객체를 View에 맵핑합니다. 여기서 궁금한 것은 Handler Mapping과 분리 된 파일에 정의 해 둘 수도 있고 같은 곳에 둘 수도 있겠죠?? 아마 그래서 Spring In Action에서는 따로 그리고 Spring Reference에서는 Front Controller로 향하도록 그린것 같습니다. 이 bean에 있는 정보를 바탕으로 이 객체의 정보를 사용할 view에 객체를 전달하게 되는 듯 합니다. (여기서 부터 주춤거리기 시작합니다. ㅎㅎㅎ)

View는 JSP나 HTML같은 파일을 말하는 것 같습니다.

'Spring > 주소록 만들기' 카테고리의 다른 글

화면 작성  (0) 2006.12.26
Alt + Shift + X, R 주의  (2) 2006.12.25
Web Application Context 작성  (3) 2006.12.25
Spring MVC 구동을 위한 web.xml 작성  (0) 2006.12.25
이클립스에서 웹 프로젝트 생성하기  (0) 2006.12.25
Spring MVC 공부 중  (10) 2006.12.23
CSS 공부 중  (2) 2006.12.21
주소록 화면 완성  (3) 2006.12.19
중간점검  (0) 2006.12.17
HTML 공부 중 2탄  (2) 2006.12.14
Strict HTML 4.01 지침서  (6) 2006.12.14
top

  1. Favicon of http://chanwook.tistory.com BlogIcon 찬욱 2006.12.24 21:25 신고 PERM. MOD/DEL REPLY

    Spring In Action에 나오는 그림이 더 이해가 쉬운거 같습니다.

    Dispatcher Sevlet이 바로 web.xml 이다라기 보다는 web.xml에서 모든 서블릿의 요청을 받아서 처리하도록 선언되어 있는 서블릿을 말하는 것 같습니다. servlet_name-servlet.xml 처럼 말이죰.

    위에서 Handler Mapping이라고 예를 들으신 부분(Servlet 매핑 부분)은 Handler Mapping이 아니라 Dispatcher Servlet을 선언한 부분인 것 같습니다. Handler Mapping은 선언된 Dispatcher Servlet 안에 선언이 되겠죠.

    View Resolver도 web.xml에 바로 설정하기 보다는 다른 xml파일로 작성해서 web.xml에 선언해 두는게 많이 쓰이는 것 같습니다.(web.xml에 바로 선언되도 되나요?)
    마지막에 궁금해 하신 mapping 부분과 resolver를 분리하는 건 가능하고, 그렇게 하는게 더 옳은 방법일 것 같군욤^0^

    Favicon of https://whiteship.tistory.com BlogIcon 기선 2006.12.24 22:19 신고 PERM MOD/DEL

    Dispatcher Sevlet이 XXX-sevlet.xml 같은 파일을 말한다는 것인가요? 글쎄.. 제가 이해한 바로는 web.xml에서 어떤 Hanler Mapping들이 어떤 URL들을 담당할지 정의해 두는 요청을 받아들이는 맨 앞단으로 이해를 했고..그 생각이 별로 바뀌지 않는군요.

    예제에 대한 부분은 예제의 위치가 오해의 소지가 있지만 내용은 딴지 걸게 없는것 같은데요. 전 그 예제가 Disapatcher의 예고 Handler Mapping을 등록해 두고 있다고 이해했다고 말하고 있죠.

    View Resolver를 web.xml에 둔다는 말을 한적도 없습니다. 'Handler Mapping에 같이 둘 수도 있고 따로 둘 수도 있지 않을까?' 라고 했는데. Handler Mapping은 XXX-sevlet.xml파일로 제 머릿속에서 매칭시키고 있습니다.(Dispatcher를 web.xml로 매칭시키듯이) 예제로 긁어 올린 부분은 springkorea 에서 개발 하던 소스에서 본것이니 직접 확인하시면 될 것 같습니다.
    --------------------------------------------------
    열심히 딴지 걸어줘서 다시 한번 점검하는데 도움이 됐어. 쌩큐. 하지만 '욤'같은 글자체는 별로 안 이쁘군.

  2. Favicon of http://chanwook.tistory.com BlogIcon 찬욱 2006.12.25 10:23 신고 PERM. MOD/DEL REPLY

    딴지(?)는 아니었고 제 생각과 다른 부분이 있어서 댓글을 달아 봤죠.
    다시한 번 댓글 달아 봅니다^^.

    "Dispatcher Sevlet은 흔히 web.xml 파일을 말하며"
    => Dispatcher Servlet은 web.xml이 아니라 servletName-servlet.xml을 말합니다.

    "Handler Mapping은 요청에 따라 어떤 controller 객체가 사용될지에 대한 정보를 가지고 있으며 web.xml에 하나 이상의 Handler Mappling들이 등록되어 있습니다."
    => web.xml에는 Dispatcher Servlet을 선언하는 것 같습니다. 매핑부분에 보시면 DispatcherServlet이라고 선언되어 있기 때문에 그렇게 생각됩니다.

    제 생각에 형과 저의 이해한 부분이 DispatcherServlet과 Handler Mappings 부분에 대한 이해가 약간
    상이한 것 같습니다. 그렇죠? 시간이 없어서 정리를 마저 못 했지만 앞부분만 제 생각을 정리해봤습니다

    사실 약간 표현이 다를 뿐이지 의미는 같은 것 같은데요.
    글을 쓰신 것에 대한 딴지는 아니구요, 보다 더 정확히 이해해 보자는 말씀입니다.
    지나치지 않는 논쟁은 언제나 활력소를 불러 일으키자나요.

    -----------------------------------------------------------------------------------------
    '욤'은 제 나름대로 귀여움의 표현이었지만, 기분이 상하셨다면 안남기도록 하죠.
    사과하겠습니다.

    Favicon of https://whiteship.tistory.com BlogIcon 기선 2006.12.25 10:51 신고 PERM MOD/DEL

    먼저 DispatcherServlet의 경우 Spring In Action에서 이것이 Spring MVC의 핵심이라고 말하면서 8.1.2에 다음과 같이 말하고 있지.

    "At the heart of Spring MVC is DispatcherServlet, a servlet that functions as
    Spring MVC’s front controller. Like any servlet, DispatcherServlet must be configured
    in your web application’s web.xml file."

    내가 이 부분을 읽고 너무 단순하게 web.xml파일이라고 써논 것은 억측이지만 내 이해를 단순화 시키기 위해 그렇게 써놓은 것이고.. 다시 쓰자면..

    web.xml 파일안에 <sevlet> </sevler> 사이 부분이 Dispatcher 부분이라고 써야겠지.

    그래서 "Dispatcher Servlet은 web.xml이 아니라 servletName-servlet.xml을 말합니다."라고 반박해준 부분에 난 동의 할 수 없지.. servletName-servlet.xml은 Handler Mapping이라고 이해 했거든(이것도 단순화 시켜서) 그리고 이 Handler Mapping을 Dispatcher안에 등록 해두는 것으로 이해했지..

    Handler Mapping은 어떤 요청을 어떤 컨트롤러 객체가 처리하도록 매핑 시킬 때 사용하되는 것으로 이해를 했고.

    내가 보기에.. 너랑 나랑 이해의 차이가 생긴 이유가 너는 Dispatcher Servlet과 Handler Mapping을 동일시 하는 것 같고 난 다른 존재로 인식해서 발생한 것 같은데.. 이런 생각이 드는 이유는

    "web.xml에는 Dispatcher Servlet을 선언하는 것 같습니다. 매핑부분에 보시면 DispatcherServlet이라고 선언되어 있기 때문에 그렇게 생각됩니다." 이 부분은 내가 이 댓글의 위에서 말한 부분과 거의 같은 말이라.. 이해가 같은데.. 이 글을 Handler Mapping에 관한 반박 부분에 달아 놓았다는 건.. Handler Mapping과 Dispatcher를 동일시하고 있다고 생각하게 되는 이유지..

    Anyway~ 덕분에 MVC 주요 용어들과 실제 파일과의 매칭이나 개념적인 이해에는 많은 도움이 된 것 같아서 고마워.

    Favicon of http://chanwook.tistory.com BlogIcon 찬욱 2006.12.25 11:34 신고 PERM MOD/DEL

    고맙긴요, 부끄럽게..-_-ㅋ
    형 말처럼 저도 단순화를 위해 둘을 동일시 했거든요.^^
    저도 형 덕에 다시 한 번 생각해보게 됐습니다.
    쌩유에요.

    정체된 지식만큼 경계해야 할게 없겠죠.^^

  3. Favicon of http://chanwook.tistory.com BlogIcon 찬욱 2006.12.25 10:29 신고 PERM. MOD/DEL REPLY

    크리스마스 아침인데 제가 글 쓰고 트랙백 달기 전에 벌써 트랙백을 달으시다니..ㅋ
    저야 출근했다 치지만요~

    Favicon of https://whiteship.tistory.com BlogIcon 기선 2006.12.25 10:51 신고 PERM MOD/DEL

    ㅋㅋㅋ난 오늘 밤에 제사라서 집에서 공부나 하려고

    Favicon of http://chanwook.tistory.com/ BlogIcon 찬욱 2006.12.25 11:33 PERM MOD/DEL

    ㅋㅋ 좋구만요.
    제사를 가장한 공부. 밤에 제사면 낮에는 놀아도 되자나요. 음..여긴 분위기가 급박합니다. 같이 한 번 느껴봐야 하는 건데요!ㅎ(근데 왠 블로그질을 할까요?ㅋㅋ)

    Favicon of https://whiteship.tistory.com BlogIcon 기선 2006.12.25 11:38 신고 PERM MOD/DEL

    그러게 나도 일좀 해볼걸 그랬어. 경험치도 쌓이고 돈도 주고~ 30일에 보겠군. 그때 봅세~

  4. Favicon of https://whiteship.tistory.com BlogIcon 기선 2007.05.11 12:38 신고 PERM. MOD/DEL REPLY

    이런 지금 다시 보니까 말도 안되게 써놨군 아 창피해;;-_-;;;

Write a comment.


Web Layer



Web Layer

이 계층에서 다루는 주요 기능 두가지
- Navigation Logic 담당
- Domain model 과 Service Layer의 중계자 역할

특징
- servlet 으로 간단하게 구현될 수 있다. 이런 servlet은 request 파라미터를 객체로 바꾸고 service 인터페이스의 메소드를 호출한다.
- 유저들을 위해서 비즈니스 exception들을 적당한 에러 메시지로 바꿔야 하는 책임도 있다.

Spring MVC가 하는 일
- Spring MVC는 request 파라미터를 비즈니스 로직이 직접 작동할 수 있는 POJO로 맵핑하는 등의 request 파라미터와 비즈니스 로직 계층간의 복잡한 메카니즘을 제공한다.
- Spring은 request들을 처리하고 확장이 편하도록 복잡한 업무 흐름을 구현하고 있다.

종속성
-Service Layer(web에서 받은 정보를 service layer에 전해 줄 domain 객체로 전환)
-Domain Layer
사용자 삽입 이미지
Spring MVC Web Layer API
- org.springframework.web.servlet.mvc.Controller 인터페이스
- HttpServletRequest와 HttpServletResponse를 받을 때 필요하다.
- client에게 정보를 돌려줄 때 ModelAndView 객체를 만든다.


'Spring MVC > 3장 Spring MVC' 카테고리의 다른 글

Spring MVC에서 사용하는 ApplicationContext와 WebApplicationContext  (6) 2008.07.03
Service Layer  (2) 2006.12.13
Web Layer  (0) 2006.12.12
User Interface Layer  (0) 2006.10.09
Layers of Abstractions  (0) 2006.10.08
top

Write a comment.


User Interface Layer



Layers in a Spring MVC Application

User Interface Layer

The user interface layer is responsible for presenting the application to the end user. 이 계층은 web layer에서 생성된 응답을 유저가 요청한 양식으로 변환합니다. 예를 들어 휴대폰 사용자들을 위해서는 WML 또는 최소한 특화된 XHTML을 필요로 할 것입니다.

웹 개발자들에게 user interface layer 추상단계는 매우 중요합니다. user interface layer를 weblayer 의 sublayer로 생각하면 쉬울 것입니다. 이 책은 웹 에플리케이션에 초점을 맞췄기 때문에 이 계층을 따로 분리를 했으며 이 계층 만의 관심사와 특징들이 존재한다.


User Interface Layer는 최상위 계층입니다. 개념적으로 이 말은 유저(Client)에게 데이터를 보내기 전 마지막 계층 이라는 것입니다. 이 계층에 다다르기 전에 이미 비즈니스 로직과 트랜잭션이 처리가 되고 모든 자원들이 반환되었었을 것입니다.

이 계층이 마지막에 있는 것은 좋은 것입니다. 이 계층은 유저들에게 보내질 데이터를 원하는 양식으로 바꿔(rendering)줍니다. UI 계층은 다른 계층들과 분리 되어 있기 때문에 시스템은 계속해서 다른 요청들을 처리할 수 있습니다. 유저에게 보낼 응답을 랜더링 하는 것은 응답을 모아오는 행위(DB 커넥션 유지, 비즈니스 로직 처리 등등을 마말하는 거겠죠?? 긴가 민가 하네요. 응답을 처리하는 행위가 더 나르려나..)와 분리 되어 있다는 것입니다.

UI 계층을 분리 시키는 것은 현실적입니다. 여러가지 UI 랜더링을 위한 툴들이 존재하기 때문입니다. JSP, Velocity, Freemarker등에 종속되지 않고 UI 인터페이스를 사용하여 특정 랜더링 기술을 사용하여 UI를 변경하더라도 다른 계층들에 영향을 주지 않을 수 있습니다.

Spring MVC's User Interface Layer


Spring MVC UI 관심사를 몇몇 주요 인터페이스들로 분리시킵니다. org.springframework.web.servlet.View 인터페이스는 에플리케이션의 view 또는 page 를 나타냅니다. 유저가 요청한 작업의 결과를 고객이 볼 수 있는 폼으로 전환하는 역할을 합니다.


Model은 객체들의 이름의 집합입니다. 어떤 객체든지 Model 안에 있는 View로 랜더링 될 수 있습니다. Model은 일반적인 목적으로 설계되었기 때문에 어떠한 랜더링 기술과도 작업이 가능합니다. View 랜더링 툴킷은 Model안에 있는 각각의 객체들을 랜더링 합니다.


View 인터페이스는 완전히 일반적이고 특정한 뷰 랜더링에 종속되어 있지 않습니다. 각각의 뷰 기술들은 이 인터페이스를 구현한 클래스로 제공됩니다.  Spring MVC는 기본적으로 JSP, FreeMarker, Velocity, JasperReports, Excel, PDF를 지원합니다.

org.springframework.web.servlet.ViewResolver는 인디렉션을 하는 유용한 인터페이스를 제공합니다. ViewResolever는 뷰 개체들과 그들의 논리적인 이름간의 맵핑하는 기능을 제공합니다. 예를 들어 /WEB-INF/jsp/onSuccess.jsp 파일을 success라는 이름으로 참조 할 수 있도록 합니다. 이것은 실제 View 객체와 코드 내에서 그것을 참조하는 것을 decoupling 시킵니다. ViewResolver를 사용하여 보다 유연한 설정을 할 수 있습니다.



Dependencies

View 계층은 일반적으로 domain 계층에 종속됩니다. 항상 그런 것은 아니지만, 보통 도메인 모델에 직접 접근하여 랜더링 하는 것이 편리합니다. Spring MVC를 사용하는 대부분의 편리함은 view가 도메인 객체에 직접 작업을 한다는 것으로부터 생깁니다.



Summary

User interface 계층(View 계층이라고도 합니다.)은 유저를 위한 결과물의 랜더링을 책입집니다. Spring MVC는 다양한 view 랜더링 기술을 지원합니다. 중요한 인터페이스로는 org.springframework.web.servlet.View와 org.springframework.web.servlet.ViewResolver입니다. view기술들에 대해서는 7장과 8장에서 자세히 다룰것입니다.



'Spring MVC > 3장 Spring MVC' 카테고리의 다른 글

Spring MVC에서 사용하는 ApplicationContext와 WebApplicationContext  (6) 2008.07.03
Service Layer  (2) 2006.12.13
Web Layer  (0) 2006.12.12
User Interface Layer  (0) 2006.10.09
Layers of Abstractions  (0) 2006.10.08
top

Write a comment.


Layers of Abstractions



Layers of Abstractions

Spring MVC 에플리케이션들은 여러 계층으로 나누어져있다. layer is a discrete, othogonal area of concern within an application. 여러 계층들은 에플리케이션의 추상화에 해당하며 인터페이스는 계층들간 상호작용의 규약을 제공한다. 어떤 계층들은 몇몇 다른 Layer들과 상호작용을 하지만 매우 중요한 계층은 모든 계층과 상호작용을 한다.
계층은 개념적인 경계선이고 물리적으로 떨어져 있을 필요는 없다.

A Layer is a logical abstraction within an application. A tier is best thought of as a physical deployment of the layers.


계층 구조로 생각하는 것이 에플리케이션의 전체 흐름을 개념화하는데 도움이 된다. 에플리케이션 계층들을 케잌처럼 쌓아 놓은 모습으로 보는 것이 가장 흔하고 편리한 방법이다.
Spring MVC 에플리케이션은 최소 다섯 개의 추상화된 계층을 가지고 있으며 각각은 다음과 같다.
  • user interface
  • web
  • service
  • domain object model
  • persistence

위 그림을 보면 Domain Model이 왼쪽에 세로로 서있는 것을 볼 수 있습니다. 이것은 다른 모든 계층들이 Domain Model 계층에 종속하기 때문입니다.
매우 중요한 계층인듯 합니다. 저런 경우에 AOP를 사용한다고 본 것 같은데 지금 저 계층들에 없는 tracjaction management, security같은 것은 AOP를 사용하여 뺏다고 하는데 Domain Model은 그럴만한 성격이 아닌가 보네요.

Layer Isolation


계층을 분리시키는 것은 에플리케이션을 보다 유연하고 테스트가 용이하도록 만듭니다. 이러한 분리는 계층 사이의 종속성을 최소화 함으로써 달성할 수 있습니다. 종속성 남발을 피할 수 있는 최소한 두가지 방법이 있습니다. 만약에 어떤 계층이 다른 여러 계층들에 종속하기 시작하면 다른 계층간의 상호작용을 추상화하는 새로운 계층을 만드는 것을 고려해 봅니다. 또 하나의 계층이 여러 계층들에서 사용된다면 Spring의 AOP를 사용하는 것을 어떨지 생각해 봅니다.
여기서 기억하야 할 것은 에플리케이션을 여러 계층으로 나누는 것은 decouple 된 설계를 만들어 낸다는 것입니다. 그렇게 함으로써 여러분의 에플리케이션이 보다 유연하고(확장이나 변동이 쉽고), 테스트가하기 편해집니다.

Java Interface As Layer Contract


에플리케이션의 계층을 나누는데 Java 인터페이스가 중요한 역할을 합니다. 인터페이스는 계층간의 규약이며 그들의 구현과 세부사항을 숨긴 채 계층 간의 작동이 유지될 수 있도록 합니다. 인터페이스에 의해 제공되는 low coupling의 이점에 대해서는 잘 알 고있을 것입니다. 그러나 여태까지 그러한 장점은 여태까지 인터페이스가 아닌 실제 구현된 클래스를 사용할 수 밖에 없는 상황이였기 때문에 잘 살리지 못했습니다. 하지만 Spring과 다른 DI 프레임웤을 사용한다면 가능합니다. Spring이 직접 에플리케이션의 코드 대신 객체의 생성에 대한 일을 해주기 때문입니다.
계층간의 규약을 인터페이스로 정의해두면 개발 시간을 단축시킵니다. 개발자들이 인터페이스에 맞춰 개발을 하기 때문에 그것을 구현한 코드가 작성되고 바뀌고 테스트되더라도 개발이 가능하기 떄문입니다.
계층간의 상호작용을 인터페이스로 정의해 두면 단위 테스트가 간편합니다. EasyMock과 같은 프레임웤을 사용하여 쉽게 인터페이스의 구현체를 만들어서 테스트할 수 있기 때문입니다.
인터페이스를 사용하여 계층에 접근하는 것은 컴파일 시간을 단축시키고 보다 모듈화된 개발을 가능케 합니다. Client code가 이미 사용하고 있는 것들을 재컴파일하지 않아도 새로운 클래스를 추가하거나 변경이 가능하기 때문입니다.
인터페이스를 사용하면 또한 시스템이 매우 유연해 집니다. 시스템이 시작할 때 또는 이미 실행 중일 때도 특정 구현체로 변동이 가능합니다. Client code가 인터페이스에 맞춰 컴파일 되었기 때문에 실행중에도 구현된 클래스를 바꿀수가 있습니다. 매우 동적인 시스템을 만들수가 있습니다.

여기까지 매우 간단하게 요약하자면 인터페이스를 사용하여 각 계층간의 규약을 정의한다. 인터페이스는 계층의 추상화를 제공하고 계층을 구현한 것이 다른 계층에 영향을 주지 않고 쉽게 변할 수 있도록 허용한다.

'Spring MVC > 3장 Spring MVC' 카테고리의 다른 글

Spring MVC에서 사용하는 ApplicationContext와 WebApplicationContext  (6) 2008.07.03
Service Layer  (2) 2006.12.13
Web Layer  (0) 2006.12.12
User Interface Layer  (0) 2006.10.09
Layers of Abstractions  (0) 2006.10.08
top

Write a comment.