참조 및 번역: http://static.springframework.org/spring-webflow/docs/2.0.x/reference/html/index.html

3.1. 소개

웹 플로우는 EL을 사용하여 데이터 모델에 접근하며 액션을 호출한다. 이번 장에서 여러분은 EL 문법과 플로우 정의에서 참조할 수 있는 특별한 EL 변수들에 익숙해질 것이다.

3.2. 지원하는 EL 구현체

3.2.1. Unified EL

웹 플로우는 기본으로 Unified EL 사용을 시도한다. jboss-el이 현재 기본 EL 구현체이다. 여러분의 클래스패스에서 el-api을 발견하면 자동적으로 그것을 사용한다. JBoss EL jar 파일은 스프링소스 번들 저장소에서 찾을 수 있다.

노트

el-api 의존성은 보통 웹 컨테이너에서 제공하는 provided다. 예를 들어 톰캣 6는 그것을 가지고 있다.

3.2.2. OGNL

OGNL은 웹 플로우 2가 지원하는 또다른 EL이다. OGNL은 웹 플로우 버전 1.0 사용자에게 가장 익숙한 EL이다. ognl을 사용하려면, jboss-el 대신에 ognl을 클래스패스에 추가하면 된다. 문법을 익히려면 OGNL 레퍼런스 가이드를 참조하라.

3.3. EL 이식성

보통, UEL(Unified EL)과 OGNL은 문법이 비슷하다. 기본 변수 인식, 프로퍼티 접근, 그리고 메소드 호출 문법이 동일하다. 우리는 가능하면 UEL을 사용할 것을 권장하며 필요한 경우에만 별도의 EL 기능을 사용하라.

3.4. EL 사용법

EL은 플로우에서 여러 경우에 사용할 수 있다.

  1. 플로우 input 속성이나 request 매개변수 같은 클라이언트가 제공하는 데이터에 접근하기.
  2. flowScope 같은 내부 데이터 구조에 접근하기
  3. 스프링 빈의 메소드 호출하기
  4. 상태 전이 criteria, 하위 플로우 id 그리고 뷰 이름 같은 구조 인식하기

플로우에 의해 보여지는 뷰는 일반적으로 EL을 사용하여 플로우 데이터 구조에 접근한다.

3.4.1. 표현식 타입

웹 플로우에는 기본적으로 두 종류의 표현식이 있다.

3.4.1.1. 표준 평가 표현식(standard eval expressions)

처음으로 살펴볼 것은 가장 흔히 사용하는 표현식 타입으로 eval 표현식이다. 이 표현식은 EL에 의해 동적으로 평가되고 ${} 나 #{} 같은 구분자로 감싸지 않는다. 예제를 보자.

<evaluate expression="searchCriteria.nextPage()" />
       
위의 표현식은 값을 구해올 때 searchCriteria 변수의 nextPage라는 메소드를 호출하는 표준 표현식이다. 이 표현식을 ${} 나 #{} 같은 구분자로 감싸면 IllegalArgumentException 예외가 발생한다.

노트

이 상황에서 별도의 평가 구분자를 사용하는 것은 필요없다고 본다. 따라서 오직 expression 속성에 사용할 수 있는 값은 평가 표현식 문자열이다.

3.4.1.2. 템플릿 표현식

두 번째 표현식 타입은 "템플릿" 표현식이다. 이런 표현식은 문자열을 한 개 또는 여러 평가 블럭으로 혼합하는 것을 허용한다. 각각의 평가 블럭은 ${} 구분자를 사용하여 명시적으로 구분한다. 예제를 보자.

<view-state id="error" view="error-${externalContext.locale}.xhtml" />
               
위의 표현식은 템플릿 표현식이다. view 속성 값의 결과는 error- 뒤에 externalContext.locale 값을 합친 문자열이 될 것이다. 보시다시피 여기서는 템플릿 내에 평가 블럭을 구분하기 위해 명시적인 구분자가 필요하다.

웹 플로우 XML 스키마를 참조하여 표준 표현식과 템플릿 표현식에서 사용할 수 있는 XML 속성들을 전부 확인할 수 있다.

3.5. 특별한 EL 변수

플로우 안에서 참조할 수 있는 암묵적인 변수들 몇 개가 있다. 이번 절에서 이런 변수들을 논의할 것이다.

3.5.1. flowScope

flowScope를 사용하여 플로우 변수를 할당한다. 플로우 스코프는 플로우가 시작할 때 할당되고 플로우가 끝날 때 소멸된다. 기본 구현에 따라, 플로우 스코프에 저장된 모든 객체는 직렬화 할 수 있어야 한다.

<evaluate expression="searchService.findHotel(hotelId)" result="flowScope.hotel" />

