본문 바로가기

JSP

[JSP] 내부객체

내부 객체(Implicit Object)

  • 자바 클래스 또는 인터페이스의 형태로 JSP 컨테이너 내에 이미 인스턴스화 된 상태로 제공된다.
  • JSP페이지 작성시 해당 객체를 이용해 동적으로 페이지를 작성할 수 있다.
  • JSP Script, Directive, Action Tag등과 같은 JSP의 문법 요소들과 함께 동작해 사용자의 요청을 적절히 처리할 수 있다.
  • 서블릿의 _jspService()메서드 안에서 선언되기 때문에 선언문(<%! ... %>)내에서는 사용할 수 없다.

내부 객체의 사용 범주에 따른 분류

  • 입출력 관련 객체
    • request, response, out
  • 외부 환경 정보 제공 객체
    • session. application, pageContext
  • 서블릿 관련 객체
    • page, config
  • 예외 관련 객체
    • exception

pageContext , request, session, application 객체

  • 임의 속성 값(attribute)을 저장하고 읽을 수 있는 메서드를 제공한다.
  • 속성 값을 저장하고 읽을 수 있는 기능은 JSP페이지간 또는 서블릿 간에 정보를 주고받을 수 있게 해준다.

입출력 관련 객체

  • JSP페이지의 입출력과 관련한 내부 객체
  • 클라이언트로부터 JSP 페이지의 호출에 의해서 전달되는 데이터의 요청과 응답 그리고 출력을 담당한다.
클래스 객체 설명
HttpServletRequest request 클라이언트에서 JSP페이지로 전달되는 데이터의 묶음

HTTP 헤더와 HTTP 바디로 구성되어 있다.

JSP컨테이너는 요청된 HTTP 메서드와 해당 내부객체를 이용해 전달된 데이터를 사용할 수 있다.

여러가지 요청에 대한 정보를 제공하는 메서드를 제공하며, 폼 태그로부터 넘어오는 요청정보를 분석할 수 있는 기능또한 지원한다.

웹 브라우저와 웹 서버의 정보를 가져오기 위해 사용되기도 한다.
HttpServletResponse response 요청을 시도한 클라이언트로 전송할 응답을 나타내는 데이터 묶음
JspWriter out JSP페이지의 결과를 클라이언트에게 전송해주는 출력 스트림

java.io.Writer 클래스를 상속받았다.

표현식 <%= %>는 서블릿 변환시 내부객체인 out.print()로 변환이 되어 실행되므로, 이 둘은 똑같은 역할을 한다. 단지 개발자의 편의성을 위해 내부객체를 표현식을 통해 사용할 수 있을 뿐이다.

버퍼를 사용하기 때문에 flush되기 이전에는 화면에 출력되지 않는다. 때문에 printWriter와 함께 사용시 오차가 발생할 수 있다.

request 예제1

  • form태그를 통해 request.jsp 페이지에 새 요청을 보낸다.
  • 이때 form태그 내부에 name속성은 서버로 제출된 form data를 참조하기 위해 사용된다.
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
	<h1>Request Example1</h1>
	<form action="request.jsp" method="post">
		<div>이름 : <input type="text" name="name"></div>
		<div>학번 : <input type="text" name="studentnum"></div>
		<div>
			<span>성별 : </span>
			<label for="man">남자 : </label>
			<input type="radio" name="gender" value="man" id="man">
			<label for="woman">여자 : </label>
			<input type="radio" name="gender" value="woman" id="man">
		</div>
		<div>
			<span>전공 : </span>
			<select name="major" multiple>
				<option value="국문학과" selected>국문학과</option>
				<option value="영문학과" selected>영문학과</option>
				<option value="수학학과" selected>수학학과</option>
				<option value="정치학과" selected>정치학과</option>
				<option value="체육학과" selected>체육학과</option>
			</select>
		</div>
		<input type="submit" value="보내기">
	</form>
	
