어떤 파일이 어느 곳에 위치하는지는 중요하다.
php를 개발 할 때 프로그래머가 임의로 정하는 장소와는 달리 Java(JSP)는 어느정도 rule을 가지고 특정 위치에 특정 파일을 배포해야지만, 전체 웹 애플리케이션이 돌아가기 때문이다.
따라서 중요한 몇개의 파일 타입별 배포 위치에 대해 정리해 보면 아래와 같다.

  • 정적인 컨텐츠(html, 이미지) 및 jsp
    • 루트 디렉토리 및 그 하위 디렉토리
    • WEB-INF 밑에 배포 할 경우에는 클라이언트가 직접 접근할 수 없다. 대신 웹 애플리케이션에서 접근을 하게 만들 경우를 위해서 배포할 순 있다.
  • 태그파일(.tag) - http://www.4te.co.kr/567 참고
    • WEB-INF/tags 디렉토리에 배포
  • DD 파일
    • 이름은 web.xml이어야 하며 WEB-INF 바로 밑에 두어야 한다.
  • jar 파일
    • WEB-INF/lib 밑에 두어야 한다.
    • jar파일 내 구조
      • jar 최상위 디렉토리 바로 밑에서부터 시작해야 한다.(패키지 시작부터)
      • jar로 배포할 경우 최상위 디렉토리에 META-INF 디렉토리가 있어야 하며, tld 파일은 META-INF 디렉토리 아래 배포 해야한다.
  • class 파일
    • WEB-INF/classes 밑에 패키지 구조로 배포 되어야 한다.

* WAR 파일로 배포하기

jar 파일로 애플리케이션 전체를 압축한 후 확장자만 war로 바꿔서 배포하는 것을 말한다.
압축하는 디렉토리는 웹 애플리케이션의 내용이 들어있는 디렉토리를 압축해서 배포하면 된다.
압축을 하는 위치는 디렉토리 위에서 압축하는 것이 아니라, 디렉토리 내부에서 압축해야 한다.
또한 압축 파일명은 웹애플리케이션의 이름이 된다(톰캣의 경우)

ex) /webapps/BeerApp 를 압축하기 위해서는 /webapps에서 BeerApp를 압축하는 것이 아니라 BeerApp 아래 들어가서 압축

WAR 파일의 경우 META-INF/MANIFEST.MF 파일에 라이브러리 의존성을 작성해 두면, 배포 시 컨테이너가 애플리케이션을 실행하기 위해 필요한 라이브러리가 있는지 사전 체크할 수 있다.

* 서블릿 맵핑

서블릿 맵핑은 물리적인 디렉토리가 아닌 가상의 디렉토리(URL)에서 실행할 내용을 찾기 위해 사용하는 것이다. 관련 내용은 http://www.4te.co.kr/538를 참고하면 된다.

참고)서블릿 맵핑은 와일드 카드와 같이 패턴 형식으로 맵핑할 수도 있다.

* DD에 환영 파일 설정하기

파일명을 안치고 디렉토리명까지 치면 자동을 찾게 할 파일명을 설정할 수 있다. web.xml에 다음과 같이 적어주면 된다.

  <welcome-file-list>
    <welcome-file>index.html</welcome-file>
    <welcome-file>index.htm</welcome-file>
    <welcome-file>index.jsp</welcome-file>
    <welcome-file>default.html</welcome-file>
    <welcome-file>default.htm</welcome-file>
    <welcome-file>default.jsp</welcome-file>
  </welcome-file-list>

위 리스트 중에서 index.html과 index.jsp가 같이 있게 된다면 먼저 나온 index.html을 보여주게 된다.
apache의 httpd.con파일에 있는 다음과 같은 설정과 같은 역할을 해 주는 것이다.

<IfModule mod_dir.c>
    DirectoryIndex index.html index.php
</IfModule>

* DD에 오류 페이지 설정하기

오류 페이지를 web.xml에 설정하는 방법은 http://www.4te.co.kr/565 를 참고하면 된다.
프로그램에서 오류코드를 일부러 방생하고자 할 경우에는 다음과 같이 하면 된다.

response.sendError(HttpServletResponse.SC_FORBIDDEN);

위 내용은 403 에러를 내뱉는 경우를 프로그램적으로 처리한 경우이다. 실제 403 에러를 내 뱉는 것과 프로그램을 통해 내뱉는 것 사이의 차이를 클라이언트는 알 수 없다.

* DD에서 강제로 서블릿 초기화 하기

서블릿을 배포하게 되면 가장 처음 요청하는 클라이언트는 해당 서블릿이 로딩 될 때까지 기다려야 한다. 그리 무겁지 않은 서블릿일 경우에는 자동 로딩을 적용 하지 않아도 되지만, 무거운 서블릿일 경우에는 클라이언트에 의해 로딩되지 않고, 배포 할 때 로딩 되도록 만들어야 한다.
따라서 그럴 경우에는 아래와 같이 web.xml에 정의해 주면 된다.

  <servlet>
      <servlet-name>Chapter1 Servlet</servlet-name>
      <servlet-class>Ch1Servlet</servlet-class>
      <load-on-startup>1</load-on-startup>
  </servlet>

해당 숫자는 초기화 하는 순서를 말한다. 동일한 숫자가 여러개 있다면 web.xml에 정의한 순서대로 로딩한다.

* mime mapping 하기

DD(web.xml)에서 mime type을 확장자와 맵핑해 둘 수 있다.

  <mime-mapping>
      <extension>mpg</extension>
      <mime-type>video/mpeg</mime-type>
  </mime-mapping>




신고

'Java > Servlet & JSP' 카테고리의 다른 글

필터 - REQUEST  (1) 2009.04.16
웹 애플리케이션 보안  (4) 2009.04.10
웹 애플리케이션 배포하기  (0) 2009.04.07
부모 자식 태그간의 통신  (0) 2009.03.26
클래식 커스텀 태그  (0) 2009.03.26
사용자 정의 태그 개발 (1)  (0) 2009.03.23

WRITTEN BY
체리필터
프로그램 그리고 인생...

받은 트랙백이 없고 , 댓글이 없습니다.
secret
커스텀 태그 안에 커스텀 태그가 위치해 있을 경우 서로간에 필요한 속성이라던가 내용 등을 읽어올 필요가 있다. 이럴 경우에는 다음과 같은 방법으로 접근할 수 있다.

myCustomTag3.tld

<?xml version="1.0" encoding="UTF-8"?>

<taglib 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/web-jsptaglibrary_2_0.xsd" version="2.0">

<tlib-version>0.1</tlib-version>

<uri>Nested</uri>
<tag>
    <description>NestedLevel Check</description>
    <name>NestedLevel</name>
    <tag-class>com.example.tag.NestedLevelTag</tag-class>
    <body-content>JSP</body-content>
</tag>
</taglib>

NestedLevelTag.java

package com.example.tag;

import java.io.IOException;

import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.Tag;
import javax.servlet.jsp.tagext.TagSupport;

public class NestedLevelTag extends TagSupport {
    private int nestLevel = 0;
   
    public int doStartTag() throws JspException {
        nestLevel = 0;
        Tag parent = getParent();
       
        while(parent != null) {
            parent = parent.getParent();
            nestLevel++;
        }
       
        try {
            pageContext.getOut().println("<br>Tag nested level : " + nestLevel);
        } catch (IOException e) {
            // TODO: handle exception
            throw new JspException("IOException - " + e.toString());
        }
       
        return EVAL_BODY_INCLUDE;
    }
}

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib prefix="mine" uri="Nested" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<mine:NestedLevel>
    <mine:NestedLevel>
        <mine:NestedLevel/>
    </mine:NestedLevel>
</mine:NestedLevel>
</body>
</html>

결과물

Insert title hereTag nested level : 0
Tag nested level : 1
Tag nested level : 2

getParent 메소드를 반복해서 호출해서 depth가 몇단계인지 알아내는 예제이다.

