최근 포토로그


treemenu JAVA SCRIPT


애견 대소변 가리기 훈련 개키우기

개는 먹고 자는 곳 즉 [사는곳]에서는 배변을 하지 않는 습성과 땅굴을 좋아하는 본능을 이용하는 훈련입니다. 개는 먹고 자는 곳은 [사는곳]으로 생각하고 청결하게 유지하는 성격을 가지고 있습니다. 크레이트에 가두고 일정한 장소에서 밥과 물을 주게 되면 밥을 먹는 곳과 크레이트는 자신이 [사는곳]가 되지만, 그 곳에서 일정한 거리가 있는 화장실은 [밖]로 인식하게 됩니다. 배변훈련은 “사는곳”과 “밖”을 가르치는 것 입니다.

배변훈련은 처음 데려왔을 때 시작하는 것이 가장 효과적입니다. 처음으로 새로운 가정에 입양된 강아지는 집안의 모든 공간을 자신이 [사는곳]이라고는 생각지 않습니다. 따라서 처음에 탐색을 한 후 대소변을 보는 경우가 많습니다. 이 때 대소변 훈련을 시작하세요.

강아지를 처음 입양할 때 미리 화장실을 만들어 놓거나, 크레이트에 가둔 상태에서 화장실을 만들고 화장실로 데리고 가는 방법도 있습니다.

만약 입양한지 며칠이 지났는데도 대소변을 가리지 못한다면 오늘부터 시작해도 늦지 않습니다. 약간의 시간의 차이만 있을 뿐 어린강아지부터 성견까지 모두 훈련이 가능합니다

훈련을 위해서는 약 7일간이 소요되며 거의 대부분의 개는 7일 후면 대소변을 가리게 됩니다. 배변훈련을 위해서는 강아지를 가두는데 사용하는 크레이트 그리고 화장실(실외화장실도 가능)이 필요합니다.


배변훈련 원칙

1. 규칙적인 식사습관들이기 (사료와 물을 제한함)

2. 개가 배설하기를 원하지 않는 “크레이트”에 가두기

3. 훈련계획을 철저하게 지키기

4. 충분히 칭찬하기 (아주 중요)


[배변훈련 프로그램 예시]

1. 보호자가 하루 종일 집에 있는 경우

2. 보호자가 하루 종일 집에 없는 경우

7:00(기상)

밖으로(또는 화장실)

7:00(기상)

밖으로(또는 화장실)

7:10∼7:30

자유시간

7:10∼7:30

자유시간

7:30∼8:00

식사시간

7:30∼8:00

식사시간

8:00∼8:15

밖으로(화장실)

8:00∼8:15

밖으로(화장실)

8:15∼8:45

자유시간

8:15∼ 오후 6:00

크레이트에 가둠

8:45∼12:00

크레이트에 가둠

오후 6:00

밖으로(화장실)

12:00∼12:30

식사시간

6:15∼6:30

자유시간

12:30∼12:45

밖으로(화장실)

6:30∼7:00

식사시간

12:45∼1:15

자유시간

7:00∼7:15

밖으로(화장실)

1:15∼5:00

크레이트에 가둠

7:15∼9:00

크레이트에 가둠

5:00∼5:30

식사시간

9:00∼9:30

식사시간

5:30∼6:15

밖으로(화장실)

9:30∼9:45

밖으로(화장실)

6:15∼8:15

크레이트에 가둠

9:45∼10:10

자유시간

8:15∼8:30

밖으로(화장실)

10:10∼11:00

크레이트에 가둠

8:30∼9:00

자유시간

11:00∼11:15

밖으로(화장실)

9:00∼11:00

크레이트에 가둠

11:15∼

이후

밤새도록 크레이트에 가둠

11:00∼11:15

밖으로(화장실)

11:15∼이후

밤새도록 크레이트에 가둠



훈련방법

