Whiteship's Note


[Spring Web Flow] booking 예제 분석 3 - webmvc-config.xml 설정

Spring Web Flow/etc : 2009.10.16 20:28


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

    <!-- Scans for application @Components to deploy -->
    <context:component-scan base-package="org.springframework.webflow.samples.booking" />

    <!-- Imports the configurations of the different infrastructure systems of the application -->
    <import resource="webmvc-config.xml" />
    <import resource="webflow-config.xml" />
    <import resource="data-access-config.xml" />
    <import resource="security-config.xml" />

</beans>

web.xml에 유일하게 등록되어 있는 빈 설정파일이었는데, 열어보니 네 개의 다른 빈 설정 파일들을 import 하고 있습니다. 이 중에서 webmvc-config.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"
       xsi:schemaLocation="
           http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">

    <!-- Maps request paths to flows in the flowRegistry; e.g. a path of /hotels/booking looks for a flow with id "hotels/booking" -->
    <bean class="org.springframework.webflow.mvc.servlet.FlowHandlerMapping">
        <property name="order" value="0" />
    </bean>

    <!-- Maps request paths to @Controller classes; e.g. a path of /hotels looks for a controller named HotelsController -->
    <bean class="org.springframework.web.servlet.mvc.support.ControllerClassNameHandlerMapping">
        <property name="order" value="1" />
        <property name="defaultHandler">
            <!-- If no @Controller match, map path to a view to render; e.g. the "/intro" path would map to the view named "intro" -->   
            <bean class="org.springframework.web.servlet.mvc.UrlFilenameViewController" />
        </property>
    </bean>

    <!-- Resolves logical view names returned by Controllers to Tiles; a view name to resolve is treated as the name of a tiles definition -->
    <bean id="tilesViewResolver" class="org.springframework.js.ajax.AjaxUrlBasedViewResolver">
        <property name="viewClass" value="org.springframework.webflow.mvc.view.FlowAjaxTilesView"/>
    </bean>

    <!-- Configures the Tiles layout system -->
    <bean id="tilesConfigurer" class="org.springframework.web.servlet.view.tiles2.TilesConfigurer">
        <property name="definitions">
            <list>
                <value>/WEB-INF/layouts/layouts.xml</value>
                <value>/WEB-INF/views.xml</value>
                <value>/WEB-INF/hotels/views.xml</value>
                <value>/WEB-INF/hotels/booking/views.xml</value>
            </list>
        </property>
    </bean>
   
    <!-- Dispatches requests mapped to POJO @Controllers implementations -->
    <bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter" />

    <!-- Dispatches requests mapped to org.springframework.web.servlet.mvc.Controller implementations -->
    <bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter" />

    <!-- Dispatches requests mapped to flows to FlowHandler implementations -->
    <bean class="org.springframework.webflow.mvc.servlet.FlowHandlerAdapter">
        <property name="flowExecutor" ref="flowExecutor"/>
    </bean>

    <!-- Custom FlowHandler for the hotel booking flow -->
    <bean name="hotels/booking" class="org.springframework.webflow.samples.booking.BookingFlowHandler" />   
       
</beans>

1. org.springframework.webflow.mvc.servlet.FlowHandlerMapping

이 클래스는 (FlowUrlHandler를 사용하여) URL을 분석하여 해당 URL을 처리할 FlowHandler를 찾아서 반환해주는 역할을 합니다.

먼저, ApplicationContext에서 찾고, 다음은 FlowRegistry에서 찾아보고, 그래도 없으면 null을 반환합니다. 그럼 이제 이 다음 핸들러 맵핑 체인을 타게 되겠죠.

따라서 이 클래스에 설정할 수 있는 주요 속성은 FlowUrlHandler와 FlowRegistry입니다. 하지만 이중에서 FlowUrlHandler는 스프링이 기본으로 제공하는 DefaultFlowHandler를 사용하는게 일반적일 것 같군요.

2. org.springframework.webflow.mvc.servlet.FlowHandlerAdapter