SimpleTag 인터넾이스와 Tag인터페이스는 JspTag 인터페이스를 구현한 것이다. SimpleTag의 getParent 메소드는 JspTag를 리턴하는데 반해 Tag(클래식 커스텀 태그)의 getParent 메소드는 Tag를 리턴한다.
이 점은 중요한데 왜냐하면 이 차이로 인해 Tag가 SimpleTag의 부모 태그가 될 수 있지만, SimpleTag가 Tag의 부모 태그가 될 수 없기 때문이다.
아래 내용은 Tag가 SimpleTag의 부모 태그로서 사용 되어질 경우 부모 태그의 attribute를 알아오는 예제이다.

classicParent.tld

<?xml version="1.0" encoding="UTF-8"?>

<taglib 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/web-jsptaglibrary_2_0.xsd" version="2.0">

<tlib-version>0.1</tlib-version>

<uri>ClassicParentTag</uri>
<tag>
    <description>classic parent</description>
    <name>ClassicParent</name>
    <tag-class>com.example.tag.MyClassicParent</tag-class>
    <body-content>JSP</body-content>
    <attribute>
        <name>name</name>
        <required>true</required>
        <rtexprvalue>true</rtexprvalue>
    </attribute>
</tag>
<tag>
    <description>Simple Inner Tag</description>
    <name>SimpleInner</name>
    <tag-class>com.example.tag.SimpleInner</tag-class>
    <body-content>empty</body-content>
</tag>
</taglib>

SimpleInner.java

package com.example.tag;

import java.io.IOException;

import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.SimpleTagSupport;

public class SimpleInner extends SimpleTagSupport {
    public void doTag() throws JspException, IOException {
        MyClassicParent parent = (MyClassicParent) getParent();
        getJspContext().getOut().print("Parent attribute is : " + parent.getName());
    }
}

MyClassicParent.java

package com.example.tag;

import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.TagSupport;

public class MyClassicParent extends TagSupport {
    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
   
    public int doStartTag() throws JspException {
        return EVAL_BODY_INCLUDE;
    }
}

classicParentTag.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib prefix="mine" uri="ClassicParentTag" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<mine:ClassicParent name="aaa">
    <mine:SimpleInner/>
</mine:ClassicParent>
</body>
</html>

결과물

Insert title hereParent attribute is : aaa

tld 파일에서는 ClassicParent 부모 태그와 SimpleInner 자식 태그를 정의 한다. ClassicParent 에는 name 이란 attribute가 존재 한다.
ClassicParent와 SimpleInner태그를 구현한 각 Java 파일은 위 소스와 같이 구현한다.
SimpleInner.java 파일에서 눈여겨 볼 것은 getParent 메소드를 통해 리턴 받은 JspTag형 객체를 ClassicParent로 형변환 해서 사용하는 것이다.
ClassicParent.java 파일에는 setter와 getter가 있는데, 자동으로 setter는 tld 에서 정의한 name이란 attribute에 값을 할당해 주며, getter는 SimpleInner.java에서 사용한다.
물론 ClassicParent.java의 doStartTag()에서 EVAL_BODY_INCLUDE를 리턴해 주어야지만 자식 태그인 SimpleInner가 실행 되게 된다.

중요한 것은 자식 태그에서 부모 태그의 정보를 읽을 수는 있어도 부모에서 자식 태그의 정보를 읽을 수는 없다.
따라서 부모에서 자식 태그를 알기 위해서는 반대로 자식에수 부모 쪽에 값을 셋팅 하는 방법을 사용해야 한다.
다음 예제를 통해서 부모가 자식의 속성 값을 알아내는 방법을 살펴보자.

menuTag.tld

<?xml version="1.0" encoding="UTF-8"?>

<taglib 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/web-jsptaglibrary_2_0.xsd" version="2.0">

<tlib-version>0.1</tlib-version>

<uri>MenuTag</uri>
<tag>
    <description>parent menu tag</description>
    <name>Menu</name>
    <tag-class>com.example.tag.Menu</tag-class>
    <body-content>JSP</body-content>
</tag>
<tag>
    <description>child menu tag</description>
    <name>MenuItem</name>
    <tag-class>com.example.tag.MenuItem</tag-class>
    <body-content>JSP</body-content>
    <attribute>
        <name>itemValue</name>
        <required>true</required>
        <rtexprvalue>true</rtexprvalue>
    </attribute>
</tag>
</taglib>

Menu.java

package com.example.tag;

import java.util.ArrayList;

import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.TagSupport;

public class Menu extends TagSupport {
    private ArrayList<String> items;
   
    public void addMenuItem(String item) {
        items.add(item);
    }
   
    public int doStartTag() throws JspException {
        items = new ArrayList<String>();
       
        return EVAL_BODY_INCLUDE;
    }
   
    public int doEndTag() throws JspException {
        try {
            pageContext.getOut().println("Menu items are : " + items);
        } catch (Exception e) {
            // TODO: handle exception
            throw new JspException("Exception : " + e.toString());
        }
        return EVAL_PAGE;
    }
}

MenuItem.java

package com.example.tag;

import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.TagSupport;

public class MenuItem extends TagSupport {
    private String itemValue;

    public void setItemValue(String itemValue) {
        this.itemValue = itemValue;
    }
   
    public int doStartTag() throws JspException {
        return EVAL_BODY_INCLUDE;
    }
   
    public int doEndTag() throws JspException {
        Menu parent = (Menu) getParent();
        parent.addMenuItem(itemValue);
        return EVAL_PAGE;
    }
}

menuItem.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib prefix="mine" uri="MenuTag" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<mine:Menu>
    <mine:MenuItem itemValue="Dogs"></mine:MenuItem>
    <mine:MenuItem itemValue="Cats"></mine:MenuItem>
    <mine:MenuItem itemValue="Horses"></mine:MenuItem>
</mine:Menu>
</body>
</html>

결과물

Insert title hereMenu items are : [Dogs, Cats, Horses]

menuTag.tld 파일에선 Menu태그와 MenuItem 태그를 정의한다. MenuItem 태그가 child 태그이며, itemValue라는 attribute를 가지고 있다.
Menu 태그를 정의한 Menu.java 파일에서는 ArrayList 변수 addMenuItem 메소드를 하나 만들고 값을 받아 하나씩 추가할 수 있도록 한다. addMenuItem 메소드는 child 태그인 MenuItem 클래스에서 사용할 메소드이다.
MenuItem 태그를 정의한 MenuItem.java에서는 doEndTag 부분에서 parent 객체를 하나 생성한 후 Menu 클래스에 있는 addMenuItem 메소드를 호출해 자신이 가지고 있는 itemValue라는 속성을 넘겨준다.
마지막으로 Menu 클래스의 doEndTag 메소드에서는 child 태그로부터 넘겨 받게 된 값을 화면에 보여준다.



신고

'Java > Servlet & JSP' 카테고리의 다른 글

웹 애플리케이션 보안  (4) 2009.04.10
웹 애플리케이션 배포하기  (0) 2009.04.07
부모 자식 태그간의 통신  (0) 2009.03.26
클래식 커스텀 태그  (0) 2009.03.26
사용자 정의 태그 개발 (1)  (0) 2009.03.23
커스텀 태그 사용하기  (0) 2009.03.17

WRITTEN BY
체리필터
프로그램 그리고 인생...

받은 트랙백이 없고 , 댓글이 없습니다.
secret
JSP2.0 이전 버젼에서의 커스텀 태그는 심플 방식이 아닌 클래식 방식을 사용한다. simple 방식에서는 doTag() 메소드 하나로 모든 작업을 하고, exception 처리도 JspException, IOException를 throw 해서 catch 블럭이 없지만, 클래식 방식에는 doStartTag(), doEndTag() 메소드를 사용하며, JspException만을 throw 해서 catch 블럭에서 IOException을 잡을 필요가 있다.
간단하게 아래 예제를 통해 알아보자

tld 파일

<?xml version="1.0" encoding="UTF-8"?>

<taglib 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/web-jsptaglibrary_2_0.xsd" version="2.0">

<tlib-version>0.9</tlib-version>

<uri>KathyClassicTags</uri>
<tag>
    <description>ludicrous use of a Classic tag</description>
    <name>classicOne</name>
    <tag-class>com.example.tag.Classic1</tag-class>
    <body-content>empty</body-content>
</tag>
</taglib>

com.example.tag.Classic1.java 파일

package com.example.tag;

import java.io.IOException;

