▶ JSP 태그
① ASP 스타일의 태그 : 주석(comment), JSP 지시어(Directives), 스크립트 요소(Scripting Elements)
② XML 기반의 태그 : 액션 구문(Action)
(1) 주석
㈀ 코드에 대한 설명
㈁ 버그나 에러에 대한 디버깅 작업의 효율성
㈂ 다른 개발자가 그 코드를 읽어야 할 때 가이드의 역할(프로젝트 개발 후 유지보수와 관계)
(예) test.jsp
- 소스 보기는 : [보기] -> [소스(C)] , Explorer 창 내용부분에서 오른쪽 버튼을 누르고 -> 소스보기(V)
- 결론은 JSP 파일은 원본 파일이 아닌이상 JSP 주석 및 JAVA 주석문을 확인할 수 없다.
(2) JSP 지시어(Directives)
Directive(s) 단수가 아니라 복수죠, 한 개 이상이라는 의미 입니다.
클라이언트로 전송되는 응답에 직접적인 영향을 미치기보다는 JSP페이지 내에서 JSP 컨테이너에게 해당 페이지를 어떻게
처리할 것인가에 대한 정보
① page 지시어 - <%@ page 속성1="값1", 속성2="값2" , 속성3="값3" ......한 줄로 사용.....%>
- <%@ page 속성1="값1">
<%@ page 속성2="값2">
........................ 나누어 사용도 가능 ....................
.
- import 속성을 뺀 나머지는 중복해서 사용할 수 없다.
(예) - 불가능 session 속성을 중복해서 사용한 경우
<%@ page lanuage="java" session="false" %>
<%@ page isThreadSafe="false" session="false" %>
(예) - 가능 import 속성은 중복사용이 가능하다.
<%@ page isErrorPage="true" import="java.io.IOException" %>
<%@ page import = "java.net.*" %>
- 속성가지 수는 총 11가지가 있습니다.
㉠ language
- JSP 파일 내에서 사용할 스크립트 언어를 선언하는 속성이다. (무조건 java라고 생각해도 무방하다.)
- 지정하지 않을 경우 Default 스크립트로 사용하는 언어는 자바로 설정된다.
- include 지시어에 의해 읽혀지는 다른 JSP파일의 스크립트 언어 역시 반드시 언어 일치가 해야 한다. (당연하겠죠)
<%@ page language="java" %>
㉡ extends 속성
- JSP 컨테이너가 JSP 파일을 서블릿으로 변환할 때 상속하게 되는 부모 클래스를 지정하는 속성
- extends 속성을 사용하지 않은 상태에서 JSP 파일이 변환된 서블릿 파일의 소스(/tomcat 설치 폴더/work/CATALINA
디렉토리에 웹어플리케이션 가상도메인명이 있다. tomcat 가상도메인을 바꾸지 않으면 localhost 가 디렉토리가 된다.
,tomcat 컨테이너 기준) HttpJspBase라는 클래스를 상속한 것을 발견 할 수 있다. 이 클래스는 JSP 스펙에서 제공된
클래스가 아니라, JSP 컨테이너(예, tomcat 컨테이너) 개발자가 해당 컨테이너에 최적화되도록 개발한 클래스이다.
- JSP 페이지가 정상적으로 변환하여 실행하려면 javax.servlet.jsp.HttpJspPage 혹은 javax.servlet.jsp.JspBase
인터페이스를 구현한 클래스를 상속 받아야만 하기 때문에 , 우리는 JSP 파일 내에서 아무 클래스나 상속받아서는
절대로 안된다. 반드시 HttpJspPage나 JspBase 를 구현한 클래스여야만 한다.
/tomcat 설치 폴더/bin 폴더 밑에 jsp-api.jar 압축을 풀면 javax 폴더가 나온다.
javax/servlet/jsp 폴더 밑에 HttpJspPage.class 가 있다.
[<%@ page extends="javax.servlet.jsp.HttpJspPage" %> 이런식으로 상속을 받아서 작업을 하면 될 거 같은데
되지 않습니다. 컴파일 되지 않고 에러 납니다. (당연히 서블릿이 되지 않는다는 의미겠죠)
이것은 컨테이너 개발자가 서블릿하는데 필요한 super 클래스를 자동으로 상속받도록 해두어서 그런 거 같네요
즉, 컨테이너가 서블릿에 필요한 인터페이스 클래스를 상속받도록 자동으로 지정해두어서 그런 거 같습니다. ]
- 결국은 JSP 페이지는 JSP 컨테이너의 의해 일단 servlet으로 변환된다는 것은 당연한 얘기고 servlet 변환한다는 것
은 자바파일을 생성한다는 것인데 이때 java를 생성할 때 컴파일이라는 것을 하는데 이때 자바의 상속의 개념을 이용
하여 servlet 필요한 파일을 상속 받는다고 보면 됩니다. 아무것이나 상속받는 것이 아니라 위에서 얘기한
HttpJspPage 나 JspBase를 구현한 클래스여야만 한다는 것이다. 대부분은 컨테이너가 알아서 적정한 클래스들을 상
속시켜 변환해줌으로 거의 사용할 일은 없다.
- JSP 상속관계
㉢ import 속성
- JSP 페이지 내에서 사용할 클래스를 미리 지정해 놓는 것으로써 여기에 선언된 import는 JSP파일이 변환된
서블릿 소스에 문자 그대로 반영하게 된다. import는 특정 패키지내의 모든 클래스 파일을 지정할 수도 있고,
특정 클래스 파일 하나만을 지정할 수도 있다.
- jsp 파일소스 : importTest.jsp (http://cafe.naver.com/tonkjsp/15)
- 실행결과 (웹어플리케이션/jsp/BuiltIn_Object/importTest.jsp) 이런식으로 실행시켰습니다.
(실무 프로젝트개발에서는 폴더관리가 중요합니다.)
※ 아래 그램과 같이 한글이 나오지 않는 분은 - 톰캣 기준
/톰캣 설치 폴더/conf 폴더 밑에 server.xml 에서 밑줄 부분을 추가합니다.
<Connector port="9999" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443"
URIEncoding="euc-kr">
㉣ session 속성
- HTTP 프로토콜은 기본적으로 클라이언트의 매 요청마다 새로운 커넥션(연결)을 생성하여 응답한 후 , 커넥션(연결)
을 끊는다. 이러한 HTTP 프로토콜의 특성때문에 HTTP 프로토콜을 'Stateless Protocol' 이라고 부르기도 한다.
(상태 유지를 하지 않는 프로토콜이라는 의미)
- 상태를 유지하여 관리하기 위한 방법으로 session Management 가 등장함.
- 클라이언트의 정보를 지속적으로 유지하고(상태 유지)하고 있는 상태를 Virtual Connetion 또는 HTTP 세션 이라고
부른다. (연결은 끊어졌지만 가상으로 연결된 상태를 유지한다고 보면 됩니다.)
(클라이언트의 정보를 유지하는 방법은 여러가지가 있는데 이것은 따로 정리)
- page directives session 속성은 요청된 페이지에 대한 서블릿이 방금 설명한 세션을 유지할 것인가를 jsp
컨테이너에게 알려주는 역할
- 표현은
<%@ page session="false" %> ← "false" session 종료 개념이 아니라 단순히 내장객체에서 session
사용하지 않는다는 의미
<%@ page session="true" %> ← "true" 은 기본값으로 생략도 가능하다. (session 생략하면 무조건 true )
- jsp 파일소스 : importTest.jsp (http://cafe.naver.com/tonkjsp/16)
- 실행결과
㉤ buffer 속성
- JSP 페이지에 대한 클라이언트 요청 시 이를 처리하는 것은 실제로 해당 페이지에 대한 서블릿이 처리(서블릿 컨테이
너가 처리를 하는 거죠)
- 구체적으로 보면 서블릿의 JspWriter 객체인 out 이다. 이 out 객체에다 writer() 혹은 print()하는 내용이 응답으로 전송
된는 것으로 볼 수 있습니다.
(톰캣 기준으로 보면 /톰캣 설치 폴더/lib/ jsp-api.jar 를 압축을 풀면 /javax/servlet/jsp 폴더 밑에 JspWriter.class)
- buffer 속성은 out 객체에다 출력할 내용(응답으로 전송할 내용)을 임시로 저장할 버퍼의 사용 여부(사용하고자 하는 경
우 버퍼의 크기)를 지정하는 속성이다.
- buffer를 사용하는 경우 표현
<%@ page buffer = "none" %>
<%@ page buffer ="10kb" %> ← buffer 속성을 생략하는 경우 기본값으로 8kb가 잡힌다.
- session 속성에서 만들었던 예제 파일인 sessionTest.jsp 파일에 대한 서블릿 파일로 작성된 파일을 여러
소스를 해석하면 buffer 속성에 대한 이해가 될 것이다.
- /톰캣 설치 폴더/work/Catalina/www.tonkjsp.com/tonkjsp/org/apache/jsp/jsp/directives/sessionTest_jsp.java
메모장으로 열어 봅니다.
① servlet 하는데 필요한 클래스하고 패키지 이런 것이 나옵니다.
package org.apache.jsp.jsp.directives;
import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.jsp.*;
② org.apache.jasper.runtime.HttpJspBase 상속받고
implements 놈이 나오는데 이것은 인터페이스만 가능하다는 의미 입니다.
인터페이스는 다중상속을 위해 만든겁니다. (자바는 다중상속 못함)
그러므로 인터페이스만 implements 할 수 있습니다.
public final class sessionTest_jsp extends org.apache.jasper.runtime.HttpJspBase
implements org.apache.jasper.runtime.JspSourceDependent {
---- 내용 ---
}
③ 호출한 메소드를 재정의 하고 초기화 시키는 과정
private static final JspFactory _jspxFactory = JspFactory.getDefaultFactory();
private static java.util.List _jspx_dependants;
private javax.el.ExpressionFactory _el_expressionfactory;
private org.apache.AnnotationProcessor _jsp_annotationprocessor;
public Object getDependants() {
return _jspx_dependants;
}
public void _jspInit() {
_el_expressionfactory =
_jspxFactory.getJspApplicationContext(getServletConfig().getServletContext()).getExpressionFactory();
_jsp_annotationprocessor = (org.apache.AnnotationProcessor)
getServletConfig().getServletContext().getAttribute(org.apache.AnnotationProcessor.class.getName());
}
public void _jspDestroy() {
}
④ jspInit() 메소드를 호출하여 _jspService()에서 처리하여 클라이언트에게 처리결과를 응답한다.
public void _jspService(HttpServletRequest request, HttpServletResponse response)
throws java.io.IOException, ServletException {
PageContext pageContext = null;
HttpSession session = null;
ServletContext application = null;
ServletConfig config = null;
JspWriter out = null;
Object page = this;
JspWriter _jspx_out = null;
PageContext _jspx_page_context = null;
// 아래 내용이 버퍼에 남겨져 출력된다고 보시면 됩니다.
// 클라이언트 요청을 처리할 JSP 페이지의 서블릿에서는 응답 내용을 보내기 전에 응답에 필요한 헤더 정보를 먼저
설정
try {
response.setContentType("text/html;charset=euc-kr"); ← PageContext 객체에서 얻어온 것
pageContext = _jspxFactory.getPageContext(this, request, response, null, true, 8192, true); ← buffer size
_jspx_page_context = pageContext;
application = pageContext.getServletContext();
config = pageContext.getServletConfig();
session = pageContext.getSession();
out = pageContext.getOut();
_jspx_out = out;
out.write("\r\n");
out.write(" \r\n");
out.write("<html>\r\n");
out.write("\t<head>\r\n");
out.write("\t\t<title> Session Attribute Test</title>\r\n");
out.write("\t</head>\r\n");
out.write("\t\t\r\n");
out.write("\t<body>\r\n");
out.write(" \r\n");
out.write("\t");
// getAttribue()는 object형을 반환
// wrapper클래스의 사용이 필요.
Integer number = (Integer)session.getAttribute("counter");
if(number==null){
number = new Integer(1);
}else{
number = new Integer(number.intValue()+1);
}
// 세션의 저장.
session.setAttribute("counter", number);
out.write("\r\n");
out.write(" \r\n");
out.write("\tCount Today : ");
out.print( number );
out.write("\r\n");
out.write(" \r\n");
out.write("\t</body>\r\n");
out.write("</html>");
} catch (Throwable t) {
if (!(t instanceof SkipPageException)){
out = _jspx_out;
if (out != null && out.getBufferSize() != 0)
try { out.clearBuffer(); } catch (java.io.IOException e) {}
if (_jspx_page_context != null) _jspx_page_context.handlePageException(t);
}
} finally {
_jspxFactory.releasePageContext(_jspx_page_context);
}
}
- buffer 속성을 사용하지 않는 경우 "none" 으로 경우라면 위 빨간 것으로 표기된 8192 값 대신 JspWriter.No_Buffer 값으
로 설정되어 out 객체에 의해 모든 출력 결과는 클라이언트로 전송된다.
- 버퍼에 저장된 응답 내용이 실제 클라이언트로 전송되는 시점
① 버퍼가 다 찼을 경우 ← page directive autoFlush 속성이 "true" 인 경우
② 해당 페이지의 서블릿의 실행을 마쳤을 대 (_jspService() 메소드 종료시)
※ HTTP ?
HTTP는 기본적으로 클라이언트 요청/서버 응답 메커니즘을 사용한다.
⒜ get , post , header 이런 말이 나오면 좀 어려워 보인다. 그래서 그림으로 간단히 표현시켜 보왔다.
⒝ 클라이언트 기본정보 : 클라이언트의 HTTP 프로토콜 버전 , 브라우저 정보, 처리가능한 MIME
⒞ 서버 기본정보 : 서버 HTTP 프로토콜 버전, 웹서버 버전, ContentType
⒟ 요청에 대한 결과(클라이언트가 받는 응답)은 웹서버가 전송한 HTTP 헤더와 HTTP 본문으로 구성된다고 볼 수 있
다.
⒠ 서버로 부터 HTTP 헤더가 먼저 클라이언트 브라우저에 도착해야 하는지 아니면 HTTP 본문이 먼저 도착해야 하는
지 순서를 지정해야 하는 의무이 따른다.
결론은 서버로 부터 HTTP 헤더가 먼저 도착하는 것이 좋다. 클라이언트 브라우저는 서버로부터 전송된 응답 헤더
를 먼저 확인하여 이것에 근거하여 응답 HTTP 본문 내용을 브라우저로 출력하려 하기 때문이다.
⒡ HTTP 서블릿에서 요청을 처리하는 doGet(), doPost(), service()와 같은 메소드 내에서 HttpServletResponse
객체를 통해 클라이언트로 응답 내용을 보내기 전에 먼저 컨텐트 타입(MIME)을 지정하는 것도 이러한 이유이다.
response.setContentType("text/html;charset=euc-kr"); 위에 서블릿 파일 예제 일부
⒢ HTTP 헤더를 먼저 보내야 하는 이유
① 프로그램 로직에서 응답 내용을 전송하는 도중에라도 조건이 만족되면 클라이언트에 쿠키를 저장하도록 쿠키
를 설정하는 헤더를 포함하고자 한다면 HTTP 응답 헤더가 HTTP 본문보다 늦게 도착하는 문제가 발생한다.
② 클라이언트에 응답이 전송되고 나면 서버측에서는 이전까지 전송된 응답에 대해서 클라이언트 브라우저가
출력하는 것을 취소하도록 할 수 있는 방법이 존재하지 않기 때문에 코드가 실행되는 도중 실행 타임 에러나
예외로 인하여 문제가 발생한 경우라 할지라도 그 전에 전송된 내용이 그대로 브라우저로 출력되고 뒤이어
스택 트레이스(예외가 발생한 위치에 대한 추적 경로)에 에러 메시지가 출력된다.
- JSP buffer 속성의 중요성
여태까지 얘기한 내용은 결국 buffer 속성이 중요하다는 것을 강조하기 위한 요소에 불가하다. 서버는 응답과 관련된
HTTP의 고유한 문제를 해결하기 위해 응답을 바로 전송하지 않고 메모리 버퍼에 미리 저장하였다가 응답 처리를 완료
하였거나 버퍼가 다 채워졌을 때 응답을 전송하는 것이다. 이러게 하면 출력된 내용이 일단 버퍼로 출력되어 저장되기
때문에 나중에라도 헤더정보를 추가할 수 있고 실행중 예외가 발생하여 정상적인 서비스를 제공하지 못할 상황에서 그
때까지 출력한 응답 내용을 취소함으로써, 클라이언트에 대한 응답을 당혹스로운 스택 트레이스 에러메시지 대신 완곡
한 에러 페이지를 전송할 수 도 있게 된다.
㉥ autoFlush 속성
- 응답을 저장한 버퍼가 다 채워졌을 경우에 이를 어떻게 처리할 것인지 JSP 컨테이너에게 알려주는 속성이다.
- 표현은
<%@ page autoFlush="true" %> ← 기본값으로 지정된 버퍼가 다 채워졌을 경우나 응답을 처리하는 서블릿
의 메소드(_jspService())가 종료될 때 버퍼의 내용이 브라우저로 전송
되고 버퍼의 내용은 리셋된다.
<%@ page autoFlush="false" %> ← 로 지정된 경우 JSP 컨테이너는 버퍼가 다 채워졌을 때 버퍼를 브라우저
에 전송하는 대신에 예외를 발생시킨다.
(톰캣 기준 - IOCException , ServletException 에러 발생)
- buffer의 내용이 일단 클라이언트로 전송된 이후에는 취소할 방법은 없다.
- buffer 속성이 "none" 인 경우에 autoFlush 속성을 "false"로 지정하는 것은 불가능하다. (당연한 결과다,
buffer의 내용에 아무것도 없는데 buffer 내용이 "다 채워져" 있어야지 동작하는 autoFlush가 무슨 의미가 있겠습니까.)
- 해당 페이지가 출력할 내용의 크기를 정확히 예측하기 힘든 경우 무조건 "true" 로 설정합니다.
㉦ isTreadSafe 속성
- JSP 파일에 대한 서블릿이 동시에 다중 클라이언트의 요청을 처리하는 데 문제가 있는지 없는지를 JSP 컨테이너
에게 알려주는 속성이다.
- 서블릿과 마찬가지로 JSP에 대한 요청도 새로운 프로세스를 생성하지 않고 스레드에 의해 처리된다는 것을 기억
하고 있을 것이다. 그리고 해당 페이지에 대한 서블릿의 _jspService() 메소드가 요청을 처리한다고 했다.
다시 말하면 JSP에 대한 클라이언트 요청이 발생하면 JSP 컨테이너는 스레드를 생성하여 이 스레드가 해당 페이지
에 대한 서블릿 _jspService(). 메소드를 호출하고 여기에서 응답을 생성하여 전송하게 된다는 말이다.
(말로 설명되어 있어서 좀 어렵다. 라이프 사이클 그림을 떠 올리면 이해가 더 빨라질 것으로 보인다. )
http://cafe.naver.com/tonkjsp/12 ← 라이프 사이클 이미지 참조한다.
※ 스레드 ? , 프로세스 ?
⒜ 프로세스란 운영체제에서 실행중인 하나의 프로그램 말한다.
⒝ 멀티프로세스란 두 개 이상의 (멀티) 프로세스가 실행되는 것을 말한다.
⒞ 멀티태스킹란 멀티프로세스를 실행하여 일을 처리하는 것을 말한다.
⒟ 프로세스 내에서 실행되는 세부 작업 단위
(자바 5.0 프로그래밍 차근차근 배우는 자바 A to Z - p636)
- 표현은
<%@ page isThreadSafe = "true" %> ← 기본값이다. JSP 컨테이너는 해당 JSP 페이지에 대한 서
블릿이 다중 클라이언트의 동시 요청을 처리하는 데 문제가
없다는 것이다. (Thread-Safe : 스레드를 쓰는데 안정적이다.)
<%@ page isThreadSafe = "false" %> ← 해당 페이지가 다중 클라이언트의 동시 요청을 처리하는데
문제가 있을 수 있다는 의미다.
(Thread-Unsafe : 스레드를 쓰는데 안정적이지 못하다.)
- Thread를 사용하는 것으로 속성을 지정하여 주고 3명의 클라이언트로부터 요청을 받는다. 그러면 JSP
컨테이너는 3개의 스레드를 생성하여 해당 페이지의 서블릿 인스턴스에 대해 _jspService() 메소드를
호출하게 한다는 것이다. 이 경우 동시에 여러 개의 스레드가 동일한 서블릿 인스턴스의 _jspService()
메소드를 실행할 수 있다.
- Thread를 사용하지 않는 것으로 속성을 지정하는 경우는 동시에 두 개 이상의 스레드가 하나의 서블릿
인스턴스를 실행하지 못한다는 것이다. 다시 말하자면 JSP 컨테이너는 하나의 스레드가 해당 서블릿의
_jspService() 메소드를 실행하고 있을 때 다른 스레드는 먼저 실행하고 있는 스레드가 _jspService()
메소드 실행을 마칠 때까지 기다린다는 것이다. (교착상태에서 비선점 조건에 빠질 수 있습니다. )
(javax.servlet.SingleThreadModel 인터페이스 제공)
- isThreadSafe="false" 지정하고 실행시켜 서블릿 파일을 확인하여 보면 아래와 같은 결과가 나온다.
http://cafe.naver.com/tonkjsp/17 ← jsp 자료실에서 isThreadSafe.jsp 파일 다운로드
public final class isTreadSafeTest_jsp extends org.apache.jasper.runtime.HttpJspBase
implements org.apache.jasper.runtime.JspSourceDependent,SingleThreadModel {
-- 소스 내용 생략 --
}
- 다중 스레드 문제 SingleThreadModel 인터페이스가 탄생했지만 비효율성과 컨테이너별로 운영방식의 차이 때문에
이식성에도 문제가 있어 사용을 권하지는 않는다. 실제로 앞으로 사용될 서블릿 스펙 2.4 이상에서는 SingleThread
Model이 Deprecated(권장하지 않음)된 것이 이를 반증하고 있다. 따라서 앞으로는 스레드로 인한 문제를
SingleThreadModel과 같은 API를 이용하여 해결할 것이 아니라 개발자 자신의 논리적으로 풀어나가야 할 것이다.
㉧ info 속성
- 페이지 작성자가 해당 페이지의 기능이나 특징에 대한 설명을 지정하는 속성이다.
- getServletInfo() 메소드를 통해 정보를 읽어 온다.
- getServletInfo() 메소드는 javax.servlet.Servlet 인테페이스에 선언된 메소드로써 모든 서블릿과 JSP페이지는 이를 구
현한다.
http://cafe.naver.com/tonkjsp/18 ← jsp 자료실에서 infoTest.jsp 파일 다운로드
㉨ errorPage 속성
- 해당 페이지에 대한 서블릿이 요청을 처리할 때 발생하는 예외를 처리할 페이지를 JSP 컨테이너에게 알려주는 속성
- 표현은
<%@ page errorPage="error.jsp" %>
- 에러페이지로 제어권을 넘길 수 없는 경우
㈀ buffer 속성값을 "none" 으로 지정한 상태에서 해당 페이지에서 발생한 예외의 처리를 errorPage로 지정된 페이지로
넘겨주어서는 안된다.
㈁ 출력 buffer를 사용하고 autoFlush 속성을 "true"로 지정했을 경우라도 일단 버퍼가 다 채워져서 클라이언트로 응답
이 전송된 경우에는 예외가 발생하더라도 에러 페이지로 응답에 대한 출력 제어권을 넘겨주어서는 안된다.
㈂ ㈀,㈁ 에서는 에러 페이지를 지정할 수 없는 이유는
예외가 발생하기 전까지의 응답 내용이 이미 클라이언틀 전송되고 나면 해당 페이지에 대한 출력 제어권을 다른
페이지로 넘겨주는 데 문제가 발생하기 때문
- http://cafe.naver.com/tonkjsp/19 ← jsp 자료실에서 error.jsp & errorTest.jsp 파일 다운로드
- page 지시어의 errorPage 속성에 지정된 JSP 파일(error.jsp)은 현재 페이지(errorTest.jsp) 서블릿 코드와는 별개로
자신의 페이지 서블릿 코드가 생성된다. (error_jsp.java, errorTest_jsp.java 이런식으로 서블릿 파일이 생깁니다.)
- 동작
제어권은 errorTest.jsp → error.jsp로 넘어간 것이 된다.
㉩ isErrorPage 속성
- 해당 페이지가 다른 페이지에서 발생한 예외를 처리할 페이지(errorPage)임을 JSP 컨테이너에게 알려주는 속성
- 표현은
<%@ page isErrorPage="true" %>
<%@ page isErrorPage="false"%>
기본값은 "false" 이다. (당연하다. 그렇지 않으면 매번 JSP 파일을 만들때마다 <%@ page isErrorPage="false" %>
해주어야 하는 번거러움이 있기 때문이다.)
- 속성 값이 "true" 로 지정된 경우 해당 페이지에서는 자신의 URL을 errorPage 속성값으로 지정한 페이지에서 발생한
예외를 Exception이라는 내장 객체를 받아서 사용한다.
- 내장객체(implicit Object)는 특별히 페이지 내에서 정의하지 않았음에도 실제로 해당 페이지에 대한 서블릿 코드
내에 정의되어 있는 객체이기 때문에 jsp 파일 내에서 접근이 가능한 가능한 객체를 말한다.
- isErrorPage 속성이 "true"로 되어 있다면 클라이언트가 이 해당페이지를 직접 요구할 수 없다.
예외처리가 발생했을 때 예외처리가 발생한 파일(errorPage="파일경로")이 isErrorPage="true"
인 파일을 불러 올 수 있다는 얘기 입니다.
㉪ contentType 속성
- 해당 JSP 파일이 클라이언트로 전송할 응답의 MIME(Multipurpose Internet Mail Extension) 형식을 지정하는 속성
- 표현은
<%@ page contentType="text/html;charset=euc-kr" %>
"text/html" 대신에 text/plain, text/xml, image/gif 등.....
- http://cafe.naver.com/tonkjsp/20 ← jsp 자료실에서 contentTypeTest.jsp 파일 다운로드
㉫ pageEncoding 속성
- 페이지의 캐릭터셋 인코딩 방식을 지정하는 속성이다.
- 인코딩 타입은 contentType 혹은 pageEncodingType 둘 중 하나만 지정하는 것이 좋다. 두 개의 타입이 틀리면
당연히 한글이 깨지는 현상이 나옵니다.
둘 다 지정하는 경우 같은 인코딩 타입으로 지정해야 한다. (두번 써야 하니까 한번 지정하는 것이 좋습니다.)
- 표현은
<%@ page pageEcoding="euc-kr" %>
② Include 지시어
- 해당 JSP 파일에 지정된 파일을 삽입하도록 하는 지시어다. (JSP 파일 안에 외부에 있는 또 다른 JSP(HTML)를 넣는다
는 의미입니다.)
- 조각코드로 작성된 페이지를 읽어오는데 실무에서 종종 사용하기도 한다. (조각 코드에 대해서는 아래 주소를 참조)
(http://cafe.naver.com/tonkjsp/65)
- 표현은
<%@ include file = "header.jsp" %>
<%@ include file = "footer.html" %>
- 여러개의 jsp 파일을 include 할 경우 서블릿 파일은 하나만 생성된다.
(결국 include 당하는 jsp(html) 파일은 파일 내용만 복사가 되는 것입니다.)
- 중첩하여 include가 가능하다. (예) a.jsp가 b.jsp를 include 한다. 그러고 b.jsp는 c.jsp를 include 하는 것이 가능하다.
- JSP 파일은 요청시에 해당 파일이 수정이나 변경된 시간을 검사하여 새로운 서블릿 코드를 생성하고 이에 대한 인스
턴스를 새로이 생성한다. 그런데 include 지시어를 통해서 지정된 jsp파일의 경우에는 대부분 서블릿 컨테이너가
파일의 의존성을 검사하지 않기 때문에 include된 jsp 파일을 수정해도 그 효과가 바로 나타나지 않는다.
(예) a.jsp가 b.jsp를 include 한다고 할 때 b.jsp를 수정하였다. 그러면 a.jsp에 바로 반영되야하는데 그렇지 않다는 것
이다. 왜냐 하면 어차피 서블릿 파일은 하나만 만들어진다. a_jsp.java 가 변경이 되지 않는다는 의미다. 위에서 얘기하
였지만 그것은 대부분의 컨테이너가 의존성을 검사를 하지 않는데 있다. 우리가 일반적으로 생각하는 b.jsp는 a.jsp 하
고 연결이 되어있으니까, 서블릿이 되겠지 하고 생각하는데 있다. 결국은 a.jsp를 실행시켜 서블릿(a_jsp.java)를 변경
시켜 주어야해 했지만 요즘은 컨테이너들이 너무 좋아져서 결국은 이러한 문제가 다 해결 되었다고 한다.
"톰캣 4.1대 부터 JASPER2 엔진을 이용하면서 해결되었으며 OC4J의 경우도 R3에서 부터 해결되었다."
- include 지시어 사용시 주의할 점
㈀ contentType 중복사용
JSP 페이지에서는 하나의 문서에 단 한번의 contentType 속성 선언을 허용하고 있다.
(page directive 속성 선언 중에 주의 할 점 → import 빼고는 중복으로 속성을 선언할 수 없다고 하였다.)
실무 개발 중에 모든 개발자가 무심고 습관적으로 contentType를 모든 JSP에 포함시켜서 작업을 하는 경우가 있다.
"Page directive : can't have multiple occurrences of contentType" ← 에러 메세지
㈁ 또 한 가지는 코딩 방법에 따른 것이다.
예를 들어 <%@ include file="<%=mypagte1%>" 코딩을 하는 것이다. 이 경우는 아무것도 include가 되지
않는다.
"File "" not found" ← 에러 메세지
- http://cafe.naver.com/tonkjsp/21 ← jsp 자료실에서 contentTypeTest.jsp 파일 다운로드
- 서블릿 이 하나만 생기는 지도 확인하세요 / 실행 결과도 확인하여 보세요
③ taglib 지시어
- 기본적인 JSP의 내장 기능을 확장하기 위한 커스텀 태그들의 집합(JSP가 가지고 있는 내장 기능만으로 모든 것을
편현하여 개발하기가 어려움이 있어 결국에는 별도로 중요한 태그들만 빼서 집합으로 만들었다고 보면 됩니다.)
- 해당 페이지가 해당 애플리케이션에 필요한 기능을 구현한 커스텀 태그를 사용한다고 JSP 컨테이너에게 알려주는 역할
(당연히 알려주어야 겠죠. JSP 컨테이너는 인공지능를 가진 놈이 아니기 때문에 알려주어야 합니다.)
- 표현은
<%@ taglib uri="/yangtags" prefix="tagPrefix"%>
㉠ uri 속성
태그 라이브러리에서 정의한 태그와 속성을 담고 있는 TLD(Tag Library Descriptor) 파일(확장자가 .tld)이 존재하는
URI를 지정
㉡ prefix 속성
사용할 커스텀 태그들의 네임 스페이스(namespace)를 지정
- 간단한 예 -
※ URL과 URI 차이는 ?
㉠ URL(Uniform Resource Locator) : http://ww.tonkjsp.com/jsp/ .... 이런식으로 표현합니다.
인터넷 상에서 자원의 접근 경로를 표시해 주는 형식을 말한다고 할 수 있습니다.
㉡ URI(Uniform Resource Identifier) : jsp/directvies/sample.jsp 이런식으로 표현합니다.
자원이 존재하고 있는 위치의 식별을 위한 경로로 볼 수 있습니다.
㉢ URL 이나 URI는 모두 Uniform 입니다. 어떤 형식이냐 Resource 자원의 위치 및 경로를 나타내기 위한
형식이라는 말입니다.
※ TLD ?
- JSP 페이지 컴파일 서블릿이 JSP 파일에 대한 서블릿 코드 생성시 해당 페이지에서 사용하고 이는 커스텀 태그가
유효한 것인지를 JSP 컨테이너가 일차적으로 검증하는 데 사용되는 XML 문서
(말이좀 어렵다. JSP에서 커스텀 태그나 라이브러리 태그 파일을 사용한 경우 JSP 서블릿 파일을 만들 때
JSP 파일내에서 커스텀 태그나 라이브러리 태그가 제대로 사용한 것을 검증하는다는 것이다. 쉽게 표현하면 맞춤범
검사한다고 보면 된다)
※ 네임스페이스 ?
- 특정 변수나 속성이 알려지는 영역이나 범위를 지정하는 데 사용하는 용어
- 특정 태그 집합을 그룹으로 지정한 이름 정도로 네임 스페이스를 생각하면 된다.
(3) 스크립트 요소
- jsp 파일에서는 java 코드를 스크립트로 사용한다고 했다. 자바코드를 어떻게 삽입할 것인지를 컨테이너에게 알려주어야
한다.
① 선언문(declarations)
- 선언문 태그는 페이지에서 삽입된 코드를 통해 변수나 메소드를 선언하는데 사용된다.
- jsp 페이지 내에서 선언문 태그를 통해 선언된 변수나 메소드는 페이지를 컴파일할 때 (.jsp 파일에 대한 서블릿 소스
코드 생성시에) 해당 클래스의 멤버 변수나 메소드로 지정된다.
- 표현은
<%! 선언문 %> ← 단일선언문
<%! 선언문-1; 선언문-2; 선언문; ......%> ← 다중선언문
- 스크립트 언어로 자바를 사용할 경우 주의 사항
㈀ 각 선언문은 반드시 세미콜론을 사용하여야 한다.(자바하고 똑같습니다.)
㈁ 선언문 태그 내에서 page 지시어를 사용하여 import 된 클래스의 변수나 메소드를 호출할 수 있다.
㈂ include 지시어를 통해 특별히 include되는 파일이 지정되지 않은 선언문 태그를 통해 선언된 변수나 메소드
는 해당 페이지에서만 접근할 수 있다.
㈃ include 지시어를 통해 include된 페이지 내에서는 선언문 태그에서 선언된 변수나 메소드를 사용할 수 있다.
㈄ <jsp:include/> 액션을 통해 요청시(Request Time)에 동적으로 include 된 페이지의 경우 페이지 scope를 갖는다.
즉, include된 파일 내에서는 사용하지 못하고 해당 페이지에서만 접근하여 사용 할 수 있다.
㈅ ㈂ ~㈄ 을 말로 표현 하면 좀 어렵다. 그래서 아래 그림으로 다시 한번 표현시켜 보왔다.
㈆ 선언문을 이용하여 멤버 변수나 멤버 메소드를 선언 할 경우 다중 스레드로 인하여 동시에 사용되는 문제가 발생될
수 있다. 되도록 이면 사용을 자제하도록 하고 꼭 필요한 경우라면 static으로 선언하여 스레드로 인한 문제가 발생
되지 않도록 하는 것이 좋다.
- http://cafe.naver.com/tonkjsp/22 ← jsp 자료실에서 declareTest.jsp 파일 다운로드
- 서블릿 파일과 실행결과를 확인하여 봅니다.
㈀ 서블릿 파일
package org.apache.jsp.jsp.directives;
import - 파일 -
public final class declareTest_jsp extends org.apache.jasper.runtime.HttpJspBase
implements org.apache.jasper.runtime.JspSourceDependent {
private String msg_am="";
private String msg_pm="";
public String helloMessage(){
Calendar cal=Calendar.getInstance();
int hour_day = cal.get(Calendar.HOUR_OF_DAY);
switch(hour_day){
case 7:
msg_am="출근 시간입니다. 서두르세요";
break;
case 8:
case 9:
msg_am="즐거운 업무 시간이 되세요";
break;
case 10:
case 11:
msg_am="안녕하세요 좋은 아침입니다.";
break;
case 12:
msg_am="점심시간입니다. 맛있게 드세요";
break;
case 13:
msg_pm="오후시간도 열정적으로 업무에 임합시다.";
break;
case 14:
msg_pm="점심 먹고 조립더라도 할일 하셔야죠?";
break;
case 15:
msg_pm="오늘 할일 계획대로 진행하고 계십니까?";
break;
case 16:
msg_pm="이제는 슬슬 퇴근 준비 하셔야지요?";
break;
case 17:
msg_pm="안녕하세요. 오늘 일과에 수고 하셨습니다.";
break;
case 18:
case 19:
case 20:
msg_pm="안녕하세요. 내일을 위해 준비하는 시간이 되세요";
break;
default:
msg_pm="내일봐요.";
}
if(cal.get(Calendar.AM_PM) == Calendar.AM){
return msg_am;
}
return msg_pm;
}
-- 아래 부분은 생략 --
javax.servlet.jsp.HttpJspPage 인터페이스에서 정의하고 있는 jspInit(), jspDestroy(), _jspService()
페이지 서블릿 초기화 작업과 자원반납, 그리고 클라이언트에게 응답에 대한 처리 결과를 전송하기 모든 설정 부분
}
㈁ 실행결과 - 확인(화면하고 다른을 수도 있습니다.)
※ C 언어 등에서는 반드시 변수를 선언한 뒤에 그 변수를 참조할 수 있지만 자바에서는 변수의 선언이 그 변수를
사용하는 라인보다 뒤에서 선언 되어도 사용이 가능하다. 따라서 자바 기반의 JSP에서도 그 특징이 그대로 적용
② 스크립틀릿(scriptlets)
- 선언문 태그를 이용하여 멤버변수나 메소드를 정의하고 필요에 따라 jspInit()이나 jspDestroy()와 같은 페이지
서블릿의 라이프사이클과 관련된 메소드를 재정의(오버라이딩) 할 수 있다는 것을 알게되었다.
- HttpJspPage 인터페이스에서 정의하고 있는 _jspService() 메소드는 재정의해서는 안 된다.
그 이유는 jsp 컨테이너가 페이지 서블릿을 정의할 때 구현할 메소드이기 때문이다.
클라이언트 요청에 대한 처리하여 응답하는 것도 _jspService() 메소드이다.
- 스크립틀릿 태그의 주목적은 바로 _jspService() 메소드에 하고자 하는 코드를 .jsp 페이지에서 정의 할 수 있도록
하는 것이다. 즉, 페이지 내의 스크립틀릿 태그에 삽입된 코드는 요청마다 실행된다고 보면 된다.
- 표현식 태그 내에서는 페이지에 지정된 스크립트 언어의 유효한 표현식을 삽입해야 하지만
스크립틀릿 태그 내에서는 유효한 문장들이 정의되어야 함.
- 표현은
<% 문장 %>
<% 문장-1; 문장-2; 문장-3; .....%>
<%--- 문장 ----%> ← _jspService() 메소드의 자바 문장으로 포함되어 있다. (out 객체가 필요하지 않다는 의미)
스크립틀릿 파일을 하나만들고 서블릿 파일을 열어보면 확인할 수 있다.
③ 표현식(expressions)
- 페이지 서블릿의 멤버 변수나 메소드를 선언하는 데 선언문 태그를 사용하는 반면에 ,
표현식은 태그는 jsp 페이지 내에서 직접 클라이언트로 출력될 내용(텍스트)을 포함시키는 데 사용된다.
- 표현은
<%= 스크립트 언어의 표현식 %>
- 표현식 내에서 사용하는 표현식이 자바 구문일 때 주의 해야 할 사항
㈀ 세미코론을 사용해서는 안된다.
※ jsp 컨테이너가 표현식 태그를 변환하여 클라이언트에 전송할 때 JspWriter 의 write 메소드를 사용하지 않고
print 메소드를 사용한다.
그렇다면 "<%=(int)(Math.random()*100)+1;%>" 이것은 out.print((int)(Math.random()*100)+1;);
이렇게 되어 에러가 에러가 난다.
㈁ 자바언어의 유효한 표현식이어야 한다.
- 표현식 태그 내의 표현식의 평가된 결과 값은 그에 상응하는 자바의 문자열로 변환되고 이렇게 변환된 자바의 문자열이
표현식 태그 자체를 치환하여 클라이언트로 전송한다.
④ 스크립트에서 선언문, 스크립틀릿, 표현식 각각을 서블릿 하였을 경우 비교하면 다음과 같다. 
[출처] [JSP 이론 5] JSP 구성 요소 (모델2로 다시 배우는 JSP 요약) (tonkjsp) |작성자 tonk000
'소프트웨어개발 > 자바' 카테고리의 다른 글
| JAVA - 개발자가 놓치기 쉬운 자바의 개념, 기본원리 (0) | 2009/02/17 |
|---|---|
| [JAVA] static(정적) vs instance(인스턴스) method (0) | 2009/02/17 |
| [JSP 이론 5] JSP 구성 요소 (모델2로 다시 배우는 JSP 요약) (0) | 2009/02/11 |
| [JSP]JSP 1.2 스펙에서 1.1 보다 낳은 점? (0) | 2009/02/11 |
| [JavaFX] 기본 (0) | 2009/02/11 |