휴.. 폼 태그 파일 완성.

<o:popuppage title=”사원등록”>
    <o:buttons>
        <o:savebtn />
        <o:cancelbtn />
    </o:buttons>
    
    <o:form>
        <o:ftext label=”이름” path=”name” size=”10″ maxlength=”20″ />
        <o:ftext label=”아이디” path=”loginId” size=”15″ maxlength=”20″ desc=”최대 20자리까지 입력 할 수 있습니다.” />
        <o:fpassword label=”패스워드” path=”password” size=”10″ maxlength=”16″ desc=”최대 16자리까지 입력 할 수 있습니다.” />
        <o:fradiobuttons label=”성별” path=”sex” items=”${ref.sexType}” />
        <o:fcheckboxes label=”취미” path=”hobbies” items=”${ref.hobbyType}” />
        <o:fselect label=”국적” path=”location” items=”${ref.locations}” isCOV=”yes” />
        <o:ftextarea label=”메모” path=”memo” rows=”3″ cols=”50″ />
    </o:form>
</o:popuppage>

이게 추가와 수정시에 사용할 JSP 페이지 코드입니다. JSP를 몰라도 금방 태그 파일 몇개만 익히면 쉽게 페이지를 찍어낼 수 있습니다. 이 페이지에서 사용하고 있는 태그 파일들은 다음과 같습니다.

사용자 삽입 이미지
흠냐~ 이 녀석들로 만들어 낸 화면입니다.
사용자 삽입 이미지
물론 CSS도 가미가 되어 있습니다. CSS는 잘 몰라서 사부님이 만들어 둔 걸 그대로 쓰고 있습니다. 저기 items 뿌리는 부분의 label 스타일을 좀 변경하고 싶은데;; 일단 스타일은 나중에 변경하기로.. ㅋㅋ

사용자 삽입 이미지
업데이트 뷰에서도 위와 동일한 태그를 사용하면 됩니다. 흠.. 버튼을 하나 추가해서 삭제버튼을 달아야겠군요.

이것으로 폼 태그 파일들은 다 준비가 됐습니다. 이제 그리드 태그 파일만 완성하면… 드디어 OSAF를 출시할 수 있게 됩니다. 캬오~~

1년 반 만에 다시 찾은, EL 안에 EL 사용하는 방법

커스텀 태그에서 Expression Language를 사용하다보면, 언젠간 아래처럼 쓰고 싶은 경우가 발생할 수도 있습니다. 전 예전에 한 번 이 벽에 부딪혀서 결국 못 넘고 좌절한 적이 있는데, 해당 글에 물개선생님이 남겨주신 댓글과 사부님이 만든 태그를 보니.. 이해가 됩니다.

먼저 상황부터 설명을 하자면,..

일단 EL 안에 EL을 사용하고 싶은 경우가 어떤 경우냐면.. 보통 ${member.name} 이렇게 쓰는데, 만약 이 때 이 name라는 값도 변수화 해서 property라는 태그 파일 속성으로 받도록 할 수 있겠습니다. 그리고 이 속성에는 name 뿐만 아니라, age, height 등등 여러 가지 member 객체가 가지고 있는 속성 값을 넣을 수 있다고 했을 때.. EL로 그 속성값을 뿌리려면..

<%@ attribute name=”property” required=”false” %>

${member.${property}}

이렇게 하고 싶습니다. 그쵸? 하지만, 해보시면 아시겠지만 안 됩니다. 저런 문법을 EL이 지원하질 않습니다.