import javax.servlet.jsp.JspException;
import javax.servlet.jsp.JspWriter;
import javax.servlet.jsp.tagext.TagSupport;

public class Classic1 extends TagSupport {
    JspWriter out;
   
    public int doStartTag() throws JspException {
        out = pageContext.getOut();
        try {
            out.println("in doStartTag()");
        } catch (IOException e) {
            // TODO: handle exception
            throw new JspException("IOException - " + e.toString());
        }
        return SKIP_BODY;
    }
   
    public int doEndTag() throws JspException {
        try {
            out.println("in doEndTag");
        } catch (IOException e) {
            // TODO: handle exception
            throw new JspException("IOException - " + e.toString());
        }
        return EVAL_PAGE;
    }
}

closeTag1.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib prefix="mine" uri="KathyClassicTags" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
Classic Tag One : <br>
<mine:classicOne/>
</body>
</html>

Classic1 클래스를 보면 SimpleTagSupport가 아닌 TagSupport를 확장한다. 또한 getJspContext 대신에 pageContext를 사용한다.

doStartTag() 메소드에서 SKIP_BODY를 리턴 하는 것은 컨테이너가 다음에 어떤 일을 수행하도록 알려주는 것이다. 이 뜻은 body가 있더라도 실행하지 말고 곧바로 doEndTag()로 가라는 뜻이다.
화면에 print 해보면 해당 값이 0이라는 것을 알 수 있다.

또한 doEndTag() 메소드에서는 EVAL_PAGE를 리턴 하는데, 이 뜻은 작업이 끝났으니 페이지 뒷 부분을 실행하라는 의미이다.
심플 태그 핸들러의 SkipPageException과 비슷한 의미이다.

태그에 몸체가 있는 경우 몸체 안의 내용은 다음처럼 사용할 수 있다.

<?xml version="1.0" encoding="UTF-8"?>

<taglib 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/web-jsptaglibrary_2_0.xsd" version="2.0">

<tlib-version>0.9</tlib-version>

<uri>KathyClassicTags</uri>
<tag>
    <description>ludicrous use of a Classic tag</description>
    <name>classicOne</name>
    <tag-class>com.example.tag.Classic1</tag-class>
    <body-content>tagdependent</body-content>
</tag>
</taglib>

com.example.tag.Classic1.java 파일

package com.example.tag;

import java.io.IOException;

import javax.servlet.jsp.JspException;
import javax.servlet.jsp.JspWriter;
import javax.servlet.jsp.tagext.TagSupport;

public class Classic1 extends TagSupport {
    JspWriter out;
   
    public int doStartTag() throws JspException {
        out = pageContext.getOut();
        try {
            out.println("in doStartTag()");
            out.println("SKIP_BODY : " + SKIP_BODY);
            out.println("EVAL_BODY_INCLUDE : " + EVAL_BODY_INCLUDE);
        } catch (IOException e) {
            // TODO: handle exception
            throw new JspException("IOException - " + e.toString());
        }
        //return SKIP_BODY;
        return EVAL_BODY_INCLUDE;
    }
   
    public int doEndTag() throws JspException {
        try {
            out.println("in doEndTag");
            out.println("EVAL_PAGE : " + EVAL_PAGE);
        } catch (IOException e) {
            // TODO: handle exception
            throw new JspException("IOException - " + e.toString());
        }
        return EVAL_PAGE;
    }
}


closeTag1.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib prefix="mine" uri="KathyClassicTags" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
Classic Tag One : <br>
<mine:classicOne>
This is the body
</mine:classicOne>
</body>
</html>

Insert title here결과물

Insert title hereClassic Tag One :
in doStartTag() SKIP_BODY : 0 EVAL_BODY_INCLUDE : 1 This is the body in doEndTag EVAL_PAGE : 6

EVAL_BODY_INCLUDE는 몸체를 실행 시키라는 내용이며, 화면에 print 해 보면 1이라는 것을 알 수 있다. EVAL_PAGE의 값은 6이다.

심플 태그에서는 doTag 안에서 iterator를 실행 하면서 getJspBody().invoke(null)을 실행하면 루핑을 돌리면서 반복적인 작업을 할 수 있었다.
클래식 커스텀 태그에서는 doStartTag와 doEndTag로는 iterator 작업을 할 수 없으므로, doAfterTag를 이용할 수 밖에 없다. doAfterTag는 doStartTag에서 EVAL_BODY_INCLUDE를 리턴 하는 경우에만 실행 된다.
관련 소스는 아래를 참고하면 된다.

myCustomTag2.tld

<?xml version="1.0" encoding="UTF-8"?>

<taglib 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/web-jsptaglibrary_2_0.xsd" version="2.0">

<tlib-version>0.9</tlib-version>

<uri>KathyClassicTags2</uri>
<tag>
    <description>ludicrous use of a Classic tag</description>
    <name>iterateMovies</name>
    <tag-class>com.example.tag.Classic2</tag-class>
    <body-content>scriptless</body-content>
</tag>
</taglib>

Classic2.java

package com.example.tag;

import java.io.IOException;

import javax.servlet.jsp.JspException;
import javax.servlet.jsp.JspWriter;
import javax.servlet.jsp.tagext.TagSupport;

public class Classic2 extends TagSupport {
    String[] movies = new String[] {"Spiderman", "Saved!", "Amelie"};
    int movieCounter;
   
    public int doStartTag() throws JspException {
        movieCounter = 0;

        pageContext.setAttribute("movie", movies[movieCounter]);
        movieCounter++;
       
        return EVAL_BODY_INCLUDE;
    }
   
    public int doAfterBody() throws JspException {
        if(movieCounter < movies.length) {
            pageContext.setAttribute("movie", movies[movieCounter]);
            movieCounter++;
            return EVAL_BODY_AGAIN;
        } else {
            return SKIP_BODY;
        }
    }
   
    public int doEndTag() throws JspException {
        return EVAL_PAGE;
    }
}

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib prefix="mine" uri="KathyClassicTags2" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<table border="1">
<mine:iterateMovies>
    <tr><td>${movie}</td></tr>
</mine:iterateMovies>
</table>
</body>
</html>

doStartTag()에서는 EVAL_BODY_INCLUDE를 리턴하며 따라서 doAfterBody()를 호출하게 된다. doAfterBody 안에서는 movies 배열을 이용해 iterator 하면서 movie 객체에 값을 담는다. movieCounter가 movies의 길이만큼 루프를 돌게 되면 SKIP_BODY를 리턴 하면서 doEndTag를 호출하게 된다.
유의 할 점은 doAfterTag는 body가 한번 호출된 후부터 호출 되므로, doStartTag에서 "pageContext.setAttribute("movie", movies[movieCounter]);"를 한번 호출 한다.
doStartTag에서 호출하지 않을 경우 빈 값으로 <tr> 부분이 한번 iterator를 하기 때문에 빈 row가 하나 들어가게 된다.

movieCounter를 doStartTag 안에서 0으로 초기화 하는 것은 컨테이너가 풀(pool)로 관리하기 때문이다. 선언하면서 바로 초기화를 하게 되면, 재사용 될 경우에는 0으로 시작하지 않고 doAfterTag 의 iterator가 끝날 때 가지고 있는 값을 사용하게 될 것이기 때문이다.









신고

'Java > Servlet & JSP' 카테고리의 다른 글

웹 애플리케이션 배포하기  (0) 2009.04.07
부모 자식 태그간의 통신  (0) 2009.03.26
클래식 커스텀 태그  (0) 2009.03.26
사용자 정의 태그 개발 (1)  (0) 2009.03.23
커스텀 태그 사용하기  (0) 2009.03.17
JSTL 사용하기 (2)  (0) 2009.03.16

WRITTEN BY
체리필터
프로그램 그리고 인생...

받은 트랙백이 없고 , 댓글이 없습니다.
secret
<jsp:include> 표준 액션 또는 <c:import> JSTl과 같은 기능을 하는 태그 파일을 만들어 보자.

<img src="http://wstatic.naver.com/w9/lg_naver_v3.gif"><br>

위와 같이 코딩 한 후 WEB-INF 아래 tags란 디렉토리를 만들어 Header.tag 파일로 저장한다.
그리고 난 후 우리가 url에 호출할 파일을 만들어 보자.

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib prefix="myTags" tagdir="/WEB-INF/tags" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<myTags:Header></myTags:Header>
Welcome to our site.
</body>
</html>