이 녀석은 FlowHandler가 담당하기로 한 요청을 FlowExecutor를 이용해서 처리하는 일련의 워크 플로우에 따라 실행시켜주는 곳입니다. 실질적인 작업들은 상당 부분을 위임하고 있으면서 그 골격을 만들어둔 곳입니다.

플로우 id에 해당하는 플로우 정의를 가져오고, 플로우 정의로 플로우 실행 객체(FlowExecution)을 만들고, FlowUrlHandler로 필요한 execution 매개변수도 만들는 등.. 한 번의 코드리뷰로 파악하기에는 분량이 많더군요. 특히 FlowExecutor 쪽으로 들어가면.. 크헉.. 클래스가 팍팍 늘어납니다.

3. org.springframework.webflow.mvc.servlet.FlowHandler

특정 플로우 정의에 접근하는 것을 커스터마이징 할 때 이 녀석을 구현한다고 합니다.
- Launch executions of that flow with data in the execution input map
- 플로우 결과는 맘대로 처리하고 싶을 때.
- 플로우에서 다루지 않은 예외를 맘대로 다루고 싶을 때.

위 예제에서 BookingFlowHandler 이녀석이 구현한 건 두 개.
- String handleExecutionOutcome: 실행이 끝났을 때 갈 위치
- String handleException: 에러가 발생했을 때 갈 위치



top

Write a comment.


[Spring Web Flow] booking 예제 분석 2 - Resources Servlet

Spring Web Flow/etc : 2009.10.15 16:05


