뷰(View) 보여주기

개요

view-state 는 flow 내에서 화면을 생성하는 요소이다.
여기서는 view-state 에 대해서 알아보도록 하자.

설명

뷰 상태(view state) 정의하기

view-state 는 기본적으로 해당 뷰를 생성하여 보여준 후, 사용자가 화면을 통해 응답을 하는 것을 기다린다.
아래는 view-state는 enterBookingDetails 라는 ID 를 가지고 있으며 또한 별도의 view 설정이 없기 때문에 ID 가 곧 view 를 뜻한다.

<view-state id="enterBookingDetails">
	<transition on="submit" to="reviewBooking" />
</view-state>

따라서. 디렉토리 상의
booking.xml(or booking-flow.xml) 이 존재하는 디렉토리에 있는 enterBookingDetails.jsp 이 자동으로 view 로 동작한다.
또는 절대경로를 이용하여 명시적으로 view=”/WEB-INF/hotels/booking/enterBookingDetails.jsp” 설정할 수도 있다.
아래에서 다시 설명하겠다.

뷰 식별자 지정하기

뷰 속성을 여러 방법으로 지정할 수 있다.

  • 상대 경로 사용
<view-state id="enterBookingDetails" view="bookingDetails.xhtml">
  • 절대 경로 사용
<view-state id="enterBookingDetails" view="/WEB-INF/hotels/booking/bookingDetails.jsp>
  • 논리적인 경로 사용: Spring MVC 등과 통합 시
<view-state id="enterBookingDetails" view="bookingDetails">

뷰 범위

view-state 내부에서 유지되는 변수. Ajax 요청처럼 동일한 뷰가 여러번 보여줘야 하는 경우 유용.

  • var 태그를 사용해서 view 변수 선언.
<var name="searchCriteria" class="com.mycompany.myapp.hotels.SearchCriteria" />
  • viewScope 변수에 할당하기
<on-render>
	<evaluate expression="bookingService.findHotels(searchCriteria)" result="viewScope.hotels"/>
</on-render>

뷰 범위내에서 Object 다루기

아래코드는 화면 ID 가 searchResults 인 view-state 화면을 그리되
그리기전 bookingService.findHotels(searchCriteria) 메소드를 호출한 후 그 결과를 viewScope내의 hotels 로 저장한 후 화면을 보여주고 있다.
그리고 화면상에 next 또는 previous 이벤트 발생시 eval(searchCriteria.nextPage()/previousPage()) 이 발생
그 결과를 fragments으로 지정된 영역에 뿌려주고 있다.

<view-state id="searchResults">
	<on-render>
		<evaluate expression="bookingService.findHotels(searchCriteria)"
			result="viewScope.hotels" />
	</on-render>
	<transition on="next">
		<evaluate expression="searchCriteria.nextPage()" />
		<render fragments="searchResultsFragment" />
	</transition>
	<transition on="previous">
		<evaluate expression="searchCriteria.previousPage()" />
		<render fragments="searchResultsFragment" />
	</transition>
</view-state>

자세한 것은 아래에서 다시 설명하도록 하겠다.

화면을 보여줄 때 액션 실행

뷰를 보여주기 전에 특정 액션을 실행하려면 on-render 사용한다.

<on-render>
  <evaluate expression="bookingService.findHotels(searchCriteria)" result="viewScope.hotels" />
</on-render>

Model Binding

<view-state id="enterBookingDetails" model="booking">

뷰 이벤트가 발생했을 때 지정된 모델에 대해서 다음 행동이 일어난다.

  1. view-to-model binding.
  2. 모델 유효성 검증.

타입 변환 수행

변환기(Converter) 구현

org.springframework.binding.convert.converters.TwoWayConverter을 구현하면 됨. StringToObject를 구현하는게 더 좋다.

protected abstract Object toObject(String string, Class targetClass) throws Exception;
protected abstract String toString(Object object) throws Exception;

구현 예.

public class StringToMonetaryAmount extends StringToObject {
	public StringToMonetaryAmount() {
	super(MonetaryAmount.class);
  }
  @Override
  protected Object toObject(String string, Class targetClass) {
  	return MonetaryAmount.valueOf(string);
  }
  @Override
  protected String toString(Object object) {
  	MonetaryAmount amount = (MonetaryAmount) object;
  	return amount.toString();
  }
}

org.springframework.binding.convert.converters에 이미 구현된 변환기가 위치.

변환기 등록하기

org.springframework.binding.convert.service.DefaultConversionService을 상속해서 addDefaultConverters() 메소드를 재정의 하면 된다.
자세한 것은 시스템 설정 에서 ConversionService 확장을 이용하여 설정하는 곳에서 다루고 있다.

바인딩 금지하기

bind 속성으로 특정 뷰 이벤트에서 모델 바인딩과 유효성 검증을 안 하게 할 수도 있다.