위와 같이 만든 다음 DocumentRoot 아래 customTag란 디렉토리 안에 customTag.jsp란 파일로 만들었다.
브라우져에 http://localhost:8080/customTag/customTag.jsp를 호출하면 아래와 같은 모습이 보여진다.


위에서 <myTags:Header></myTags:Header> 라고 사용한 부분을 보면 파일명이 바로 Tag 명이 된 것을 알 수 있다.
또한 <jsp:include> 표준액션에서 param을 사용한 것처럼 사용할 수 있다.

customTag.jsp

<jsp:include page="Header.jsp">
    <jsp:param name="subTitle" value="We take the sting out of SOAP"/>
</jsp:include>

Header.jsp

<img src="http://wstatic.naver.com/w9/lg_naver_v3.gif"><br>
<em><strong>${param.subTitle}</strong></em>

표준 액션을 사용하면 위와 같이 할 수 있다. 태그를 사용하면 아래와 같이 사용하면 된다.

customTag.jsp

<myTags:Header subTitle="We take the sting out of SOAP" />
Welcome to our site.

Header.tag

<%@ attribute name="subTitle" required="true" rtexprvalue="true" %>
<img src="http://wstatic.naver.com/w9/lg_naver_v3.gif"><br>
<em><strong>${subTitle}</strong></em>

attribute로 넘어온 값은 param 이라는 이름 없이 ${subTitle} 과 같이 바로 사용하면 된다. 또한 사용하기 위해서는 상단에 "<%@ attribute name="subTitle" required="true" rtexprvalue="true" %>" 와 같이 attribute 정의를 해 놔야 한다.
tld에 정의한 바와 같이 required는 필수 여부, rtexprvalue는 표현식 사용 여부를 나타내는 것이다.

속성으로 넘겨야 할 내용이 길다면 다음과 같이 사용할 수 있다.

customTag.jsp

<myTags:Header fontColor="#660099" subTitle="We take the sting out of SOAP">
Welcome to our site.
Welcome to our site.
Welcome to our site.
Welcome to our site.
Welcome to our site.
Welcome to our site.
Welcome to our site.
Welcome to our site.
Welcome to our site.
</myTags:Header>

Header.tag

<%@ attribute name="fontColor" required="true" %>
<%@ tag body-content="tagdependent" %>

<em><strong><font color="${fontColor}"><jsp:doBody></jsp:doBody></font></strong></em>

body-content에 들어가는 내용은 tld 정의에서 배운 내용 그대로이다.

컨테이너가 태그 파일을 찾는 위치는 4군데이다.

1. WEB-INF/tags 바로 밑
2. WEB-INF/tags의 하위 디렉토리
3. WEB-INF/lib에 JAR 파일로 배포되었다면, JAR파일 META-INF/tags 밑에
4. WEB-INF/lib에 JAR 파일로 배포되었다면, JAR파일 META-INF/tags의 하위 디렉토리

태그 파일이 JAR 파일로 배포 되었다면, 반드시 TLD 파일이 있어야 한다.

태그 파일만으로 부족할 경우에는 자바 클래스를 이용한 사용자 정의 태그를 만들 수 있다. http://www.4te.co.kr/566에서 이미 만들어 본 내용이지만 다시 한번 정리하면 아래와 같다.

package com.example;

import java.io.IOException;

import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.SimpleTagSupport;

public class simpleTagTest1 extends SimpleTagSupport {
    public void doTag() throws JspException, IOException {
        getJspContext().getOut().print("This is the lamest use of a custom tag");
    }
}

/WEB-INF/simpleTag.tld

<?xml version="1.0" encoding="UTF-8"?>

<taglib 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/web-jsptaglibrary_2_0.xsd" version="2.0">

<tlib-version>1.2</tlib-version>
<uri>simpleTags</uri>
<tag>
    <description>worst use of a custom tag</description>
    <name>simple1</name>
    <tag-class>com.example.simpleTagTest1</tag-class>
    <body-content>empty</body-content>
</tag>

</taglib>

/customTag/customTag2.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib prefix="myTags" uri="simpleTags" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<myTags:simple1/>
</body>
</html>

설명은 http://www.4te.co.kr/566 에서 설명한 내용을 참고하면 된다.
몸체가 있는 태그일 경우에는 아래와 같이 하면 된다.

package com.example;

import java.io.IOException;

import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.SimpleTagSupport;

public class simpleTagTest1 extends SimpleTagSupport {
    public void doTag() throws JspException, IOException {
        //getJspContext().getOut().print("This is the lamest use of a custom tag");
        getJspBody().invoke(null);    //태그 몸체를 읽은 후 응답에 출력하라는 의미, 인자가 null이므로 Response로 출력하라는 의미
    }
}

<?xml version="1.0" encoding="UTF-8"?>

<taglib 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/web-jsptaglibrary_2_0.xsd" version="2.0">

<tlib-version>1.2</tlib-version>
<uri>simpleTags</uri>
<tag>
    <description>worst use of a custom tag</description>
    <name>simple1</name>
    <tag-class>com.example.simpleTagTest1</tag-class>
    <body-content>scriptless</body-content>
</tag>

</taglib>

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib prefix="myTags" uri="simpleTags" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<myTags:simple1>
    This is the body
</myTags:simple1>
</body>
</html>

태그 몸체에 표현식이 있을 경우에는 다음과 같이 할 수 있다.

<myTags:simple1>
    This is the body ${message}
</myTags:simple1>

public class simpleTagTest1 extends SimpleTagSupport {
    public void doTag() throws JspException, IOException {
        //getJspContext().getOut().print("This is the lamest use of a custom tag");
        getJspContext().setAttribute("message", "Wear sunscreen");
        getJspBody().invoke(null);
    }
}

동적으로 테이블 행을 출력하는 태그를 만들어 보면 아래와 같이 하면 된다.

public class simpleTagTest1 extends SimpleTagSupport {
    String[] movies = {"Monsoon Wedding", "Saved!", "Fahrenheit 9/11"};
    public void doTag() throws JspException, IOException {
        //getJspContext().getOut().print("This is the lamest use of a custom tag");
        //getJspContext().setAttribute("message", "Wear sunscreen");
       
        for(int i=0 ; i<movies.length ; i++) {
            getJspContext().setAttribute("movie", movies[i]);
            getJspBody().invoke(null);
        }
    }
}

<table>
<myTags:simple1>
    <tr><td>${movie}</td></tr>
</myTags:simple1>
</table>

태그 속성이 반드시 있어야 한다고 TLD에서 설정했다면, 태그핸들러 클래스에서는 Bean 스타일의 Setter가 있어야 한다.

<%@ taglib prefix="myTags" uri="simpleTags5" %>
<myTags:simple1 movieList="${movieCollection}">
    <tr>
        <td>${movie.name}</td>
        <td>${movie.gener}</td>
    </tr>
</myTags:simple1>

package com.example;

import java.io.IOException;
import java.util.Iterator;
import java.util.List;

import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.SimpleTagSupport;

public class simpleTagTest5 extends SimpleTagSupport {
    private List<String> movieList;

    public void setMovieList(List<String> movieList) {
        this.movieList = movieList;
    }
   
    public void doTag() throws JspException, IOException {
        Iterator<String> i = movieList.iterator();
       
        while(i.hasNext()) {
            Movie movie = (Movie) i.next();
            getJspContext().setAttribute("movie", movie);
            getJspBody().invoke(null);
        }
    }
}

<?xml version="1.0" encoding="UTF-8"?>

<taglib 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/web-jsptaglibrary_2_0.xsd" version="2.0">

<tlib-version>1.2</tlib-version>
<uri>simpleTags5</uri>
<tag>
    <description>worst use of a custom tag</description>
    <name>simple1</name>
    <tag-class>com.example.simpleTagTest5</tag-class>
    <body-content>scriptless</body-content>
    <attribute>
        <name>movieList</name>
        <required>true</required>
        <rtexprvalue>true</rtexprvalue>
    </attribute>
</tag>

</taglib>


어떤 태그를 호출 했을 경우, 오류가 떨어지더라도 지금까지 출력 된 내용은 화면에 나와야 한다면 SkipPageException을 사용할 수 있다.