우선 훈련 프로그램을 시작하기 전에 크레이트에 가두기는 것을 연습해야 한다. 푹신한 담요나 매트, 개가 좋아하는 장난감을 넣어두고 가두기를 시도한다. 만일 개가 짓거나 우~우 거리면 개의 목걸이를 크레이트에 던지거나 개에게 물총을 쏘아서 벌을 준다. 이렇게 하면 개는 벌을 받되 다치지는 않을 것이다. 만약에 개가 짖는데 여러분이 개를 밖으로 나오게 한다면 이것은 개로 하여금 ‘여러분의 관심을 끌려면 많이 짖어야 되겠구나’ 하는 것을 가르치는 것이 될 뿐이다.

만약 훈련하는 개가 3개월 령이 넘었다면 밤새 크레이트에 가둘 수 있다. 훈련프로그램을 시작하기 전날 밤 개를 밖으로 데리고 나가서 완전히 배설하도록 한다. 다음으로 개를 크레이트에 밤새 가둔다. 개를 가두어 두었다면 다음날 일어나자마자 화장실에 갈 수 있도록 실내에서 화장실을 할 곳에 신문지나 패드를 깔아두고 미리 준비를 해둔다. 부엌, 욕실 또는 거실의 한쪽 구석을 택하는 것이 좋으며 잠자고 식사하는 곳과 떨어진 곳에 화장실을 준비해야 한다. 90×120cm 공간의 바닥에 비닐 봉투를 펼쳐놓고 그 위에 신문지 6~8장을 깐다.(배변패드를 사용하는 경우에는 두세장의 패드를 펼쳐 사용) 종이나 패드 가장자리는 개가 미끄러지지 않도록 테이프로 붙여야 한다. 매일 같은 장소에 신문지를 깔아놓는 것이 중요하다. 배변을 유도하는 프로그램은 앞장에 적힌 것과 같고, 그 시간이 되면 신문지위로 데리고 가라.(처음에는 개를 안고간다.) 배설 장소가 아닌 곳에서 배설할 것 같아 보이면 즉시 개를 안고 배설할 장소로 데리고 간다. 신문지는 정기적으로 갈아주되 오줌을 싼 종이 중의 한 장을 남겨 새 종이 위에 다시 깔아놓는다. 배설물 냄새가 개를 같은 장소로 유인할 것이다. 개가 종이에다 배설하는 법을 배우자마자, 개가 식사를 마치면 약간 떨어진 곳에 데려다 놓고 “이리와” 하고 부르면서 신문지가 있는 곳으로 유도한다.

익숙해지면 종이를 까는 공간의 크기를 줄이기 시작한다. 개가 한 번이라도 종이를 깔아놓은 장소가 아닌 곳에서 배설한다면 훈련 과정을 다시 시작해야 한다. 실외화장실을 훈련하는 경우에는 프로그램에서 실내화장실 대신 밖에 화장실이 있다고 생각하고 목줄 훈련이 선행되어야 한다.


배변훈련시 주의사항

1. 화장실 훈련에서 실수했다고 절대 개를 때리거나 야단치지 말아야한다. 이때 개는 실수를 해서 야단을 맞았다고 생각하지 않고, 주인이 있을 때는 벌을 받으니까 오줌을 누면 안 된다고 착각한다. 개를 다른 곳으로 데리고 가고, 개가 보지 않게 한 후 냄새제거제로 냄새를 없애야 한다. 크레이트 안에서 실수 한 경우에도 마찬가지이다.

2. 크레이트 안에서 대소변을 참을 수 있는 시간은 개월 수에 1을 더한 시간 만큼이며 3개월령 이상이 되어야 밤을 세울 수 있다.(예 3개월령 4시간) 크레이트 안에서 실수를 하는 경우에는 크레이트가 너무 크거나 시간이 초과된 경우이다.

3. 생후 12주(3개월령) 미만의 강아지는 항문 괄약근 조절능력이 완전하지 않기 때문에 완벽한 훈련을 기대할 수 없다.(약간의 실수는 인정하라)

4. 훈련기간에는 사료와 물만 제공한다.(물도 정해진 시간에만 주되 양껏 먹게 한다.)

5. 한번 선택한 배설 장소는 바꾸지 말아야한다.

6. 개가 정해진 자리에 배설을 할 때마다 아낌없는 칭찬을 하라. 먹이가 아닌 칭찬으로 해야 한다.

