초보자를 위한 JSP 예제 튜토리얼에 오신 것을 환영합니다. 지난 몇 개의 게시물에서, 저는 Java Servlet에 대해 많이 썼고 독자들로부터 아주 좋은 반응을 받았습니다. 그래서 저는 JSP 튜토리얼에 대한 또 다른 시리즈를 시작했으며, 이것은 시리즈의 첫 번째 게시물입니다.
JSP 예제 튜토리얼
이 JSP 예제 튜토리얼에서는 JSP의 기본 개념, Servlet에 비해 JSP의 장점, JSP의 라이프 사이클, JSP API 인터페이스 및 클래스, 그리고 JSP 파일을 웹 애플리케이션에 어디에 둘 수 있는지에 대해 알아볼 것입니다. 또한 JSP 주석, 스크립틀, 디렉티브, 표현식, 선언 및 JSP 속성에 대해서도 간략히 살펴볼 것입니다. 이 중 일부 주제는 매우 중요하며, 향후 게시물에서 더 자세히 다룰 것입니다.
JSP 튜토리얼
- JSP란 무엇이며 왜 필요한가요?
- Servlet에 비해 JSP의 장점은 무엇인가요?
- JSP 페이지의 라이프 사이클
- JSP의 라이프 사이클 메서드
- 일반적인 JSP 예제(이클립스 및 톰캣과 함께)
- 웹 응용 프로그램 WAR 파일 내의 JSP 파일 위치
- JSP API 인터페이스 및 클래스
- JspPage 인터페이스
- HttpJspPage 인터페이스
- JspWriter 추상 클래스
- JspContext 추상 클래스
- PageContext 추상 클래스
- JspFactory 추상 클래스
- JspEngineInfo 추상 클래스
- ErrorData 최종 클래스
- JspException 클래스
- JspTagException 클래스
- SkipPageException 클래스
-
JSP란 무엇이며 왜 JSP가 필요한가요?
JSP (JavaServer Pages)는 동적 자바 웹 애플리케이션을 생성하기 위한 서버 측 기술입니다. JSP는 사용자 뷰를 쉽게 생성할 수 있도록 기능을 제공하기 때문에 서블릿 기술의 확장으로 볼 수 있습니다. JSP 페이지는 HTML 코드로 구성되어 있으며 동적 콘텐츠를 위한 자바 코드를 포함할 수 있는 옵션을 제공합니다. 웹 애플리케이션에는 많은 사용자 화면이 포함되어 있기 때문에 JSP가 웹 애플리케이션에서 많이 사용됩니다. JSP에서 자바 코드와 HTML 간의 간격을 줄이기 위해 JSP 태그, 표현 언어, 사용자 지정 태그와 같은 추가 기능을 제공합니다. 이로써 이해하기 쉬워지며 웹 개발자가 빠르게 JSP 페이지를 개발할 수 있습니다.
-
JSP가 Servlet에 비해 장점?
- 우리는 서블릿에서도 HTML 응답을 생성할 수 있지만, 복잡한 HTML 응답을 작성하는 과정은 다소 번거롭고 오류가 발생하기 쉽습니다. 서블릿에서 복잡한 HTML 응답을 작성하는 것은 악몽이 될 것입니다. JSP는 이러한 상황에서 도움을 주며, 필요한 곳에만 자바 코드를 포함하여 일반 HTML 페이지를 작성할 수 있는 유연성을 제공합니다.
- JSP는 태그 라이브러리, 표현 언어, 사용자 지정 태그 등 추가 기능을 제공하여 사용자 뷰의 빠른 개발에 도움이 됩니다.
- JSP 페이지를 배포하기 쉽습니다. 수정된 페이지를 서버에 바꾸기만 하면 컨테이너가 배포를 처리합니다. 반면에 서블릿은 전체 프로젝트를 다시 컴파일하고 배포해야 합니다. 사실 서블릿과 JSP는 서로 보완적입니다. 서블릿은 서버 측 컨트롤러로 사용하고 모델 클래스와 통신하기 위해 사용하고, JSP는 프레젠테이션 계층에 사용해야 합니다.
-
JSP 페이지의 라이프 사이클
JSP 라이프 사이클은 컨테이너에 의해 관리됩니다. 보통 서블릿 컨테이너를 포함하는 모든 웹 컨테이너에는 JSP 페이지를 관리하기 위한 JSP 컨테이너도 포함되어 있습니다. JSP 페이지의 라이프 사이클 단계는 다음과 같습니다:
- 번역 – JSP 페이지는 일반적인 자바 클래스와 같지 않습니다. 실제로 JSP 컨테이너는 JSP 페이지를 구문 분석하고 해당하는 서블릿 소스 코드를 생성하기 위해 번역합니다. JSP 파일 이름이 home.jsp인 경우, 일반적으로 home_jsp.java로 명명됩니다.
- 컴파일 – 번역이 성공하면 컨테이너가 생성된 서블릿 소스 파일을 컴파일하여 클래스 파일을 생성합니다.
- 클래스 로딩 – JSP가 서블릿 클래스로 컴파일되면 그 라이프 사이클은 서블릿과 유사하며 메모리에 로드됩니다.
- 인스턴스 생성 – JSP 클래스가 메모리에 로드되면 컨테이너에 의해 해당 객체가 인스턴스화됩니다.
- 초기화 – 그런 다음 JSP 클래스가 초기화되어 일반 클래스에서 서블릿으로 변환됩니다. 초기화 후에는 ServletConfig 및 ServletContext 객체가 JSP 클래스에서 액세스할 수 있게 됩니다.
- 요청 처리 – 각 클라이언트 요청마다 ServletRequest 및 ServletResponse와 함께 새로운 스레드가 생성되어 HTML 응답을 처리하고 생성합니다.
- 소멸 – JSP 라이프 사이클의 마지막 단계로, 메모리에서 언로드됩니다.
-
JSP의 라이프사이클 메서드
JSP 라이프사이클 메서드는 다음과 같습니다:
- jspInit()는 JspPage 인터페이스에 선언됩니다. 이 메서드는 JSP 라이프사이클에서 구성 매개변수를 초기화하기 위해 한 번만 호출됩니다.
- _jspService(HttpServletRequest request, HttpServletResponse response)는 HttpJspPage 인터페이스에 선언되며 클라이언트 요청을 처리하는 응답을 합니다.
- jspDestroy()는 JspPage 인터페이스에 선언됩니다. 이 메서드는 JSP를 메모리에서 언로드합니다.
-
이클립스 및 톰캣을 사용한 간단한 JSP 예제
We can use Eclipse IDE for building dynamic web project with JSPs and use Tomcat to run it. Please read [Java Web Applications](/community/tutorials/java-web-application-tutorial-for-beginners#first-web-app-servlet) tutorial to learn how can we easily create JSPs in Eclipse and run it in tomcat. A simple JSP example page example is: `home.jsp`
```
<%@ page language="java" contentType="text/html; charset=US-ASCII"
pageEncoding="US-ASCII"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "https://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=US-ASCII">
<title>First JSP</title>
</head>
<%@ page import="java.util.Date" %>
<body>
<h3>Hi Pankaj</h3><br>
<strong>Current Time is</strong>: <%=new Date() %>
</body>
</html>
```
If you have a simple JSP that uses only JRE classes, we are not required to put it as WAR file. Just create a directory in the tomcat webapps folder and place your JSP file in the newly created directory. For example, if your JSP is located at apache-`tomcat/webapps/test/home.jsp`, then you can access it in browser with URL `https://localhost:8080/test/home.jsp`. If your host and port is different, then you need to make changes in URL accordingly.
We can place JSP files at any location in the WAR file, however if we put it inside the WEB-INF directory, we wont be able to access it directly from client. We can configure JSP just like servlets in web.xml, for example if I have a JSP example page like below inside WEB-INF directory: `test.jsp`
```
<%@ page language="java" contentType="text/html; charset=US-ASCII"
pageEncoding="US-ASCII"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "https://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=US-ASCII">
<title>Test JSP</title>
</head>
<body>
Test JSP Page inside WEB-INF folder.<br>
Init Param "test" value =<%=config.getInitParameter("test") %><br>
HashCode of this object=<%=this.hashCode() %>
</body>
</html>
```
And I configure it in web.xml configuration as:
```
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance" xmlns="https://java.sun.com/xml/ns/javaee" xsi:schemaLocation="https://java.sun.com/xml/ns/javaee https://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" version="3.0">
<display-name>FirstJSP</display-name>
<servlet>
<servlet-name>Test</servlet-name>
<jsp-file>/WEB-INF/test.jsp</jsp-file>
<init-param>
<param-name>test</param-name>
<param-value>Test Value</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>Test</servlet-name>
<url-pattern>/Test.do</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>Test1</servlet-name>
<jsp-file>/WEB-INF/test.jsp</jsp-file>
</servlet>
<servlet-mapping>
<servlet-name>Test1</servlet-name>
<url-pattern>/Test1.do</url-pattern>
</servlet-mapping>
</web-app>
```
Then I can access it with both the URLs https://localhost:8080/FirstJSP/Test.do and https://localhost:8080/FirstJSP/Test1.do Notice that container will create two instances in this case and both will have their own servlet config objects, you can confirm this by visiting these URLs in browser. For Test.do URI, you will get response like below.
```
Test JSP Page inside WEB-INF folder.
Init Param "test" value =Test Value
HashCode of this object=1839060256
```
For Test1.do URI, you will get response like below.
```
Test JSP Page inside WEB-INF folder.
Init Param "test" value =null
HashCode of this object=38139054
```
Notice the init param value in second case is null because it's not defined for the second servlet, also notice the hashcode is different. If you will make further requests, the hashcode value will not change because the requests are processed by spawning a new thread by the container. Did you noticed the use of **config** variable in above JSP example but there is no variable declared, it's because its one of the 9 implicit objects available in JSP page, read more about them at [**JSP Implicit Objects**](/community/tutorials/jsp-implicit-objects "JSP Implicit Objects with Examples").
All the core JSP interfaces and classes are defined in `javax.servlet.jsp` package. Expression Language API interfaces are classes are part of `javax.servlet.jsp.el` package. JSP Tag Libraries interfaces and classes are defined in `javax.servlet.jsp.tagext` package. Here we will look into interfaces and classes of Core JSP API.
-
JspPage 인터페이스
JspPage 인터페이스는 Servlet 인터페이스를 확장하고 JSP 페이지의 jspInit() 및 jspDestroy() 라이프사이클 메서드를 선언합니다.
-
HttpJspPage 인터페이스
HttpJspPage 인터페이스는 HTTP 프로토콜을 사용할 때 JSP 페이지 구현 클래스가 만족해야 하는 상호작용을 설명합니다. 이 인터페이스는 JSP 페이지의 HTTP 프로토콜을 위한 서비스 메서드를 다음과 같이 선언합니다: public void _jspService(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException.
-
JspWriter 추상 클래스
서블릿의 PrintWriter와 유사하지만 버퍼링 지원 기능이 추가된 클래스입니다. 이는 JSP 페이지의 암시적 변수 중 하나로 “out”이라는 이름으로 사용됩니다. 이 클래스는 java.io.Writer를 확장하며 컨테이너는 이 추상 클래스에 대한 자체 구현을 제공하고 JSP 페이지를 서블릿으로 변환하는 동안 사용합니다. PageContext.getOut() 메서드를 사용하여 이 객체를 가져올 수 있습니다. JspWriter의 Apache Tomcat 구체 클래스는
org.apache.jasper.runtime.JspWriterImpl
입니다. -
JspContext 추상 클래스
JspContext는 PageContext 클래스의 기본 클래스로 작동하며 서블릿과 관련이 없는 모든 정보를 추상화합니다. JspContext는 출력용 JspWriter를 얻는 메커니즘, 속성과 작업을 수행하는 메커니즘, 다양한 범위의 네임스페이스를 관리하기위한 API를 제공합니다.
-
PageContext 추상 클래스
PageContext는 웹 애플리케이션에서 JSP를 사용할 때 유용한 컨텍스트 정보를 제공하기 위해 JspContext를 확장합니다. PageContext 인스턴스는 JSP 페이지와 관련된 모든 네임스페이스에 액세스하고, 여러 페이지 속성에 액세스할 수 있으며, 구현 세부 정보 위에 레이어를 제공합니다. 암시적 객체가 자동으로 pageContext에 추가됩니다.
-
JspFactory abstract Class
JspFactory는 JSP 페이지에서 런타임에 사용되는 여러 인터페이스 및 클래스의 인스턴스를 생성하기 위한 목적으로 정의된 추상 클래스입니다.
-
JspEngineInfo abstract Class
JspEngineInfo는 현재 JSP 엔진에 대한 정보를 제공하는 추상 클래스입니다.
-
ErrorData final Class
오류 페이지에 대한 오류에 대한 정보를 포함합니다.
-
JspException Class
JSP 컨테이너에서 알려진 일반적인 예외로서, ServletException과 유사합니다. JSP 페이지가 JspException을 throw하면 오류 페이지 메커니즘이 사용되어 사용자에게 오류 정보가 표시됩니다.
-
JspTagException 클래스
Tag Handler에서 일부 회복할 수 없는 오류를 나타내기 위해 사용되는 예외입니다.
-
SkipPageException 클래스
호출 페이지의 평가를 중지해야 함을 나타내는 예외입니다. 페이지의 나머지 부분을 평가해서는 안 됩니다. 간단한 태그 핸들러에 의해 발생하여 JSP 페이지에서 수동으로 throw되어서는 안 됩니다.
Since JSP is built on top of HTML, we can write comments in JSP file like html comments as `<-- This is HTML Comment -->` These comments are sent to the client and we can look it with view source option of browsers. We can put comments in JSP files as: `<%-- This is JSP Comment--%>` This comment is suitable for developers to provide code level comments because these are not sent in the client response.
Scriptlet tags are the easiest way to put java code in a JSP page. A scriptlet tag starts with `<%` and ends with `%>`. Any code written inside the scriptlet tags go into the `_jspService()` method. For example:
```
<%
Date d = new Date();
System.out.println("Current Date="+d);
%>
```
Since most of the times we print dynamic data in JSP page using _out.print()_ method, there is a shortcut to do this through JSP Expressions. JSP Expression starts with `<%=` and ends with `%>`. `<% out.print("Pankaj"); %>` can be written using JSP Expression as `<%= "Pankaj" %>` Notice that anything between `<%= %>` is sent as parameter to `out.print()` method. Also notice that scriptlets can contain multiple java statements and always ends with semicolon (;) but expression doesn't end with semicolon.
JSP Directives are used to give special instructions to the container while JSP page is getting translated to servlet source code. JSP directives starts with `<%@` and ends with `%>` For example, in above JSP Example, I am using _page_ directive to to instruct container JSP translator to import the Date class.
JSP Declarations are used to declare member methods and variables of servlet class. JSP Declarations starts with `<%!` and ends with `%>`. For example we can create an int variable in JSP at class level as `<%! public static int count=0; %>`
Once JSP files are translated to Servlet source code, the source code (.java) and compiled classes both are place in **Tomcat/work/Catalina/localhost/FirstJSP/org/apache/jsp** directory. If the JSP files are inside other directories of application, the directory structure is maintained. For JSPs inside WEB-INF directory, its source and class files are inside **Tomcat/work/Catalina/localhost/FirstJSP/org/apache/jsp/WEB\_002dINF** directory. Here is the source code generated for above test.jsp page. `test_jsp.java`
```
/*
* Generated by the Jasper component of Apache Tomcat
* Version: Apache Tomcat/7.0.32
* Generated at: 2013-08-21 03:40:59 UTC
* Note: The last modified time of this file was set to
* the last modified time of the source file after
* generation to assist with modification tracking.
*/
package org.apache.jsp.WEB_002dINF;
import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.jsp.*;
public final class test_jsp extends org.apache.jasper.runtime.HttpJspBase
implements org.apache.jasper.runtime.JspSourceDependent {
private static final javax.servlet.jsp.JspFactory _jspxFactory =
javax.servlet.jsp.JspFactory.getDefaultFactory();
private static java.util.Map<java.lang.String,java.lang.Long> _jspx_dependants;
private javax.el.ExpressionFactory _el_expressionfactory;
private org.apache.tomcat.InstanceManager _jsp_instancemanager;
public java.util.Map<java.lang.String,java.lang.Long> getDependants() {
return _jspx_dependants;
}
public void _jspInit() {
_el_expressionfactory = _jspxFactory.getJspApplicationContext(getServletConfig().getServletContext()).getExpressionFactory();
_jsp_instancemanager = org.apache.jasper.runtime.InstanceManagerFactory.getInstanceManager(getServletConfig());
}
public void _jspDestroy() {
}
public void _jspService(final javax.servlet.http.HttpServletRequest request, final javax.servlet.http.HttpServletResponse response)
throws java.io.IOException, javax.servlet.ServletException {
final javax.servlet.jsp.PageContext pageContext;
javax.servlet.http.HttpSession session = null;
final javax.servlet.ServletContext application;
final javax.servlet.ServletConfig config;
javax.servlet.jsp.JspWriter out = null;
final java.lang.Object page = this;
javax.servlet.jsp.JspWriter _jspx_out = null;
javax.servlet.jsp.PageContext _jspx_page_context = null;
try {
response.setContentType("text/html; charset=US-ASCII");
pageContext = _jspxFactory.getPageContext(this, request, response,
null, true, 8192, true);
_jspx_page_context = pageContext;
application = pageContext.getServletContext();
config = pageContext.getServletConfig();
session = pageContext.getSession();
out = pageContext.getOut();
_jspx_out = out;
out.write("\n");
out.write("<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" \"https://www.w3.org/TR/html4/loose.dtd\">\n");
out.write("<html>\n");
out.write("<head>\n");
out.write("<meta http-equiv=\"Content-Type\" content=\"text/html; charset=US-ASCII\">\n");
out.write("<title>Test JSP</title>\n");
out.write("</head>\n");
out.write("<body>\n");
out.write("Test JSP Page inside WEB-INF folder.<br>\n");
out.write("Init Param \"test\" value =");
out.print(config.getInitParameter("test") );
out.write("<br>\n");
out.write("HashCode of this object=");
out.print(this.hashCode() );
out.write("\n");
out.write("</body>\n");
out.write("</html>");
} catch (java.lang.Throwable t) {
if (!(t instanceof javax.servlet.jsp.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);
else throw new ServletException(t);
}
} finally {
_jspxFactory.releasePageContext(_jspx_page_context);
}
}
}
```
Notice following points in above servlet code;
- The package of class starts with org.apache.jsp and if JSPs are inside other folders, it includes directory hierarchy too. Usually we dont care about it.
- The generates servlet class is final and can't be extended.
- It extends `org.apache.jasper.runtime.HttpJspBase` that is similar to HttpServlet except that it's internal to Tomcat JSP Translator implementation. HttpJspBase extends HttpServlet and implements HttpJspPage interface.
- Notice the local variables at the start of \_jspService() method implementation, they are automatically added by JSP translator and available for use in service methods, i.e in scriptlets.As a java programmer, sometimes it helps to look into the generated source for debugging purposes.
We can define init parameters for the JSP page as shown in above example and we can retrieve them in JSP using **config** implicit object, we will look into implicit objects in JSP in more detail in future posts.
We can override JSP init method for creating resources to be used by JSP service() method using JSP Declaration tags, we can override jspInit() and jspDestroy() or any other methods also. However we should never override \_jspService() method because anything we write in JSP goes into service method.
Apart from standard servlet attributes with request, session and context scope, in JSP we have another scope for attributes, i.e Page Scope that we can get from pageContext object. We will look it's importance in custom tags tutorial. For normal JSP programming, we don't need to worry about page scope.
그것은 초보자를 위한 JSP 예제 튜토리얼입니다. JSP의 기본 개념을 이해하고 시작하는 데 도움이 되기를 바랍니다. 우리는 앞으로 다른 JSP 기능을 살펴볼 것입니다.
Source:
https://www.digitalocean.com/community/tutorials/jsp-example-tutorial-for-beginners