<view-state id="enterBookingDetails" model="booking">
	<transition on="proceed" to="reviewBooking">
	<transition on="cancel" to="bookingCancelled" bind="false" />
</view-state>

명시적으로 바인딩 지정하기

아래와 같이 binder 속성으로 바인딩 할 프로퍼티를 명시적으로 지정할 수 있다.

<view-state id="enterBookingDetails" model="booking">
	<binder>
		<binding property="creditCard" />
		<binding property="creditCardName" />
		<binding property="creditCardExpiryMonth" />
		<binding property="creditCardExpiryYear" />
	</binder>
	<transition on="proceed" to="reviewBooking" />
	<transition on="cancel" to="cancel" bind="false" />
</view-state>

binder로 지정하지 않으면 모든 프로퍼티를 바인딩된다. converter를 이용하여 변환기 지정 가능하다.

<view-state id="enterBookingDetails" model="booking">
	<binder>
		<binding property="checkinDate" converter="shortDate" />
		<binding property="checkoutDate" converter="shortDate" />
		<binding property="creditCard" />
		<binding property="creditCardName" />
		<binding property="creditCardExpiryMonth" />
		<binding property="creditCardExpiryYear" />
	</binder>
	<transition on="proceed" to="reviewBooking" />
	<transition on="cancel" to="cancel" bind="false" />
</view-state>

Model 유효성 검증

Model 유효성 검사에 대한 부분은 Web flow 에서는 프로그래밍적으로 제약사항을 강제화 하는 형태로 지원하고 있다.

프로그램 내에서 유효성 검증

첫 번째 방법으로 유효성 검증 로직을 모델 객체 내에 정의하는 방법이다.
Web Flow 는 view-stat 에서 모델로 넘어간 시점(view-state postback lifecycle)에서 자동적으로 validate 메소드를 자동으로 호출한다.

<view-state id="enterBookingDetails" model="booking">
	<transition on="proceed" to="reviewBooking">
</view-state>

Booking class내의 validate{view-state 명) 코드는 아래와 같이 볼 수 있다.(메소드명 : validate + EnterBookingDetails)

public class Booking {
	private Date checkinDate;
	private Date checkoutDate;
  ...
	public void validateEnterBookingDetails(ValidationContext context) {
		MessageContext messages = context.getMessages();
		if (checkinDate.before(today())) {
			messages.addMessage(new MessageBuilder().error().source("checkinDate").
 
			defaultText("Check in date must be a future date").build());
		} else if (!checkinDate.before(checkoutDate)) {
			messages.addMessage(new MessageBuilder().error()
			                                        .source("checkoutDate")
			                                        .defaultText("Check out date must be later than check in date")
			                                        .build());
		}
	}
}

enterBookingDetails에 대한 이벤트가 발생했을 때 자동으로 validateEnterBookingDetails이 호출 된다.
메소드 이름을 validate$<state> 로 정의하면 된다.

Validator 구현

Validator로 불리는 별도의 객체로 정의할 수도 있다. 클래스 이름을 $<model>Validator 로 지정하면 된다.
메소드 이름은 역시 validate$<state>로 한다.
아래 클래스명은 Booking + Validator 이며 메소드 이름은 validate + EnterBookingDetails 임을 볼 수 있다.

@Component
public class BookingValidator {
	public void validateEnterBookingDetails(Booking booking, ValidationContext context) {
		MessageContext messages = context.getMessages();
		if (booking.getCheckinDate().before(today())) {
			messages.addMessage(new MessageBuilder().error()
			                                        .source("checkinDate")
			                                        .defaultText("Check in date must be a future date")
			                                        .build());
		} else if (!booking.getCheckinDate().before(booking.getCheckoutDate())) {
			messages.addMessage(new MessageBuilder().error()
			                                        .source("checkoutDate")
			                                        .defaultText("Check out date must be later than check in date")
			                                        .build());
		}
	}
}

spring mvc의 Error 객체도 받을 수 있다.

ValidationContext

유효성 검증 동안에 MessageContext에 접근할 수 있게 해주며, 다양한 객체에 접근 가능하게 해준다.

유효성 검증 하지 않기

validate=“false” 설정함으로 유효성 검사를 하지 않을 수 있다

<view-state id="chooseAmenities" model="booking">
	<transition on="proceed" to="reviewBooking">
	<transition on="back" to="enterBookingDetails" validate="false" />
</view-state>

뷰 transition 실행

전이 대상은 (1)다른 뷰, (2)현재 뷰를 다시, (3)action을 실행, (4)Ajax 이벤트를 제어할 때
'fragments'로 불리는 일부 뷰를 보여주라는 요청일 수도 있다.

전이 액션(Transition actions)

<transition on="submit" to="bookingConfirmed">
	<evaluate expression="bookingAction.makeBooking(booking, messageContext)" />