7. 개가 일을 본자리는 즉시 청소하고, 항상 개의 청결을 유지하고 미용에 신경을 써라.

8. 시간표를 철저히 지켜라. 개가 7일 이후에도 대소변을 잘 못가리면 꾸준히 해야 한다. 대소변을 가린 후에도 크레이트는 개의 집이고 보금자리이자 안식처이며 놀이터이다.

9. 화장실에 15분이상 있지 말아야 한다. 15분이 지나도 대소변을 보지 않는 경우에는 1시간 동안 다시 크레이트에 가두고, 다시 화장실로 데리고 간다..첫날은 3-4회 정도 반복해야 한다고 생각하면 된다.

10. 7일간 투자가 개의 평생을 보장할 것이다. h



http://kin.naver.com/qna/detail.nhn?d1id=13&dirId=13050201&docId=101292022&qb=7JWg7JmE6rKsIOuMgOyGjOuzgOqwgOumrOq4sA==&enc=utf8&section=kin&rank=5&search_sort=0&spq=0&sp=1&pid=gWKD3c5Y7vlssu8J7v0ssc--018553&sid=TtLqhqrC0k4AAEoqJL0


specifies a resouce outside the web application 에러 JAVA

환경설정 Tip

2011/11/03 21:59

복사http://blog.naver.com/korn123/30122621225


JEUS 6.0 환경에서
INCLUDE DIRECTIVE 사용시 상대경로를 이용하면 에러가 발생함

<%@ include file= "../../inclusion/footer.jsp" %> 와 같이 페이지를 상대경로로 설정하면
The path /testPro/../../inclusion/footer.jsp specifies a resouce outside the web application 라는
에러메세지가 출력됨

Tomcat6.0환경에서 개발해서 테스트할때는 정상적으로 페이지가 출력되지만
JEUS에서는 에러가 발생함
아래와 같이 상대경로를 절대경로로 변경해서 해결함

<%@ include file= "/testPro/inclusion/footer.jsp" %>

JSTL : IF EXAMPLE JSTL

JSTP core tag:if
<%@ taglib uri="http://java.sun.com/jstl/core" prefix="c" %>
<html>
<head><title>Using the Core JSTL tags</title></head>
<body>
<h2>Here are the available Time Zone IDs on your system</h2>
<jsp:useBean id="zone" class="com.java2s.ZoneWrapper" /> 
<jsp:useBean id="date" class="java.util.Date" /> 

<c:if test="${date.time != 0}" >

    <c:out value="Phew, time has not stopped yet...<br /><br />" escapeXml="false" />

</c:if>

<c:set var="zones" value="${zone.availableIDs}" scope="session" />

    <c:forEach var="id" items="${zones}">

        <c:out value="${id}<br />" escapeXml="false" />


    </c:forEach>

</body>
</html>
// Save the ZoneWrapper.class into WEB-INF/classes/com/java2s
//ZoneWrapper.java

package com.java2s;           


import java.util.TimeZone;

public class ZoneWrapper {

  public ZoneWrapper() {
  }

  public String[] getAvailableIDs() {

    return TimeZone.getAvailableIDs();

  }

}


JSTL RT If
<%@ taglib uri="http://java.sun.com/jstl/core" prefix="c" %>
<%@ taglib uri="http://java.sun.com/jstl/core-rt" prefix="c-rt" %>
<html>
  <head>
    <title>If Caseless</title>
  </head>

  <body>
    <c:set var="str" value="jStL" />

    <jsp:useBean id="str" type="java.lang.String" />

    <c-rt:if test='<%=str.equalsIgnoreCase("JSTL")%>'> They are
    equal</c-rt:if>
  </body>
</html>



JSTL If Else
<%@ taglib uri="http://java.sun.com/jstl/core" prefix="c" %>
<html>
  <head>
    <title>Using Choose,Otherwise and When</title>
  </head>

  <body>
    <c:if test="${pageContext.request.method=='POST'}">Ok, we'll
    send 
    <c:out value="${param.enter}" />

    <c:choose>
      <c:when test="${param.enter=='1'}">pizza.
      <br />
      </c:when>

      <c:otherwise>pizzas.
      <br />
      </c:otherwise>
    </c:choose>
    </c:if>

    <form method="post">Enter a number between and 5:
    <input type="text" name="enter" />

    <input type="submit" value="Accept" />

    <br />
    </form>
  </body>
