부스트코스 강의를 듣고 정리한 내용.
Java Server Pages
JSP란?
간단한 JSP 실습
우선 1부터 10까지 계산하는 JSP 예제 파일을 작성해 보자.
http://localhost:8080/servlet-test/sum10.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<%
int total = 0;
for(int i = 1; i <= 10; i++) total += i;
%>
1부터 10까지의 합! <%=total %>
</body>
</html>
HTML가 비슷해 보이나 곳곳에 <%@ page
같은 기호들이 보일 것이다. 이것들을 지시자라고 한다.
JSP는 JSP 자체가 동작하는 것이 아니라 서블릿으로 바뀌어 동작한다. 지시자는 JSP가 서블릿으로 바뀔 때 “이렇게 바꿔주세요”라고 알려주는 역할을 한다고 보면 된다.
그럼 다시 예제로 돌아와서 코드 첫 줄을 보자.
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
page
지시자가 있는 page 지시문이고, language
속성은 이 JSP 파일 안에서 무슨 언어로 작성된 코드가 나올건지를 명시한다. 이론적으로 JSP는 내부적으로 자바 말고 다른 언어를 써도 된다고 하긴 하는데 자바를 쓴다. contentType
은 이 JSP 파일로 출력되는 결과를 받는 브라우저에게 컨텐츠의 타입을 알려준다. 마지막으로 pageEncoding
은 해당 JSP 파일의 인코딩 방식을 지정한다.
이런 지시를 듣는 것은 JSP를 실행하는 WAS라 생각하면 된다.
그런데 HTML 안에 굳이 코드를 넣는 이유는 이 HTML 페이지에서 코드를 실행시키고 싶기 때문이다. 이 부분은 scriptlet이라 부른다.
<%
int total = 0;
for(int i = 1; i <= 10; i++) total += i;
%>
scriptlet로 코드를 실행시킨 결과를 HTML로 가져올 때는 표현식이라는 것을 사용한다.
1부터 10까지의 합! <%=total %>
JSP가 서블릿으로 바뀔 때 어떻게 바뀔까 생각해면서 작성하는 것이 중요하다.
JSP 등장 배경
- MS사에서 ASP(Active Server Page)라는 쉽게 웹을 개발할 수 있는 스크립트 엔진 발표 (1998)
- 1997년에 발표된 서블릿은 ASP에 비해 개발 방식이 상대적으로 불편함
- ASP에 대항하기 위해 1999년 썬마이크로시스템즈에서 JSP 발표
- JSP는 실제로 서블릿 기술 사용
JSP Life Cycle
WAS는 웹브라우저로부터 JSP에 대한 요청을 받게 되면, JSP 코드를 서블릿 소스코드로 변환 후 컴파일해 실행한다. 서블릿으로 컴파일되어 실행될 때, 상황에 따라 어떤 메소드들이 실행되는지 잘 알아야 JSP를 알맞게 작성할 수 있다.
위의 sum10.jsp가 최초로 실행하게 되면 특별한 형태의 서블릿으로 소스가 변환된다. 우리는 톰캣을 사용하니까 톰캣이 JSP를 서블릿으로 바꿔주는데, 어떻게 바꿔주는지 알아보자.
우선 파일 탐색기를 열어 workspace로 이동한 다음 .metadata > .plugins > org.eclipse.wst.server.core > tmp0 > wtpwebapps로 이동하면 프로젝트 이름과 같은 폴더들이 들어있을 것이다. 여기서 servlet-test 디렉토리를 클릭하면 sum10.jsp 파일이 있고, 이 jsp 파일이 서블릿으로 바뀐 코드는 work 디렉토리 안의 servlet-test 폴더에 들어있다.
C:\Users\user\eclipse-workspace\.metadata\.plugins\org.eclipse.wst.server.core\tmp0\work\Catalina\localhost\servlet-test\org\apache\jsp
sum10_jsp.class
sum10_jsp.java
sum10_jsp.java를 열어보자.
/*
* Generated by the Jasper component of Apache Tomcat
* Version: Apache Tomcat/9.0.16
...
*/
package org.apache.jsp;
import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.jsp.*;
public final class sum10_jsp extends org.apache.jasper.runtime.HttpJspBase
implements org.apache.jasper.runtime.JspSourceDependent,
org.apache.jasper.runtime.JspSourceImports {
...
public void _jspInit() { }
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 {
...
try {
response.setContentType("text/html; charset=UTF-8");
...
out.write("\r\n");
out.write("<!DOCTYPE html>\r\n");
out.write("<html>\r\n");
out.write("<head>\r\n");
out.write("<meta charset=\"UTF-8\">\r\n");
out.write("<title>Insert title here</title>\r\n");
out.write("</head>\r\n");
out.write("<body>\r\n");
int total = 0;
for(int i = 1; i <= 10; i++) total += i;
out.write("\r\n");
out.write("\r\n");
out.write("1부터 10까지의 합! ");
out.print(total );
out.write("\r\n");
out.write("</body>\r\n");
out.write("</html>");
} catch (java.lang.Throwable t) {
...
}
} finally {
_jspxFactory.releasePageContext(_jspx_page_context);
}
}
}
중간에 public void _jspService()
라는 메소드가 있는데, 서블릿의 init
, service
, destroy
역할을 하는 메소드라 생각하면 된다.
우리가 만드는 코드는 기본적으로 Service라는 메소드 안에 그래도 만들어진다. JSP가 서블릿으로 만들 때, 자바 코드로 만들 때 ㄹ알아서 만들어놓는 객체들이 있는데 이를 내장 객체라 부른다.
public void _jspService()를 보면
out.write("\r\n");
out.write("<!DOCTYPE html>\r\n");
out.write("<html>\r\n");
out.write("<head>\r\n");
out.write("<meta charset=\"UTF-8\">\r\n");
out.write("<title>Insert title here</title>\r\n");
out.write("</head>\r\n");
out.write("<body>\r\n");
int total = 0;
for(int i = 1; i <= 10; i++) total += i;
out.write("\r\n");
out.write("\r\n");
out.write("1부터 10까지의 합! ");
out.print(total );
out.write("\r\n");
out.write("</body>\r\n");
out.write("</html>");
진짜 내가 작성한 코드를 자바로 옮겨온 것을 확인할 수 있다. 신기해 ㅋㅋㅋㅋ
sum10.jsp가 실행될 때 벌어지는 일
- eclipse workspace 아래의 .metadata 폴더에 sum10_jsp.java 파일이 생성된다.
- 해당 파일의 _jspService() 메소드 안을 살펴보면 jsp 파일의 내용이 변환돼 들어가 있는 것을 확인할 수 있다.
- sum10_jsp.java는 서블릿 소스로 자동으로 컴파일되면서 실행돼 그 결과가 브라우저에 보여진다.
JSP 실행 순서
- 브라우저가 웹서버에게 JSP에 대한 요청 정보를 전달한다.
- 이때 서버는 이 JSP에 해당되는 서블릿이 존재하는지를 체크한다. 만약 존재하지 않으면 최초로 요청한 거임
- 브라우저가 요청한 JSP가 최초로 요청한 경우
- JSP로 작성된 코드가 서블릿 코드로 변환된다. (java 파일 생성)
- 서블릿 코드를 컴파일해 실행 가능한 bytecode로 변환한다. (class 파일 생성)
- 서블릿 클래스를 로딩하고 인스턴스를 생성한다.
- 서블릿이 실행돼 요청을 처리하고 응답 정보를 생성한다.
그럼 init할 때만 실행되는 코드를 작성하고 싶을 때는 어떻게 하면 좋을까?
%!
라는 선언식을 사용하면 이 클래스에 메소드나 필드를 선언할 때 넣어주면 service 메소드 내에 만들어지는게 아니라 메소드 바깥쪽에 할 수 있다. 이를 응용해 init()과 destroy()를 내가 직접 작성해 주면 됨.
<%!
public void jspInit() {
System.out.println("jspInit()");
}
%>
<%!
public void jspDestroy() {
System.out.println("jspDestroy()");
}
%>
JSP 문법
스크립트 요소의 이해
JSP 페이지에는 선언문, 스크립트릿, 표현식이라는 세가지 스크립트 요소 제공
- 선언문 (Declaration)
<%! %>
- 전역변수 선언 및 메소드 선언에 사용
- 스크립트릿 (Scriptlet)
<% %>
- 프로그래밍 코드 기술에 사용
- 표현식
<%=%>
- 화면에 출력할 내용 기술에 사용
- 응답 결과에 포함할 부분을 넣을 때 사용하는 부분
선언문 (Declaration)
<%! 문장 %>
- JSP 페이지 내에서 필요한 멤버변수나 메소드가 필요할 때 선언해 사용하는 요소
- 선언문을 사용하면 서비스 메소드가 아니라 클래스 바디 쪽에 해당 코드가 바뀌는 것을 볼 수 있다.
id를 출력해주는 예제를 작성해보자.
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
id: <%=getId() %>
<%!
String id = "u001"; // 멤버변수 선언
public String getId() { // 메소드 선언
return id;
}
%>
</body>
</html>
참고로 JSP 파일 안에서 선언문의 위치는 중요하지 않다. body 안에만 있으면 되는 듯?
변환된 자바 파일을 열어보면
...
public final class exam1_jsp extends org.apache.jasper.runtime.HttpJspBase
implements org.apache.jasper.runtime.JspSourceDependent,
org.apache.jasper.runtime.JspSourceImports {
String id = "u001"; // 멤버변수 선언
public String getId() { // 메소드 선언
return id;
}
...
처럼 클래스 바디에 해당 코드가 작성되었음을 확인할 수 있다.
스크립트릿 (Scriptlet)
<% 문장 %>
- 가장 일반적으로 많이 쓰이는 스크립트 요소
- 주로 프로그래밍의 로직을 기술할 때 사용
- 스크립트릿에서 선언된 변수는 지역변수. 모두 service 메소드 안에 선언된다.
그런데 스크립트릿 안의 값은 응답 결과에 포함되지 않는데, 만약 스크립트릿 안에서 html을 조작하고 싶다면 어떻게 할까?
스크립트릿을 쪼개 작성하면 된다.
<%
for(int i = 1; i <= 6; i++) {
%>
<H<%=i%>>점점 작아지는 폰트 사이즈</H<%=i%>>
<%
}
%>
이렇게 응용하면 태그가 동적으로 만들어져 추가된다! +_+
표현식 (Expression)
<%=a문장%>
- JSP 페이지에서 웹 브라우저에게 출력할 부분을 표현
- 화면에 출력하기 위한 것
- 스크립트릿 내에서 출력할 부분은 내장 객체인 out 객체의 print() 또는 println() 메소드를 사용해 출력
주석
- JSP에서 사용할 수 있는 주석: HTML 주석, 자바 주석, JSP 주석
- HTML 주석
<!--
로 시작해-->
로 끝나는 형태
- JSP 주석
<%--
로 시작해--%>
로 끝나는 형태- JSP 페이지에서만 사용됨
- 해당 페이지를 웹 브라우저를 통해 출력 결과로서 표시하거나 웹 브라우저 상에서 소스 보기를 해도 표시되지 않음. 또한 JSP 주석 내에 실행코드를 넣어도 그 코드는 실행되지 않음
- 자바 주석
//
,/**/
을 사용- 자바와 주석 처리 방법 같음
HTML, JSP, 자바 주석을 넣어 실행시키고
<body>
<%--JSP 주석
여거 줄로 사용 가능
--%>
<!-- HTML 주석 -->
<%
// 자바 주석
/*
여러 줄도 가능
*/
%>
<%
for(int i = 1; i <= 6; i++) {
%>
<H<%=i%>>점점 작아지는 폰트 사이즈</H<%=i%>>
<%
}
%>
</body>
소스를 뜯어보면 HTML은 화면에 출력되는 것을 볼 수 있다.
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<!-- HTML 주석 -->
<H1>점점 작아지는 폰트 사이즈</H1>
<H2>점점 작아지는 폰트 사이즈</H2>
<H3>점점 작아지는 폰트 사이즈</H3>
<H4>점점 작아지는 폰트 사이즈</H4>
<H5>점점 작아지는 폰트 사이즈</H5>
<H6>점점 작아지는 폰트 사이즈</H6>
</body>
</html>
자바 주석은 자바 파일에서 확인 가능하다.
out.write("\r\n");
out.write("<!DOCTYPE html>\r\n");
out.write("<html>\r\n");
out.write("<head>\r\n");
out.write("<meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\">\r\n");
out.write("<title>Insert title here</title>\r\n");
out.write("</head>\r\n");
out.write("<body>\r\n");
out.write("\r\n");
out.write("<!-- HTML 주석 -->\r\n");
// 자바 주석
/*
여러 줄도 가능
*/
...
out.write('\r');
out.write('\n');
for(int i = 1; i <= 6; i++) {
out.write("\r\n");
out.write("<H");
out.print(i);
out.write(">점점 작아지는 폰트 사이즈</H");
out.print(i);
out.write('>');
out.write('\r');
out.write('\n');
}
out.write("\r\n");
out.write("</body>\r\n");
out.write("</html>");
반면 JSP 주석은 볼 수 없다.
JSP 내장 객체
JSP 내장객체란?
- JSP를 실행하면 서블릿 소스가 생성되고 실행된다.
- JSP에 입력한 대부분의 코드는 생성되는 서블릿 소스의 _jspService() 메소드 안에 삽입되는 코드로 생성된다.
- _jspService()에 삽입된 코드의 윗부분에 미리 선언된 객체들이 있는데, 해당 객체들은 JSP에서도 사용 가능하다.
- response, request, application, session, out과 같은 변수를 내장 객체라 한다.
response.setContentType("text/html; charset=UTF-8");
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;
내장 객체의 종류
내장 객체를 사용해 본 코드. JSP는 이런 내장 객체들이 있으니까 필요에 따라서 갖다 쓰면 된다는 정도 기억하기
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<%
StringBuffer url = request.getRequestURL();
out.print("url: " + url);
%>
</body>
</html>