</body>
</html>
  • form의 actaion속성으로 이동된 jsp페이지
  • request의 setCharacterEncoding("Enctype") 메서드는 Form data전송시 HTTP POST 방식으로 데이터가 전송된경우, 해당 데이터의 인코딩 타입을 설정하기 위해 사용된다.
  • request의 getParameter("name") 메서드를 사용해, 서버로 전송된 form data를 참조할 수 있으며, 이때 인자로 사용되는 name은 form data전송시 각 태그에 설정한 name태그와 동일하다.
  • request의 getParameterValues("name") 메서드는 서버로 전송된 동일한 name을 갖는 form data를 배열형식으로 가져온다.
  • request의 getParameterNames()는 해당 JSP로 넘어온 모든 데이터의 ''name"을 Enumeration객체로 반환한다.
<%@page import="java.util.Enumeration"%>
<%@ 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>
<%
	request.setCharacterEncoding("UTF-8");
	String name = request.getParameter("name");
	String studentNum = request.getParameter("studentnum");
	String gender = request.getParameter("gender");
	String[] majors = request.getParameterValues("major");
	Enumeration<String> names = request.getParameterNames();
	String major = "";
	
	if(gender != null && gender.equals("man")) gender = "남자";
	else gender = "여자";
	
	for(int i=0; i<majors.length; i++) {
		major += majors[i];
		if(i != majors.length-1) major += ", ";
	}
%>
	<h1>Request Example</h1>
	
	<h2>getParameterNames()</h2>
	<% while(names.hasMoreElements()) {	%>
	<div>
	<% out.println(names.nextElement());%>	
	</div>
	<% } %>
	
	<hr>
	
	<h2>getParameter('name'), getParameterValues('name')</h2>
	<div>성명 : <%= name %></div>
	<div>학번 : <%= studentNum %></div>
	<div>성별 : <%= gender %></div>
	<div>학과 : <%= major %></div>


</body>
</html>

결과

  • 물른 request객체는 form태그만을 통해 페이지간 데이터를 주고받을 수 있는것은 아니다.
  • JSP페이지에서는 forward의 특성을 이용해 데이터를 넘겨줄 수 있다.
  • 데이터를 넘겨주기 위해 reqeust.setParameter('name', object)메서드를 사용할 수 있으며, 객체의 전송이가능하다.

request 예제2

  • request객체는 서버로부터 넘어오는 요청정보를 가져오는 것 외에도 웹서버와 웹브라우저의 정보를 가져올 수 있다.
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%
	String protocol = request.getProtocol();
	String serverName = request.getServerName();
	int serverPort = request.getServerPort();
	String remoteAddr = request.getRemoteAddr();
	String remoteHost = request.getRemoteHost();
	String method = request.getMethod();
	StringBuffer requestURL = request.getRequestURL();
	String requestURI = request.getRequestURI();
	String useBrowser = request.getHeader("User-Agent");
	String fileName = request.getHeader("Accept");
%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
	<h1>Request Example</h1>
	<div>protocol : <%= protocol %></div>
	<div>serverName : <%= serverName%></div>
	<div>serverPort : <%= serverPort%></div>
	<div>사용자 컴퓨터의 주소 : <%= remoteAddr%></div>
	<div>사용자 컴퓨터의 이름 : <%= remoteHost%></div>
	<div>method : <%= method%></div>
	<div>requestURL : <%= requestURL%></div>
	<div>requestURI : <%= requestURI%></div>
	<div>useBrowser : <%= useBrowser%></div>
	<div>fileName : <%= fileName%></div>
</body>
</html>

결과

  • 여기서 사용자 컴퓨터의 주소인 0:0:0:0:0:0:0:1 또는 :::1은 루프백 주소로써, 루프백 인터페이스를 식벽하는 데 사용되며, 노드가 자신에게 패킷을 보낼 수 있도록한다. 이 주소는 IPv4의 루프백 주소인 127.0.0.1과 같다.
  • 루프백주소가 지정된 패킷은 링크에서 전송되거나 라우터에 의해 전달되면 안된다.

response 예제

  • response1_1.jsp페이지에서 response1.jsp페이지로 redirect하는 예제이다.
  • response객체의 sendRedirect("URL") 을통해 페이지간 redirect가 가능하다.

response1.jsp페이지

<h1>Response Example</h1>
<% response.sendRedirect("response1_1.jsp"); %>