</html>



JSTL If No Body
<%@ taglib uri="http://java.sun.com/jstl/core" prefix="c" %>
<html>
  <head>
    <title>If with NO Body</title>
  </head>

  <body>
    <c:if test="${pageContext.request.method=='POST'}">
    <c:if test="${param.guess=='5'}" var="result" />

    I tested to see if you picked my number, the result was 
    <c:out value="${result}" />
    </c:if>

    <form method="post">Guess what number I am thinking of?
    <input type="text" name="guess" />

    <input type="submit" value="Try!" />

    <br />
    </form>
  </body>
</html>


If with Body
<%@ taglib uri="http://java.sun.com/jstl/core" prefix="c" %>
<html>
  <head>
    <title>If with Body</title>
  </head>

  <body>
    <c:if test="${pageContext.request.method=='POST'}">
      <c:if test="${param.guess=='5'}">You guessed my number!
      <br />

      <br />

      <br />
      </c:if>

      <c:if test="${param.guess!='5'}">You did not guess my number!
      <br />

      <br />

      <br />
      </c:if>
    </c:if>

    <form method="post">Guess what number I am thinking of?
    <input type="text" name="guess" />

    <input type="submit" value="Try!" />

    <br />
    </form>
  </body>
</html>

필터를 이용한 웹 프로그래밍 Part2, 필터의 응용! JSP

서블릿 2.3에 새롭게 추가된 필터를 이용한 사용자 인증, XSL/T 변환을 구현해본다.

필터의 응용

사실 필터는 그 동안 많은 개발자들이 필요로 하는 기능이었으며, 다른 페이지로 이동하거나(forwarding) 다른 페이지를 포함하는(include) 방법을 사용하여 서블릿 체인(또는 서블릿과 JSP의 체인) 형태로 필터링을 구현하는 경우가 많았다. 이러한 필터링을 적용할 수 있는 분야에는 다음과 같은 것들이 있을 것이다.

  • 데이터 변환(다운로드 파일의 압축 및 데이터 암호화 등)
  • XSL/T를 이용한 XML 문서 변경
  • 사용자 인증
  • 자원 접근에 대한 로깅
이 외에도 많은 활용 방법들이 존재할 수 있겠지만 여기서 제시한 네 가지 정도가 가장 많이 사용되지 않을까 생각된다. 특히, 데이터 변환이나 XSL/T는 필터를 적용하기에 가장 알맞은 구조를 갖고 있다. 데이터 변환의 경우 데이터 압축 필터와 암호화 필터를 체인으로 만들어 암호화한 데이터를 다시 압축하는 등의 다양한 방식이 존재할 수 있다. 또한, XSL/T를 사용할 경우 최종 자원은 XML 문서를 생성하고, 그 문서를 다양한 포맷으로 변환해주는 필터가 존재할 수 있다. 예를 들어, 서블릿/JSP는 사용자가 요청한 정보를 XML로 출력하고 필터는 XSL/T를 사용하여 자원의 출력 결과를 다양한 기기(웹브라우저, 모바일 폰 등)에 맞게 변형할 수도 있을 것이다.

이 글에서는 사용자 인증 필터, XSL/T 필터에 대해서 살펴볼 것이다. 이 두가지 필터는 필터를 통한 흐름 제어 및 응답 데이터의 변경 방법 등을 보여주고 있기 때문에, 이 두 가지 형태의 필터가 어떤 식으로 구현되는 지 이해한다면 여러분은 그 외의 모든 다른 종류의 필도 어렵지 않게 구현할 수 있게 될 것이다. 지금부터 차례대로 살펴보도록 하자.

로그인 검사 필터