getJspContext().getOut().print("Message from within doTag()<br>");
getJspContext().getOut().print("About to throw a SkipPageException");

if(thingsDontWork) {
    throw new SkipPageException();
}

<myTags:simple/>
Back in the page after invoking the tag.

위 클래스에서 thingsDontWork가 참이라서 SkipPageException이 던져지게 되면, 그 이전에 출력하려 했던 "Message from within doTag()<br>About to throw a SkipPageException은 나오지만, "Back in the page after invoking the tag."은 출력되지 않는다.

다음과 같이 하게 됬을 경우 나오게 되는 내용에 주의해야 한다.

pageA.jsp

aaaa<br>
<jsp:include page="pageB.jsp"></jsp:include>
after aaaa<br>

pageB.jsp

<%@ taglib prefix="myTags" uri="simpleTags" %>
bbbb<br>
<myTags:simple1></myTags:simple1>
after bbbb<br>

doTag() 메소드

    public void doTag() throws JspException, IOException {
        getJspContext().getOut().print("in doTag()<br>");
        throw new SkipPageException();
    }

pageB 안에 있는 myTags.simple1 태그는 doTag() 메소드를 호출 할 것이며 doTag 메소드에서는 SkipPageException을 throw 할 것이다.
이럴 경우에는 pageB.jsp에서만 처리가 중지 되며, pageA.jsp에서는 그대로 나머지 내용이 출력된다.
즉 다음과 같이 내용이 나오게 될 것이다.

aaaa
bbbb
in doTag()
after aaaa

즉, after bbbb 라는 내용은 나오지 않게 된다.


신고

'Java > Servlet & JSP' 카테고리의 다른 글

부모 자식 태그간의 통신  (0) 2009.03.26
클래식 커스텀 태그  (0) 2009.03.26
사용자 정의 태그 개발 (1)  (0) 2009.03.23
커스텀 태그 사용하기  (0) 2009.03.17
JSTL 사용하기 (2)  (0) 2009.03.16
JSTL 사용하기 (1)  (5) 2009.03.12

WRITTEN BY
체리필터
프로그램 그리고 인생...

받은 트랙백이 없고 , 댓글이 없습니다.
secret
사용자 정의 태그를 만들어서 사용할 수 있다.
사용 방법은 EL에서 함수를 만드는 방법과 유사하나 조금 더 복잡한 부면이 있다.
커스텀 태그를 만들기 위해서는 tld 파일과 java class 파일이 필요하다.
예제로 유저에게 랜덤하게 조언을 해 주는 커스텀 태그 소스를 보면 이해하는데 도움이 된다.(소스는 역시 Head & First Servelet & JSP에서 사용된 것이다.)

우선 tld 파일은 EL과 마찬가지로 WEB-INF 밑에 작성한다. 이름은 myCustomTag.tld로 한다.

<?xml version="1.0" encoding="UTF-8"?>

<taglib 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/web-jsptaglibrary_2_0.xsd" version="2.0">

<tlib-version>0.9</tlib-version>

<short-name>RandomTags</short-name>
<function>
    <name>rollIt</name>
    <function-class>com.example.DiceRoller</function-class>
    <function-signature>int rollDice()</function-signature>
</function>

<uri>randomThings</uri>
<tag>
    <description>random advice</description>
    <name>advice</name>
    <tag-class>com.example.AdvisorTagHandler</tag-class>
    <body-content>empty</body-content>
    <attribute>
        <name>user</name>
        <required>true</required>
        <rtexprvalue>true</rtexprvalue>
    </attribute>
</tag>
</taglib>

태그 이름은 <name> 태그의 내용을 사용하며 해당 태그가 호출될 경우 사용하는 java class 파일은 <tag-class> 태그에 있는 클래스를 사용한다.
<body-content>가 empty인 것은 몸체가 없이 사용한다는 뜻이며, 속성으로 사용되는 것으로 user라는 것이 있다는 의미이다.
rtexprvalue가 true인 것은 EL과 같은 표현식(스크립팅, 표준액션 포함) 값이 들어갈 수 있다는 뜻이다. 만일 rtexprvalue가 false라면 EL 표현식은 사용 불가이다.
위 내용을 jsp 페이지에서 커스텀 태그로 사용한다면 아래와 같이 사용할 수 있다.

<%@ taglib prefix="mine" uri="randomThings" %>

<c:set var="userName" value="오봉근"></c:set>
<mine:advice user="${userName}" />

위와 같이 쓰게 된다면 AdvisorTagHandler 클래스에서는 user라는 변수를 사용하여 어떤 액션을 하게 될 것이다.
AdvisorTagHandler 클래스의 소스는 아래와 같다.

com.example.DiceRoller.java 파일
package com.example;

import java.io.IOException;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.SimpleTagSupport;

public class AdvisorTagHandler extends SimpleTagSupport {
    private String user;
   
    public void doTag() throws JspException, IOException {
        getJspContext().getOut().write("Hello " + user + " <br>");
        getJspContext().getOut().write("Your advice is : " + getAdvice());
    }
   
    public void setUser(String user) {
        this.user = user;
    }
   
    String getAdvice() {
        String[] adviceStrings = {"That color's not working for you", "You should call in sick", "You might want to rethink that haircut."};
        int random = (int) (Math.random() * adviceStrings.length);
       
        return adviceStrings[random];
    }
}


위 클래스에서 주의 해야 할 점은 doTag 메소드이다.
JSP가 태그를 실행하게 되면 컨테이너는 자동으로 doTag 메소드를 실행하게 된다. EL에서 메소드 명을 지정할 수 있었던 것과 다르다.
또 주의해서 볼 것은 setUser 메소드이다. 이름에서 볼 수 있듯이 자바 빈 프로퍼티 명명 규칙을 따서 사용하게 된다. 즉 커스텀 태그에서 사용하는 attribute의 이름을 빈 프로퍼티로 사용하게 된다.

태그 몸체에 들어갈 수 있는 내용들은 아래와 같다.

<body-content>empty</body-content>
=> 몸체를 가질 수 없다.

<body-content>scriptless</body-content>
=> 스크립팅(스크립틀릿, 스크립팅 표현식, 선언문)은 올 수 없다. 하지만 템플릿 텍스트, EL, 커스텀 태그, 표준 액션은 가능하다.

<body-content>tagdependent</body-content>
=> 태그 몸체를 그냥 텍스트로 취급한다.

<body-content>JSP</body-content>
=> JSP 안에 들어갈 수 있는 것이라면 무엇이든지 가능하다.

<body-content>empty</body-content>라고 되어 있어도 jsp 표준액션을 사용하면 body에 내용을 기술 할 수 있다.

<mine:advice>
    <jsp:attribute name="user">${userName}</jsp:attribute>
</mine:advice>

<jsp:attribute> 태그는 속성을 기술하는 또 하나의 방식이므로, body content 개수로 치지 않으며, 따라서 시작 태그와 마침 태그에 들어갈 수 있다.

taglib에 들어가는 uri는 실제 uri(위치정보)가 아니다. 다른 태그 라이브러리와 구별하기 위한 유일한 값을 지정하기 위해 사용하는 이름일 뿐이다.
uri와 실제 TLD 파일은 컨테이너가 알아서 맵핑한다. 하지만 jsp 2.0 이전 버젼에서는 web.xml에 맵핑 정보를 적어 줘야 했었다.

  <jsp-config>
      <taglib>
          <taglib-uri>randomThings</taglib-uri>
          <taglib-location>/WEB-INF/</taglib-location>
      </taglib>
  </jsp-config>

jsp 2.0 버전에서는 사용하지 않아도 컨테이너가 알아서 uri 이름에 대한 맵을 만든다는 의미이지, 위 내용을 web.xml에 기술 안해야지만 된다는 의미는 아니다. web.xml에 기술을 하게 된다면 해당 내용을 사용하게 되며, 없을 경우 자동으로 searching을 하게 된다.
컨테이너가 자동으로 TLD 파일을 찾는 위치는 다음과 같다.