response1_1.jsp 페이지

  • Paragma : http 1.0
  • Chache-Control : http 1.1
  • Paragma와 Chache-Control은 같은 의미이나 사용되는 HTTP의 버전이 다르다.
  • 브라우저나 프록시 서버로 하여금 요청 시에 cache된 문서 처리를 위한 헤더이다.
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<% 
	/* 브라우저가 캐시에 저장하여 사용하지 않고 매번 새로운 요청을 통해 서버로부터 전송받도록 설정됨 */
	if(request.getProtocol().equals("HTTP/1.1")) response.setHeader("Cache-Control", "no-store");
	else if(request.getProtocol().equals("HTTP/1.0")) response.setHeader("Pragma", "no-cache");
%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
	<h1>Response Example</h1>
	<div>response1.jsp redirect response1_1.jsp</div>
	<div><%= response.getCharacterEncoding() %></div>
</body>
</html>

결과

  • redirect시 주목해야할점은 forward방식과 달리 클라이언트에서 전환을 담당하므로, URL이 변경되고 이전에 사용되던 객체가 재사용될 수 없다는 점이다.
  • 또한 getCharacterEncoding() 메서드를 통해 요청에 사용된 Query 문장을 반환할 수 있으며
  • setHeader(name, value), setcontentType(type)을 통해 응답 Header와 출력되는 페이지의 contentType을 설정하는 메서드 또한 지원한다.

out 예제

response.getWirter()의 출력스트림과 JspWriter 객체 out의 차이점

  • response
    • 내장객체인 response객체를 통해 서블릿 클래스 작성시 데이터를 출력하기 위한 PrintWirter를 얻을 수 있다.
    • 버퍼를 사용하지 않는다.
  • out
    • JSP페이지가 servlet으로 변환될 때 표현식 <%= %>이 JspWriter의 객체인 out.print()로 변환된다.
    • servlet에서 사용하는 PrintWirter객체와 사용목적은 같으나 버퍼를 사용한다.
  • 버퍼의 사용유무로 인해 목적은 같으나, 동작방식에 차이가 발생하게된다.
  • JspWriter와 PrintWriter를 동시에 사용하면, 클라이언트측에 두개의 스트림이 열리게되는데 버퍼를 사용하지 않은 PrintWriter는 곧바로 출력되고, 버퍼를 사용한 JspWirter는 flush가 되어야만 출력된다.
  • 그렇기 때문에 PrintWirter의 출력 내용이 먼저 브라우저에 출력이 된후 JspWriter의 출력 내용이 출력된다.
<%@page import="java.io.PrintWriter"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8" buffer="5kb" %>
<%
	PrintWriter out2 = response.getWriter();

	int totalBuffer = out.getBufferSize();
	int remainBuffer = out.getRemaining();
	int userBuffer = totalBuffer - remainBuffer;
		
%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>


	<div>현재 페이지의 Buffer 상태</div>
	<div>출력 Buffer의 전체 크기 : <%= totalBuffer %></div>
	<div>남은 Buffer의 크기 : <%= remainBuffer %></div>
	<div>현재 Buffer의 사용량 : <%= userBuffer %></div>
	
	<%
	out2.println("for문 시작 전 <br>");	
	for(int i=1; i<=10; i++) {
		if(i%2 == 0) out.println("짝수 = " + i + "<br>");
		else out.println("짝수 = " + i + "<br>");
	}
	out2.println("for문 종료 후 <br>");
	%>

</body>
</html>

결과

  • JSP페이지가 Servlet으로 변환시 <%= %>표현식이 JspWriter의 내부객체인 out으로 변환되고, Servlet의 HTML표현을 위한 PrintWirter과는 달리 버퍼를 사용한다는것을 알리기위한 예제일뿐이므로, 이 둘을 같이 사용하지는 말자

외부 환경 정보 제공 객체

  • 현재 실행되는 페이지의 외부 환경정보(Context)와 관련된 내부 객체
클래스 객체 설명
PageContext pageContext 현재 실행중인 JSP의 Context를 나타낸다.

해당 객체를 통해 다른 내부 객체에 접근이 가능하다.
HttpSession session 웹 브라우저에서 서버가 클라이언트의 정보를 저장하고 요청을 시도한 특정 클라이언트를 다른 클라이언트와 구별하기 위해 각각의 클라이언트에 대한 정보를 지속적으로 관리하는 객체이다.