요즘 많은 웹 사이트들이 회원제로 운영되고 있으며 로그인을 한 이후에 컨텐츠에 접근할 수 있도록 제한한 곳도 많다. 특히 컨텐츠의 유료화 추세에 발맞추어 이처럼 사용자 인증이 필요한 사이트는 점차적으로 증가하고 있다. 심지어 무료 사이트 조차도 사용자가 인증을 거친 이후에 컨텐츠에 접근할 수 있도록 하고 있다. 이처럼 사용자 인증이 웹 사이트의 필수 요소로 등장하면서 개발자들은 각각의 JSP/서블릿 등의 코드에 사용자가 로그인을 했는지의 여부를 판단하기 위한 코드를 삽입하고 있다. 여기서 각각의 JSP/서블릿은 같은 코드 블럭을 갖게 되며 이는 회원 인증이 변할 경우 모든 페이지를 변경해주어야 한다는 문제를 일으키게 된다.

이러한 문제는 로그인을 검사하는 필터를 사용함으로써 말끔하게 해소할 수 있다. 1부에서도 살펴봤듯이 클라이언트의 요청은 서블릿/JSP에 전달되기 전에 먼저 필터를 통과하게 된다. 따라서, 필터에서 조건에 따라 알맞게 흐름을 제어할 수 있다는 것을 의미한다. 먼저 소스 코드부터 작성해보자. 어떤 형태로 구현했는지 집중적으로 관찰하기 바란다.

  import javax.servlet.*;
  import javax.servlet.http.*;
  
  public class LoginCheckFilter implements Filter {
     
     public void init(FilterConfig filterConfig) throws ServletException {
     }
     
     public void doFilter(ServletRequest request,
                          ServletResponse response,
                          FilterChain chain)
                 throws java.io.IOException, ServletException {
        if (LoginChecker.isLogin((HttpServletRequest)request)) {
           // 로그인을 했다면 다음 필터를 실행한다.
           chain.doFilter(request, response);
        } else {
           // 로그인을 하지 않았을 경우 로그인 페이지로 이동한다.
           ((HttpServletResponse)response).sendRedirect(LOGIN_URL);
        }
     }
     
     public void destroy() {
     }
     
     private static String LOGIN_URL = "/login.jsp";
  }
  

로그인 여부를 검사하는 필터는 위와 같이 매우 간단하다. 여기서 LoginChecker.isLogin() 메소드는 파라미터로 전달받은 HttpServletRequest를 사용하여 로그인 여부를 판단해주는 일종의 보조 클래스이다. 회원이 로그인을 했을 때 LoginChecker.isLogin() 메소드가 true를 리턴한다고 가정할 경우, 위 코드와 같이 로그인을 하면 필터 체인의 다음 필터로 이동하고 로그인을 하지 않은 상태로 판단되면 response를 사용하여 다른 페이지로 이동하면 된다. 로그인을 하지 않았을 때 이동하는 페이지는 일반적으로 로그인 폼을 보여주는 페이지가 될 것이다.

위 코드를 보면 알겠지만 클라이언트의 요청이 반드시 필터 체인의 모든 필터를 통과해야 하는 것은 아니며, 어떤 필터든지 간에 다음 필터로 이동하지 않고 중간에 체인을 끝낼 수 있도록 되어 있다. 사용자 인증 필터는 바로 그러한 특징을 이용한 것이다. 사용자 인증 필터는 거의 대부분의 회원 서비스에서 사용될 것이며 다음과 같이 web.xml을 설정하여 사용자 인증 필터를 적용하면 될 것이다.

   <filter>
      <filter-name>LoginChecker</filter-name>
      <filter-class>LoginCheckFilter</filter-class>
   </filter>
   
   <filter-mapping>
      <filter-name>LoginChecker</filter-name>
      <url-pattern>/board/-</url-pattern>
   </filter-mapping>

인증 필터를 사용함으로써 얻게 되는 장점은 서블릿/JSP와 같은 최종 자원에서 일일이 로그인 여부를 판단하지 않아도 된다는 점이다. 이는 서블릿과 JSP는 클라이언트의 요청에 알맞은 작업만을 수행하는 역할을 맡게 되고 사용자 인증을 검사하는 역할은 맡지 않아도 된다는 것을 의미한다. 즉, 역할에 알맞게 객체가 분리되는 것이다.

XSL/T 필터