3.5.2. viewScope

viewScope를 사용하여 뷰 변수를 할당한다. 뷰 스코프는 view-state에 들어갈 때 할당되고 상태가 종료되면 소멸된다. 뷰 스코프는 오직 view-state에서만 참조할 수 있다. 기본 구현체 따라, 뷰 스코프에 저장된 모든 객체는 질렬화 할 수 있어야 한다.

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

3.5.3. requestScope

requestScope를 사용하여 요청 변수를 할당한다. 요청 스코프는 플로우를 호출한 순간에 할당되고 플로우가 반환을 하면 소멸된다.

<set name="requestScope.hotelId" value="requestParameters.id" type="long" />

3.5.4. flashScope

flashScope를 사용하여 플래시 변수를 할당한다. 플래시 스코프는 플로우가 시작될 때 할당되고, 모든 뷰 랜더링을 마친뒤에 클리어하고 플로우가 끝날 때 소멸한다. 기본 구현에 따라, 플래시 스코프에 저장된 모든 객체는 직렬화 할 수 있어야 한다.

<set name="flashScope.statusMessage" value="'Booking confirmed'" />   

3.5.5. conversationScope

conversationScope를 사용하여 컨버세이션 변수를 할당한다. 컨버세이션 스코프는 최상위 플로우가 시작할 때 할당되고 최상위 플로우가 종료되면 소멸한다. 컨버세이션 스코프는 최상위 플로우와 모든 하위플로우에서 공유한다. 기본 구현에 따라, 컨버세이션 스코프에 저장하는 객체는 HTTP session에 저장하고 일반 세션 복사를 하기 위해 보통 직렬화 할 수 있어야 한다.

<evaluate expression="searchService.findHotel(hotelId)" result="conversationScope.hotel" />
           
3.5.6. requestParameters

requestParameters를 사용하여 클라이언트 요청 매개변수에 접근한다.

<set name="requestScope.hotelId" value="requestParameters.id" type="long" />
           
3.5.7. currentEvent

currentEvent를 사용하여 현재 이벤트 속성에 접근한다.

<evaluate expression="booking.guests.add(currentEvent.guest)" />
           
3.5.8. currentUser

currentUser를 사용하여 로그인한 사용자 정보(authenticated Principal)에 접근한다.

<evaluate expression="bookingService.createBooking(hotelId, currentUser.name)"
          result="flowScope.booking" />
           
3.5.9. messageContext

messageContext를 사용하여 플로우 에러나 성공 메시지를 포함한 플로우 실행 메시지를 생성하고 가져오는데 사용할 컨텍스트에 접근한다.MessageContext Javadoc에서 자세한 내용을 참조하라.

<evaluate expression="bookingValidator.validate(booking, messageContext)" />
           
3.5.10. resourceBundle

resourceBundle을 사용하여 메시지 리소스에 접근하라.

<set name="flashScope.successMessage" value="resourceBundle.successMessage" />
           

3.5.11. flowRequestContext

flowRequestContext를 사용하여 RequestContext API에 접근하라. 이것은 현재 플로우 요청을 나타낸다.자세한 내용은 API Javadoc을 참조하라.

3.5.12. flowExecutionContext

flowExecutionContext를 사용하여 FlowExecutionContext API에 접근하라. 이것은 현재 프로우 상태를 나타낸다. 자세한 내용은 API Javadoc을 참조하라.

3.5.13. flowExecutionUrl

flowExecutionUrl을 사용하여 현재 플로우 실행 view-state에 대한 컨텍스트 관련 URI에 접근하라.

3.5.14. externalContext

externalContext를 사용하여 사용자 세션 속성같은 클라이언트 환경에 접근하라. 자세한 내용은 ExternalContext API JavaDoc을 참조하라.

<evaluate expression="searchService.suggestHotels(externalContext.sessionMap.userProfile)"
          result="viewScope.hotels" />
           
3.6. Scope 검색 알고리즘

변수를 어떤 플로우 스코프에 할당할 때, 해당 스코프를 참조하는 것이 필요하다. 예제를 보자.

<set name="requestScope.hotelId" value="requestParameters.id" type="long" />
       
어떤 스코프에 들어있는 변수에 단순하게 접근할 때는, 스코프를 반드시 참조하지 않아도 된다. 예제를 보자.

<evaluate expression="entityManager.persist(booking)" />
       
위에서 booking을 사용한것처럼 만약 스코프를 적지 않으면 스코프 검색 알고리즘이 적용된다. 알고리즘은 request, flash, view, flow, conversation 스코프에서 변수를 찾아본다. 만약 해당 변수를 찾지 못하면 EvaluationException 예외를 던진다.