</transition>
public class BookingAction {
	public boolean makeBooking(Booking booking, MessageContext context) {
		try {
			bookingService.make(booking);
			return true;
		} catch (RoomNotAvailableException e) {
			context.addMessage(builder.error().defaultText("No room is available at this hotel").build());
			return false;
		}
	}
}

글로벌 전이(Global transitions)

<global-transitions>
	<transition on="login" to="login">
	<transition on="logout" to="logout">
</global-transitions>

이벤트 핸들러(Event handlers)

<transition on="event">
	<!-- Handle event -->
</transition>

프레그먼트 보여주기(fragments)

현재 뷰 중 일부만을 다시 보여줄 수 있는 방법으로, Ajax 기반일 때 주로 사용한다.

<transition on="next">
	<evaluate expression="searchCriteria.nextPage()" />
	<render fragments="searchResultsFragment" />
</transition>

','로 구분해서 다수의 fragment를 지정할 수도 있다.

메세지 사용하기

MessageContext는 플로우 실행 동안에 메세지를 저장하는데 사용되는 API다.
일반 메세지나 국제화가 지원된 메세지 모두 사용 가능하다.
메세지 수준도 지정 가능하며, 지원되는 수준은 info, warning, error이 있다. 메세지를 추가할 때는 MessageBuilder를 사용하자.

  • 일반 메세지 추가
MessageContext context = ...
MessageBuilder builder = new MessageBuilder();
context.addMessage(builder.error().source("checkinDate").defaultText("Check in date must be a future date").build());
context.addMessage(builder.warn().source("smoking").defaultText("Smoking is bad for your health").build());
context.addMessage(builder.info().defaultText("We have processed your reservation - thank you and enjoy your stay").build());
  • 국제화가 지원되는 메세지 추가
MessageContext context = ...
MessageBuilder builder = new MessageBuilder();
context.addMessage(builder.error().source("checkinDate").code("checkinDate.notFuture").build());
context.addMessage(builder.warn().source("smoking").code("notHealthy").resolvableArg("smoking").build());

메세지 번들 사용하기

스프링의 MessageSource를 사용해서 메세지 번들을 정의가 가능하다. 간단히 프로퍼티 파일로 관리하면 된다.

#messages.properties
checkinDate=Check in date must be a future date
notHealthy={0} is bad for your health
reservationConfirmation=We have processed your reservation - thank you and enjoy your stay

뷰나 플로우에서는 resourceBundle EL 변수로 접근도 가능하다.

<h:outputText value="#{resourceBundle.reservationConfirmation}" />

시스템 생성 메세지 이해하기

시스템에서 발생한 예외에 대해 메세지 지정 가능하다. 예를 들어 타입 변환 시 예외가 발생하면 typeMismatch를 통해서 메세지 지정 가능하다.

booking.checkinDate.typeMismatch=The check in date must be in the format yyyy-mm-dd.

팝업 띄우기

모달 팝업 다이얼로그를 뷰로 렌더링하고 싶다면, view-state 내에 popup=“true” 설정하면 된다.

<view-state id="changeSearchCriteria" view="enterSearchCriteria.xhtml" popup="true">

특히 스프링 자바 스크립트와 함께 사용하면, 팝업을 보여주는데 클라이언트 코드가 전혀 필요 없다.
SWF가 클라이언트 요청을 팝업으로 재전송(redirect)해준다.

뷰 백트랙킹(View backtracking)

기본적으로 브라우저의 백 버튼으로 이전 view-state로 돌아갈 수 있다. history를 사용해서 이에 대한 설정이 가능하다.

  • 'discard'로 설정하면 백트랙킹(backtracking) 예방 가능하다.
<transition on="cancel" to="bookingCancelled" history="discard">
  • 'invalidate'로 설정하면 이전에 보여줬던 모든 뷰 뿐만 아니라 현재 뷰까지도 백트랙킹 예방된다.
<transition on="confirm" to="bookingConfirmed" history="invalidate">

참고자료

 
egovframework/rte/bsl/rendering_views.txt · 마지막 수정: 2023/12/21 05:21 (외부 편집기)
 
이 위키의 내용은 다음의 라이센스에 따릅니다 :CC Attribution-Noncommercial-Share Alike 3.0 Unported
전자정부 표준프레임워크 라이센스(바로가기)

전자정부 표준프레임워크 활용의 안정성 보장을 위해 위험성을 지속적으로 모니터링하고 있으나, 오픈소스의 특성상 문제가 발생할 수 있습니다.
전자정부 표준프레임워크는 Apache 2.0 라이선스를 따르고 있는 오픈소스 프로그램입니다. Apache 2.0 라이선스에 따라 표준프레임워크를 활용하여 발생된 업무중단, 컴퓨터 고장 또는 오동작으로 인한 손해 등에 대해서 책임이 없습니다.
Recent changes RSS feed CC Attribution-Noncommercial-Share Alike 3.0 Unported Donate Powered by PHP Valid XHTML 1.0 Valid CSS Driven by DokuWiki