Valiation 실패시 입력화면 재출력

Validation이 실패하면 원래화면(입력화면)으로 다시 forward를 해서 에러 메세지를 표시함으로써 에러가 난 부분을 수정해서 다시 submit을 하는 것이 일반적이다. 이 때 화면을 다시 그릴 때 필요로 하는 데이터들 (예를 들어서 드롭다운 리스트)을 다시  준비해야 한다. 
만약 이러한 준비처리들이  input()이나 execute() 같은 Action 대응 메서드에 구현해 두었다고 하면 validation이 실패해서 되돌가 간 경우에는 준비처리가 실행되지 않은 상태가 될 것이다. 이런 경우에 활용할 수 있는 것이 Preparable 인터페이스를 구현하는 것이나  스트럿츠의 <action>태그이다.

Preparable 인터페이스

Action 대응 매서드에서 준비처리를 하는 것 대신에 Preparable 인터페이스를 구현해서 prepare()메서드에 준비처리를 넣어 두는 방법이다. prepare()메서드는 validation처리보다 선행되어 실행되기 때문에 validation이 실패하더라도 문제가 없다. prepare()메서드는 이러한 경우 이외에도 활용할 곳이 아주 많다.

Input.jsp
<%@ taglib prefix="s" uri="/struts-tags" %>
<s:form>
<s:select
   tooltip="Choose Your Favorite Language"
   label="Favorite Language"
   list="languages"
   name="language"
   listKey="key"
   listValue="description"
   emptyOption="true"
   headerKey="None"
   headerValue="None"/>
<s:submit>
</form>

Input.java
class Input extends ActionSupport {

    public String prepare() {
        languages.add(new Language("EnglishKey", "English Language"));
        languages.add(new Language("FrenchKey", "French Language"));
        languages.add(new Language("SpanishKey", "Spanish Language"));
        return SUCCESS;
    }

    List languages = new ArrayList();
    public List getLanguages() {
        return languages;
    }

    String language;
    public void setLanguage(String value) {
        language = value;
    }
    public String getLanguage() {
        return language;
    }

    public static class Language {

        public Language(String key, String description) {
            this.key = key;
            this.description = description;
        }

        String key;
        public String getKey() {
            return key;
        }

        String description;
        public String getDescription() {
            return description;
        }
    }
 }

만약 스택정의를 커스터마이즈했다면 Prepare Interceptor가 Validation Interceptor보다 앞에 두어야 한다는 점을 잊지 말자.

Action 태그

다른 해결방법으로는 스트럿츠의 action 태그를 활용하는 방법이다. action태그는 즉시 Action을 실행해주는 태그이다. action태그를 활용하는 한가지 방법으로 어떤 Action의 결과를 어떤 컨트롤(예>드롭다운리스트)을 출력하도록 하고 다른 어떤 JSP에서 마치 부품처럼 이 Action을 사용하도록 하는 것이다. action태그의 executeresult속성을 true로 정의하면 Action의 실행결과를  action태그가 사용된 곳에 삽입되게 된다.

Input.jsp
<%@ taglib prefix="s" uri="/struts-tags" %>
<s:form>
   <s:action name="Languages" executeResult="true"/>
   <s:submit/>
</s::form>

struts.xml
<action name="Input">
    <result>/app/Input.jsp</result>
</action>
<action name="Languages" class="app.Languages">
    <result>Languages.jsp</result>
</action>

Languages.jsp
<%@ taglib prefix="s" uri="/struts-tags" %>
<s:select
   tooltip="Choose Your Favorite Language"
   label="Favorite Language"
   list="languages"
   name=language"
   listKey="key"
   listValue="description"
   emptyOption="true"
   headerKey="None"
   headerValue="None"/>

Languages.java
public class Languages extends ActionSupport {
    public String execute() {
        languages.add(new Language("EnglishKey", "English Language"));
        languages.add(new Language("FrenchKey", "French Language"));
        languages.add(new Language("SpanishKey", "Spanish Language"));
        return SUCCESS;
    }

    List languages = new ArrayList();
    public List getLanguages() {
        return languages;
    }

    public static class Language {
        String description;
        String key;

        public Language(String key, String description) {
            this.key = key;
            this.description = description;
        }

        public String getKey() {
            return key;
        }

        public String getDescription() {
            return description;
        }
    }
}

언어 드롭다운리스트 컨트롤이 필요한 곳에서는 action태그를 이용해서 Languages액션을 호출기만 하면 그 곳에 드롭다운리스트가 출력될 것이다. DB에서 값을 가지고 와야 한다고 쳐도 캐싱을 지원하는 IBATIS나 Hibernate같은 DB레이어를 이용하면 첫 번째만 DB에서 읽어오고 이후 부터는 메모리내에서의 처리만 일어나게 된다.

역자주: Languages에 변수를 전달할 수 없다는 단점이 있습니다.

원문:http://struts.apache.org/2.x/docs/how-do-we-repopulate-controls-when-validation-fails.html
2009년 3월 현재
허 련호(airless at funit.net)

Comments