1. WEB-INF 안
2. WEB-INF 아래 하위 디렉토리
3. WEB-INF/lib 밑에 jar 파일로 배포 했다면 jar 안 META-INF 디렉토리
4. WEB-INF/lib 밑에 jar 파일로 배포 했다면 jar 안 META-INF 아래 하위 디렉토리

jsp에서 여러개의 태그라이브러리를 사용한다면, 각각의 TLD에 대한 uri를 작성해야 한다. uri는 유일해야 하며, 같은 값을 중복해서 사용할 수 없다.
또한 예약어를 첨자로 사용할 수 없다.

jsp:, jspx:, java:, javax:, servlet:, sun:, sunw:




신고

'Java > Servlet & JSP' 카테고리의 다른 글

클래식 커스텀 태그  (0) 2009.03.26
사용자 정의 태그 개발 (1)  (0) 2009.03.23
커스텀 태그 사용하기  (0) 2009.03.17
JSTL 사용하기 (2)  (0) 2009.03.16
JSTL 사용하기 (1)  (5) 2009.03.12
템플릿 형태로 JSP 사용하기  (0) 2009.02.16

WRITTEN BY
체리필터
프로그램 그리고 인생...

받은 트랙백이 없고 , 댓글이 없습니다.
secret
프로퍼티의 프로퍼티를 스크립틀릿이나 표준액션으로만 표현하기가 어렵거나 아예 불가능한 경우가 있다.
즉 다음과 같은 서블릿 코드를 스크립틀릿이나 표준액션으로 표현하려고 하면 다음과 같이 표현할 수 밖에 없을 것이다.

    public void doPost(HttpServletRequest request, HttpServletResponse response)
                throws IOException, ServletException {
        foo.Person p = new foo.Person();
        p.setName("Evan");
       
        foo.Dog dog = new foo.Dog();
        dog.setName("spike");
        p.setDog(dog);
       
        request.setAttribute("person", p);
       
        RequestDispatcher view = request.getRequestDispatcher("result.jsp");
        view.forward(request, response);
    }

<%= ((foo.Person) request.getAttribute("person")).getDog().getName() %>

<jsp:useBean id="person" class="foo.Person" scope="request" />
<jsp:getProperty name="person" property="dog"/>

스크립틀릿으로 쓰면 결과물은 제대로 나오지만 많이 지져분한 모습이다.
표준액션을 사용하게 되면 dog라는 프로퍼티가 있는 것이 아니라 dog라는 객체안에 있는 name이라는 프로퍼티를 출력해야 하므로 결과가 잘못 나오게 된다.

이런 경우를 위해서 사용하는 것이 EL(Expression Language) 이다.
위 내용을 EL로 표현하게 되면 ${person.dog.name} 이라고 간단하게 표현할 수 있는 것이다.
EL에서 도트연산자(.) 앞에 있는 것(person)은 반드시 맵이거나 빈이여야 한다. 도트 연산자 우측에 있는 것은 맵의 키이거나 빈 프로퍼티여야 한다.
${person.dog.name}을 php로 표현하자면 $person[$dog['name']] 정도로 표현할 수 있을지도 모르겠다. ^^
오른쪽에 오는 값은 일반적인 자바 명명규칙을 따라야 한다.

도트 연산자 대신에 [] 연산자를 사용할 수도 있다.
즉 ${person.name}은 ${pserson["name"]}처럼 쓸 수 있다.

도트 연산자의 왼쪽에는 맵, 빈만 올 수 있었지만, [] 연산자의 경우에는 왼쪽에 맵, 빈 외에도 배열, 리스트가 올 수 있다.
또한 [] 안에 따옴표로 감싸져 있으므로 [] 안의 내용은 맵 키, 빈 프로퍼티, 리스트나 배열의 인덱스가 될 수 있다.
다음은 []의 예제이다.

서블릿 코드

String[] favoriteMusic = {"Zero 7", "Tahiti 80", "BT", "Frou Frou"};
request.setAttribute("musicList", favoriteMusic);

JSP 코드

${musicList}
${musicList[0]}
${musicList["1"]}

${musicList}은 배열을 toString()으로 변환해서 보여주기 때문에 제대로 된 값이 출력되진 않는다. ${musicList[0]}는 "Zero 7"이 ${musicList["1"]}는 "Tahiti 80"이 나오게 된다.

php에서 $array[key] 라고 하면 key라는 상수가 있나 없나를 확인 후 없을 경우 해당 key에 맵핑 된 value를 찾아 보여준다.(따라서 한번의 확인 과정을 더 거치므로 속도가 떨어진다.)
이와 마찬가지로 EL에서도 다음과 같이 작성해도 무방하다.

서블릿 코드

java.util.Map musicMap = new java.util.HashMap();
musicMap.put("Ambient", "Zero 7");
musicMap.put("Surf", "Tahiti 80");
musicMap.put("DJ", "BT");
musicMap.put("Indie", "Frou Frou");

request.setAttribute("musicMap", musicMap);
request.setAttribute("Genre", "Ambient");

JSP 코드

${musicMap[Genre]}
${musicMap["Genre"]}

위 코드에서 따옴표가 없는 Genre는 request.setAttribute를 통해서 Ambient라는 String이 할당되어 있다. 따라서 ${musicMap[Genre]}는 ${musicMap["Ambient"]}와 같은 내용이며 결과 값은 "Zero 7"이 나오게 되는 것이다.
하지만 따옴표가 있는 "Genre"는 말 그대로 String Genre이므로 변환이 되지 않으며 musicMap에서 해당 키가 있나 찾게 되는 것이다.
musicMap에는 Genre라는 키가 없으므로 결과 값이 null이 나오게 된다.

위와 같은 형식으로 아래와 같은 표현도 가능하다.

서블릿 코드

java.util.Map musicMap = new java.util.HashMap();
musicMap.put("Ambient", "Zero 7");
musicMap.put("Surf", "Tahiti 80");
musicMap.put("DJ", "BT");
musicMap.put("Indie", "Frou Frou");

String[] musicType = {"Ambient", "Surf", "DJ", "Indie"};
request.setAttribute("MusicType", musicType);

JSP 코드

${musicMap[MusicType[0]]}    //${musicMap["Ambient"]}와 같은 뜻.

MusicType[0]의 값이 "Ambient"이기 때문에 ${musicMap["Ambient"]}와 같은 뜻이다.
주의 할 점은 도트연산자의 우측에 오는 내용은 자바 명명규칙을 따르기 때문에 ${musicList["1"]}은 가능해도 ${musicList.1}과 같이 사용할 수는 없다.

* EL 내장객체

EL에서 사용하는 내장객체가 있다. EL에서 사용하는 내장 객체는 pageContext만 제외하고는 모드 맵이다. EL에서 사용하는 내장 객체는 다음과 같다.

pageScope, requestScope, sessionScope, applicationScope, param, paramValues, header, headerValues, cookie, initParam, pageContext

요청 파라미터와 같은 경우에는 다음과 같이 사용할 수 있다.

<form action="TestBean.jsp">
    <input type="text" name="name">
    <input type="text" name="empID">
   
    <input type="checkbox" name="food">
    <input type="checkbox" name="food">
</form>

${param.name}
${param.empID}
${param.food}
${paramValues.food[0]}
${paramValues.food[1]}
${paramValues.name[0]}

이름이 같은 경우에 paramValues를 사용할 수 있으며 이름이 한개인 경우에 paramValues를 사용하게 되면 0번째 인덱스가 그 값이 된다.

request parameter를 param 또는 paramValues를 이용해서 사용할 수 있는데 그보다 더 많은 내용은 어떻게 알 수 있을까?
기타 정보는 다음과 같은 방법으로 알 수 있다.

host 정보

${header["host"]}
${header.host}

http 요청 메소드

${pageContext.request.method}

스크립팅에서는 <%= request.getMethod() %>와 같이 사용하였지만, EL에서 ${request.method} 또는 ${requestScope.method}라고 하면 오류가 난다.
request란 내장객체가 EL에는 존재하지 않고, 또한 requestScope는 단순 request 생존 범위에 묶여 있는 속성에 대한 단순 맵이기 때문이다.

* 생존 범위

생존범위를 사용하는 이유는 이름 충돌을 피하기 위해서이다. 또한 한가지 이유로 생존범위를 쓰는데 다음과 같은 경우를 위해서이다.

서블릿

