<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>forward Page</title>
</head>
<body>
<pre>
아래 forward 액션태그가 동작하면,
이 글은 보이지 않게 됨!
</pre>
<jsp:forward page="./dstForm.html"/>
</body>
</html>
dstForm.jsp
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Forward Check</title>
</head>
<body>
<pre>
만약 forward가 동작했다면,
여러분은 이 페이지를 보고 계신 겁니다.
하지만 URL은 변하지 않았습니다.
</pre>
</body>
</html>
url은 forward.jsp를 가리키지만, 화면의 내용은 dstForm.jsp의 내용이 출력된 것을 확인할 수 있다.
jsp:useBean
java class를 참조하여 빈 객체를 생성하고, setProperty와 getProperty를 통해 값을 저장, 조회할 수 있다.
이미 같은 이름의 객체가 생성된 경우 기존의 객체를 참조한다.
jsp : setProperty
자바빈 객체의 속성값을 설정하거나 수정할때 사용
‘param=“*’ 사용하면 request객체에 저장된 param값과 일치하는 멤버변수의 값을 전부 변경
이후 페이지 소스 보기 시 html 주석 태그는 나오지만 jsp 주석 태그는 출력되지않는 것을 확인할 수 있다.
태그3. 선언 태그 (declare) - <%! ___ %>
서블릿으로 변환 시 선언 태그 내에 작성한 내용을 필드로 선언해준다.
자바 코드 안에서 필드 선언하듯이 해당 태그 내에 필드처럼 작성해줄 수 있다.
태그4. 스크립틀릿 태그 (scriptlet) - <% ___ %>
간단한 자바 코드를 작성할 수 있는 부분이다.
스크립틀릿 태그 내에서의 주석은 자바 주석과 동일하다.
선언 태그에서 작성한 내용을 초기화 하고 출력할 수 도 있으며, 이 안에선 간단한 자바코드, 간단한 로직 처리도 가능하다
태그 3에서 필드 역할을 하는 name 과 age 를 작성했다면, 아래와같은 로직 작성이 가능하다.
<%
//간단한 자바 코드를 작성할 수 있는 부분이다.
/* 스크립틀릿 태그 내에서의 주석은 자바 주석과 동일하다. */
/* 선언 태그에서 작성한 내용을 초기화 하고 출력할 수 도 있으며, 간단한 로직 처리도 가능하다. */
name = "홍길동";
age = 20;
System.out.println("name : " + name);
System.out.println("age : " + age);
/* 간단한 로직 작성도 가능하다. */
for(int i = 0; i < name.length(); i++) {
System.out.println(name.charAt(i));
}
%>
태그5. 익스프레션 태그 (expression) - <%= ___ %>
PrintWriter를 이용하여 브라우저에 '값을 내보내기' 하여 브라우저에 보여지게 한다.
아래와 같은 코드를 작성했다면 화면상엔 이미지와 같이 보여지게 될 것이다.
name : <%= name %> <br>
age : <%= age %> <br>
html Elements 요소에서도 확인 가능
JSP 특징
1. JSP 파일이 변경되지 않는다면, ‘.jsp’ 파일에 대한 컴파일은 다시 일어나지 않는다.
2. JSP 파일이 변경될 때 마다, Web Container는 translation, compile, load, initialization 과정을 수행한다. ※ 주의 : 구 버전의 JSP 파일을 overwrite 할 경우 제대로 반영이 되지 않는 경우가 발생할 수 있다.
public class 클래스명 implements Filter {
@Override
public void init(FilterConfig config) throws ServletException
{ Filter호출시 작업 설정 }
@Override
public void doFilter(ServletRequest req, ServletResponse resp,
FilterChain chain) throws ServletException, IOException
{ 필터링 작업할 내용 }
@Override
public void destroy()
{ 삭제시 작업 설정 }
}
Filter Interface
init(FilterConfig config);
웹 컨테이너가 필터를 호출할 경우 해당 메소드가 호출되어 필터 객체를 생성하며 초기화한다.
매개변수 FilterConfig는 web.xml에 있는 <filter>정보를 가지고 있음.
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;
@WebFilter("/first/*")
public class FirstFilter implements Filter {
public FirstFilter() {
/* 기본 생성자 */
System.out.println("FirstFilter 인스턴스 생성!");
}
public void destroy() {
/* 필터 인스턴스가 소멸될 때 호출 되는 메소드 (톰캣 종료 시) */
System.out.println("filter destory 호출");
}
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
/* Servlet으로 request가 전달 되기 전에 요청을 가로채는 역할을 하는 메소드 */
System.out.println("filter doFilter 호출");
/* request, response의 가공을 처리하기 위해서는 여기에 코드를 작성한다. */
/* 위에서 뭔가 처리를 한 뒤 다음 필터 혹은 서블릿의
service(doGet/doPost)를 호출한다. */
chain.doFilter(request, response);
/* 서블릿에서 처리 후에 다시 수행할 내용이 있으면 작성한다 */
System.out.println("서블릿 요청 처리 완료!");
}
public void init(FilterConfig fConfig) throws ServletException {
/* 필터 인스턴스가 최초 생성 될 때 호출되는 메소드 */
System.out.println("filter init 호출");
}
}
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
/* 필터 등록은 xml에서 설정 */
public class EncodingFilter implements Filter {
private String encodingType;
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
HttpServletRequest hrequest = (HttpServletRequest) request;
if("POST".equals(hrequest.getMethod())) {
request.setCharacterEncoding(encodingType);
}
chain.doFilter(request, response);
}
public void init(FilterConfig fConfig) throws ServletException {
/* xml에서 설정한 init-param의 key를 이용하여 fConfig에서 값을 꺼내올 수 있다. */
encodingType = fConfig.getInitParameter("encoding-type");
}
}
PasswordEncryptFilter implements Filter
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
/* member 서비스인 경우에만 암호화 처리 할 수 있도록 한다. */
@WebFilter("/member/*")
public class PasswordEncryptFilter implements Filter {
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
HttpServletRequest hrequest = (HttpServletRequest) request;
RequestWrapper wrapper = new RequestWrapper(hrequest);
chain.doFilter(wrapper, response);
}
}
RegistMemberServlet extends HttpServlet
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
@WebServlet("/member/regist")
public class RegistMemberServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
/* 1. 인코딩 필터
* 2. 암호화 필터
* */
String userId = request.getParameter("userId");
String password = request.getParameter("password");
String name = request.getParameter("name");
System.out.println("userId : " + userId);
System.out.println("password : " + password);
System.out.println("name : " + name);
/* 암호화 처리된 패스워드는 동일한 값이 입력되더라도 매번 실행시마다
다른 값을 가지게 된다.
* 그럼 나중에 DB에 이 상태로 기록하게 되면 가입 된 회원정보로 로그인
할 때 비밀번호가 같은지 어떻게 비교할까?
* 암호화 된 문자열은 일반 문자열 비교가 불가능하고 matches()라는
메소드를 이용해야 한다.
* */
BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
System.out.println("비밀번호가 pass01인지 확인 : "
+ passwordEncoder.matches("pass01", password));
System.out.println("비밀번호가 pass02인지 확인 : "
+ passwordEncoder.matches("pass02", password));
}
}
RequestWrapper extends HttpServletRequestWrapper
package com.greedy.section02.uses;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
public class RequestWrapper extends HttpServletRequestWrapper{
/* 부모 쪽에 기본 생성자가 존재하지 않기 때문에 request를
전달해주는 생성자가 필요하다. */
public RequestWrapper(HttpServletRequest request) {
super(request);
}
@Override
public String getParameter(String key) {
String value = "";
if("password".equals(key)) {
/* 랜덤 솔팅 기법을 적용한 다이제스트 생성을 지연시킨
단방향 해시 암호화 알고리즘 */
BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
value = passwordEncoder.encode(super.getParameter(key));
} else {
value = super.getParameter(key);
}
return value;
}
}
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Enumeration;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
@WebServlet("/redirect")
public class RedirectServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
/* 쿼리스트링을 통한 데이터 전달 */
String test = request.getParameter("test");
System.out.println("test : " + test);
String firstName = request.getParameter("firstName");
String lastName = request.getParameter("lastName");
System.out.println("firstName : " + firstName);
System.out.println("lastName : " + lastName);
/* 앞서 작성한 페이지와 동일한 세션 아이디를 반환한다. */
HttpSession session = request.getSession();
System.out.println("redirect 페이지 session id : " + session.getId());
/* 세션에 담긴 모든 Attribute 키 목록을 반환받을수도 있다. */
Enumeration<String> sessionNames = session.getAttributeNames();
while(sessionNames.hasMoreElements()) {
System.out.println(sessionNames.nextElement());
}
/* 동일한 아이디를 가진 세션에서는 setAttribute한 값을
getAttribute로 꺼내올 수 있다. */
firstName = (String) session.getAttribute("firstName");
lastName = (String) session.getAttribute("lastName");
/* 꺼내온 값을 이용해서 페이지에 응답용 html 전송 */
StringBuilder responseText = new StringBuilder();
responseText.append("<!doctype html>\n")
.append("<html>\n")
.append("<head>\n")
.append("</head>\n")
.append("<body>\n")
.append("<h3>your first name is ")
.append(firstName)
.append(" and last name is ")
.append(lastName)
.append("</h3>")
.append("</body>\n")
.append("</html>\n");
response.setContentType("text/html; charset=UTF-8");
PrintWriter out = response.getWriter();
out.print(responseText.toString());
out.flush();
out.close();
}
}
SessionHandlerServlet extends HttpServlet
package com.greedy.section01.session;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
@WebServlet("/session")
public class SessionHandlerServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
request.setCharacterEncoding("UTF-8");
String firstName = request.getParameter("firstName");
String lastName = request.getParameter("lastName");
System.out.println("firstName : " + firstName);
System.out.println("lastName : " + lastName);
/* 이전 챕터에서는 값을 유지하기 위한 기술로 쿠키를 이용해보았다.
* 하지만 쿠키의 보안적인 단점과 지원하지 않는 브라우저 문제 등으로
상태를 유지해야 하는
* 매커니즘이 적합하지 않은 경우들이 다수 있는데 특히 회원 정보를
이용해서 회원의 로그인 상태를
* 지속적으로 유지해야 하는 경우가 그러하다. 그렇기에 서버 쪽에서 조금
더 안전하게 관리 되는
* 세션이라는 인스턴스를 이용해서 상태를 유지하는 매커니즘을 제공하고 있다.
* HttpSession은 직접 생성할 수는 없고, request에 있는 getSession()
메소드를 이용해서 리턴 받는다.
* */
HttpSession session = request.getSession();
/* 세션은 강제로 만료 시킬 수 있는 기능도 있지만 만료 시간을
설정해주는 것이 좋다.
* 설정 된 기분 시간은 30분이며 필요에 따라 늘리거나 줄이면 된다.
* */
System.out.println("session default 유지 시간 : "
+ session.getMaxInactiveInterval());
session.setMaxInactiveInterval(60 * 10); // 세션 만료 시간을 10분으로 설정
System.out.println("변경 후 session 유지 시간 : "
+ session.getMaxInactiveInterval());
/* 세션은 브라우저 당 한 개 씩 고유한 아이디를 가지고 하나의 인스턴스를 이용한다.
* 매번 반복적인 요청 시 동일한 session id를 리턴한다.
* */
System.out.println("session id : " + session.getId());
/* 세션은 redirect를 해도 값을 유지할 수 있는 request보다
더 넒은 범위의 공유 영역이라고 표현할 수 있다.
* 세션에 값을 담을 때 setAttribute(String key, Object value)
형태로 담을 수 있고,
* 값을 꺼낼 때에는 key를 이용해서 getAttribute(key)를 이용해 꺼내게 된다.
* */
session.setAttribute("firstName", firstName);
session.setAttribute("lastName", lastName);
response.sendRedirect("redirect?test=hello");
}
}
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet("/cookie")
public class CookieHandlerServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
request.setCharacterEncoding("UTF-8");
String firstName = request.getParameter("firstName");
String lastName = request.getParameter("lastName");
System.out.println("firstName : " + firstName);
System.out.println("lastName : " + lastName);
/* redirect는 url을 재작성하여 url을 이용해 요청하는 방식이기 때문에
get 방식의 요청이다.
* 따라서 redirect 되는 서블릿은 doGet 메소드 쪽에서 처리해야 한다.
* */
/* 쿠키를 사용하는 방법은 간단하며, 쿠키를 사용하는 절차가 있다.
* 1. 쿠키를 생성한다.
* 2. 해당 쿠키의 만료 시간을 설정한다.
* 3. 응답 헤더에 쿠키를 담는다.
* 4. 응답 한다.
*
* 하지만 쿠키는 일부 제약 항목이 있다.
* 쿠키의 이름은 아스키코드 문자만을 사용해야하며 한 번 설정한 쿠키의
이름은 변경할 수 없다.
* 또한 공백문자와 일부 특수문자([ ] ( ) = , " \ ? @ : ;)를 사용할 수 없다.
* */
Cookie firstNameCookie = new Cookie("firstName", firstName);
Cookie lastNameCookie = new Cookie("lastName", lastName);
// 초 단위 설정으로 하루를 만료시간으로 둘 때의 예시
firstNameCookie.setMaxAge(60 * 60 * 24);
lastNameCookie.setMaxAge(60 * 60 * 24);
response.addCookie(firstNameCookie);
response.addCookie(lastNameCookie);
response.sendRedirect("redirect");
}
}
RedirectServlet extends HttpServlet
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet("/redirect")
public class RedirectServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String firstName = request.getParameter("firstName");
String lastName = request.getParameter("lastName");
System.out.println("firstName : " + firstName);
System.out.println("lastName : " + lastName);
/* null 값이 나오는 것을 확인할 수 있다.
* 따라서 request는 공유되지 않는다는 것을 볼 수 있다.
* */
/* 쿠키를 사용하는 방법
* 1. request에서 쿠키 목록을 쿠키 배열 형태로 꺼내온다.
* 2. 쿠키의 getName과 getValue를 이용해 쿠키에 담긴 값을 사용한다.
* */
Cookie[] cookies = request.getCookies();
for(int i = 0; i < cookies.length; i++) {
System.out.println("[cookie] " + cookies[i].getName()
+ " : " + cookies[i].getValue());
if("firstName".equals(cookies[i].getName())) {
firstName = cookies[i].getValue();
} else if("lastName".equals(cookies[i].getName())) {
lastName = cookies[i].getValue();
}
}
StringBuilder responseText = new StringBuilder();
responseText.append("<!doctype html>\n")
.append("<html>\n")
.append("<head>\n")
.append("</head>\n")
.append("<body>\n")
.append("<h3>your first name is ")
.append(firstName)
.append(" and last name is ")
.append(lastName)
.append("</h3>")
.append("</body>\n")
.append("</html>\n");
response.setContentType("text/html; charset=UTF-8");
PrintWriter out = response.getWriter();
out.print(responseText.toString());
out.flush();
out.close();
/* 쿠키는 텍스트 파일 형태로 클라이언트 컴퓨터에 저장 된다.
* 다른 사용자와 함께 사용하는 컴퓨터인 경우 쿠키에 민감한
개인 정보를 담기에는 보안에 취약해지는 문제가 있다.
* 따라서 민감한 개인 정보를 취급하는 경우에는 쿠키보다는
세션을 이용하게 된다.
* 세션은 쿠키와 유사한 형태로 key=value 쌍으로 저장 되지만
서버(톰캣)에서 관리 되기 때문에 보안에 더 우수하다.
* */
}
}
HTTP헤더의 내용으로 보내는 방식으로 데이터 크기에 제한이 없고, 헤더에 포함되어 보안이 뛰어남
☞ Servlet이 두 방식 중 하나로 전달받으면 해당하는 매소드를 호출함 html <form>에서 method속성을 이용해서 방식결정, default : get
서블릿 메소드
doGet
client에서 데이터를 전송 방식을 get방식으로 전송하게 되면 호출되는 메소드
doPost
client에서 데이터를 전송 방식을 Post방식으로 전송하게 되면 호출되는 메소드
☞ 반드시 ServletException 처리해야 함.
서블릿 매개변수 객체
HttpServletRequest (interface)
HTTP Servlets을 위한 요청정보(request information)를 제공 메소드 지정
** 인터페이스 구현은 컨테이너가 알아서 설정 / 메소드만 이용 **
상속 : javax.servlet.ServletRequest (interface)
HttpServletRequest (interface)
HttpServletResponse (interface)
요청에 대한 처리결과를 작성하기 위해 사용하는 객체
** 인터페이스 구현은 컨테이너가 알아서 설정 / 메소드만 이용 **
상속 : javax.servlet.ServletResponse (interface)
sendRedirect VS RequestDispatcher
sendRedirect / encodeRedirectURL
client의 브라우저에게 매개변수로 등록한 페이지를 재요청하라고 응답해주는 것(301/302코드 전송)
encodeRedirectURL은 매개변수(URL)에 세션ID정보를 추가 재요청 처리
client가 별도로 다른 페이지 요청을 안해도 url주소(페이지)가 변경됨.
** 브라우저가 알아서 서버에 해당 페이지를 요청 / 쿼리스트링으로 별도의
데이터를 전송하지 않으면 요청데이터가 없음
sendRedirect VS RequestDispatcher
RequestDispatcher() ~ forward()
컨테이너 내에서 처음 요청 받은 페이지가 요청 데이터 (HttpServletRequest,
HttpServletResponse)를 다른 페이지에 전송하여 처리를 요청을 하고 자신이 처리한 것처럼 하는 것.
url주소(페이지)가 변경되지 않음.
서블릿 데이터 공유
객체별 공유 데이터 설정
** 공유값은 Map형식으로 저장됨.
▼ 코드 예시 보기 ▼
Response
ResponseTestServlet extends HttpServlet
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* Servlet implementation class ResponseTestServlet
*/
@WebServlet("/response")
public class ResponseTestServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
public ResponseTestServlet() {
super();
}
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
/* 서블릿이 하는 역할은 크게 3가지라고 볼 수 있다.
* 1. 요청받기 (http method GET/POST 요청에 따른 parameter로 전달 받은 데이터를
꺼내올 수 있다.)
* 2. 비즈니스 로직 처리 (DB 접속과 CRUD에 대한 로직 처리 -> 서비스를 호출하는
쪽으로 해결 (MVC))
* 3. 응답하기 (문자열로 동적인 웹(html 태그)페이지를 만들어서 스트림을
이용하여 내보내기)
*
* */
/* 기본값은 text/plain 이지만 html 태그를 사용하면 요청 시 text/html도 응답으로
수락 가능하도록
* 헤더 설정이 되어 있기 때문에 text/html로 인식하게 된다.
* 하지만 명시적으로 text/plain 으로 설정되면 html 태그를 태그로 인식하지
않고 문자열로 인식하게 된다. */
//response.setContentType("text/plain");
response.setContentType("text/html");
/* 응답시에도 별도로 인코딩을 지정하지 않으면 기본적으로 설정 된
인코딩 방식을 따르게 된다. (iso-8859-1)
* 따라서 한글로 페이지를 응답하는 경우 글씨가 깨져서 나오게 된다.
* */
/* 인코딩 설정 확인 */
System.out.println("default response encoding : "
+ response.getCharacterEncoding());
// 콘솔창 : default response encoding : ISO-8859-1
/* 이 때 응답할 인코딩 방식이 UTF-8임을 응답 헤더에 알려주게 되면 브라우저가
이를 해석할때 UTF-8로 인식한다.
* 즉, 한글 값이 깨지지 않게 된다. */
/* 유의할 점은 반드시 getWriter()로 스트림을 얻어오기 전에 설정해야 한다. : */
response.setCharacterEncoding("UTF-8");
System.out.println("default response encoding : "
+ response.getCharacterEncoding());
/* 콘솔창 출력 */
/* default response encoding : ISO-8859-1
default response encoding : UTF-8 */
/* 사용자 브라우저에 응답하기 위해 HttpServletResponse가 가지는 getWriter() 메소드로
* PrintWriter 인스턴스를 반환 받는다. PrintWriter는 BufferedWriter와 형제격인
* 클래스이지만 더 많은 형태의 생성자를 제공하고 있어서 실제로는 범용성으로
인해 더 많이 사용된다. */
PrintWriter out = response.getWriter();
/* 문자열을 이용해 사용자에게 내보내기를 할 페이지를 작성한다. */
StringBuilder responseBuilder = new StringBuilder();
responseBuilder.append("<!doctype html> \n")
.append("<html>\n")
.append("<head>\n")
.append("</head>\n")
.append("<body>\n")
.append("<h1>안녕 servlet response</h1>\n")
.append("</body>\n")
.append("</html>\n");
/* 스트림을 이용해 내보내기 */
out.print(responseBuilder.toString());
/* 버퍼에 잔류한 데이터를 강제로 내보낸다. */
out.flush();
/* 스트림을 닫아준다. */
out.close();
}
}
HeaderPrintServlet
package com.greedy.section02.headers;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Collection;
import java.util.Enumeration;
import java.util.Iterator;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet("/headers")
public class HeaderPrintServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
/* request header 출력 */
Enumeration<String> headerNames = request.getHeaderNames();
while(headerNames.hasMoreElements()) {
System.out.println(headerNames.nextElement());
}
/* request.getHeader()에 name 값을 전달해서 값을 가져올 수 있다. */
System.out.println("accept : " + request.getHeader("accept"));
System.out.println("host : " + request.getHeader("host"));
response.setContentType("text/html; charset=UTF-8");
/* 1초에 한번씩 새로고침 */
//response.setHeader("Refresh", "1");
/* 출력할 스트림 */
PrintWriter out = response.getWriter();
long currentTime = System.currentTimeMillis();
out.print("<h1>" + currentTime + "</h1>");
out.close();
/* response header 출력 */
Collection<String> responseHeaders = response.getHeaderNames();
Iterator<String> iter = responseHeaders.iterator();
while(iter.hasNext()) {
String headerName = iter.next();
System.out.println(headerName + " : " + response.getHeader(headerName));
}
}
}
StatusCodeTestServlet
package com.greedy.section03.status;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* Servlet implementation class StatusCodeTestServlet
*/
@WebServlet("/status")
public class StatusCodeTestServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//response.sendError(404, "없는 페이지 입니다. 경로를 확인해주세요.");
response.sendError(500, "서버 내부 오류입니다. 서버 오류는 개발자의 잘못이고,
개발자는 여러분입니다.");
}
}
package com.greedy.section01.forward;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet("/print")
public class PrintLoginSuccessServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
/* forward 받은 서블릿에서도 요청 방식이 get이면 doGet 메소드를,
요청 방식이 post이면 doPost 메소드를 호출한다. */
/* request에 이전 서블릿에서 전달하고자 하는 정보를 담았기 때문에
해당 서블릿에서는 다시 꺼내온다. */
String userId = (String)request.getAttribute("userId");
System.out.println("forward 확인 : " + userId);
/* 응답에 필요한 데이터가 다 준비 되면 동적인 웹 페이지를 생성한다. */
StringBuilder responseText = new StringBuilder();
responseText.append("<!doctype html>\n")
.append("<html>\n")
.append("<head>\n")
.append("</head>\n")
.append("<body>\n")
.append("<h3 align='center'>")
.append(userId)
.append("님 환영합니다.</h3>")
.append("</body>\n")
.append("</html>");
response.setContentType("text/html; charset=UTF-8");
PrintWriter out = response.getWriter();
out.print(responseText.toString());
out.flush();
out.close();
/* 변수의 기본 스코프는 메소드(page)이기 때문에 다른 페이지(서블릿)
으로 데이터 공유 불가
* forward 방식은 request와 response를 넣어서 위임하므로 request에
정보를 저장하여
* forward 했을 경우 위임 당한 서블릿에서도 서블릿의 정보를
공유할 수 있게 된다.
* 또한 forward 방식은 해당 서블릿의 존재를 client가 알 필요가 없어
url 자체가 변경 되지 않는다.
* 단, 서버로 전송한 데이터가 남아있는 상태로 새로고침(재요청)을
하게되면 요청을 계속 반복하게 되어
* DB에 insert하는 행위가 반복 되어 중복 행이 발생하는 등의 문제가 있을 수 있다.
* 이러한 경우는 또 다른 페이지 전환 방식 sendRedirect를 사용해야 한다.
* */
}
}
ReceiveInformationServlet extends HttpServlet
package com.greedy.section01.forward;
import java.io.IOException;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet("/forward")
public class ReceiveInformationServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
request.setCharacterEncoding("UTF-8");
String userId = request.getParameter("userId");
String password = request.getParameter("password");
System.out.println("userId : " + userId);
System.out.println("password : " + password);
/* 위에서 요청 정보를 받았고
* 모든 비즈니스 로직은 성공이라는 가정 하에
* user01을 입력 시 해당 아이디를 이용해 user01님 환영합니다 라는 메세지를
출력해주는 화면을 만들자
*
* PrintLoginSuccessServlet으로 위임하기 위해서는 RequestDispatcher
인스턴스 생성 후
* forward 메소드를 이용해서 요청과 응답에 대한 정보를 전달한다.
* 이 때 다른 서블릿으로 요청하기 위한 데이터는 request에 setAttribute로
전달하여 받는 쪽에서는 getAttribute를 이용해 꺼내서 사용한다.
* */
request.setAttribute("userId", userId);
RequestDispatcher rd = request.getRequestDispatcher("print");
rd.forward(request, response);
}
}
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet("/othercite")
public class OtherCiteRedirectServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
System.out.println("get 요청 후 naver 사이트로 redirect");
/* 브라우저의 개발자 도구 network 탭을 보면 302번 status code와 함께
naver 사이트로 이동하는 것을 볼 수 있다.
* 사용자 url 재작성이라고 불리는 redirect 방식은 302번 응답 코드인
경우 요청에 대한 처리를 잘 했으며
* 사용자의 url을 강제적으로 redirect 경로로 이동시키라는 의미이다.
* */
response.sendRedirect("http://www.naver.com");
}
}
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet("/redirect")
public class RedirectServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
System.out.println("이 서블릿으로 redirect 성공!");
StringBuilder redirectText = new StringBuilder();
redirectText.append("<!doctype html>\n")
.append("<head>\n")
.append("</head>\n")
.append("<body>\n")
.append("<h1>이 서블릿으로 redirect 성공!</h1>")
.append("</body>\n")
.append("</html>");
response.setContentType("text/html; charset=UTF-8");
PrintWriter out = response.getWriter();
out.print(redirectText.toString());
out.flush();
out.close();
/* redirect를 하는 경우 url이 재작성 되어 새로 고침 해도 redirect
된 페이지에 대한 요청만을 반복한다.
* 즉, 이전 요청에 남아있던 정보는 더이상 남아있지 않게 된다.
또한 url도 변경 된다.
* http 요청은 요청 시에 잠시 connection을 맺고 응답 시에도 잠시
connection을 맺으며
* 요청 단위 당 request 객체는 한 개만 생성이 된다.
* 따라서 첫 요청 시의 request와 redirect된 페이지의 request는
서로 다른 객체이다.
* 그렇기 때문에 redirect를 이용하게 되면 이전 서블릿의 값을
공유해서 사용할 수 없게 된다.
* 그럼 redirect시 값을 유지하는 방법은? 크게 쿠키와 세션이라는
것을 이용할 수 있다.
* */
}
}