JAVA/JSP 5. 내장 객체 - 내장 객체란? Request, Response 객체
*JSP의 내장 객체란?
- JSP에 내장되어있는, 웹 프로그래밍에 있어 가장 핵심적이고 유용한 객체 (광범위하게 사용됨)
→ 클라이언트에서 요청받기, 클라이언트의 요청에 응답하기, 화면 출력, 세션, 페이지, 애플리케이션
등을 내장 객체로 제공 - 웹의 동작 방식: 아래 그림처럼 클라이언트가 서버로 요청을 보내면, 서버는 그에 맞는 결과를 응답으로 돌려주는 형태 → 이때 내장 객체가 요청, 응답, HTTP 헤더(header) 등의 정보를 쉽게 다룰 수 있도록 해 줌
- JSP 페이지가 실행될 때 컨테이너가 자동으로 생성해 줌 (별도로 선언하거나 객체로 생성하지 않아도 즉시 사용 가능 → JSP가 실행될 때 자바 파일인 서블릿으로 변환되고 클래스 파일로 컴파일되는 과정에서,
생성된 _jspService() 메소드 안의 코드가 중요
*윈도우 탐색기에서 이동
C:\[설정한 작업공간 경로 (필자는JavaMiniProject)]\.metadata\.plugins\org.eclipse.wst.server.core\ tmp0\work\Catalina\localhost\MustHaveJSP_origin\org\apache\jsp\_01DirectiveScript
→ ScriptElements.jsp 파일이 서블릿으로 변환된 .java파일과, 그후 컴파일이 완료된 .class파일이 존재함 (총 2개)
: ScriptElements.jsp를 처음 실행했을 때, ScriptElements_jsp.java로 변환된 후 ScriptElements_jp.class로 컴파일된 것
→ 그 중 .java 파일을 메모장으로 열어봄 (마우스 우클릭 → [연결 프로그램] → 메모장)
// _jspService() 메소드 안의 코드-객체를 선언하고 초기화하는 선언문인 것을 알 수 있음
// =내장 객체의 참조 변수를 컨테이너가 생성하는 부분
public void _jspService() {
... 생략 ...
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;
... 생략 ...
}
- 컨테이너가 미리 선언해놓은 참조 변수를 이용해 사용
- JSP 문서 안의 <% 스크립틀릿 %>과 <%= 표현식 %>에서만 사용 가능
- <%! 선언부 %>에서는 즉시 사용 불가능 → 매개변수로 전달받아 사용하는 건 가능
- 내장 객체의 종류 - page와 config는 거의 사용되지 않음
request | javax.servlet.http.HttpServletRequest | 클라이언트의 요청 정보 저장 |
response | javax.servlet.http.HttpServletResponse | 클라이언트의 요청에 대한 응답 정보 저장 |
out | javax.servlet.jsp.JspWriter | JSP 페이지에 출력할 내용을 담는 출력 스트림 |
session | javax.servlet.http.HttpSession | ‘웹 브라우저 정보를 유지하기 위한’ 세션 정보를 저장 |
application | javax.servlet.ServletContext | ‘웹 애플리케이션 관련’ 컨텍스트 정보 저장 |
pageContext | javax.servlet.jsp.PageContext | JSP 페이지에 대한 정보 저장 |
page | java.lang.Object | ‘JSP 페이지를 구현한’ 자바 클래스의 인스턴스 |
config | javax.servlet.ServletConfig | JSP 페이지에 대한 설정 정보를 저장 |
exception | java.lang.Throwable | 예외가 발생한 경우 사용 |
1. request 객체
- JSP에서 가장 많이 사용되는, 클라이언트(주로 웹 브라우저)가 전송한 요청 정보를 담고 있는 객체
*클라이언트의 요청을 전송하기 위한 페이지(HTML로만 구성되어 있음)
// RequestMain.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<html>
<head><title>내장 객체 - request</title></head>
<body>
<h2>1. 클라이언트와 서버의 환경정보 읽기</h2>
<a href="./RequestWebInfo.jsp?eng=Hello&han=안녕"> <!--1. GET 방식으로 요청-->
GET 방식 전송
</a>
<br />
<form action="RequestWebInfo.jsp" method="post"> <!--2. POST 방식으로 요청-->
영어 : <input type="text" name="eng" value="Bye" /><br />
한글 : <input type="text" name="han" value="잘 가" /><br />
<input type="submit" value="POST 방식 전송" />
</form>
<h2>2. 클라이언트의 요청 매개변수 읽기</h2>
<form method="post" action="RequestParameter.jsp"> <!--3. 다양한 <input> 태그 사용-->
아이디 : <input type="text" name="id" value="" /><br />
성별 :
<input type="radio" name="sex" value="man" />남자
<input type="radio" name="sex" value="woman" checked="checked" />여자
<br />
관심사항 :
<input type="checkbox" name="favo" value="eco" />경제
<input type="checkbox" name="favo" value="pol" checked="checked" />정치
<input type="checkbox" name="favo" value="ent" />연예<br />
자기소개:
<textarea name="intro" cols="30" rows="4"></textarea>
<br />
<input type="submit" value="전송하기" />
</form>
<h2>3. HTTP 요청 헤더 정보 읽기</h2>
<a href="RequestHeader.jsp"> <!--4. HTTP 요청 헤더 읽기-->
요청 헤더 정보 읽기
</a>
</body>
</html>
1. GET 방식으로 요청
: 클라이언트의 요청에 따른 서버의 환경정보를 읽기 위해 링크 생성.
<a> 태그(한 페이지에서 다른 페이지 연결할 때 사용하는 하이퍼링크 정의)로 생성한 링크이므로 GET 방식으로 전송됨
링크 뒤에는 2개의 매개변수가 쿼리스트링(query string: URL 뒤에 “?키=값&키=값”형태로 덧붙여진 부분)으로 전달됨
2. POST 방식으로 요청
: 1. 과 똑같은 링크이나 <form> 태그를 사용하고 method 속성을 “post”로 설정하여 POST 방식으로 요청을 전송함 (method 속성을 ‘get’으로 설정하거나 아예 정의하지 않으면, GET 방식으로 요청을 전송함)
3. 다양한 <input> 태그 사용
: 2. 와 같이 <form> 태그를 통해 POST 방식으로 요청을 전송하는데,
여기에, ‘type 속성에 따라 매개변수를 읽어오는 방식이 달라지는’ 다양한 <input>태그 사용
4. HTTP 요청 헤더 읽기
: 링크를 통해 이동했을 때와 직접 실행했을 때 출력되는 정보가 차이가 있음
→ 위에서 작성한 RequestMain.jsp 파일을 [Run As] → [Run on Server]하면 아래와 같은 화면이 나타난다.
주요 기능 1) 클라이언트와 서버의 환경 정보 읽기
- 클라이언트는 웹 브라우저를 통해 서버 측으로 요청을 함
→ 이때 요청은 GET 방식/POST 방식으로 구분되고, 요청 URL/포트 번호/쿼리스트링 등을 명시 가능 - RequestMain.jsp 페이지에서 ‘GET 방식 전송’ 링크나 [POST 방식 전송] 버튼을 클릭했을 때 나타나는 페이지의 소스 (request 내장 객체로부터 클라이언트와 서버의 환경정보를 읽어와 화면에 표시해줌)
//RequestWebInfo.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<html>
<head><title>내장 객체 - request</title></head>
<body>
<h2>1. 클라이언트와 서버의 환경정보 읽기</h2>
<ul>
<li>데이터 전송 방식 : <%= request.getMethod() %></li> //1.
<li>URL : <%= request.getRequestURL() %></li> //2.
<li>URI : <%= request.getRequestURI() %></li> //3.
<li>프로토콜 : <%= request.getProtocol() %></li>
<li>서버명 : <%= request.getServerName() %></li>
<li>서버 포트 : <%= request.getServerPort() %></li>
<li>클라이언트 IP 주소 : <%= request.getRemoteAddr() %></li> //4.
<li>쿼리스트링 : <%= request.getQueryString() %></li> //5.
<li>전송된 값 1 : <%= request.getParameter("eng") %></li> //6-1.
<li>전송된 값 2 : <%= request.getParameter("han") %></li> //6-2.
</ul>
</body>
</html>
- 여기의 getMethod() 메소드는 GET과 POST 같은 전송 방식을 반환함
→ ‘GET 방식 전송’ 링크를 클릭했다면 “GET”을, [POST 방식 전송] 버튼을 클릭했다면 “POST”를 반환 - 여기의 getRequestURL() 메소드는 요청 주소를 반환함. (URL은 호스트를 포함한 전체 주소를 뜻함)
- 여기의 getRequestURI() 메소드는 2.와 같이 요청 주소를 반환함.
(URI는 호스트를 제외한 컨텍스트[호스트명 다음에 나오는 프로젝트명] 루트부터의 주소를 뜻함) - 여기의 getRemoteAddr() 메소드는 클라이언트의 IP 주소를 반환함
→ localhost로 접속 시에는 0:0:0:0:0:0:0:1과 같이 출력됨
(*윈도우 10에서는 위처럼 IPv6을 반환하는 게 기본인데, WAS 설정을 IPv4로 변경하면 localhost 접속 시 127.0.0.1을 출력함) - 여기의 getQueryString() 메소드는 요청 주소 뒷부분의 매개변수를 전달하기 위한 쿼리스트링 전체를 반환함.
- 여기의 getParameter() 메소드는 요청 주소 뒷부분의 매개변수를 전달하기 위한 쿼리스트링 중 특정 키 값을 반환함 (이 메소드에 키 값을 인수로 넣어주면 됨)
- RequestMain.jsp 실행화면 중 ‘1. 클라이언트와 서버의 환경정보 읽기’ 부분
-> ‘GET 방식 전송’ 클릭 시 결과
→ 주소표시줄에 쿼리스트링으로 매개변수가 2개 전달되었고, 정상적으로 출력됨
-> [POST 방식 전송] 버튼 클릭 시 결과
→ 주소표시줄에는 경로 외에 아무것도 표시되지 않음(=쿼리스트링 null 출력)
주요 기능 2) 클라이언트가 전송한 요청 매개변수에 대한 정보 읽기
- RequestMain.jsp 실행화면 중 ‘2. 클라이언트의 요청 매개변수 읽기’ 부분
→ 값을 적당히 입력하고 [전송하기] 버튼 클릭 시 POST 방식으로 RequestParameter.jsp에 전송
//RequestParameter.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<html>
<head><title>내장 객체 - request</title></head>
<body>
<%
request.setCharacterEncoding("UTF-8"); //1.
String id = request.getParameter("id"); //2.
String sex = request.getParameter("sex");
String[] favo = request.getParameterValues("favo"); //3.
String favoStr = "";
if (favo != null) { //4.
for (int i = 0; i < favo.length; i++) {
favoStr += favo[i] + " ";
}
}
String intro = request.getParameter("intro").replace("\\r\\n", "<br/>"); //5.
%>
<ul>
<li>아이디 : <%= id %></li>
<li>성별 : <%= sex %></li>
<li>관심사항 : <%= favoStr %></li>
<li>자기소개 : <%= intro %></li>
</ul>
</body>
</html>
- UTF-8: 다국어 지원 인코딩
- 전송되는 값이 하나일 경우 getParameter() 메소드 사용 - 주로 type 속성이 text, radio, password인 경우 사용
- 전송되는 값이 여러 개여야 할 때 getParameterValues() 메소드 사용 - 주로 type 속성이 checkbox인 경우 사용
(값이 2개 이상이므로 String 배열을 반환) - for문을 이용해서 String 배열에 담긴 값들을 하나의 문자열로 합침
- textarea 태그에서는 택스트를 여러 줄 입력할 수 있는데,
출력 시에는 enter 키를 <br> 태그로 변환해야 줄바꿈이 제대로 반영됨. enter는 특수 기호 \r\n으로 입력됨
- 아무 값을 입력하고 [전송하기] 버튼을 클릭했을 때 결과
주요 기능 3) HTTP 요청 헤더 및 쿠키 정보 읽기
- ReuestMain.jsp 실행 화면에서 ‘3. HTTP 요청 헤더 및 쿠키 정보 읽기’ 부분
→ ‘요청 헤더 정보 읽기’ 하이퍼링크 클릭 시 RequestHeader.jsp 코드가 실행되게 함
// RequestHeader.jsp
<%@ page import="java.util.Enumeration"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<html>
<head><title>내장 객체 - request</title></head>
<body>
<h2>3. 요청 헤더 정보 출력하기</h2>
<%
Enumeration headers = request.getHeaderNames(); //1.
while (headers.hasMoreElements()) { //2.
String headerName = (String)headers.nextElement(); //3.
String headerValue = request.getHeader(headerName); //4.
out.print("헤더명 : " + headerName + ", 헤더값 : " + headerValue + "<br/>");
}
%>
<p>이 파일을 직접 실행하면 referer 정보는 출력되지 않습니다.</p>
</body>
</html>
- 이 줄의 getHeaderNames() 메소드는 모든 요청 헤더의 이름을 반환(반환 타입은 Enumeration)
- 이 줄에서는 while문에서 hasMoreElements()를 이용해 출력할 요청 헤더명이 더 있는지 확인
- hasMoreElements()를 이용해 출력할 요청 헤더명이 더 있다면, 요청 헤더의 이름을 얻어옴
- getHeader() 메소드에 요청 헤더의 이름을 건네 헤더값을 얻어옴
- ‘요청 헤더 정보 읽기’ 하이퍼링크 클릭 시 결과
*user-argent: 웹 브라우저의 종류를 나타냄. 크롬, 파이어폭스, 익스플로러 등 여러가지 웹 브라우저에서 테스트해보면 조금씩 다른 결과가 출력됨.
*referer: 웹을 서핑하면서 하이퍼링크 클릭을 통해 다른 사이트로 방문 시 남는 흔적. 웹 사이트 방문객이 어떤 경로로 접속했는지 알아볼 때 유용함
*cookie: 요청 헤더를 통해 확인 가능(4장 ‘쿠키’에서 자세히 알아볼 것)
*개발환경 변경함!! - 이클립스 2022-12, jdk 11, Apache Tomcat 9.0.7.0
2. response 객체
- request 객체와는 반대로, 요청에 대한 응답을 웹 브라우저로 보내주는 객체
- 아래 두 주요 기능 외에, 다른 기능들은 거의 사용하지 않음
- 간단한 로그인 폼 제작 - 로직, 코드
//ResponseMain.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<html>
<head><title>내장 객체 - response</title></head>
<body>
<h2>1. 로그인 폼</h2>
<%
String loginErr = request.getParameter("loginErr"); //1.
if (loginErr != null) out.print("로그인 실패"); //2.
%>
<form action="./ResponseLogin.jsp" method="post"> //3.
아이디 : <input type="text" name="user_id" /><br />
패스워드 : <input type="text" name="user_pwd" /><br />
<input type="submit" value="로그인" />
</form>
<h2>2. HTTP 응답 헤더 설정하기</h2>
<form action="./ResponseHeader.jsp" method="get"> //4.
날짜 형식 : <input type="text" name="add_date" value="2021-10-25 09:00" /><br /> //5.
숫자 형식 : <input type="text" name="add_int" value="8282" /><br />
문자 형식 : <input type="text" name="add_str" value="홍길동" /><br />
<input type="submit" value="응답 헤더 설정 & 출력" />
</form>
</body>
</html>
- loginErr는 로그인 실패 여부를 알려주는 매개변수 (로그인에 실패하면 매개변수에 값을 설정)
- 위의 매개변수에 설정한 값이 들어있다면 “로그인 실패” 출력
- 아이디와 패스워드를 입력받는 간단한 로그인 폼 구성
- 응답 헤더 추가를 위한 입력 폼 구성
- 응답 헤더에 추가할 데이터의 형식 별로, value 속성에 입력해 둠
→ 위에서 작성한 RequestMain.jsp 파일을 [Run As] → [Run on Server]하면 아래와 같은 화면이 나타난다.
(빨간색 숫자는 주요기능 1,2번을 나타냄)
주요 기능 1) sendRedirect()로 페이지 이동
- response 내장 객체의 sendRedirect()를 이용
//ResponseLogin.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<html>
<head><title>내장 객체 - Response</title></head>
<body>
<%
String id = request.getParameter("user_id"); //1.
String pwd = request.getParameter("user_pwd"); //1.
if (id.equalsIgnoreCase("must") && pwd.equalsIgnoreCase("1234")) { //2.
response.sendRedirect("ResponseWelcome.jsp"); //3.
}
else {
request.getRequestDispatcher("ResponseMain.jsp?loginErr=1") //4.
.forward(request, response);
}
%>
</body>
</html>
- request 내장 객체로 전송된 매개 변수를 얻어옴
- 회원 인증 진행-아이디 must, 비밀번호 1234
- 회원 인증에 성공하면 실행. sendRedirect() 메소드에 건넨 응답 페이지로 이동.
(ResponseWelcome.jsp는 로그인 성공 페이지) - 회원 인증에 실패하면,
request 내장 객체를 통해 로그인 페이지(ResponseMain.jsp)로
포워드(forward/전달, 제어 흐름을 넘겨주고자 할 때 사용)됨
→ 쿼리스트링으로 loginErr 매개변수 전달하여 로그인 성공 여부 알려줌
- 로그인 성공 화면
//ResponseWelcome.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<html>
<head><title>내장 객체 - response</title></head>
<body>
<h2>로그인 성공</h2>
</body>
</html>
- 로그인 실패 화면: 화면에는 ResponseMain.jsp의 내용이 출력되었지만,
웹 브라우저의 주소표시줄에는 ResponasMain.jsp로 표시되어 있음
→ 로그인 실패 시 ResponseMain.jsp로 포워드하는데,
이때 매개변수 loginErr이 전달되고 ‘로그인 실패’ 메시지가 출력됨
주요 기능 2) HTTP 헤더에 응답 헤더 추가하기
- response 내장 객체는 응답 헤더에 정보를 추가하는 기능을 제공
- 정보 추가 메소드: 헤더값을 새로 추가하는 add 계열과 기존의 헤더를 수정할 때 사용하는 set 계열이 있음
→ add 계열 메소드: 새로운 헤더명으로 값 추가 (동일한 헤더명이 있으면 동일한 이름으로 값 추가)
→ set 계열 메소드: 기존의 헤더값 수정(동일한 헤더명이 존재하지 않으면 새롭게 추가)
//ResponseHeader.jsp
<%@ page import="java.util.Collection"%>
<%@ page import="java.text.SimpleDateFormat"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%
// 응답 헤더에 추가할 값 준비
SimpleDateFormat s = new SimpleDateFormat("yyyy-MM-dd HH:mm"); //1.
long add_date = s.parse(request.getParameter("add_date")).getTime(); //1.
int add_int = Integer.parseInt(request.getParameter("add_int")); //2.
String add_str = request.getParameter("add_str");
// 응답 헤더에 값 추가
response.addDateHeader("myBirthday", add_date);
response.addIntHeader("myNumber", add_int);
response.addIntHeader("myNumber", 1004); //3. 추가
response.addHeader("myName", add_str);
response.setHeader("myName", "안중근"); //4. 수정
%>
<html>
<head><title>내장 객체 - response</title></head>
<body>
<h2>응답 헤더 정보 출력하기</h2>
// 5.
<%
Collection<String> headerNames = response.getHeaderNames();
for (String hName : headerNames) {
String hValue = response.getHeader(hName);
%>
<li><%= hName %> : <%= hValue %></li>
<%
}
%>
<h2>myNumber만 출력하기</h2>
// 6.
<%
Collection<String> myNumber = response.getHeaders("myNumber");
for (String myNum : myNumber) {
%>
<li>myNumber : <%= myNum %></li>
<%
}
%>
</body>
</html>
- 0000-00-00(년-월-일) 형식으로 전송된 add_date 매개변수의 값을 long 타입으로 변경
(변경된 값: 타임스탬프→1970년 1월 1일 0시 0분 0초부터 현재까지의 시간을 밀리초 단위로 환산한 값) - 폼값으로 전송되는 값은 항상 String 타입이므로, add_int도 문자열로 얻어짐
(*정수 형태로 사용 시 반드시 변환해야 함) - add 계열의 메소드로 새로운 값 추가
-바로 위에서 추가한 ‘myNumber’라는 동일한 헤더명으로 새로운 값을 추가하고 있는데,
add 계열이므로 같은 헤더명으로 값이 하나 더 추가됨 - set 계열의 메소드로 값 수정-이전 값이 수정됨(같은 이름의 헤더가 없다면 새로 헤더가 추가됨)
- 아래 화면에서 ‘응답 헤더 설정&출력’ 클릭
5. 부분 실행 결과
- myNumber는 두 번 출력되며 그 값은 모두 8282로 동일함
-> addHeader 메소드-같은 헤더명으로 값이 하나 더 추가됨
-> getHeader() 메소드-값이 여러 개라도 첫 번째 값만 가져옴)
- myName은 ‘안중근’이 출력됨(setHeader 메소드-입력값을 ‘안중근’으로 수정함)
6. 부분 실행 결과