request.setAttribute("foo.person", p);

JSP

${foo.person.name}    //틀린 표현
${requestScope["foo.person"].name}    //맞는 표현

${foo.person.name}와 같이 표현하게 되면 foo란 속성 밑에 person이란 프로퍼티가 있다는 식으로 컨테이너가 생각할 우려가 있다.("foo.person"이란 String임에도 불구하고)
따라서 ${requestScope["foo.person"].name}와 같은 식으로 표현하게 되면 문자열에 도트가 들어가 있어도 문제 없이 사용할 수 있다.

* 쿠키

쿠키를 스크립팅을 사용해서 보여주기 위해서는 매우 복잡(?)한 코드가 필요하다.

스크립팅

<%
Cookie[] cookies = request.getCookies();

for(int i=0 ; i<cookies.length ; i++) {
    if((cookies[i].getName().equals("userName"))) {
        out.println(cookies[i].getValue());
    }
}
%>

EL

${cookie.userName.value}

* 컨텍스트 초기화 파라미터

web.xml

  <context-param>
      <param-name>breed</param-name>
      <param-value>Great Dane</param-value>
  </context-param>

스크립팅

<%= application.getInitParameter("breed") %>

EL

${initParam.breed}

context-param이지만 EL에서는 contextParam이라고 하지 않고 initParam이라고 한다.



신고

'Java > Servlet & JSP' 카테고리의 다른 글

템플릿 형태로 JSP 사용하기  (0) 2009.02.16
EL 함수 사용하기  (0) 2009.02.13
EL 사용하기  (3) 2009.02.12
표준 액션을 사용한 JSP  (0) 2009.02.11
JSP 초기화 하기  (0) 2009.02.10
스크립틀릿에서 변수 선언하기  (0) 2009.02.04

WRITTEN BY
체리필터
프로그램 그리고 인생...

받은 트랙백이 없고 , 댓글  3개가 달렸습니다.
  1. 정말 잘 정리하셨네요. ^^
    잘 보고 갑니다~!
  2. 비밀댓글입니다
secret
"자바 빈을 이용해서 특정 객체의 값을 가져와 보여주는 소스는 아래와 같은 형식으로 jsp에서 사용할 수 있다.

<% foo.Person p = (foo.Person) request.getAttribute("person"); %>
Person is : <%= p.getName() %>

jsp내에서 스크립틀릿을 없애기 위해 나온 것이 표준 액션이므로 스크립틀릿을 없애는 방법으로 표현하자면 아래와 같이 할 수 있다.

<jsp:useBean id="person" class="foo.Person" scope="request"></jsp:useBean>
Person created by servlet : <jsp:getProperty name="person" property="name"/>

위에서 id로 지정한 것을 아래 getProperty에서 name으로 가져다 쓸 수 있다.
property의 name은 자바빈의 getter, setter에서 사용하는 값이다. 즉 name은 getName()과 같은 기능을 하게 되는 것이다.
class는 패키지 명까지 다 써야한다.

getProperty가 있다면 당연히 setProperty도 있다.
setProperty는 다음과 같이 사용할 수 있다.

<jsp:setProperty name="person" property="name" value="Fred"/>

setProperty를 useBean 안에 사용하게 되면, 새로운 빈이 만들어지는 경우에만 설정하고, 이미 있는 경우에는 설정하지 않게 된다.
즉 다음과 같이 코딩하게 되면 빈이 없을 경우에만 값을 설정하게 된다.

<jsp:useBean id="person" class="foo.Person" scope="request">
    <jsp:setProperty name="person" property="name" value="Fred"/>
</jsp:useBean>

위와 같이 코딩하게 되면 컨테이너가 자동으로 생성해 주는 _jspService() 메소드는 다음과 같은 형식을 가지게 되는 것이다.

foo.Person person = null;
person = (foo.Person) _jspx_page_context.getAttribute("person", PageContext.PAGE_SCOPE);

if(person == null) {
    person = new foo.Person();
    _jspx_page_context.setAttribute("person", person, PageContext.PAGE_SCOPE);
   
    org.apache.jasper.runtime.JspRuntimeLibrary.JspRuntimeLibrary.introspecthelper(
            _jspx_page_context.findAttribute("person"), "name", "Fred", null, null, false);
}

없다면 해당 객체를 만들어서 할당하고, 값을 추가 한다.
아래 "org.apache.jasper.runtime.JspRuntimeLibrary..." 부분은 컨테이너가 자동으로 생성하는 코드이므로 어떤 식으로 처리되는지 자세히 알 필요는 없다.

* 다형성 사용하기

빈 참조에 대해서도 다형성 기법을 사용할 수 있다.
가령 foo.Person이 추상 객체이고 Employee객체가 이를 상속 받았다면 아래와 같은 형식으로 쓸 수 있다.

<jsp:useBean id="person" type="foo.Person" class="foo.Employee" scope="page"></jsp:useBean>

type에는 클래스, 추상클래스, 인스턴스 등이 들어갈 수 있으며, class에는 type에 명기한 클래스를 상속한 것이거나 구현한 클래스가 들어가야 한다.

* HTML에서 JSP로 form 전송을 바로 하기

html에서 jsp로 바로 form을 전송하게 될 경우가 있다.

<form action="TestBean.jsp">
    name : <input type="text" name="userName">
    ID# : <input type="text" name="userID">
</form>

위와 같이 하게 되면 jsp에서는 어떻게 처리해야 할까?
request.getParameter를 사용하여 setProperty의 value 속성에 넣을 수도 있겠지만 param 속성을 이용하면 더 쉽게 빈에 값을 설정할 수 있다.

<jsp:useBean id="person" type="foo.Person" class="foo.Employee">
    <jsp:setProperty name="person" property="name" param="userName"/>
</jsp:useBean>

html에서 userName이라고 설정을 하였다면 param에 userName이라고 넣어주게 되면 name이란 빈 프로퍼티에 값이 설정되게 된다.
param이란 속성을 이용하는 것보다 더 간단한 방법이 있다.
html에서 form element의 이름이 빈 프로퍼티의 이름과 같게 되면 자동으로 들어가게 된다.
즉 다음과 같으면 param이란 속성을 안 적어 줘도 된다.

<form action="TestBean.jsp">
    name : <input type="text" name="name">
    ID# : <input type="text" name="userID">
</form>

<jsp:useBean id="person" type="foo.Person" class="foo.Employee">
    <jsp:setProperty name="person" property="name"/>
</jsp:useBean>

만일 빈의 모든 프로퍼티와 html form 객체의 모든 이름이 같다면 더욱더 간단하게 아래와 같이 할 수 있다.

<jsp:useBean id="person" type="foo.Person" class="foo.Employee">
    <jsp:setProperty name="person" property="*" />
</jsp:useBean>






신고

'Java > Servlet & JSP' 카테고리의 다른 글

EL 함수 사용하기  (0) 2009.02.13
EL 사용하기  (3) 2009.02.12
표준 액션을 사용한 JSP  (0) 2009.02.11
JSP 초기화 하기  (0) 2009.02.10
스크립틀릿에서 변수 선언하기  (0) 2009.02.04
간단한 Jsp 시작하기  (0) 2009.02.04

WRITTEN BY
체리필터
프로그램 그리고 인생...

받은 트랙백이 없고 , 댓글이 없습니다.
secret
ServletConfig를 web.xml에 정의해 두고 나서 서블릿에서 가져다 쓰는 방법에 대해 http://www.4te.co.kr/540 에서 다루었었다.
JSP에서도 마찬가지로 초기화를 통해서 web.xml에 있는 ServletConfig를 변수처럼 사용할 수 있다.
방법은 서블릿 생명 주기에서 가장 처음에 한번만 호출하는 메소드인 jspInit() 메소드를 오버라이드 해서 사용하면 되는 것이다.
사용 방법은 아래와 같다.

  <servlet>
      <servlet-name>MyTestInit</servlet-name>
      <jsp-file>/TestInit.jsp</jsp-file>
      <init-param>
          <param-name>email</param-name>
          <param-value>ikickedbutt@wickedlysmart.com</param-value>
      </init-param>
  </servlet>
 
  <servlet-mapping>
      <servlet-name>MyTestInit</servlet-name>
      <url-pattern>/TestInit.jsp</url-pattern>
  </servlet-mapping>

