start.spring.io
build.gradle에 id='war'되어있는지 확인(jsp 공부하려면 war 해야됨)
서버 실행해서 localhost:8080 해보고 창없음 오류 뜨는지 확인
setting>Gradle검색>Build and run using, Run tests using: intellij IDEA로 바꾸기
setting> plubins검색>Lombox install>intellij 재시작
setting>annotaion processors검색> Enable anntation processing 체크
(이걸 해줘야 롬복이 잘 작동함)
postman 설치(os에 맞는 버전): api 테스트할 때 편리하다!
스프링 부트 환경에서 서블릿을 등록하고 사용해보자!
참고
서블릿은 톰캣 같은 웹 애플리케이션 서버를 직접 설치하고, 그 위에 서블릿 코드를 클래스 파일로 빌드해서 올린 다음, 톰캣 서버를 실행하면 된다. 하지만 이 과정은 매우 번거롭다.
스프링 부트는 톰캣 서버를 내장하고 있으므로, 톰캣 서버 설치 없이 편리하게 서블릿 코드를 실행할 수 있다.
@SurvletComponentScan
스프링 부트는 서블릿을 직접 등록해서 사용할 수 있도록 해당 애노케이션을 지원한다. 다음과 같이 추가하자.
hello.servlet.ServletApplication
package hello.servlet;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.ServletComponentScan;
@ServletComponentScan // 서블릿 자동 등록
@SpringBootApplication
public class ServletApplication {
public static void main(String[] args) {
SpringApplication.run(ServletApplication.class, args);
}
}
처음으로 실제 동작하는 서블릿 코드를 등록해보자.
hello.servlet.basic.HelloServlet
package hello.servlet.basic;
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 java.io.IOException;
@WebServlet(name= "helloServlet", urlPatterns = "/hello")
public class HelloServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//ctrl + o: service(자물쇠 없는게 protected)
System.out.println("HelloServlet.service");
// 실제로 서블릿을 실행하는지 확인 가능.
System.out.println("request = " + request);
System.out.println("response = " + response);
//각각의 객체 출력 가능.
String username = request.getParameter("username");
System.out.println("username = " + username);
// 리스펀스 응답 메시지에 답 넣기
response.setContentType("text/plain");
response.setCharacterEncoding("utf-8"); // 요즘엔 문자 대부분 utf-8을 사용
response.getWriter().write("hello " + username); //http body에 문자가 들어감.
}
}
@WebServlet
: 서블릿 애노테이션
HttpServlet 상속받기. 단축키 ctrl+O 눌러서 service 오버라이딩.
(자물쇠 없는게 protected임. 그거 오버라이딩 합니다.)
서버 실행 후 주소창에 “http://localhost:8080/hello?username=kim”
결과1. 콘솔창
HttpServletRequest, HttpServletRespone: 인터페이스
톰캣이나 제티 등 was 서버가 서블릿 표준 스팩을 구현한 구현체. sysout으로 그 구현체들을 확인할 수 있음.
서블릿은 쿼리 파라미터(?username=kim)를 편하게 읽을 수 있는 기능을 제공.
String username = request.getParameter("username");
내가 일일이 http의 문자들을 파싱해서 가져오면 굉장히 번거롭고 불편하다. 서블릿은 메서드로 그런 이름을 가져오기 용이하게 돕는다!
결과2. 화면창
HTTP 요청을 통해 매핑이 된 URL이 호출되면서 서블릿 컨테이너는 다음 메서드를 실행한다.
prtected void service(HttpServletReqest request, HttpServletResponse response)
팁입니당. HTTP로 어떤 정보를 전달하는지 로그로 정확히 확인하고 싶을때 쓸수 있습니당.
application.properties
logging.level.org.apache.coyote.http11=debug
참고: 운영 서버에 이렇게 모든 요청 정보를 다 남기면 성능저하 유발 가능. 개발시에만 사용 권장.
내장 톰캣 서버 생성
스프링부트 실행 -> 내장 톰켓 서버 띄움 -> 내부에 서블릿 컨테이너를 통해 서블릿을 다 생성해줌. 서블릿 컨테이너 안의 HelloServlet 생성
웹 브라우저가 HTTP 요청 메시지를 만들어서 던져줌. 서버는 helloServlet의 service()호출하고, request, response를 넘겨줌. 필요한 작업을 하고, WAS 서버가 reponse정보를 가지고 HTTP 응답 메시지를 만들어서 반환해줌. 그럼 웹 브라우저에서 볼 수 있음!
참고) HTTP 응답에서 Content-Length는 웹 애플리케이션 서버가 자동으로 생성해준다.
지금까지 개발할 내용을 편리하게 참고할 수 있도록 wlcome 페이지를 만들어두자.
webapp
경로에 index.html
을 두면 http://localhost:8080 호출 시 index.html
페이지가 열린다.
main/webapp/index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<ul>
<li><a href="basic.html">서블릿 basic</a></li>
</ul>
</body>
</html>
main/webapp/basic.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<ul>
<li>hello 서블릿
<ul>
<li><a href="/hello?username=servlet">hello 서블릿 호출</a></li>
</ul>
</li>
<li>HttpServletRequest
<ul>
<li><a href="/request-header">기본 사용법, Header 조회</a></li>
<li>HTTP 요청 메시지 바디 조회
<ul>
쿼리 파라미터</a></li>
li>
<li><a href="/request-param?username=hello&age=20">GET -
<li><a href="/basic/hello-form.html">POST - HTML Form</a></
<li>HTTP API - MessageBody -> Postman 테스트</li>
</ul>
</li>
</ul>
</li>
<li>HttpServletResponse
<ul>
<li><a href="/response-header">기본 사용법, Header 조회</a></li>
<li>HTTP 응답 메시지 바디 조회
<ul>
<li><a href="/response-html">HTML 응답</a></li>
<li><a href="/response-json">HTTP API JSON 응답</a></li>
</ul>
</li>
</ul>
</li>
</ul>
</body>
</html>
basic 화면을 이렇게 꾸며주셨다. 지금까지 배운 것들 하나씩 확인해 볼 수 있도록. 세심한 배려가 미쳤다. 혼자 외로운 공부에 진짜 같이 공부해주시는 선생님이 옆에 있는 느낌이다. 김영한선생님 감사합니다. 꼭 취직해서 더 많은 강의 구입으로 이 은혜를 갚겠습니다 선생님...
HTTP 요청 메시지를 개발자가 직접 파싱해서 사용해도 되지만, 매우 불편할 것이다. 서블릿은 개발자가 HTTP 요청 메시지를 편리하게 사용할 수 있도록 개발자 대신에 HTTP 요청 메시지를 파싱한다. 그리고 그 결과를 HttpServletRequest
객체에 담아서 제공한다.
HttpServletRequest를 사용하면 다음과 같은 HTTP 요청 메시지를 편리하게 조회할 수 있다.
POST /save HTTP/1.1
Host: localhost:8080
Content-Type: application/x-www-form-urlencoded
username=kim&age=20
START LINE (첫번째 줄 + 호스트까지 합쳐서)
헤더 (=Content-type)
바디 (한칸 띄우고 있는 것 다)
HttpSErvletRequest객체는 추가로 여러 가지 부가 기능을 함께 제공한다.
1. 임시 저장소 기능
해당 HTTP 요청이 시작부터 끝날 때 까지 유지되는 임시 저장소 기능
request.setAttribute(name, value)
request.getAttribute(name)
2. 세션 관리 기능
request.getSession(create:true)
중요
HttpServletRequest, HttpServletResponse를 사용할 때 가장 중요한 점은 이 객체들이 HTTP 요청 메시지, HTTP 응답 메시지를 편리하게 사용하도록 도와주는 객체라는 점이다. 따라서 이 기능에 대해서 깊이 있는 이해를 하려면 ‘HTTP 스펙이 제공하는 요청, 응답 메시지 자체를 이해’해야 한다.
HttpServletRequest가 제공하는 기본 기능을 알아보자.
ctrl + alt + M : 메서드 추출 단축키
hello.servlet.basic.request.RequestHeaderServlet
package hello.servlet.basic.request;
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;
import java.io.IOException;
@WebServlet(name="requestHeaderServlet", urlPatterns = "/request-header")
public class RequestHeaderServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
printStartLine(request);
printHeaders(request);
printHeaderUtils(request);
printEtc(request);
}
}
private void printStartLine(HttpServletRequest request) {
System.out.println("--- REQUEST-LINE - start ---");
System.out.println("request.getMethod() = " + request.getMethod()); //GET
System.out.println("request.getProtocol() = " + request.getProtocol()); // HTTP/1.1
System.out.println("request.getScheme() = " + request.getScheme()); //http
// http://localhost:8080/request-header
System.out.println("request.getRequestURL() = " + request.getRequestURL());
// /request-header
System.out.println("request.getRequestURI() = " + request.getRequestURI());
//username=hi
System.out.println("request.getQueryString() = " +
request.getQueryString());
System.out.println("request.isSecure() = " + request.isSecure()); //https 사용 유무
System.out.println("--- REQUEST-LINE - end ---");
System.out.println();
}
private void printHeaders(HttpServletRequest request) {
System.out.println("--- Headers - start ---");
// Enumeration<String> headerNames = request.getHeaderNames();
// while(headerNames.hasMoreElements()) {
// String headerName = headerNames.nextElement();
// System.out.println(headerName +" : " + headerName);
// }
// 요즘 스타일
request.getHeaderNames().asIterator()
.forEachRemaining(headerName -> System.out.println(headerName+ " : " + headerName));
System.out.println("--- Headers - end ---");
System.out.println();
}
private void printHeaderUtils(HttpServletRequest request) {
System.out.println("--- Header 편의 조회 start ---");
System.out.println("[Host 편의 조회]");
System.out.println("request.getServerName() = " +
request.getServerName()); //Host 헤더
System.out.println("request.getServerPort() = " +
request.getServerPort()); //Host 헤더
System.out.println();
System.out.println("[Accept-Language 편의 조회]");
request.getLocales().asIterator()
.forEachRemaining(locale -> System.out.println("locale = " +
locale));
System.out.println("request.getLocale() = " + request.getLocale());
System.out.println();
System.out.println("[cookie 편의 조회]");
if (request.getCookies() != null) {
for (Cookie cookie : request.getCookies()) {
System.out.println(cookie.getName() + ": " + cookie.getValue());
}
}
System.out.println();
System.out.println("[Content 편의 조회]");
System.out.println("request.getContentType() = " +
request.getContentType());
System.out.println("request.getContentLength() = " + request.getContentLength());
System.out.println("request.getCharacterEncoding() = " +
request.getCharacterEncoding());
System.out.println("--- Header 편의 조회 end ---");
System.out.println();
}
[HOST 편의 조회]
해더의 기능을 편리하게 조회하는 기능
브라우저가 보낼 때 호스트 정보를 보냄. 이 값들을 꺼낼 수 있음
[Accept_Language]
:나는 한글이 좋아, 그다음은 영어가 좋아.. 이런 언어 선호도 셋팅
getLocals: local 정보를 다 가져올 수 있음. 언어 선호도 정보를 꺼내올 수 있음.
[Cookie]
쿠키 정보도 계속 넘어옴. 쿠키도 결국 http 헤더에 담김. 쿠키가 모양이 여러 가지가 있기 때문에 데이터 보기가 쉽지 않은데, 이 쿠키도 편하게 꺼낼 수 있도록 지원함. 지금은 쿠키가 없어서 값이 안나옴.
[content]
content = null. Get방식은 content를 안 보내기 때문에 비어있음.
postman을 통해 해더에 post 방식으로 데이터 전달 가능
body에 raw 데이터로 전달.
content-type: text/plaiin 추가됨.
Remote: 요청이 온것에 대한 정보
Local: 나의 서버에 대한 정보
private void printEtc(HttpServletRequest request) {
System.out.println("--- 기타 조회 start ---");
System.out.println("[Remote 정보]");
System.out.println("request.getRemoteHost() = " +
request.getRemoteHost()); //
System.out.println("request.getRemoteAddr() = " +
request.getRemoteAddr()); //
System.out.println("request.getRemotePort() = " +
request.getRemotePort()); //
System.out.println();
System.out.println("[Local 정보]");
System.out.println("request.getLocalName() = " +
request.getLocalName()); //
System.out.println("request.getLocalAddr() = " +
request.getLocalAddr()); //
System.out.println("request.getLocalPort() = " +
request.getLocalPort()); //
System.out.println("--- 기타 조회 end ---");
System.out.println();
}
HTTP 요청 메시지를 통해 클라이언트에서 서버로 데이터를 전달하는 방법을 알아보자.
이 세가지가 다라고 보면 됨. 이 세가지 방식을 분명히 구분해서 알아둬야 나중에 헷갈리지 않는다!
주로 다음 3가지 방법을 사용한다.
다음 데이터를 클라이언트에서 서버로 전송해보자
전달 데이터
메시지 바디 없이, URL의 쿼리 파라미터를 사용해서 데이터를 전달하다.
예) 검색, 필터, 페이징등에서 많이 사용되는 방식
쿼리 파라미터는 URL에 다음과 같이 ?
를 시작으로 보낼 수 있다. 추가 파라미터는 &
로 구분하면 된다.
서버에서는 HttpServletRequest
가 제공하는 다음 메서드를 통해 쿼리 파라미터를 간단하게 구할 수 있다.
String username = request.getParameter("username"); //단일 파라미터 조회
Enumeration<String> parameterNames = request.getParameterNames(); //파라미터 이름들
모두 조회
Map<String, String[]> parameterMap = request.getParameterMap(); //파라미터를 Map
으로 조회
String[] usernames = request.getParameterValues("username"); //복수 파라미터 조회
RequestParamServlet
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 java.io.IOException;
import java.util.Enumeration;
/*
1. 파라미터 전송 기능
http://localhost:8080/request-param?username=hello&age=20
2. 동일한 파라미터 전송 기능
http://localhost:8080/request-param?username=hello&age=20&username=spring
*/
@WebServlet(name="requestParamServlet", urlPatterns = "/request-param")
public class RequestParamServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("[전체 파라미터 조회] - start");
request.getParameterNames().asIterator()
.forEachRemaining(paramName -> System.out.println(paramName + " = " + request.getParameter(paramName)));
// paramName: key이름
// request.getParam(paramName): value
System.out.println("[전체 파라미터 조회] - end");
System.out.println();
System.out.println("[단일 파라미터 조회]");
String username = request.getParameter("username");
System.out.println("username = " + username);
String age = request.getParameter("age");
System.out.println("age = " + age);
System.out.println("[이름이 같은 복수 파라미터 조회]");
String[] usernames = request.getParameterValues("username");
for (String name : usernames) {
System.out.println("username = " + name);
}
response.getWriter().write("ok");
}
}
1. 파라미터 전송 기능
http://localhost:8080/request-param?username=hello&age=20
2. 동일한 파라미터 전송 기능
http://localhost:8080/request-param?username=hello&age=20&username=spring
request.getParameter()
: 하나의 파라미터 이름에 대해서 단 하나의 값만 있을 때 사용.
(중복으로 받는 경우, request.getParameterValues()의 첫 번째 값을 반환함.)
request.getParametrValues("이름")
: 중복인 경우 사용.
HTML의 Form을 사용해서 클라이언트에서 서버로 데이터를 전송해보자.
주로 회원가입, 상품 주문 등에서 사용하는 방식이다
applicaion/x-www-form-urlencoded
username=hello&age=20
src/main/webapp/basic/hello-form.html
생성
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action="/request-param" method="post">
username: <input type="text" name="username" />
age: <input type="text" name="age" />
<button type="submit">전송</button>
</form>
</body>
</html>
http://localhost:8080/basic/hello-form.html
정적 html그대로 보여줌.
action="/request-param". Get방식일 때 사용했던 url로 전송. => 콘솔창에 결과 출력.
주의: 웹 브라우저가 결과를 캐시하고 있어서, 과거에 작성했던 html 결과가 보이는 경우도 있다. 이때는 웹 브라우저의 새로 고침을 직접 선택해주면 된다. 물론 서버를 재시작하지 않아서 그럴수도 있다.
POST의 HTML Form을 전송하면 웹 브라우저는 다음 형식으로 HTTP 메시지를 만든다.(웹 브라우저 개발자 모드 확인)
application/x-www-form-urlencode
username=kim&age=19
application/x-www-form-urlencode
형식은 앞서 GET에서 살펴본 쿼리 파라미터 형식과 같다. 따라서 쿼리 파라미터 조회 메서드를 그대로 사용하면 된다. 클라이언트(웹 브라우저) 입장에선느 두 방식에 차이가 있지만, 서버 입장에서는 둘의 형식이 동일하므로, request.getParameter()
로 편리하게 구분없이 조회할 수 있다.
즉, request.getParameter()
는 GET URL 쿼리 파라미터 형식도 지원하고, POST HTML Form 형식도 둘 다 지원한다.
참고
content-type은 HTTP 메시지 "바디"의 데이터 형식을 지원한다.
GET URL 쿼리 파라미터 형식으로 클라이언트에서 서버로 데이터를 전달할 때는 HTTP 메시지 바디를 사용하지 않기 때문에 content-type이 없다.(출력하면 null이 뜸)
POST HTML Form 형식으로 데이터를 전달하면 HTTP 메시지 바디에 해당 데이터를 포함해서 보내기 때문에 바디에 포함한 데이터가 어떤 형식인지 content-type을 꼭 지정해야 한다. 이렇게 폼으로 데이터를 전송하는 형식을application/x-www-form-urlencoded
라 한다.
이런 간단한 테스트에 HTML Form을 만드는건 너무 귀찮다. 그럴때 Postman을 사용하면 된다.
Postman 테스트 주의 사항
Post 전송 시
x-www-form-urlencoded
선택application/x-www-form-urlencoded
로 지정된 부분 꼭 확인API: 웹 브라우저에서 사용 X. (GET, POST가 주로 html을 전송하기 위해 사용)
HTTP message body 에 데이터를 직접 담아서 요청
먼저 "가장 단순한 텍스트 메시지"를 HTTP 메시지 바디에 담아서 전송하고, 읽어보자!!
HTTP 메시지 바디의 데이터를 InputStream을 사용해서 직접 읽을 수 있다.
request>RequestBodyStringServlet
package hello.servlet.basic.request;
import org.springframework.util.StreamUtils;
import javax.servlet.ServletException;
import javax.servlet.ServletInputStream;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
@WebServlet(name="RequestBodyStringServlet", urlPatterns="/request-body-string")
public class RequestBodyStringServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
ServletInputStream inputStream = request.getInputStream(); //BODY의 내용을 BYTE 코드로 바로 얻을 수 있음.
String messageBody = StreamUtils.copyToString(inputStream, StandardCharsets.UTF_8);// (BYTE -> String) 인코딩 정보를 알려줘야 함.
System.out.println("messageBody = " + messageBody);
response.getWriter().write("ok");
}
}
inputStream은 byte코드를 반환한다. byte코드를 우리가 읽을 수 있는 문자(Strig)로 보려면 문자표(Charset)을 지정해줘야 한다. 여기서는 "UTF_8Charset"을 지정해주었다.
Postman을 이용해 데이터를 보내보자
이번에는 HTTP API에서 주로 사용하는 JSON 형식으로 데이터를 전달해보자.
JSON 형식 파싱 추가
JSON 형식으로 파싱할 수 있게 객체를 하나 생성하자
hello.servlet.basic.HelloData
보통 json을 그대로 사용하지 않고 객체로 바꿔서 사용함 (자바빈 접근법, 자바 프로퍼티 접근법.)
package hello.servlet.basic;
import lombok.Getter;
import lombok.Setter;
@Getter @Setter
public class HelloData {
private String username;
private int age;
}
롬복 install하면다 지우고, @Getter @Setter
적어주면, 코드가 그대로 자동으로 들어가게 됨. (눈에는 안 보인다)
** request> RequestBodyJsonServlet
package hello.servlet.basic.request;
import com.fasterxml.jackson.databind.ObjectMapper;
import hello.servlet.basic.HelloData;
import org.springframework.util.StreamUtils;
import javax.servlet.ServletException;
import javax.servlet.ServletInputStream;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
@WebServlet(name="requestBodyJsonServlet", urlPatterns = "/request-body-json")
public class RequestBodyJsonServlet extends HttpServlet {
private ObjectMapper objectMapper = new ObjectMapper();
@Override
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
ServletInputStream inputStream = request.getInputStream();
String messageBody = StreamUtils.copyToString(inputStream, StandardCharsets.UTF_8);
System.out.println("messageBody = " + messageBody);
// http body에 있는거 다 뿌려주는 것.
HelloData helloData = objectMapper.readValue(messageBody, HelloData.class);
System.out.println("helloData.getUsername() = " + helloData.getUsername());
System.out.println("helloData.getAge() = " + helloData.getAge());
response.getWriter().write("ok");
}
}
받아온 코드를 helloData로 변환시키자
json library가 필요함. 스프링 부트 만들면 jackson이라는 library를 사용하고 있음.
Postman으로 실행해보자.
{"username": "hello", "age": 20}
출력결과
참고: JSON 결과를 파싱해서 사용할 수 있는 자바 객체로 변환하려면 Jackson, Gson 같은JSON 변환 라이브러리를 추가해서 사용해야 한다. 스프링 부트로 Spring MVC를 선택하면 기본으로 Jackson라이브러리 (
ObjectMapper
)를 함께 제공한다.
참고: HTML from 데이터도 메시지 바디를 통해 전송되므로 직접 읽을 수 있다.
(http 스펙에서 message body로 전달되므로 걔도 직접 읽을 수 있음. context-type이 application/x-www-form-unlencoded여도 읽을 수 있음. 단 객체가 아니여서 json으로 전환하는 건 안됨.)
하지만 편리한 파라미터 조회 기능(request.getParameter(...)
)을 이미 제공하기 때문에 파라미터 조회 기능을 사용하면 된다.
지금까지는 Http가 서버에 여러 가지 데이터를 요청하는 메시지를 만들었다면, 이제는 응답하는 메시지를 만들어 볼 것. 개발자가 일일이 만들기 번거로우니 여러 가지 기능들을 제공해준다.
1. HTTP 응답 메서지 생성
2. 편의 기능 제공
hello.servlet.basic.response.ResponseHeaderServlet
package hello.servlet.basic.response;
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;
import java.io.IOException;
import java.io.PrintWriter;
@WebServlet(name="responseHeaderServlet", urlPatterns = "/response-header")
public class ResponseHeaderServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// [status-line]
response.setStatus(HttpServletResponse.SC_OK);
// 상수로 상태들이 정의되어 있음. 의미잇는 값으로 사용되므로 그냥 200을 입력하는것보다 더 좋다!
// [response-headers]
response.setHeader("Content-type", "text/plain;charset=utf-8");
response.setHeader("Cache-Control", "no-cache, no-store, must-revalidate"); // 캐쉬 완전히 무효화
response.setHeader("Pragma", "no-cache");
response.setHeader("my-header", "hello");// 내가 원하는 임의의 헤더를 만들 수도 있음.
// [Header 편의 메서드]
content(response);
cookie(response);
redirect(response);
// [message body]
PrintWriter writer = response.getWriter();
writer.println("ok");
}
private void content(HttpServletResponse response) {
//Content-Type: text/plain;charset=utf-8
//Content-Length: 2
//response.setHeader("Content-Type", "text/plain;charset=utf-8");
response.setContentType("text/plain");
response.setCharacterEncoding("utf-8");
//response.setContentLength(2); //(생략시 자동 생성)
}
private void cookie(HttpServletResponse response) {
//Set-Cookie: myCookie=good; Max-Age=600;
//response.setHeader("Set-Cookie", "myCookie=good; Max-Age=600");
Cookie cookie = new Cookie("myCookie", "good");
cookie.setMaxAge(600); //600초
response.addCookie(cookie);
}
private void redirect(HttpServletResponse response) throws IOException {
//Status Code 302
//Location: /basic/hello-form.html
//response.setStatus(HttpServletResponse.SC_FOUND); //302
//response.setHeader("Location", "/basic/hello-form.html");
response.sendRedirect("/basic/hello-form.html");
}
}
private void content(HttpServletResponse response) {
//Content-Type: text/plain;charset=utf-8
//Content-Length: 2
//response.setHeader("Content-Type", "text/plain;charset=utf-8");
response.setContentType("text/plain");
response.setCharacterEncoding("utf-8");
//response.setContentLength(2); //(생략시 자동 생성)
}
이렇게도 설정 가능
private void cookie(HttpServletResponse response) {
//Set-Cookie: myCookie=good; Max-Age=600;
//response.setHeader("Set-Cookie", "myCookie=good; Max-Age=600");
Cookie cookie = new Cookie("myCookie", "good");
cookie.setMaxAge(600); //600초
response.addCookie(cookie);
}
Cookie를 setting할 수 있는데 이게 번거로워서 그냥 쿠키라는 객체를 제공해 설정을 도움.
private void redirect(HttpServletResponse response) throws IOException {
//Status Code 302
//Location: /basic/hello-form.html
//response.setStatus(HttpServletResponse.SC_FOUND); //302
//response.setHeader("Location", "/basic/hello-form.html");
response.sendRedirect("/basic/hello-form.html");
}
response.sendRedirect("url");
이용해 간단히 redirect 가능.
응답 데이터도 요청과 유사. 주로 다음 내용을 담아서 전달한다.
크게 3개:
writer.println("ok");
) -> 생략package hello.servlet.basic.response;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import java.io.IOException;
import java.io.PrintWriter;
@WebServlet(name="ResponseHtmlServlet", urlPatterns = "/response-html")
public class ResponseHtmlServlet extends HttpServlet {
@Override
public void service(ServletRequest request, ServletResponse response) throws ServletException, IOException {
// Content-Type: text/html;charset=utf-8
response.setContentType("text/html"); // 이게 있어야 웹 브라우저가 아, html이구나 하고 정상적으로 작돟암
response.setCharacterEncoding("utf-8"); // 이게 있어야 한글이 안깨짐
PrintWriter writer = response.getWriter();
writer.println("<html>");
writer.println("<body>");
writer.println(" <div>안녕?</div>");
writer.println("</body>");
writer.println("</html>");
}
}
test/html
로 지정해야 한다.실행
hello.servlet.web.response. ResponseJsonServlet
package hello.servlet.basic.response;
import com.fasterxml.jackson.databind.ObjectMapper;
import hello.servlet.basic.HelloData;
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 java.io.IOException;
@WebServlet(name="ResponseJsonServlet", urlPatterns = "/response-json")
public class ResponseJsonServlet extends HttpServlet {
private ObjectMapper objectMapper = new ObjectMapper();
@Override
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//Content-Type: application/json
response.setContentType("application/json");
response.setCharacterEncoding("utf-8");
HelloData helloData = new HelloData();
helloData.setUsername("kim");
helloData.setAge(20);
// json도 그냥 문자. 객체를 josn형태로 바꿔야 함.
// {"username":"kim", "age":20}
String result = objectMapper.writeValueAsString(helloData);
response.getWriter().write(result);
}
}
HTTP 응답으로 JSON을 반환할 때는 content-type을 applcation/json
로 지정해야 한다.
Jackson 라이버르러가 제공하는 objectMapper.writeValueAsString()
를 사용하면 객체를 JSON 문자로 변경할 수 있다.
참고 그냥 참고만 해주세용
applcation/json
은 스펙상 utf-8형식을 사용하도록 정의되어 있다. 그래서 스펙에서 charset=utf-8과 같은 추가파라미터를 지원하지 않는다.따라서 application/json
이라고만사용해야지application/json;charset=utf-8
이라고 전달하는 것은 의미없는 파라미터를 추가한 것이된다.response.getWriter()
를 사용하면 추가파라미터를 자동으로 추가해버린다. 이때는response.getOutputStream()
으로 출력하면 그런 문제가 없다.