심각: Servlet.service() for servlet sample threw exception
org.apache.el.parser.ParseException: Encountered “{” at line 1, column 4.
Was expecting one of:
    “}” …
    “.” …
    “[” …
    “>” …
    “gt” …
    “<” …
    “lt” …
    “>=” …
    “ge” …
    “<=” …
    “le” …
    “==” …
    “eq” …
    “!=” …
    “ne” …
    “&&” …
    “and” …
    “||” …
    “or” …
    “*” …
    “+” …
    “-” …
    “?” …
    “/” …
    “div” …
    “%” …
    “mod” …
    “(” …
   
    at org.apache.el.parser.ELParser.generateParseException(ELParser.java:1874)
    at org.apache.el.parser.ELParser.jj_consume_token(ELParser.java:1754)
    at org.apache.el.parser.ELParser.DynamicExpression(ELParser.java:156)

자.. 이런 에러가 발생합니다. 괄호를 안쪽부터 처리해주면 좋겠지만, 희망사항이었던 것 같습니다. ${property}의 값이 name이면 ${member.name} 이 되고.. 이건 내부적으로 member.getName()을 호출해서 가져다주면 좋을텐데 말이죠. 흠… 복잡해 질까봐 이렇게 구현하지 않았을지도 모르겠습니다.

어쨋든, 저 윗 글에 물개선생님이 알려주신 코드대로 하면 EL안에 EL을 사용하는 효과를 얻을 수 있습니다.

<%@ attribute name=”property” required=”false” %>

<%
property = (property != null) ? property : “name”;
Object memberPropertyValue = PageContextImpl.proprietaryEvaluate(“${member.” + property + “}“, Object.class, (PageContext)this.getJspContext(), null, false);
out.print(memberPropertyValue.toString());
%>

이렇게 PageContextImpl를 이용해서 가져오면 됩니다. 위에서 제가 원하던 방법대로 자바 코드를 사용해서 처리한 겁니다. “${member.” + property + “} 이렇게 하는 순간, 이미 안 쪽의 변수 값을 가져오기 때문에 이후에는 ${member.name}를 쓰는 것과 같은 것이 됩니다.

흠.. 이상합니다. 저 때도 분명 물개 선생님이 댓글로 코드까지 주셨는데, 저걸 못 써먹고 포기했었습니다. 거의 1년 반이 지난 이제와서 그때 포기했던걸 다시 하게 되네요. ㅋㅋ 1년 반이라…

태그 파일 중복 제거 예제

스프링 form태그를 이용해서 태그 파일 두 개를 만들었습니다. 하나는 일반 text, 하나는 password입니다.

osaf/ftext.tag

<%@ tag pageEncoding=”euc-kr” %>

<%@ taglib prefix=”form” uri=”http://www.springframework.org/tags/form” %>

<%@ attribute name=”path” required=”true” %>
<%@ attribute name=”label” required=”false” %>
<%@ attribute name=”size” required=”true” %>
<%@ attribute name=”maxlength” required=”true” %>
<%@ attribute name=”desc” required=”false” %>

<p id=”${path}row”>
    <label>${label} :</label>
    <form:input path=”${path}” size=”${size}” maxlength=”${maxlength}”  />
    &nbsp;${desc}
    <form:errors path=”${path}” cssClass=”error” />
</p>

osaf/fpassword.tag

<%@ tag pageEncoding=”euc-kr” %>

<%@ taglib prefix=”form” uri=”http://www.springframework.org/tags/form” %>

<%@ attribute name=”path” required=”true” %>
<%@ attribute name=”label” required=”false” %>
<%@ attribute name=”size” required=”true” %>
<%@ attribute name=”maxlength” required=”true” %>
<%@ attribute name=”desc” required=”false” %>

<p id=”${path}row”>
    <label>${label} :</label>
    <form:password path=”${path}” size=”${size}” maxlength=”${maxlength}”  />
    &nbsp;${desc}
    <form:errors path=”${path}” cssClass=”error” />
</p>

코드가 완전 똑같아 보입니다. 무슨 틀린그림 찾기도 아닌데, 차이를 발견하기가 힘듭니다. 어쩔까~~ 내비둘까.. 계속 다른 태그 만들까.. 중복을 제거하고 갈까.. 하다가. TDD 책이 생각났습니다.

꺠진 테스트 -> 코딩 -> 녹색 -> 리팩터링.

태그 파일도 이런 순으로 만들고 있습니다. 일단 뷰부터 만들고(저 태그를 사용하는 JSP 페이지부터 만들고) -> 태그를 작성합니다. -> 화면에 나오는지 확인!..

아무래도 리팩터링을 하고 넘어가야될 듯 합니다. 어떻게 할까.. 대충 떠오릅니다. 저 태그에서 또 다른 태그를 이용해서 화면에 뿌리면되고, 그 태그에 type을 넘겨줘서 그 태그 안에서 분기문으로 ..샤샥.. 유사코드는 떠오르는데 실제 코드는 안 떠오릅니다. OTL 코드는 제 블로그 어딘가를 치팅해가면서;; ㅋ

osaf/felement.tag

<%@ tag pageEncoding=”euc-kr” %>

<%@ taglib prefix=”c” uri=”http://java.sun.com/jstl/core_rt” %>
<%@ taglib prefix=”form” uri=”http://www.springframework.org/tags/form” %>

<%@ attribute name=”path” required=”true” %>
<%@ attribute name=”label” required=”false” %>
<%@ attribute name=”size” required=”true” %>
<%@ attribute name=”maxlength” required=”true” %>
<%@ attribute name=”desc” required=”false” %>
<%@ attribute name=”type” required=”true” %>

<p id=”${path}row”>
    <label>${label} :</label>
    <c:choose>
        <c:when test=”${type ==’text’}”>
            <form:input path=”${path}” size=”${size}” maxlength=”${maxlength}” />
        </c:when>
        <c:when test=”${type ==’password’}”>
            <form:password path=”${path}” size=”${size}” maxlength=”${maxlength}” />
        </c:when>
    </c:choose>
    &nbsp;${desc}
    <form:errors path=”${path}” cssClass=”error” />
</p>

좋아. 이 태그를 사용해서 확인해보니, 잘 동작합니다. 그럼 이제 기존의 코드들을 수정합니다.

osaf/ftext.tag

<%@ tag pageEncoding=”euc-kr” %>
<%@ taglib prefix=”o” tagdir=”/WEB-INF/tags/osaf” %>

<%@ attribute name=”path” required=”true” %>
<%@ attribute name=”label” required=”false” %>
<%@ attribute name=”size” required=”true” %>
<%@ attribute name=”maxlength” required=”true” %>
<%@ attribute name=”desc” required=”false” %>

<o:felement type=”text” label=”${label}” path=”${path}” maxlength=”${maxlength}” size=”${size}” desc=”${desc}” />

osaf/fpassword.tag

<%@ tag pageEncoding=”euc-kr” %>
<%@ taglib prefix=”o” tagdir=”/WEB-INF/tags/osaf” %>

<%@ attribute name=”path” required=”true” %>
<%@ attribute name=”label” required=”false” %>
<%@ attribute name=”size” required=”true” %>
<%@ attribute name=”maxlength” required=”true” %>
<%@ attribute name=”desc” required=”false” %>

<o:felement type=”password” label=”${label}” path=”${path}” maxlength=”${maxlength}” size=”${size}” desc=”${desc}” />

OK. 중복제거 완료 입니다. 덤으로 사용자에게 선택권이 생겼습니다. type 속성을 사용해가면서 felement를 직접 쓰거나, type 속성 쓸 필요 없이 ftext나 fpassword 엘리먼트 사용할 수 있습니다.

태그 파일 배포하기

참조 :
http://docs.sun.com/app/docs/doc/819-3669/bnalj?l=ko&a=view

1. 작성한 태그 파일을 JAR로 묶기

– META-INF/tags 밑에 또는 그 하위 폴더에 태그 파일을 옮기고 묶는다.

2. TLD 파일을 작성하기

– WEB-INF/tag 밑에 두었으면 tld 파일 자동으로 만들어 주지만, 별도의 jar로 배포할 때는 반드시 TLD 파일을 작성해야 함. 태그 파일들의 위치를 알아야할테니..
– tld 파일은 META-INF/ 폴더 또는 그 하위 폴더에 둔다. 태그들이랑 같은 폴더에 둬도 상관없음.

3. JSP에서 참조하기

– <%@ taglib prefix=”o” uri=”www.opensprout.org” %>
– 여기서 uri는 진짜 URI를 말하는게 아니라, 그냥 이름. TLD 파일에 정의한 uri와 같은 값.
– JSP 2.0 이전에는 DD에 직접 TLD 위치를 설정해줬지만, JSP 2.0부터 WEB-INF/lib에 들어있는 JAR들의 META-INF/ 폴더 밑 그 하위 폴더를 뒤져서 TLD 파일을 찾아냄.

Whiteship’s 사족

흠.. 글쿠나.. WEB-INF/tags 밑에 태그 두고 사용하면, 자동으로 TLD 파일을 컨테이너가 만들어 준댔는데.. 그럼 그 파일을 복사해서 좀만 수정해서 TLD를 만들면 편하겠네. 그렇게 자동으로 만들어진 TLD 파일은 어디에 만들어질려나.. WEB-INF/ 폴더 일려나.. 흠… 구하고 싶다. xml 파일 만들기 귀찮은데; TLD 생성기 같은거 없나.

6. The Decorating Filter Pattern

참조
– Foundation of JSP Design Patterns
http://java.sun.com/j2ee/patterns/DecoratingFilter.html

패턴의 정의

Create pluggable filters to process common services in a standard
manner without requiring changes to core request processing code. The
filters intercept incoming requests and outgoing responses, allowing
pre and post-processing. We are able to add and remove these filters
unobtrusively, without requiring changes to our existing code.

– 필터로 Http request와 response를 인터셉트 하도록 데코레이션하는 패턴

사용처
– 로깅, 사용자의 권한 체크, 데이터 전달, 데이터 검증

Participants & Responsibilities
사용자 삽입 이미지
패턴 적용 전략
– 커스텀 필터 만들기(Dynamic Filter Strategy), 표준 필터 만들기(Declared Filter Strategy)
– 커스텀 필터의 단점
1. 서블릿안에 필터를 하드 코딩해야 한다. -> 변경 사항이 생기면 서브릿을 수정하고 다시 컴파일
2. Request와 Response 객체를 변경할 수 없다. -> 왜냐면 they’ll be dispatched upon completion(?)
– 표준 필터 사용의 장점
1. 애플리케이션 코드와 상관없이 필터를 추가, 수정 할 수 있다.
2. 서블릿 컨틀롤러 밖에서 처리하기 때문에 request와 response 객체를 변경할 수 있다.

필터 적용하기
1. 필터 만들기
    – javax.servlet.Fileter 인터페이스 구현
2. web.xml에 선언하기
    – <filter>
          <filter-name>testFilter</fileter-name>
          <filter-class>x.y.foo</filter-class>
       </filter>
3. URL(또는 URL 패턴으) 또는 특정 서블릿에 매핑하기
    – <filter-mapping>
          <filter-name>testFilter</filter-name>
          <url-pattern>/*</url-pattern>
       </filter-mapping>
or
        <filter-mapping>
         <filter-name>testFilter</filter-name>
         <servlet-name>Bar</servlet-name>
      </filter-mapping>
 
생각해볼 것
1. 커스텀 필터의 단점들 중에 두 번째가 잘 이해가 안 됩니다. Request와 Response 객체를 왜 바꿀 수 없는 것인지…
2. Spring 의 HandlerInterceptor(또는 HandlerInterceptorAdapter)는 필터와 같은 역할을 하는데 프로그래밍 방식으로 구현(표준 인터페이스를 따르지 않고 구현)을 하고 사용은 선언적인 방법(web.xml에 선언하지는 않지만 역시 xml에 적용할 url을 설정해줌)으로 사용합니다. 이 경우 필터보다 구현이 간단하고 사용은 선언적인 필터와 거의 유사합니다. 그렇다면 일반적인 필터와 Spring의 인터셉터의 사용처는 어떻게 구분을 할 수 있을까요? 둘 중에 아무거나 편한 것을 사용하면 될까요?
3. (원래는 AOP를 사용하려고 했지만.. 무언가 잘 안되서..)Spring의 인터셉터를 사용하여 간단하게 사용자가 로그인 한 상태인지 아닌지를 확인하는 것을 구현해본적이 있습니다. 이 때 세션에 해당 객체가 있는지 확인하는 방법으로 구현하였습니다. 이 방법보다 보다 더 보편적이거나 유용한 방법이 있는지 궁금합니다.