위와 같이 설정을 하면 된다.
다만 servlet-class가 아니라 jsp-file 이라는 태그를 사용하게 되며, 패키지 형식이 아니라 디렉토리 형식으로 표시한다.
TestInit.jsp 파일은 아래와 같이 작성한다.

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%!
public void jspInit() {
    ServletConfig sConfig = getServletConfig();
    String emailAddr = sConfig.getInitParameter("email");
    System.out.println("emailAddr : " + emailAddr);
    ServletContext ctx = getServletContext();
    ctx.setAttribute("mail", emailAddr);
}
%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<%= pageContext.getAttribute("mail", PageContext.APPLICATION_SCOPE) %>
</body>
</html>

ServletConfig에서 email 값을 읽어온 후 ServletContext에 setting 하고 있다.
그 후 pageContext를 이용하여 ServletContext를 읽어와 화면에 뿌려주고 있다.

참고로 page생존범위를 셋팅하고 읽어오는 방법은 아래와 같다.

<% Float one = new Float(42.5); %>
<% pageContext.setAttribute("foo", one); %>
<%= pageContext.getAttributesScope("foo") %>

<% Float two = new Float(22.4); %>
<% pageContext.setAttribute("foo", two, PageContext.SESSION_SCOPE); %>
<%= pageContext.getAttribute("foo", PageContext.SESSION_SCOPE) %>

setAttribute와 getAttribute 메소드는 인자를 String 하나만 받는 경우와, String과 int 두개를 받는 것이 있다.
인자가 하나인 경우에는 pagecontext 객체의 속성에 저장된 것을 읽지만, 두개인 것은 지정한 범위에 있는 속성을 읽게 된다.

TestInit.jsp에서 사용한 "<%= pageContext.getAttribute("mail", PageContext.APPLICATION_SCOPE) %>"는 다음과 같이 사용할 수도 있다.

<%= application.getAttribute("mail") %>

scope의 범위를 PageContext.APPLICATION_SCOPE로 주는 대신에 application으로 접근해서 동일한 효과를 얻게 되는 것이다.
생존 범위가 어디인지 모르는 경우에 속성을 찾기 위해서는 다음과 같이 사용할 수 있다.

<%= pageContext.findAttribute("foo") %>

위와 같이 하게 되면 제일 처음으로 page 생존 범위에서 찾는다. page 생존 범위에 없다면 가장 작은 범위에서부터 시작해서 가장 넓은 범위로 속성을 찾게 된다.
즉 request => session => application 범위로 찾게 된다.
아래와 같이 하게 되면 결과 값은 42.5가 나오게 된다.

<% Float one = new Float(42.5); %>
<% pageContext.setAttribute("foo", one); %>
<%= pageContext.getAttributesScope("foo") %>

<% Float two = new Float(22.4); %>
<% pageContext.setAttribute("foo", two, PageContext.SESSION_SCOPE); %>
<%= pageContext.getAttribute("foo", PageContext.SESSION_SCOPE) %>

<%= pageContext.findAttribute("foo") %> => 42.5가 나옴


신고

'Java > Servlet & JSP' 카테고리의 다른 글

EL 사용하기  (3) 2009.02.12
표준 액션을 사용한 JSP  (0) 2009.02.11
JSP 초기화 하기  (0) 2009.02.10
스크립틀릿에서 변수 선언하기  (0) 2009.02.04
간단한 Jsp 시작하기  (0) 2009.02.04
리스너 예제  (2) 2009.02.03

WRITTEN BY
체리필터
프로그램 그리고 인생...

받은 트랙백이 없고 , 댓글이 없습니다.
secret
다음과 같이 jsp를 작성해서 방문자의 숫자를 세어 보는 코드를 만들 생각을 할 수 있다.

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<% int count = 0; %>
The page count is  now:
<%= ++count %>
</body>
</html>

이렇게 하게 되면 화면에 "The page count is  now:1" 이라는 메시지가 찍힐 것이다.
하짐나 브라우져를 리프레쉬 하게 되면 count가 2가 되는 것이 아니라 여전히 1이 된다.
왜냐면 위에서 선언한 count란 변수는 지역 변수로 작용하기 때문이다.

즉 jsp는 서블릿으로 변하면서 그 모든 코드가 _jspService 메소드 안에 작성 되는데 count란 변수 역시 _jspService 메소드 안에서 정의 된다는 뜻이다.
jsp 코드가 서블릿으로 변환 되게 된다면 아래와 같은 코드를 가지게 될 것이다.

    public void _jspService(HttpServletRequest request, HttpServletResponse response)
                    throws IOException, ServletException {
        PrintWriter out = response.getWriter();
        response.setContentType("text/html");
        int count = 0;
        out.println(++count);
    }

변환된 서블릿이 실행 될 때마다 _jspService 메소드는 실행 될 것이며 그때마다 count 변수는 0으로 셋팅 될 것이다.
따라서 누적된 방문자 수를 가지기 위해서는 매번 실행 되지 않는 곳에 count 변수를 위치하게 하면 될 것이다.
즉 _jspService 메소드 위로 count 변수를 빼면 된다.
이럴 경우에는 jsp 선언문을 사용해서 count가 지역 변수가 아닌 인스턴스 변수가 되도록 만들면 된다.

<%! int count = 1; %>

위에서 볼 수 있듯이 앞에 "!"(느낌표) 하나를 붙여주면 된다.
이렇게 되면 서블릿에서는 다음과 같은 방법으로 코딩한 것과 같은 효과를 주게 된다.

    int count = 0;
    public void _jspService(HttpServletRequest request, HttpServletResponse response)
                    throws IOException, ServletException {
        PrintWriter out = response.getWriter();
        response.setContentType("text/html");
        out.println(++count);
    }

"!"는 변수 뿐 아니라 메소드에도 사용할 수 있다.



신고

'Java > Servlet & JSP' 카테고리의 다른 글

표준 액션을 사용한 JSP  (0) 2009.02.11
JSP 초기화 하기  (0) 2009.02.10
스크립틀릿에서 변수 선언하기  (0) 2009.02.04
간단한 Jsp 시작하기  (0) 2009.02.04
리스너 예제  (2) 2009.02.03
HttpSessionBindingListener와 HttpSessionAttributeListener  (0) 2009.02.02

WRITTEN BY
체리필터
프로그램 그리고 인생...

받은 트랙백이 없고 , 댓글이 없습니다.
secret
Jsp를 작성하게 되면 jsp는 컨테이너에 의해서 서블릿으로 변형되게 된다.
간단하게 얼마나 많은 요청을 받았는지를 출력하는 jsp를 작성해 보면 다음과 같다.

Counter.java

package com.example;

public class Counter {
    private static int count;
    public static synchronized int getCount() {
        count++;
        return count;
    }
}

BasicCounter.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ page import="com.example.*" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<%
    out.println(Counter.getCount());
%>
</body>
</html>

Counter 클래스에서 static int 변수를 두어서 요청한 횟수를 저장할 변수를 만든다.
BasicCounter.jsp에서는 page 지시자를 사용하여 com.example.*을 import 한 후 Counter 객체를 사용해서 카운트를 표시한다.(page 지시자 끝에는 세미콜론이 없다.)

위 코드와 같이 표시하는 경우를 스크립틀릿 코드라 하며 표현식 코드로 변환해서 사용해도 무방하다.
표현식 코드는 다음과 같이 사용한다.

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ page import="com.example.*" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<%= Counter.getCount() %>
</body>
</html>

표현식 코드 역시 지시자와 마찬가지로 세미콜론을 사용하지 않는다.

신고

'Java > Servlet & JSP' 카테고리의 다른 글

JSP 초기화 하기  (0) 2009.02.10
스크립틀릿에서 변수 선언하기  (0) 2009.02.04
간단한 Jsp 시작하기  (0) 2009.02.04
리스너 예제  (2) 2009.02.03
HttpSessionBindingListener와 HttpSessionAttributeListener  (0) 2009.02.02
Cookie 사용하기  (0) 2009.02.02

WRITTEN BY
체리필터
프로그램 그리고 인생...

받은 트랙백이 없고 , 댓글이 없습니다.
secret