page지시자의 session속성을 통해 세션의 사용유무를 결정할 수 있다.
ServletContext application 어플리케이션이 실행되는 서버의 정보와 서버 측 자원에 대한 정보를 얻어내거나 어플리케이션이 실행하고 있는 동안에 발생할 수 있는 이벤트 로그와 관련된 기능들을 제공한다.

Context

  • 사전적 의미로 '문맥', '전후관계'를 의미한다.
  • 웹 환경에서의 Context는 서로 독립된 영역에 존재하는 온전한 하나의 어플리케이션 영역의 정보를 지칭한다.
  • 사용자가 URL을 통해 웹 어플리케이션에 접근시 서버내의 웹 어플리케이션을 구분하기 위해 server.xml 파일에 각 웹 어플리케이션의 <Context>태그를 추가하여 웹 컨테이너 내에 어떤 웹 어플리케이션이 사용되는지를 알 수 있다.
  • 클라이언트 -> Request(URL) -> Container(server.xml의 context 확인) -> Context에 해당하는 웹 어플리케이션 접근 -> Request에 해당하는 웹 어플리케이션 폴더 내 자원 반환

pageContext 예제

  • getRequest(), getResponse(), getOut()등의 메서드를 통해 ServletRequest, ServletResponse, JspWirter같은 해당 JSP페이지의 내장객체에 대한 정보를 모두 얻어올 수 있다.
  • 때문에 직접 사용할 경우는 적지만, JSP가 Servlet으로 변환시 _jspService()메서드에서 pageContext의 메서드 호출을 통해 해당 JSP의 Context를 얻어와 내부적으로 변환한다는것을 알면된다.
  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=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;

      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>Scriptlet Example</title>\r\n");
      out.write("</head>\r\n");
      out.write("<body>\r\n");
      out.write("</body>\r\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 {
            if (response.isCommitted()) {
              out.flush();
            } else {
              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);
    }
  }
}

session 예제

  • session은 HTML의 무상태성, 무연결성의 문제점을 해결하기 위해 만들어졌다.
  • session은 서버의 메모리에 클라이언트의 session id와 session정보를 저장한 뒤, 클라이언트에게 session id를넘겨 저장시키고 이후 요청에 매번 session id의 비교를 통해 해당 클라이언트에 저장된 상태정보로 동적페이지를 제공함으로써 마치 연결된것과 같이 사용할 수 있게된다.
  • session의 정보는 브라우저의 종료시 또는 유효시간동안 유효하다.

session.html

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
	<form action="session.jsp" method="POST">
		<div>id : <input type="text" name="id"></div>
		<div>pw : <input type="password" name="pw"></div>
		<input type="submit" value="login">
	</form>
</body>
</html>

session.jsp

  • form을통해 전송된 id를 session에 등록하고, session의 연결시간을 설정
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8" session="true" %>
<%
	request.setCharacterEncoding("UTF-8");

	String id = request.getParameter("id");
	String pw = request.getParameter("pw");
	
	session.setAttribute("idKey", id);
	session.setMaxInactiveInterval(60*5);	//id를 idkey로 세션에 연결을 설정하고, 연결시간을 5분으로 설정하였다. 5분이 지나가면 해당 정보는 사라진다.
%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>

	<form action="session2.jsp" method="get">
		<div>
			<h1>좋아하는 계절</h1>
			<label for="spring">봄</label>
			<input type="radio" name="season" value="봄" id="spring">
			<label for="summer">여름</label>
			<input type="radio" name="season" value="여름" id="summer">
			<label for="fall">가을</label>
			<input type="radio" name="season" value="가을" id="fall">
			<label for="winter">겨울</label>
			<input type="radio" name="season" value="겨울" id="winter">
		</div>
		<input type="submit" value="전송">
	</form>

</body>
</html>

session2.jsp

  • 이후 session에 등록된 정보는 클라이언트가 웹 애플리케이션에 요청하는 모든 웹 페이지 내에서 사용이 가능하다.
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8" session="true" %>
<%
	request.setCharacterEncoding("UTF-8");

	String id = (String)session.getAttribute("idKey");
	String sessionId = session.getId();
	int intervalTime = session.getMaxInactiveInterval();
	
	//session.invalidate();		//모든 세션정보 삭제
	
	String season = request.getParameter("season");