<?xml version="1.0" encoding="ISO-8859-1"?>
<web-app xmlns="http://java.sun.com/xml/ns/j2ee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"
    version="2.4">

    <!-- The master configuration file for this Spring web application -->
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>
            /WEB-INF/config/web-application-config.xml
        </param-value>
    </context-param>
   
    <!-- Enables Spring Security -->
     <filter>
        <filter-name>springSecurityFilterChain</filter-name>
        <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
    </filter>

    <filter-mapping>
      <filter-name>springSecurityFilterChain</filter-name>
      <url-pattern>/*</url-pattern>
    </filter-mapping>
   
    <!-- Loads the Spring web application context -->
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>

      <!-- Serves static resource content from .jar files such as spring-faces.jar -->
    <servlet>
        <servlet-name>Resources Servlet</servlet-name>
        <servlet-class>org.springframework.js.resource.ResourceServlet</servlet-class>
        <load-on-startup>0</load-on-startup>
    </servlet>
       
    <!-- Map all /resources requests to the Resource Servlet for handling -->
    <servlet-mapping>
        <servlet-name>Resources Servlet</servlet-name>
        <url-pattern>/resources/*</url-pattern>
    </servlet-mapping>
   
    <!-- The front controller of this Spring Web application, responsible for handling all application requests -->
    <servlet>
        <servlet-name>Spring MVC Dispatcher Servlet</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value></param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>
       
    <!-- Map all *.spring requests to the DispatcherServlet for handling -->
    <servlet-mapping>
        <servlet-name>Spring MVC Dispatcher Servlet</servlet-name>
        <url-pattern>/spring/*</url-pattern>
    </servlet-mapping>

    <welcome-file-list>
        <welcome-file>index.html</welcome-file>
    </welcome-file-list>

</web-app>

web.xml에서 눈여볼만한 부분은 먼저, 스프링 JS가 제공하는 ResourceServlet 입니다.
JAR 파일에 들어있는 정적인 자원들(이미지, javascript, css)을 효율적으로 가져오기 위한 서블릿입니다. (JAR 파일에 없으면 로컬에 있는 파일을 참조합니다.

standard.jsp 파일에 있는 헤더를 보죠.

<head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
    <title>Spring Travel: Spring MVC and Web Flow Reference Application</title>
    <link type="text/css" rel="stylesheet" href="<c:url value="/resources/dijit/themes/tundra/tundra.css" />" />
    <style type="text/css" media="screen">
        @import url("<c:url value="/resources/css-framework/css/tools.css" />");
        @import url("<c:url value="/resources/css-framework/css/typo.css" />");
        @import url("<c:url value="/resources/css-framework/css/forms.css" />");
        @import url("<c:url value="/resources/css-framework/css/layout-navtop-localleft.css" />");
        @import url("<c:url value="/resources/css-framework/css/layout.css" />");
        @import url("<c:url value="/resources/styles/booking.css" />");
    </style>
    <script type="text/javascript" src="<c:url value="/resources/dojo/dojo.js" />"></script>
    <script type="text/javascript" src="<c:url value="/resources/spring/Spring.js" />"></script>
    <script type="text/javascript" src="<c:url value="/resources/spring/Spring-Dojo.js" />"></script>
</head>

저기서 보면 /resources로 시작하는 url들이 보입니다. css와 js를 찹조하고 있군요. spring js JAR 파일을 볼까요.


위에서 참조하는 리소스들이 이 JAR 파일에 들어있네요. 그럼 JAR 파일에 들어있지 않은 자원들은 어찌할까요.

...
        <div id="branding" class="spring">
            <a href="<c:url value="/" />"><img src="<c:url value="/resources/images/header.jpg"/>" alt="Spring Travel" /></a>
        </div>
    </div>
    <div id="content" class="clearfix spring">
        <div id="local" class="spring">
            <a href="http://www.thespringexperience.com">
                <img src="<c:url value="/resources/images/diplomat.jpg"/>" alt="generic hotel" />
            </a>
            <a href="http://www.thespringexperience.com">
                <img src="<c:url value="/resources/images/tse.gif"/>" alt="The Spring Experience" />
            </a>
...

이것도 standard.jsp 파일의 일부입니다. 위에 보시면 /resources 로 시작하기 때문에 ResourceServlet이 요청을 처리할겁니다. 그러나 JAR 파일에는 저런 이미지들이 들어있지 않습니다. 그때는 프로젝트의 웹 폴더를 기준으로 /resources를 잘라낸 나머지 부분을 가지고 경로 탐색을 해서 찾아줍니다.


이렇게 보시다시피, /resoruces/images/header.jsp 라는 리소스 URL을 ResourceServelt이 받아서 프로젝트에 위치한 web/images/header.jsp를 찾아서 돌려줍니다.

마지막으로 ResourceServlet의 속성을 살펴보죠.

public void setGzipEnabled(boolean gzipEnabled)
public void setAllowedResourcePaths(java.lang.String allowedResourcePaths)
public void setCompressedMimeTypes(java.lang.String compressedMimeTypes)
public void setJarPathPrefix(java.lang.String jarPathPrefix)
public void setCacheTimeout(int cacheTimeout)

흠.. 뭐 이런 것들이 있군요.

다음..DispatcherServlet 설정이 뭔가 좀 낯설게 느껴집니다. 봄싹같은 경우는.

    <servlet>
        <servlet-name>springsprout</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    </servlet>

    <servlet-mapping>
        <servlet-name>springsprout</servlet-name>
        <url-pattern>*.do</url-pattern>
    </servlet-mapping>

이렇게 설정했습니다. 저렇게 해두면, springsprout-servlet.xml 파일을 찾아서 WebApplicationContext의 설정파일로 사용합니다.

그런데 지금 저 예제에서는

    <servlet>
        <servlet-name>Spring MVC Dispatcher Servlet</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value></param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>

    <servlet-mapping>
        <servlet-name>Spring MVC Dispatcher Servlet</servlet-name>
        <url-pattern>/spring/*</url-pattern>
    </servlet-mapping>

이렇게 설정했지요. 아무래도 설정을 간단하게 하고자.. 보통 ApplicationContext의 설정파일로 쓰는 것에 웹과 관련 된 설정까지 다 해놓고, 저기서는 별다른 설정 파일을 읽지 않도록, 기본 설정 파일을 찾지 않게 그냥 빈 문자열로 설정한 듯 합니다.

봄싹의 경우 기본 네임스페이스가 springsprout기 때문에 init-param으로 contextConfigLocation 속성을 설정하지 않아도 springsprout-servlet.xml 파일을 찾도록 되어 있습니다. 몾찾으면 에러가 납니다.

그런데, <servlet-name>Spring MVC Dispatcher Servlet</servlet-name> 이녀석은 지금 기본 네임스페이스가 Spring MVC Dispatcher Servlet 이게 되고 따라서 그냥 두면 Spring MVC Dispatcher Servlet-servlet.xml 이 파일을 찾다가 몾찾아서 에러가 날 겁니다. 그래서 contextConfigLocation을 null로 설정해서 설정 파일이 필요없도록 해둔거네요.

굳이 Web 설정이랑 App 설정을 구분할 필요가 없다면, 저렇게 해도 괜찮긴 하겠네요. 흠..

web.xml 분석은 이만~







top

  1. Favicon of https://phjang.tistory.com BlogIcon 노랑머플러 2014.10.16 16:10 신고 PERM. MOD/DEL REPLY

    아이고 아주 한참후에야 이 글을 보고 씁니다. ㅎㅎ

    org.springframework.web.context.ContextLoaderListener 와 DispatcherServer의 차이에서 발생하는 설정이 아닐까 하는데요. CCL은 어플리케이션에서 1개만 쓰이는 설정이 필요한것이고, DS는 서블릿 마다 필요한 설정이 필요할 수도 있고요. 물론 위의 예제에서는 DS에 공백 처리를 했지만 나중에 추가해줄수도 있고 해서 ㅎㅎ

    뭐 저생각이 틀릴수도..

Write a comment.


[Spring Web Flow] booking 예제 분석 1 - 예제 실행하기

Spring Web Flow/etc : 2009.10.15 14:59



위 코드를 받아서 메이븐 플젝 import를 해서 Run on server로 돌리거나, Spring 사이트에서 Spring Web Fow를 다운 받은 다음 projects 폴더에 가셔서 booking-mvc 폴젝을 메이븐을 플젝 import 하셔도 됩니다.

막상 실행해 보고나니 너무 간단한 예제라서 조금 아쉽네요. 적어도 멀티 폼 정도의 예제는 만들어줘어야 하는가 아닌가 싶기도 합니다. 그렇치만, 스프링 MVC 연동, 스프링 시큐리티 연동, 스프링 EL, ConversionService 등록, 스프링 JS 등을 눈여겨 볼 수 있는 좋은 예제입니다.

실행은 별거 없으니 여기서 마무리?

혹시 Run On Server로 실행할 때 ClassNotFound 예외가 발생한다면 mvn war:inplace를 한 번 해주고 다시 하면 될 겁니다.



top

  1. 손수현 2009.10.15 15:48 PERM. MOD/DEL REPLY

    기선님 안녕하세요. 블로그에서 좋은 내용들을 많이 적어주셔서 잘 배우고있습니다.
    매일 눈팅만 하다가 어쩌다 남기는 글이 이렇게 도움요청이 되어서 부그럽기만 합니다.

    저는 재일교포3세이며 현재 도쿄에서 시스템개발분야의 일을 하고 있는 손수현이라 합니다.
    사실은 제가 이번에 하게될 프로젝트에서 해결책을 찾지 못하여 상당히 고민중입니다.
    어떤방법으로 하면 될가 살짝 힌트주셨으면 해서 이렇게 염치불구하고 글을 남김니다.ㅠ.ㅠ
    부디 가벼운 힌트로도 받을수 있다면 너무 감사하겟습니다.
    우리말이 창피할 정도로 서투릅니다. 틀린부분이 있으면 많은 양해 부탁드립니다.

    구현하고저 하는 내용을 간단히 설명드리자면...
    1. 외부로부터 아래의 URL로 요청이 옵니다.
    http://example.com/ch00/do?parameters.......
    http://example.com/ch01/do?parameters.......
    http://example.com/ch02/do?parameters.......
    ........................
    http://example.com/ch19/do?parameters.......

    2. 서블릿은 PathInfo를 분석하고 ch00-ch19에 해당되는 설정파일(xml)을 읽어서 오브젝트를 생성합니다.
    설정파일의 구조(엘리멘트등)는 같고 설정내용을 맵핑해넣을 클래스도 동일합니다.

    3. 설정내용에 기초하여 일련의 데이터처리후 클라이언트에 결과를 보냄.


    인스턴스생성할때마다 파일IO부하가 있으므로 스프링설정파일에서 빈의 scope를 singleton으로 정의하였습니다.
    그리고 비즈네스로직을 구현한 빈의 프로퍼티중의 하나입니다.
    <bean id="ch00" class="ConfigMappingClass" init-method="init" lazy-init="true"/>
    <bean id="ch01" class="ConfigMappingClass" init-method="init" lazy-init="true"/>
    <bean id="ch02" class="ConfigMappingClass" init-method="init" lazy-init="true"/>
    .......
    <bean id="ch19" class="ConfigMappingClass" init-method="init" lazy-init="true"/>
    init메스드에서 설정파일을 읽어서 클래서의멤버변수에 넣습니다.


    여기서 문제점은. 아래와 같습니다.
    1. 데이터타입은 같지만 위에서 보시다시피 20개의 설정파일이므로 빈도 20개 정의하고 있습니다.
    2. 설정파일의 내용이 바뀌었을때 서버재시작하지 않으면 안됩니다.

    개선하고저 하는 내용.
    1. 스프링설정파일에서 빈의 정의갯수를 줄이고 싶습니다.(중요하진 않지만 가능하다면 해결책 가르쳐주세요)
    2. 두번째가 제일 고민되는 부분인데 설정파일의 변경되였을때 서버재시작없이 빈을 refresh하는 방법 없나요?
    혹은 주기적으로(1시간에한번씩) 싱글톤을 destroy하고 재생성한다든가.

    제가 거의 초보인데다가 이제 막 스프링을 접하고 배우고 있어서 문제에 부닥치면 어떻게 해야할지 모르겠습니다.
    그저 간단히 <이방면은 이런 기술을 쓰면 된다, 이것을 쓰면 해결이 가능하다> 이렇게 키워드정도라도 괜찮으니
    부디 답변 부탁드립니다. 바쁘신데 정말 죄송합니다.

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

    ConfigMappingClassFactory 라는 걸 만들면 어떨까요? 이 클래스에 다음과 같은 일들을 하는거죠.

    - cmcf.getConfig("ch00";); 을 호출하면 먼저 cache로 사용할 Map을 뒤져서 ch00이라는 키 값에 해당하는 ConfigMappingClass의 인스턴스가 있는지 확인하고 있으면 그걸 바로 돌려줍니다. 없으면 ch00에 대항하는 XML을 읽어와서 새 인스턴스를 만들어서 돌려준 다음 cache로 사용할 map에 넣어 둡니다.

    => 이렇게 하면 설정은 줄어들겠죠. 저 빈 하나만 등록하면 되니까요.

    => 설정파일을 어떻게 변경하고 싶으신거죠?

    <bean id="ch21" class="ConfigMappingClass" init-method="init" lazy-init="true"/>
    <bean id="ch22" class="ConfigMappingClass" init-method="init" lazy-init="true"/>

    혹시 런타임시에 위와 같은 설정을 계속 추가하고 싶으신거 아닌가요? 만약에 그런거라면 이미 위와 같은 방식으로 자원을 캐싱했다가 필요한 자원은 런타임시에 새로 읽어올테니 뭔가가 필요 없겠구요.

    - 빈 Refrash에 대해서는 잘 모르겠지만 ApplicationContext를 refesh 할 수는 있습니다.
    ((ConfigurableApplicationContext)getApplicationContext()).refresh();

    이렇게 하면 ApplicationContext에 등록된 빈들도 다시 만들겠죠. (흠.. 근데 테스트 해보니 잘 안 되네요.)

    또는 Groovy나 Ruby로 빈을 만들고 리프래시 주기를 설정하면 주기 별로 해당 스크립트를 실행할 수 있었던 기억이 나는데 정확하진 않습니다.

  2. 손수현 2009.10.16 10:19 PERM. MOD/DEL REPLY

    Groovy로 만든 빈을 refresh-check-delay에 지정한 시간을 주기로 refresh할수 있군요.:-)
    groovy에 관한 지식이 전혀없기에 일단은 기선님이 힌트주신대로 cache맵에 설정오브젝트를 담아두고 오브젝트에 생성한 시간을 멤버변수로 두어서 expire된것을 remove하는방법으로 하기로 하고 나중에 groovy를 이용하여 해보려합니다.
    답변 대단히 감사합니다.!

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

    아. 그 속성이었군요.
    제 머리도 일정 주기마다 refresh 되는것 같아요.ㅋㅋ

    도움이 됐다니 다행이네요.
    즐겁게 개발 하세요~

Write a comment.


Spring Web Flow 2.0 특징

Spring Web Flow/etc : 2008.04.26 11:11


참조 : http://www.infoq.com/news/2008/04/spring-webflow-2rc
예제 : http://richweb.springframework.org/swf-booking-faces/spring/intro

Web Flow 2.0의 새로운 기능은?

- Progressive Ajax:  Ajax 이벤트 핸들링 기능을 추가했다. 다른 웹 플로우 이벤트처럼 Ajax 이벤트를 처리할 수 있다. 자바스크립트를 클라이언트 쪽에서 사용하지 않아도 제대로 동작하도록해놨다. Ajax 지원 기능은 서버쪽 기능과 클라이언트쪽 기능 둘로 나눠져있다.

- Spring MVC와 더 긴밀한 통합: Spring MVC와 상호 보완 관계이다. Stateless한 Spring MVC @Controller가 Folw를 호출할 수 있고 Flow의 결과가 컨트로러에 맵핑될 수 있다.

- 재구성하고 확장된 JSF와의 통합: JSF 내용은 패스 저도 잘 모르기 땜시..

- Spring Security아의 통합: 플로우에 보안 기능을 추가할 수 있다. 플로우, 스테이트, 트랜지션에 @Secured를 애노테이션을 붙이면 SecurityFlowExecutionListener가 사용자의 인증을 요구한 뒤에 플로우를 시작하고, 스텝을 진행하고 이벤트를 시작할 것이다.

- 보다 간단한 Spring Folw Definition Language: 200줄 가량의 코드와 6개의 파일이 필요한 애플리케이션이 동일한 기능을 이제는 93라인의 코드와 2개의 파일로 할 수 있다.

- 새로운 모듈화 기능: 플로우의 개념을 "재사용 가능하며, 독립적인 애플리케이션 컨트롤 모듈"로 확장했다. 따라서 기본적으로 플로우와 그것이 사용하는 리소스인 뷰, 메시지, 헬퍼등을 하나로 패키징된다.

이번 배포의 배경이 되는 철학은 무엇인가?

- 사용성 편의다.

1.0에서 2.0으로 이전하는데 필요한 중대 변화는?

- Web Flow Definition Language다. 그래서 1.0 정의를 2.0으로 바꿔주는 기능을 제공한다. 일명 WebFlowUpgrader xnf.

스프링 웹 플로우를 지원하는 도구는?

- 스프링 IDE

앞으로 웹 플로우의 개발 방향과, 2.1 배포의 초점은?

- 선언적인 모델 검증. 애노테이션으로 Validation을 할 수 있도록.. 선언적으로 모델에 벨리데이션 규칙을 붙여두면, 그것을 서버 사이드와 클라이언트 사이드에 반영해주는..
- Grooby로 Flow Definition 작성하는 기능.

top

Write a comment.