= JSP =
Java Server Pages
Java의 특성을 물려받는다. => 플랫폼 독립적 + 보안↑ + 멀티스레드
(Servlet과 반대로) **HTML 문서에 Java 코드가 삽입되는 구조**
-> HTML 코드는 웹브라우저로 그대로 전송
-> JSP 코드는 웹 컨테이너 쪽에서 실행되고 __결과만__ 웹 브라우저로 전송 (Servlet에 비해 밑줄 친 단계가 추가된 것.)
* __**JSP 페이지** --(변환)-> **Servlet 클래스의 소스 코드**__ --(컴파일)-> **Servlet 클래스 파일** --(인스턴스화)-> **Servlet 객체** --(초기화)-> **Servlet**
{{tag>Java Web}}
= Servlet vs JSP =
^ ^ 장점 ^ 단점 ^
^ Servlet |- HTML 문서에 소스코드가 공개되지 않는다. |- Java 코드안에 HTML이 작성된다.\\ =>디자인시 수정에도 코드 변경 필요!\\ - 설치과정이 복잡하다. |
^ JSP |- HTML 중심의 코드 구조로 수정이 쉽다.\\ - 설치과정이 쉽다. |- HTML 문서에서 소스 코드가 공개된다. |
**그러나** **복잡한 로직**을 필요로 하는 경우 Servlet을 사용해서, JSP 페이지에 결과만 출력하는 구조가 적합하다!
= Servlet =
Java를 기반으로 하는 웹 어플리케이션 프로그래밍 기술
== 기본 규격 (작성시 지켜야 할 3가지 규칙) ==
# (**javax.servlet.http.HttpServlet** 를 상속받아) **javax.servlet.Servlet** 인터페이스를 구현해야 한다.
# **doGet()**, **doPost()** 메소드의 선언 및 기능을 정의해야 한다.
* Argument : (javax.servlet.http.httpServlet__Request__, javax.servlet.httpServlet__Response__)
* Exception : java.io.IOException & javax.servlet.ServletException
# 동적 HTML 문서를 생성하기 위해서는 doGet(), doPost()의 **두 번째 인자**를 이용해야 한다! 두번째 인자형 값에 getWriter() 메소드를 이용하면 PrinterWriter 객체가 반환되는 데, 이를 이용하여 print(), println(), printf()등의 메소드로 웹브라우저를 통해 HTML 문서에서 출력할 수 있다.
== 알아두어야 할 점 ==
웹 컨테이너가 Servlet을 운영하는 방법으로
* 웹 서버가 여러 웹 브라우저(User)로부터 **동시 접속**을 받을 수 있고, 여러 Servlet이 **동시 실행** 될 수 있다.\\ 그렇기 때문에 모든 웹 서버는 **Multi-Thread**로 작동한다!
* (동시 요청이 왔을 때) 웹 컨테이너가 만드는 Servlet의 개수
* Multi-Thread Model : Thread 여러개로 하나의 Servlet으로 제어
* Single-Thread Model : Thread 하나로 여러개의 Servlet 제어 → 자원 낭비! 대규모 요청시 심각! **__2.4부터 폐용화.__**
* 구현 방법 : javax.servlet.SingleThreadModel 구현.
== web.xml 설정 방법 ==
* 에서 따로 package를 import 했으면 같이 적어줘야 한다! (패키지.클래스)
* 에서 첫시작에서 "/"를 빼먹지 말자!
* "URL패턴"은 Servlet을 대표하는 URL로 자유롭게 지정할 수 있다. (나머지 URL은 웹 애플리케이션 디렉토리로써 정확히 적어줘야 한다.)
NAME
[PACKAGE.]SERVLET_NAME
NAME
/WEBAPPDIR/MyServlet
= 기초 지식 =
== 문법의 3종류 ==
* JSP에서 변환된 명령문들은 doGet(), doPost() 역할을 __동시__에 하는 **_jspService()** 안에 들어간다!
=== <% %> ===
* Scripting Elements를 아예 쓰지 않고, [[#Expression Language1 | Expression Language]]와 [[#standard action | Ac]][[#JSTL | ti]][[#Custom Action | on]]만 사용하는 것을 권장. (Web Designer를 위해)
==== 스크립팅 요소 (Scripting Elements) ====
^ Scriptlet ^ Expression ^ 선언부(Declaration) ^
| <% 명령문 %>
| <%= 식(호출된 결과값) %>
| <%! 변수 및 메소드 선언 %>
|
|
<%
int sum = 0;
for(int i=0 ; i<10 ; i++)
sum += i;
%>
|
<%= Math.sqrt(sum) %>
out.println(Math.sqrt(sum)); |
<%! final static int LIMIT = 99999 %>
※ 인스턴스 변수 선언 주의!\\ 실행 중 변경안되도록 "final static" 붙이자! |
<%@ page language="java" contentType="text/html" pageEncoding="UTF-8"%>
Insert title here
<%
int a = 3;
int b = 4;
int total = add(a, b);
%>
<%!
private int add(int a, int b) {
return a+b;
}
%>
<%=a %> + <%=b %> = <%=total %>
==== 지시자 (Directive) : <%@ %> ====
* 다른 문법들(Scripting Elements, Expression Language, Action)의 목적과 달리,\\ 웹 브라우저로부터의 요청을 처리하기 위해서가 아니라 **웹 컨테이너가 JSP 페이지를 Servlet 클래스로 변환할 때 __필요한 여러 정보들을 기술__**하기 위해 사용되는 문법
===== page =====
* JSP 페이지 전체에 적용되는 정보를 기술
^ Attribute ^ 용도 ^ 예시 ^
| contentType | JSP가 생성하는 문서 종류 및 인코딩 타입 | <%@page contentType="text/html; charset=euc-kr" %> |
| import | Scripting Elements 안에서 사용할\\ Java 클래스&인터페이스의 import | <%@page import="java.util.*, java.io.*" %> |
| buffer | 출력 Buffer 크기 | <%@page buffer="4kb" /* none */ %> |
| autoFlush | 출력 버퍼가 모두 찼을 때의 동작 | <%@page autoFlush="false" %> |
| isThreadSafe | Single-Thread로 동작 변경시 필요 | <%@page isThreadSafe="false" /* Single-Thread 동작 */ %> |
| session | 세션 참여 여부 | <%@page session=“false” %> |
| errorPage | Error 처리할 JSP 페이지 URL |[[#Exception 처리]] |
| isErrorPage | Error 처리하는 JSP 페이지 여부 |:::|
| isELIgnored | Expression Language 무시/처리 여부 |
===== include ======
* 다른 JSP/HTML 문서를 **현재 JSP 문서의 일부로 만들기 위해** 사용.
* **file** 속성으로 **상대적 URL**를 이용한다.
...
<%@include file="example.jsp" %>
...
===== taglib ======
* Action을 사용할 때, **Library가 필요할 때** 사용.
<%@taglib prefix="c" uri="http://java.sun.com/jsp/js1/core" %>
==== 주석 ====
Servlet 클래스로 컴파일 과정에서
|< 21em 50% >|
^ JSP 주석(<%-- --%>) ^ HTML 주석()\\ Java 주석(// /* */) ^
| 제거된다. | 그대로 기록된다. |
=== Expression Language : ${ } ===
* [[#Expression Language1 | Expression Language]]
=== Action : XML Tag 형태 ===
* [[#Standard Action]]
* [[#JSTL]]
* [[#Custom Action]]
== 내장 변수 (Implicit variable) ==
* 선언하지 않아도 사용할 수 있는 변수\\ ☞ **_jspServlet()**에 속하는 Parameter 변수와 Local 변수
^ 변수명 ^ Type ^ 용도 ^ 예시 ^
| request |javax.servlet.http.\\ HttpServletRequest |doGet(), doPost() 첫 번째 Parameter |
<%= request.setCharacterEncodeing("euc-kr"); %>
<%= request.getParameter("NAME"); %>
|
| response |javax.servlet.http.\\ HttpServletResponse |doGet(), doPost() 두 번째 Parameter |
<% response.sendRedirect("ex.jsp?RESULT="+msg+"&NUM=7") %>
|
| out |__javax.servlet.jsp.\\ JspWriter__\\ (PrintWriter 아님!) |웹 브라우저로 HTML 코드 출력 |
<% out.println("
"); %>
<% out.flush(); /* buffer 수동 비우기 */ %>
|
| session |javax.servlet.http.\\ HttpSession |세션 관련 기능 |[[#Session 기술의 사용 방법]] |
| application |javax.servlet.\\ ServletContext |JSP 문서가 속하는 Web App의 관련 기능 |
<%
String relPath = application.getContextPath();
String absPath = application.getRealpath("/RelativePath");
%>
|
| config |javax.servlet.\\ ServletConfig |JSP 문서의 구성 정보 가져오는 기능 |
| pageContext |javax.servlet.jsp\\ PageContext |JSP 문서 범위 내에서 사용할 수 있는\\ 데이터저장 기능등 |
| page |java.lang.\\ Object |JSP 문서로부터 생성된 Servlet |
| exception |java.lang.\\ Throwble |Exception 객체 |[[#Exception 처리]] |
== 다른 JSP 문서 호출하기 ==
* 가독성과 유지보수를 위해 JSP 문서를 여러 개로 나눴을 때 필요.
=== forward() ===
* 다른 JSP 문서를 호출할 때 사용.
* 실행 흐름의 제어를 되돌려주지 않음.\\ ☞ 어떤 JSP 문서가 **할 일을 모두 마친** 후 다른 Web Resource(JSP, Servlet, %%HTML%%, ...)를 호출할 때 사용.
* 호출하는 문서에 **HTML 코드 출력하면 Exception 발생!**
<%
RequestDispatcher dispatcher = request.getRequestDispatcher("ex.jsp"); //상대경로만 사용가능! 절대경로 불가능!
//request.setAttribute("NAME", new Integer(7)); //String, Object
dispatcher.forward(request, response);
%>
==== forward() vs sendRedirect() ====
* **핵심** : 웹 브라우저를 거치는가? (= 같은 Servlet 객체를 공유하는가? 아니면 새로 생성하는가?)
|<100% 20% 40% 40%>|
^ ^ forward() ^ sendRedirect() ^
^ 호출 방식 | 웹 서버 쪽에서 **직접**\\ =>자원 절약+응답 시간↑ | URL을 웹 브라우저로 보내서 **간접적** |
^ 호출 경로 |__상대 경로**만**__! \\ = __같은 웹서버&디렉토리**만**__ 호출 가능.\\ => 회선을 거치지 않고 **직접** 데이터를 전달하기 때문에 **보안↑** |상대 경로, 절대 경로 \\ = 다른 웹 서버의 웹 자원 호출 가능.\\ => 새 URL 유도에 사용\\ => "새로 고침"시 중복 동작 방지에 사용. |
^ Data 전달 방식 | request 내장 변수를 통해 | URL 뒤에 붙여서 |
^ 전송 가능한 Data Type | Object | String |
^ 한글 Data URL 인코딩 여부 | 불필요 | 필요 |
^ Data 송수신 예 |
//송신
request.setAttribute("Age", new Integer(11));
RequestDispatcher dispatcher = request.getRequestDispatcher("Result.jsp");
dispatcher.forward(request, response);
//수신
Integer age = (Integer)request.getAttribute("Age");
|
//송신
String str = URLEncoder.encode("안녕?", "EUC-KR");
response.sendRedirect("Test.jsp?STR=" + str + "&NUM=11")
//수신
String str = reqeust.getParameter("STR");
String num = reqeust.getParameter("NUM");
|
=== include() ===
* 다른 웹 자원(JSP, Servlet, HTML, ...)를 호출하는 기능
* 호출된 웹 자원이 끝나고 나면 **실행 흐름의 제어가 본래의 웹 자원으로 돌아온다.**\\ ☞ 여러 웹 자원이 **공통으로 사용하는 코드**를 호출 할 때 사용.
<%
out.flush(); //출력 버퍼에서 JSP 코드 이전의 HTML 코드 제거.
RequestDispatcher dispatcher = request.getRequestDispatcher("ex.jsp"); //상대경로만 사용가능! 절대경로 불가능!
//request.setAttribute("NAME", new Integer(7)); //String, Object
dispatcher.include(request, response);
%>
==== include() vs include 지시자 ====
포함된 Web component가 별도의 Servlet class를 생성하는가?
|<15em 50%>|
^ include() ^ include 지시자 ^
| O | X((해당 코드를 호출하는 JSP 페이지의 Servlet class의 일부로 만든다.)) |
= get vs post =
입력된 데이터가 URL에
|< 10em 50% >|
^ get ^ post ^
| 공개 | 비공개 |
= Cookie vs Session =
* 3개 이상의 화면으로 구성된 애플리케이션을 작성할 경우, 서로간의 __**데이터 송수신**__ 처리를 위해 필요.
^ ^ Cookie ^ Session ^
^ 저장 위치 | Client | Server |
^ 저장 Type | String | Object |
^ 용량 제한 | 4KB, 한 Client(Domain) 당 20개 | 서버가 허용하는 한 용량, 개수 제한 없음 |
^ 단일 기록량 | 1 | 多 (☞ Hashtable 사용) |
== 적절한 사용 시점? ==
* **Cookie**
* 다른 언어나 Platform끼리 연동하여 Data 송수신을 할 경우
* **Session**
* Data 크기가 큰 경우
* ☞ 용량이 큰 Cookie를 내보내면 Network 부하를 증가 시키게 되지만 \\ Session은 Servlet이 수행되는 Server의 Memory 공간에 Data가 저장되므로 \\ Client에서 Network 부하는 단지 Session ID 정도만 사용하게 됨.
* 보안이 필요한 Data인 경우
* ☞ Server에 저장되므로
== 정의 ==
Web Component(JSP 페이지와 Servlet 클래스를 통칭)간의 __**데이터를 송수신**__이 가능케하는 기술.
* **Cookie** : 전달할 Data를 __**Web Browser로 보냈다가**__ 웹 서버 쪽으로 되돌려 받는 방법. (Client)
* Data 공유 범위 : 같은 웹 서버 내에 있는 모든 웹 컴포넌트들과 자바가 아닌 웹 애플리케이션 프로그램들 전체.
* **Session** : 전달할 실제 Data를 __**Web Browser를 거치지 않고**__ **Session ID만 보내어** **웹 서버에 있는 데이터 영역**을 통해 데이터를 전달하는 방법. (Server)\\ ☞ Web Browser(Client)로 Session ID를 전송하는 기술은 **Cookie!** (웹 브라우저로 세션아이디를 보낼 때 **JSSESSIONID**란 이름의 쿠키 형태로 만들어 전송한다.)\\ ☞ Cookie에 비해 보안성 높음.
* 여러 웹 컴포넌트들이 협력 작업을 시작해서 끝내기까지의 기간
* 보안상 중요한 데이터는 Session, 그렇지 않으면 Cookie 이용.
* Session Data를 전송하기 위해 사용하는 기술도 Cookie! (☞ 둘 다 알아야 한다!)
* Data 공유 범위 : 같은 웹 애플리케이션 디렉터리에 있는 웹 컴포넌트들
=== 탄생 배경 - 왜 두 기술로 나뉘었는가? ===
WWW 등장 초창기에는 인프라 구축이 덜 되어 대규모의 동시 사용자를 위한 웹앱의 중간 데이터를 서버 쪽에 저장해 두는 것이 어려웠기 때문에 **Cookie** 기술이 먼저 개발되었다. (= Client측에서 처리)
== Cookie 기술의 사용 방법 ==
=== 입력 & 수정 ===
<%@page contentType="text/html; charset=euc-kr" %>
//HTML 코드 명령문보다 앞에 오는 것이 바람직. (Buffer 때문)
<%
//두 Argument는 "String" Type! 수치값인 경우 String Data로 만들어야 한다!
//쿠키명 같으면 "수정(Set)".
response.addCookie(new Cookie("AGE", "20"));
%>
...
=== 조회 ===
<%@page contentType="text/html; charset=EUC-KR" %>
<%
Cookie[] cookies = request.getCookies(); //배열!
%>
Age : <%= getCookieValue(cookies, "AGE") %>
<%!
private String getCookieValue(Cookie[] cookies, String name) {
if(cookies == null)
return null;
for(Cookie cookie : cookies) {
if(cookie.getName().equals(name)) {
return cookie.getValue();
}
}
return null;
}
%>
=== 삭제 ===
<%@page contentType="text/html; charset=euc-kr" %>
<%
//초단위. 수명을 0로 하면 삭제된다.
//음수면 아래 메서드를 호출하지 않았을 때와 마찬가지로 "웹 브라우저가 끝날 때" 쿠키 제거
Cookie cookie = new Cookie("Key", ""); //삭제할 쿠키이므로 Value는 아무렇게나 상관없음.
cookie.setMaxAge(0);
response.addCookie(cookie)'
%>
...
=== 전송 범위 조정 ===
==== 쿠키가 특정 경로명을 갖는 URL로만 전송되도록 만드는 방법 (전송 범위 좁히기) ====
* 웹 브라우저는 웹 서버로 URL을 보낼 때, 그 웹 서버에 속하는 모든 쿠키를 함께 보내는 것이 기본 동작이지만, 이런 전송 범위를 좁혀야 할 경우가 있을 때 사용.
<%@page contentType="text/html; charset=euc-kr" %>
<%
Cookie cookie = new Cookie("Age", "20");
cookie.setPath("/local/"); //URL 경로명은 "반드시 /로 시작"해야하고, 마지막도 /로 끝내는 것을 권장.
response.addCookie(cookie);
%>
...
==== 쿠키가 여러 웹 서버로 전송되도록 만드는 방법 (전송 범위 넓히기) ====
* 웹 브라우저가 저장할 수 있는 쿠키의 수가 웹 서버별로 한정되어 있다. 남용시 데이터 손실되니 주의!
<%@page contentType="text/html; charset=euc-kr" %>
<%
Cookie cookie = new Cookie("Age", "20");
cookie.setDomain(".site.co.kr"); //대표 도메인 설정. "."로 시작해야 한다!
response.addCookie(cookie);
%>
...
== Session 기술의 사용 방법 ==
* Session의 적용 범위는 **같은** 웹 애플리케이션 **디렉토리** 내에 있는 **웹 컴포넌트(JSP, Servlet)**로 국한된다. (= 디렉토리별로 독립적, 같은 디렉토리 내 Java 웹 애플리케이션끼리만 공유 가능)
=== Servlet 클래스에서 세션 기술을 사용하는 방법 ===
HttpSession session = request.getSession(); //Session 시작/가져오기
session.setAttribute(String, Object); //데이터 저장
Object att = session.getAttribute(String); // 데이터 가져오기. 다른 타입은 Casting 필요.
session.removeAttribute(String); // 데이터 삭제
session.invalidate(); //세션 끝내기
int timeout = session.getMaxInactiveInterval(); //타임아웃 기간 반환
session.setMaxInactiveInterval(-1); //타임아웃 기간 설정.(초단위), 음수값이면 무한대
=== JSP 페이지에서 세션 기술을 사용하는 방법 ===
* Servlet 클래스로 변환될 때, **HttpSession session = request.getSession();**이 자동으로 추가되므로 session 변수를 그냥 이용하면 된다.
* Session을 사용하지 않으려면 **<%@page session="false" %>**를 지정하면 된다. 그러나 Session을 끝내는 기능까지 하는 것이 아니므로 **반드시** invalidate()를 호출해야 한다.
=== URL 재작성 메커니즘의 사용 방법 ===
* __**Cookie**를 사용할 수 없는 웹 환경에서 사용.__ (예를 들어 정책에 따른 차단)
* **"URL;jsessionid=SESSION_ID"** 형태를 이용하는 데, SESSION_ID를 얻기 위해서는 HttpSession의 getID()를 이용할 수 있지만 더 쉽게 doGet, doPost 메서드의 두 번째 Parameter **"response"**를 이용한다.
* "response.encodeURL()"은 지능적으로 작동.
* Parameter로 넘겨준 URL이 현재 웹 애플리케이션 디렉토리에 속하지 않을 경우, URL 재작성하지 않고 본래 URL 반환
* 웹 브라우저로부터 쿠키가 하나라도 있으면 쿠키를 사용할 수 있는 웹 환경이라고 판단하여 본래 URL 반환
* 상대적인 URL 경로 사용 가능. ("myHome/main.jsp")
* 웹 서버 내 URL 경로 사용 가능. ("/root/myHome/main.jsp")
<%
/* 반환 결과는 URL;jsessionid=SESSION_ID */
String url1 = response.encodeURL("http://localhost:8080/myHome/main.jsp");
String url2 = response.encodeRedirectURL("http://localhost:8080/myHome/main.jsp"); //sendRedirect()의 URL 재작성 기법. Redirect시 세션 유지
%>
= Exception 처리 =
일반적인 Java 프로그램의 try~catch를 이용하게 되면 HTML 코드와 섞여 난잡해진다. 이를 해결하기 위해 Exception 처리를 위한 웹 컴포넌트를 별도로 만들어 호출하면 된다.
== 여러 페이지 만들어서 호출 ==
* try~catch + [[#forward()]] ☞ Servlet에서는 page 지시자를 이용할 수 없기 때문에 이를 이용.
* page 지시자의 **errorPage**/**isErrorPage** Attribute **(☞ try~catch를 쓰지 않고 간결하게 처리 가능! (JSP만 가능))**
<%@page contentType-"text/html; charset=euc-kr" errorPage="Error.jsp" %>
<%@page contentType-"text/html; charset=euc-kr" isErrorPage="true" %>
<%@ response.setStatus(200); %> //200이면 정상적인 실행 결과, 500이면 에러 발생 결과. 항상 의도한대로 작동시키기 위해 200 설정.
<%= exception.getMessage() %> //isErrorPage 지시자를 이용하면 세부적인 Exception 메시지를 확인할 수 있다.
== web.xml 파일에 여러 페이지 등록하기 ==
웹 컴포넌트의 규모가 커질 경우 여러 페이지의 공통 Exception을 처리할 수 있으므로 효율적.
* page 지시자의 errorPage 사용하지 않아야 한다.
=== Exception Type별 ===
* "HTTP 상태 코드별" 처리보다 높은 **우선권**을 갖는다.
...
java.lang.NumberFormatException
/Error.jsp
...
//① doGet(), doPost() throws 선언
//② throws 할 수 있는 Exception이 한정되어 있기 때문에 SevletException으로 포장한다.
/* 던질 수 있는 Exception 종류
* java.io.IOException, java.servlet.ServletException, java.lang.ArithmeticException, java.lang.NumberFormatException
*/
try {~}
catch (java.sql.SQLExcption e) {
throw new ServletException(e);
}
=== HTTP 상태 코드별 ===
* 웹 컴포넌트의 실행과 상관없이, 웹 브라우저로부터 받은 **URL**에 해당하는 웹 자원이 **웹 서버에 없는 경우** 사용.
...
404
/Error.jsp
...
= Servlet의 Life Cycle =
== 똑같은 데이터, 로직, 결과를 갖는 코드를 한번만 실행하기 ==
=== Servlet 클래스의 init(), destory() ===
* Init()
Finabocci 수열 출력
import java.io.IOException;
import java.io.PrintWriter;
import java.math.BigInteger;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class Finabocci extends HttpServlet {
private BigInteger[] arr;
@Override
public void init() throws ServletException {
arr = new BigInteger[100];
arr[0] = new BigInteger("1");
arr[1] = new BigInteger("1");
for (int i = 2; i < arr.length ; i++) {
arr[i] = arr[i - 2].add(arr[i - 1]);
}
}
@Override
/*public void init(ServletConfig config) throws ServletException {
// 원리적으로
// Web container에서 Servlet을 초기화할 때 이 Method가 불리어진다.
// 그런데 내부적으로 Parameter가 없는 init이 불러오기 때문에
// Parameter가 없는 init으로 초기화가 가능하다.
// 주의점으로 이 메소드를 이용할 때는 반드시 부모 Class의 init을 호출해야 한다.
// 혹시나 부모 클래스를 재정의한 경우가 있을 수 있으므로...
super.init(config);
}*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String str = request.getParameter("NUM");
int num = Integer.parseInt(str);
if(num > 100)
num = 100;
response.setContentType("text/html; charset=UTF-8");
PrintWriter out = response.getWriter();
out.println("");
out.println("Fibonacci");
for(int i = 0; i < num ; i++) {
out.println(arr[i] + " ");
}
out.println("");
out.println("