필터가 나옴으로써 객체 지향적으로 변화된 부분이 있다면 바로 XML과 관련된 부분일 것이다. 필터가 생김으로써 서블릿과 JSP는 더 이상 XSL/T를 이용하여 XML 문서를 HTML이나 WML과 같은 다른 통신 표준으로 변경해줄 필요가 없게 되었다. 이제, XSL/T를 이용한 변환 작업은 이제 필터가 맡게 되었으며 서블릿과 JSP는 XML 문서를 생성하는 것 이외에 다른 작업은 할 필요가 없게 되었다.

XSL/T 필터는 응답 데이터를 변경해주는 필터이다. 즉, 서블릿/JSP가 생성한 XML 문서를 XSL/T를 이용하여 완전히 새로운 형태로 재구성하는 것이 XSL/T 필터의 역할이다. 서블릿/JSP의 응답 결과인 XML 문서를 완전히 새로운 형태로 변경해주기 위해서는 서블릿/JSP가 출력한 XML 데이터를 클라이언트(웹브라우저)에 곧바로 전송해서는 안된다. 대신, 서블릿/JSP가 출력한 데이터를 임의의 버퍼에 저장한 후, 그 버퍼에 저장된 XML 데이터를 XSL/T를 사용하여 변환해야만 한다. 이를 위해 먼저 버퍼의 역할을 할 출력 스트림을 작성해야 하며, 또한 그 출력 스트림은 서블릿과 JSP에서 주로 사용되는 PrintWriter 타입이어야만 한다. 다음은 이 예제에서 서블릿/JSP가 출력하는 데이터를 저장해둘 버퍼의 역할을 하는 ReponseBufferWriter 클래스이다.

  class ReponseBufferWriter extends PrintWriter {
     
     public ReponseBufferWriter() {
        super(new StringWriter(4096) );
     }
     
     public String toString() {
        return ((StringWriter)super.out).toString();
     }
  }

특별히 어렵지는 않으며, ResponseBufferWriter는 print(), println(), write() 등의 메소드를 통해서 전달된 데이터를 StringWriter에 저장하는 기능을 한다. toString() 메소드는 StringWriter에 저장된 데이터를 String 타입으로 변환해주는 역할을 한다.

출력 버퍼를 만들었으니 그 다음으로 해야 할 일은 최종 자원인 서블릿과 JSP가 ResponseBufferWirter를 출력 스트림으로 사용하도록 하는 응답 래퍼 클래스를 작성하는 것이다. 이 예제에서 사용할 응답 래퍼 클래스는 다음과 같다.

  class XSLTResponseWrapper extends HttpServletResponseWrapper {
     
     private ReponseBufferWriter buffer = null;
     
     public XSLTResponseWrapper(HttpServletResponse response) {
        super(response);
        buffer = new ReponseBufferWriter();
     }
     
     public PrintWriter getWriter() throws java.io.IOException {
        return buffer;
     }
     
     public void setContentType(String contentType) {
        // do nothing
     }
     
     public String getBufferedString() {
        return buffer.toString();
     }
  }

위 코드를 보면 XSLTResponseWrapper 클래스가 복잡하지 않다는 것을 알 수 있다. XSLTResponseWrapper 클래스의 getWriter() 메소드는 실제 클라이언트로의 응답에 해당하는 스크림을 리턴하는 대신 앞에서 작성한 ResponseBufferWriter를 리턴한다. 이렇게 함으로써 ServletResponse의 getWriter() 메소드를 호출하는 서블릿/JSP는 클라이언트로의 응답 스트림이 아닌 ResponseBufferWriter를 출력 스트림으로 사용하게 된다. 또 하나 주의해야 할 부분이 바로 setContentType() 메소드가 아무 기능도 하지 않는다는 점인데, 이 이유에 대해서는 뒤에서 설명하도록 하겠다.

이제 XML 데이터를 임시로 저장할 Writer도 구현하였고 또한 응답 래퍼도 구현하였다. 이제 마지막으로 남은 것은 필터를 구현하는 것 뿐이다. 필터는 다음과 같은 4 단계로 작업을 처리한다.

  1. 응답 래퍼(XSLTResponseWrapper)를 생성한다.
  2. 생성한 응답 패퍼를 체인의 다음 필터에 전달한다.
  3. 래퍼로부터 서블릿/JSP가 출력한 데이터를 읽어와 XSL/T를 사용하여 HTML로 변환한다.
  4. 변환된 결과인 HTML을 실제 응답 스트림에 출력한다.