%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
	<% if(id != null) { %>
		<h1>Session Example</h1>
		
		<div>id : <%= id %></div>
		<div>sessionId : <%= sessionId %></div>
		<div>intervalTime : <%= intervalTime %></div>
		
	<% } %>
</body>
</html>

결과

  • 이때 sessionId는 브라우저의 구분을 위해 서버측에서 발급하는 일련번호이며, 서버와 클라이언트 양측에서 저장하고, 매 요청시마다 session id의 비교를 통해 어떤 클라이언트가 요청을했는지 식별이 가능해진다.

application 예제

  • 어플리케이션이 실행되는 서버의 정보와 서버 측 자원에 대한 정보를 얻어내거나 어플리케이션이 실행하고 있는 동안에 발생할 수 있는 이벤트 로그와 관련된 기능들을 제공한다.
  • getServerInfo(), getMimeType(), getRealPath() 등을 통해 해당 서버의 정보와 해당 웹 애플리케이션의 실제 저장경로를 얻을 수 있다.
  • 물론 application또한 setAttribute('name', 'object')메서드를 통해 서버에 데이터를 저장할 수 있으나, session과는 달리 해당 웹 애플리케이션의 모든 클라이언트가 공유하며, 웹 애플리케이션이 종료되기 이전까지 메모리를 차지한다.
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%
	String serverInfo = application.getServerInfo();
	String mimeType = application.getMimeType("request.html");
	String realPath = application.getRealPath("/");
	application.log("application 내부 객체 로그 테스트");
	
	//pageContext.forward();
	//response.sendRedirect();
%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>

	<h1>application test</h1>
	<div>서블릿 컨테이너의 이름과 버전 : <%= serverInfo %></div>
	<div>request.html의 Mime Type : <%= mimeType %></div>
	<div>로컬 파일 시스템 경로 : <%= realPath %></div>
</body>
</html>

결과

서블릿 관련 객체

  • JSP 페이지가 변환된 서블릿과 관련된 내용에 접근할 수 있도록 하는 객체
  • 이 둘은 잘 사용되지 않으므로 따로 다루지는 않았다.
클래스 객체 설명
HttpJspPage page JSP페이지 그 자체를 나타내는 객체이기 때문에 JSP페이지 내에서 this키워드로 자기 자신의 참조가 가능하다.

JSP페이지가 Servlet으로 변환된 그 자체를 의미한다.

대부분의 JSP컨테이너는 Java만을 스크립트 언어로 지원하기 때문에 거의 사용되지 않는다.
ServletConfig config Servlet에게 Servlet을 초기화하는 동안 참조해 할 정보를 전달하는 역할을 한다.

 

예외 관련 객체

클래스 객체 설명
Exception exception JSP페이지에서 발생한 예외를 처리하는 페이지를 지정한 경우, 에러 페이지에 전달되는 예외 객체이다.

page지시자의 isErrorPage속성을 true로 지정한 JSP페이지 내에서만 사용이 가능하다.

일반적인 JSP페이지에서는 생성되지 않는다.

 

exception 예제

  • page지시자의 errorPage속성에 에러발생시 이동할 page를 지정한다.
  • 에러처리를 담당할 jsp페이지의 page지시자에 isErrorPage속성을 true로 설정하여 container에게 해당 페이지가 에러페이지임을 알린다.
  • 이후 스크립트릿영역에서 0으로 나누어 강제로 예외를 발생시켰다.
  • 예외 발생페이지로 이동하는 방식은 forward방식이다.

excpetion.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8" errorPage="exceptionPage.jsp"%>
<%
	int one = 1;
	int zero = 0;
%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>exception occurred</title>
</head>
<body>

	<div>1 division zero : <%= one/zero %></div>

</body>
</html>

exceptionPage.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8" isErrorPage="true"%>
<%
	String message = exception.getMessage();
	String objectMessage = exception.toString();
%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Error page</title>
</head>
<body>
	<h1>Exception Page</h1>
	<div>에러 메시지 : <%= message %></div>
	<div>에러 실체의 클래시명과 에러 메시지 : <%= objectMessage %></div>
</body>
</html>

결과

  • forwarding 방식으로 에러페이지로 이동하기 때문에 URL의 변화가 없다.