이 과정을 구현한 것이 바로 XSLTFilter 클래스이다.

  import javax.servlet.*;
  import javax.servlet.http.*;
  import java.io.*;
  
  import javax.xml.transform.TransformerFactory;
  import javax.xml.transform.Transformer;
  import javax.xml.transform.stream.StreamSource;
  import javax.xml.transform.stream.StreamResult;
  
  public class XSLTFilter implements Filter {
     
     public void init(FilterConfig filterConfig) throws ServletException {
     }
     
     public void doFilter(ServletRequest request,
                          ServletResponse response,
                          FilterChain chain)
                 throws java.io.IOException, ServletException {
        response.setContentType("text/html; charset=euc-kr");
        PrintWriter writer = response.getWriter();
        
        XSLTResponseWrapper responseWrapper =
 
                      new XSLTResponseWrapper((HttpServletResponse)response);
        chain.doFilter(request, responseWrapper);        
        // XSL/T 변환
        try {
           TransformerFactory factory = TransformerFactory.newInstance();
           Reader xslReader = new BufferedReader(new FileReader("c:/book.xsl"));
           StreamSource xslSource = new StreamSource(xslReader);
           
           Transformer transformer = factory.newTransformer(xslSource);           
           String xmlDocument = responseWrapper.getBufferedString();
           Reader xmlReader = new StringReader(xmlDocument);
           StreamSource xmlSource = new StreamSource(xmlReader);
           
           StringWriter buffer = new StringWriter(4096);
           
           transformer.transform( xmlSource, new StreamResult(buffer) );           
           writer.print(buffer.toString());
        } catch(Exception ex) {
           throw new ServletException(ex);
        }
        
        writer.flush();
        writer.close();
     }
     
     public void destroy() {
     }
  }

XSLTFilter 클래스의 doFilter() 메소드를 차근 차근 분석해보도록 하자. doFilter() 메소드가 가장 먼저 하는 것은 응답의 컨텐츠 타입을 text/html로 지정하는 것이다. 물론, 한글을 사용하기 때문에 뒤에 charset도 추가해주었다. 여기서 response 객체는 클라이언트에 대한 응답을 나타내며, 클라이언트는 결과 데이터를 HTML 문서로 인식하게 된다. 앞에서 XSLTResponseWrapper의 setContentType() 메소드에서 아무것도 하지 않았었는데, 그 이유는 XSLTFilter의 doFilter() 메소드에서 지정한 컨텐츠 타입을 변경할 수 없도록 하기 위함이다.

그 다음에는 래퍼 클래스를 생성한다. 래퍼 클래스는 XSLTResponseWrapper이며, 생성된 래퍼 클래스는 chain.doFilter()를 통해서 다음 필터에 전달된다. 필터 체인의 실행이 완료되면 XSLTResponseWrapper 객체에는 서블릿이나 JSP가 출력한 XML 응답 데이터가 저장되며, 그 데이터는 responseWrapper.getBufferedString() 메소드를 통해서 구할 수 있게 된다. 이렇게 해서 구한 XML 데이터는 JAXP 1.1에서 제공하는 Transformer의 transform() 메소드를 통해서(즉, XSL/T를 통해서) HTML 형식으로 변환된다.

이제 XSL/T 필터와 관련된 모든 클래스의 구현은 끝이 났다. 이제 남은 것은 XSL/T에서 사용할 XSL 문서를 작성하고 XML 문서를 생성해주는 JSP/서블릿을 프로그래밍하고 그리고 web.xml 파일을 통해서 XSLTFilter를 필터로 등록하는 것이다. 먼저 web.xml 파일을 필터를 사용하여 지정해보자.

   <filter>
      <filter-name>XSLT</filter-name>
      <filter-class>XSLTFilter</filter-class>
   </filter>
   
   <filter-mapping>
      <filter-name>XSLT</filter-name>
      <url-pattern>/x-l/*</url-pattern>
   </filter-mapping>

이제 /xml/로 들어오는 모든 요청은 XSLTFilter를 토?서 처리된다. 이제 XML 문서를 생성해주는 JSP 페이지를 작성해보자. 여기서는 테스트를 위해서 다음과 같이 간단한 JSP 페이지를 사용하였다. (이 JSP를 book.jsp라 하자.)

  <?xml version="1.0" encoding="euc-kr" ?>  
  <%@ page contentType="text/xml; charset=euc-kr" %>
  
  <list>
     
     <book>
        <title>JavaCan.com의 JSP Professional</title>
        <author>이동훈, 최범균</author>
        <price>24,000</price>
     </book>
     
     <book>
        <title>JavaCan.com의 Victory Java</title>
        <author>이동훈, 최범균</author>
        <price>30,000</price>
     </book>
     
  </list>

위 JSP 페이지는 보다시피 XML 문서를 생성해낸다. 이 XML 문서를 HTML로 변환해주기 위해 사용되는 XSL은 다음과 같다. (여기서는 XSL에 대한 내용은 설명하지 않겠다.)

 <?xml version="1.0" encoding="euc-kr" ?>
  
  <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
    <xsl:output method = "html" indent="yes" encoding="euc-kr" />
  
    <xsl:template match="list">
    <html>
    <head><title>책 목록</title></head>
    <body>
      현재 등록되어 있는 책의 목록은 다음과 같습니다.
      <ul>
      <xsl:for-each select="book">
        <li><b><xsl:value-of select="title" /></b>
            (<xsl:value-of select="price" /> 원)
            <br />
            <i><xsl:value-of select="author" /></i>
        </li>
      </xsl:for-each>
      </ul>
    </body>
    </html>
    </xsl:template>
    
  </xsl:stylesheet>

book.jsp를 웹어플리케이션의 /xml 하위디렉토리에 복사한 후 웹브라우저에서 book.jsp를 요청한 결과의 소스 코드를 보면 다음과 같이 XML이 아닌 XSLTFilter 필터를 통해서 변경된 결과가 오는 것을 확인할 수 있을 것이다.

  <html>
  <head>
  <META http-equiv="Content-Type" content="text/html; charset=euc-kr">
  <title>책 목록</title>
  </head>
  <body>
       현재 등록되어 있는 책의 목록은 다음과 같습니다.
       <ul>
  <li>
  <b>JavaCan.com의 JSP Professional</b>
             (24,000 원)
             <br>
  <i>이동훈, 최범균</i>
  </li>
  <li>
  <b>JavaCan.com의 Victory Java</b>
             (30,000 원)
             <br>
  <i>이동훈, 최범균</i>
  </li>
  </ul>
  </body>
  </html>

결론

여기서 살펴본 필터의 예제는 매우 간단하게 구현되는 것들이었지만, 아마 필터를 구현하는 데 있어서 가장 기본적인 형태를 갖는 예제가 아닐까 생각된다. 이번 필터 예제를 통해서 여러분들은 필터의 쓰임새가 많겠구나 하고 생각했을 것이다. 어쩌면 벌써부터 압축 필터나 이미지 생성 필터 등을 생각하고 있을지도 모르겠다. 하지만 필터의 응용을 생각하기 이전에 다음과 같은 점을 염두해두었으면 한다.

  • 필터는 재사용이 가능해야 한다. 즉, 필터들은 객체 지향적으로 설계되고 구현되어야 한다.
  • 필터를 통과하지 않아도 JSP/서블릿/기타 자원은 알맞은 결과를 출력해야 한다.
  • 필터간에 커플링(coulpling; 결합도)이 존재해서는 안 된다.
이러한 것들을 염두하고서 필터를 설계하고 구현한다면, 그 필터는 여러분이 개발하게 될 웹 어플리케이션 곳곳에서 사용될 것이며 그만큼 여러분의 웹 어플리케이션은 역할별로 알맞게 분리된 구조를 갖게 될 것이다.

관련링크:

1 2 3 4 5 6 7 8 9 10 다음