이 포스팅은 김영한 강사님의 강의를 참고하여 포스팅을 한 것입니다. 문제가 생길 경우 즉시 처리하겠습니다.
https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81-mvc-1/dashboard
스프링 부트 서블릿 환경 구성
스프링 부트는 서블릿을 직접 등록할 수 있도록 @ServletComponentScan 을 지원한다.
@ServletComponentScan 을 class level에 적용하면 애플리케이션이 로딩되면서, 현재 패키지와 하위 패키지 내의 모든 Servlet을 스캔하여 AutoConfig 한다.
@ServletComponentScan
@SpringBootApplication
public class ServletApplication {
다음으로 실제 동작하는 Servlet 객체를 만들어보겠다.
Servlet 을 만들기 위해선, HttpServlet 을 상속하여야 하며, @WebServlet 을 적용하여 name과 매칭할 url을 다음과 같이 지정할 수 있다.
@WebServlet(name = "meronaJoA", urlPatterns = "/olddaemerona")
public class HelloServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
}
}
이전 포스팅에서도 말했듯이 Client에서 url을 호출하였다면, Servlet Container 가 클라이언트의 Request를 토대로 HttpServletRequest 를 생성하고, HttpServletResponse 또한 생성한다. 이후 Thread가 Servlet 객체의 service()를 호출하면서, Parameter로 이 두 객체를 넘겨준다.
실제로 우리가 알고 있는 지식이 정말 맞는지 확인하기 위해 디버깅을 해보자
*Servlet을 완전 처음 접하셨다면, 여기는 넘어가시거나 그렇구나 정도로 이해하시는 정도면 충분합니다!
지금부터 무식한 방식이긴 하지만 Thread가 Task에 배정되고, ServletRequest 객체를 생성하고, service()를 호출하는지 디버깅을 해보면서 내가 느낀 특징을 따로 설명없이 정리하겠다. 이렇게 하면 기억에도 오래 남을 거 같고, 복습할 때 놓지는 부분이 없어질 거 같았기 때문이다.
처음으로 Application 이 실행되고, 쭉쭉 따라 올라와봤더니, 내가 만든
Servlet 이 "meronaJoa"라는 이름으로 Servlet Container 에 빈이 등록이 된다는 것을 확인했다.
그럼 이제 해당 URL을 호출해보겠다.
- 요청이 들어오면 Tomcat 은 Thread Pool 에 있는 WorkerThread를 Task에 배정하여서 요청을 처리한다.
- 늘 얘기하던대로 Tomcat의 defaultPoolSize는 200개고, corePoolSize도 10개인 것을 눈으로 직접 확인했다.
- 실제로 HttpServletRequest/Response를 생성하는 것은 1번째 사진을 보면 알 수 있듯이 정확히 Http11Processor 이였다. 이는 ServleteContainer 내부에서 동작하는 요소중 하나이다. (내가 알고 있는 Connector와 관련이 있어 보인다.)
- 2번째 사진을 확인해보면, 정말로 Client Request를 토대로 파싱해서, HttpServletRequest 를 생성하고 있었다.
- 마지막으로 HttpServletResponse 도 생성하지만, 당연히 거의 모든 value가 null 이거나 false였다. (응답을 위한 객체니까)
- 서블렛 이전에 doFilter()를 거쳐서 들어오는 것을 확인할 수 있었다.
- 처음에 배정된 Worker Thread 가 정말로 service()를 호출하면서, parameter로 두 객체를 전달하고 있었다.
참고 : HttpFacade
하지만, 여기서 의아했던 점이 있었는데 아까의 request/response 주솟값이 현재 주솟값과 다르다. 다른 객체인건가?
처음엔 Request@5581,Response@5582 였지만, 지금은 @5501,@5502다. 분명 뭔가 변화가 생겼다.
HttpServletRequest 는 Servlet Container 내부에서 생성되고, Servlet 에게 전달되는 객체이기 때문에, 다른 클래스에서 이 메서드를 호출해서 값이 바뀌는 것과 같은 우려가 있다. 그래서 이러한 상황을 제거하기 위해서 RequestFacade 와 같은 클래스가 사용되며, 이 클래스는 HttpServletRequest 를 래핑하고 있어서, 호출되는 메서드는 아무런 구현이 없고, 단지 래핑만 하는 클래스이다.
즉, RequestFacade를 통해 HttpServletRequest 객체를 사용하면, 다른 클래스에서 이 메서드를 호출해서 값이 바뀌는 것을 방지할 수 있다.
그리고 자세히 보면 coyoteRequest 에 처음에 만든 @5581의 request 객체가 존재했고, URI도 "올때메로나"로 제대로 되어 있었다. 이름이 coyote인데, 아마도 아까 두 객체를 생성하는 Http11Processor 가 Connector 와 관련이 있고, Connector 는 Tomcat Coyote 패키지 내부에 존재하기 때문에 이러한 이름이 붙는거 같다.(*뇌피셜)
간단한 메서드들
우선, 나는 다음과 같이 service를 작성하였다.
쿼리 파라미터로 key를 icecram으로 날리고, 값을 꺼내와서 화면으로 "올 때 + icecream"을 출력할 것이다.
@WebServlet(name = "meronaJoA", urlPatterns = "/olddaemerona")
public class HelloServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String icecream = req.getParameter("icecream");
// text 형식으로 응답을 보낸다.
resp.setContentType("text/html");
// 한글 인코딩
resp.setCharacterEncoding("utf-8");
// 응답 작성
resp.getWriter().write("올 때 " + icecream);
}
}
다음과 같이 쿼리 파라미터의 값을 꺼내와서 응답이 잘 되었다.
쿼리 파라미터는 '?'로 시작을 하며, 여러 쿼리 파라미터를 보내야 할 경우엔 '&'으로 연결하면 된다. 예시를 보자.
우선 개수를 parameter로 가져오기 위하여 다음과 같은 코드를 추가하고 수정했다.
// 쿼리 파라미터 key 값
String scoop = req.getParameter("scoop");
// 응답 작성
resp.getWriter().write("올 때 " + icecream + " " + scoop);
이렇게 실제로 service()가 호출되기까지 어떠한 동작이 흘러가는지 직접 확인해았고, 간단한 메서드들을 사용하는 방법까지 알아보았다.
Welcome Page [index.html]
참고로, 서블릿은 webapp 디렉토리 내부에 index.html 파일을 놔두면 웰컴 페이지가 된다.
웰컴 페이지란 간단하게 도메인만 치고 들어왔을 때 나오는 페이지다.
HttpServletRequest의 특징
클라이언트가 서버로 보내는 요청을 매번 개발자가 직접 파싱해야 한다면, 매우 불편할 것이다.
Servlet
은 개발자가 클라이언트로부터 전송된 요청 메세지를 편리하게 파싱하고 요청을 처리할 수 있도록 개발자 대신 파싱해주고, 이 결과를 HttpServletRequest 객체에 담는다. 따라서, 가장 기본적인 HttpServletRequest 에 대해서 더 깊게 알아보자.
1. HTTP 요청 메세지
내가 위에서 서버로 요청을 보낼 때 다음과 같은 요청 메세지가 생성되었다.
- START LINE
- HTTP 메서드
- URL
- Schema, Protocol
- HEADER
- 헤더 조회
- BODY
- form 파라미터 형식 조회
- message body 데이터 형식 조회
2. 임시 저장소 기능
HttpServletRequest 와 HttpServletResponse 는 모두 요청 메세지가 생성된 이후부터, 응답이 나가기까지의 life-cycle을 가지고 있는다. 이때동안 객체 내부에 임시 저장소가 있는데 아래의 두 메서드로 임시 저장소 기능을 사용할 수 있다.
- 저장: request.setAttribute(name, value)
- 조회: request.getAttribute(name)
HttpServletRequest의 사용법
HttpServletRequest 메서드 [메타 정보 조회]
1. START LINE 조회
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://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();
}
2. HEADER 조회
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();
}
이렇게, HttpServletRequest 객체로부터 요청 메세지에 대한 여러 정보를 가져올 수 있다.
메서드가 어떠한 기능을 하는지, 명확하게 나와있기 때문에 따로 외우지 않아도 필요할 때 쳐보면 사용 가능할 것이다. (근데 이걸 쓰긴 하는지도 의문..)
물론 위와 같이 하나하나씩 꺼내오지 않고도 application.properties 파일에 다음과 같은 설정을 하면 HTTP 요청 정보를 알아서 로깅으로 남겨준다.
logging.level.org.apache.coyote.http11=debug
*하지만 운영중인 서버에 적용하면 성능 저하가 발생할 수 있으므로, 개발 단계에서만 적용하자.
이렇게, 메타 정보를 조회하는 방법을 알아봤고, 이제는 실제 쿼리 파라미터 혹은 API와 같이 메세지 바디에 데이터를 직접 담아서 전송하는 것과 같이 실제 데이터를 조회하는 방법을 알아보자.
HttpServletRequest 메서드 [Data 조회]
HTTP 프로토콜에선 다음과 같은 3가지 방식만이 사용된다.
- GET - 쿼리 파라미터
- /olddaemerona?icecream=babamba
- 메세지 바디 없이, URI과 데이터를 쿼리 파라미터 형식으로 같이 전송. 더 자세하겐, 바디를 사용할 순 있지만 호환성 문제로 추천하지 않음.
- 메세지 바디가 없으므로 content-type 이 없음.
- 주로 검색, 필터, 페이징에 쓰임
- POST - HTML Form
- content-type: application/x-www-form-urlencoded
- 메세지 바디에 다음과 같이 쿼리 파라미터 형식으로 전송
- icecream=babamba&scoop=100
- API
- JSON, XML, TEXT ...
- JSON이 주로 쓰임.
- 쿼리 파라미터 형식은 GET/POST만 사용할 수 있지만, API에서는 PUT/PATCH/DELETE 사용 가능
1. GET Quary Parameter 조회
1. 전체 파라미터 조회
req.getParameterNames().asIterator()
.forEachRemaining(paramName -> System.out.println(paramName + ":" + req.getParameter(paramName)));
2. 단일 파라미터 조회
String username = req.getParameter("username");
String age = req.getParameter("age");
System.out.println("username = " + username);
System.out.println("age = " + age);
3. 하나의 파라미터에 복수 파라미터 값 조회
String[] usernames = req.getParameterValues("username");
for (String userName : usernames) {
System.out.println("userName = " + userName);
}
이렇게 하고 다음 URL을 호출하였다.
http://localhost:8080/request-param?username=hello&age=20&username=spring
출력 결과 :
[전체 파라미터 조회] - start
username:hello
age:20
[전체 파라미터 조회] - end
[단일 파라미터 조회] - start
username = hello
age = 20
[단일 파라미터 조회] - end
[이름이 같은 복수 파라미터 조회] - start
userName = hello
userName = spring
2. POST HTML Form 데이터 조회
이젠 HTML의 Form을 사용하여 클라이언트에서 서버로 데이터를 전송하고, 간단하게 랜더링 해보겠다.
아래는 내가 아주 단순하게 작성한 회원 가입 양식이다.
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
form {
max-width: 500px;
margin: 0 auto;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 20px;
border: 1px solid #ccc;
border-radius: 10px;
}
label {
display: inline-block;
margin-bottom: 10px;
}
input[type="text"],
input[type="email"],
input[type="password"] {
width: 100%;
padding: 10px;
margin-bottom: 20px;
border: 1px solid #ccc;
border-radius: 5px;
box-sizing: border-box;
}
input[type="submit"] {
background-color: #4CAF50;
color: white;
padding: 10px 20px;
border: none;
border-radius: 5px;
cursor: pointer;
}
input[type="submit"]:hover {
background-color: #45a049;
}
</style>
</head>
<body>
<form action="/add-members" method="post">
<label for="name">이름:</label>
<input type="text" id="name" name="name" required>
<label for="email">이메일:</label>
<input type="email" id="email" name="email" required>
<label for="password">비밀번호:</label>
<input type="password" id="password" name="password" required>
<label for="confirm-password">비밀번호 확인:</label>
<input type="password" id="confirm-password" name="confirm-password" required>
<input type="submit" value="회원가입">
</form>
</body>
</html>
나는 이 리소스의 디렉토리를 "/basic/hello-form.html"로 잡았고, action 속성을 매핑할 수 있는 하나의 서블릿 객체를 추가하였다.
@WebServlet(name = "memberServlet", urlPatterns = "/add-members")
public class MemberServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("name :" + req.getParameter("name"));
System.out.println("email :" + req.getParameter("email"));
System.out.println("password :" + req.getParameter("password"));
System.out.println("confirmPWD :" + req.getParameter("confirm-password"));
resp.getWriter().write("ok");
}
}
그리고 이 양식에 데이터를 다음과 같이 적어놓고 제출해보겠다.
만약 Servlet에 대해 처음 접근하는 분들이라면, GET 방식과 POST Html Form 방식 모두 getParameter()로 가져올 수 있기 때문에, 헷갈릴 여지가 있다. 따라서 정리해보겠다.
POST의 Html Form을 전송하면 웹 브라우저는 알아서 HTTP 요청 메세지를 생성하는데 전반적으로 GET 호출과 유사하지만 다른 부분이 있다.
- content-type : application/x-www-form-urlencoded (이것은 Html Form으로 데이터를 전송하면, 웹 브라우저가 자동으로 해당 content-type으로 설정한다.
- message body :name=%EC%A7%80%EC%84%B1%EC%9D%80&email=berkleeboston%40naver.com&password=test1234&confirm-password=test1234 (name의 값이 깨진 이유는 한글이라서)
- content-type은 후에 협상(Negociation)과도 관련이 있기에 제대로 알고 있자.
딱 보면 알겠지만 GET 방식에서 쿼리 파라미터 형식과 POST Html Form의 Message Body에 작성되는 실제 데이터의 형식도 모두 key=value 형식과 같이 동일하다. 따라서 getParameter() 는 이 두 형식을 지원하기 때문에 그대로 사용하면 된다.
즉, getParameter() 는 Parameter 형식을 지원하는 메서드라고 생각하면 이해하기도 쉬울거 같다.
참고 : Postman
개발 단계에서 POST를 테스트 하기 위해서 매번 이렇게 HTML Form을 만들기엔 귀찮고 번잡한 작업이 될 수 있다.
이럴 땐 Postman 이라는 툴을 사용하자.
이제 마지막으로 API의 방식에 대해서 알아보자.
3.1 API 메세지 바디 - Simple Text
우선 나는 다음과 같은 Servlet 을 추가하였다.
@WebServlet(name = "requestBodyStringServlet", urlPatterns = "/request-body-string")
public class RequestBodyStringServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// inputStream을 사용하면 request의 body를 binary data로 읽어들일 수 있다.
ServletInputStream inputStream = req.getInputStream();
// 아래의 메서드는 inputStream을 복사하여 String으로 바꾼다.
String msgBody = StreamUtils.copyToString(inputStream, StandardCharsets.UTF_8);
System.out.println("msgBody = " + msgBody);
resp.getWriter().write("ok");
}
}
Postman으로 Body에 데이터를 적고 전송하면 제대로 인코딩 되어 출력되는 것을 확인할 수 있을 것이다.
하지만 이렇게, API 통신에서 주로 JSON으로 많이 주고 받지 단순 텍스트를 주고 받는 일은 잘 없는것 같다.
3.2 API 메세지 바디 - JSON
우선 위에서 만든 서블릿으로 JSON 데이터를 전송하였다.
- 전송 URL :http://localhost:8080/request-body-string
- Body :{"iceCreamName":"메로나", "price":"1000"}
- 출력 : msgBody = {"iceCreamName":"메로나", "price":"1000"}
JSON인 경우에도 아무 탈 없이 Body 데이터를 제대로 읽어와서 문자열 그대로 읽어온다.
하지만 서버에선 이런 JSON 그 자체의 문자열을 원하는게 아닌 이런 값들을 읽어와서 객체에 바인딩 된 결과를 원할 것이다.
따라서, 프로퍼티 규약에 알맞게 다음과 같은 클래스를 생성했다.
@Data
public class HelloIceCream {
private String iceCreamName;
private int price;
}
참고 : 롬복
Lombok에 대해서 모른다면, 간단히 설명해보겠다.
우선 Lombok 라이브러리 는 @Getter,@Setter, @AllArgsConstructor, @toString(),@Data, @RequiredArgsConstructor, @EqualsAndHashCode와 같은 다양한 편의 기능을 제공한다.
이들 모두 눈에 보이진 않지만 자동으로 생성되어 있다.
- @Getter/Setter : 클래스의 모든 필드의 Getter/Setter method를 자동 생성
- @ToString : toString()을 자동으로 오버라이딩
- @AllArgsConstructor : 모든 필드의 생성자를 자동 생성
- @Data : @Getter/Setter, @ToString, @RequireArgsConstor, @EqualsAndHashCode등을 자동 추가
- @Data는 너무 많은 기능을 제공하므로, 중요한 도메인 객체에 사용하는 것은 권장하지 않는다. 예를 들면 DTO, Form 객체에 사용하기 적당하다고 본다. 하지만 지금은 단순히 예제라서 사용했다.
- @RequiredArgsConstructor : 생성자 주입에 용이, @Autowired를 사용하지 않아도, final 제어자가 붙은 필드에 대해서 자동으로 의존성 주입 (final 안붙이면 의존성 주입 안됩니다)
JSON 형식을 파싱해서 객체로 변환하려면 Jackson, Gson 같은 JSON 변환 라이브러리를 추가적으로 사용해야 한다.
스프링 부트로 Spring MVC를 선택하면 기본으로 Jackson Library (Object Mapper) 를 같이 제공한다.
따라서 해당 Servlet 에 다음과 같은 두개의 코드를 추가하였다.
// 필드에 추가
private final ObjectMapper om = new ObjectMapper();
HelloIceCream helloIceCream = om.readValue(msgBody, HelloIceCream.class);
이렇게 하고, 출력 결과를 확인해보니 제대로 값이 바인딩 되어서 JSON 형식을 토대로 한 객체가 생성이 되었다.
HttpServletRequest 간단 정리
- HttpServletRequest 는 클라이언트의 요청 메세지를 파싱하여 만들어지고, 여기엔 많은 Start-line, Header, Body의 다양한 정보가 포함되어 있음
- HTTP 프로토콜 은 GET Quary Parameter 조회, POST HTML Form, API 3가지 형식에서 벗어나지 않는다.
- GET , POST HTML Form :
- GET Quary Parameter 조회와 POST HTML Form은 모두 Quary Parameter 형식이므로, 이 데이터를 조회할 땐 getParameter() 를 동일하게 사용하여 값을 꺼낼 수 있다. (다만, HTML Form은 메세지 바디에 데이터를 담기 때문에 content-type 헤더가 추가로 필요하다)
- API :
- API는 요즘엔 JSON을 많이 사용하고 있으며, Message Body에 데이터를 담아서 요청을 보낸다. 요청의 Message Body 데이터를 읽어들일 때, InputStream 을 얻어와서 binary data로 바꿀 수 있다. (물론 Html Form도 InputStream 으로 읽어들일 수 있다.)
- 읽어들인 binary data는 StrreamUtils의 copyToString() 으로 binary data를 String으로 복사해서 가져올 수 있다.
- 만약 content-type이 Application/json 이라면 추가로 Jackson, Gson 라이브러리를 사용해야 객체로 변환이 가능한데, 스프링 MVC는 기본적으로 (Object Mapper) 를 제공한다.
- GET , POST HTML Form :
HttpServletResponse의 사용법
내가 존경하는 김영한 강사님께서도 매번 말씀하듯이 개발자는 말보다 코드이므로 코드를 바로 확인해보자
@WebServlet(name = "responseHeaderServlet", urlPatterns = "/response-header")
public class ResponseHeaderServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// Cache invalidation
resp.setHeader("Cache-Control", "no-cache, no-store, must-revalidate");
resp.setHeader("Pragma", "no-cache");
// 임의의 헤더 생성
resp.setHeader("my-header", "hello");
// ============= Header convenience methods =============
// set Content-type
resp.setContentType("text/plain");
resp.setCharacterEncoding("utf-8");
// set-cookie
Cookie cookie = new Cookie("iceCream", "merona!");
cookie.setMaxAge(600);
resp.addCookie(cookie);
// redirect
resp.setStatus(HttpServletResponse.SC_FOUND);
resp.sendRedirect("https://bojalgorism.tistory.com/");
resp.getWriter().write("ok");
}
}
redirect 정도만 간단히 설명하자면, response의 상태 코드가 3xx이고 location이 지정되어 있다면, 응답을 받은 클라이언트는 다시 해당 location으로 서버에 요청한다. 주로 PRG 패턴으로 많이 쓰인다.
참고 : 혹시 혹시 쿠키와 세션, 캐쉬에 대해 잘 모르고 있다면?
스프링 MVC에 전반적으로 깊게 이해하기 힘들다.
HTTP 기본 지식은 정말 각 잡고 공부하면 금방 끝내니까 꼭 공부할 것을 추천한다.
나는 이 강의로 공부했는데 가격도 저렴하고 추천한다.
HTTP 응답 데이터 - 단순 텍스트, HTML
이건 간단하니까 바로 코드를 보여주겠다.
@WebServlet(name = "responseHtmlServlet", urlPatterns = "/response-html")
public class ResponseHtmlServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 먼저 인코딩과 contentType 을 지정
resp.setContentType("text/html");
resp.setCharacterEncoding("utf-8");
PrintWriter writer = resp.getWriter();
writer.println("<html>");
writer.println("<body>");
writer.println(" <div> 잠온다.. </div>");
writer.println("</body>");
writer.println("</html>");
}
}
이렇게 하면 html을 바로 작성해서 응답할 수 있다.. 이렇게 일일히 작성하는 걸 보고 있으면 벌써부터 피곤해진다..
HTTP 응답 데이터 - API JSON
HttpServletRequest 의 JSON을 객체로 변환할 때와 마찬가지로, 객체를 JSON 타입의 문자열로 변환할 때 역시, ObjectMapper를 사용하면 된다. 이번엔 writeValueAsString() 을 사용한다.
@WebServlet(name = "responseJsonServlet", urlPatterns = "/response-json")
public class ResponseJsonServlet extends HttpServlet {
private final ObjectMapper om = new ObjectMapper();
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("application/json");
HelloIceCream helloIceCream = new HelloIceCream("메로나", 1000);
String result = om.writeValueAsString(helloIceCream);
resp.getWriter().write(result);
}
}
참고 :
Application/json 은 스펙상 utf-8 형식을 사용하도록 정의가 되어 있으므로 json으로 응답을 작성할 땐 인코딩을 설정할 필요가 없다. 그런데 response.getWriter()는 추가 파라미터를 자동으로 추가해버리므로 이걸 원하지 않는다면 response.getOutputStream()으로 출력하면 된다.
댓글은 블로그 주인장에게 힘이 됩니다! 수정할 부분 있으면 알려주세요!
'스프링 > 스프링 MVC' 카테고리의 다른 글
스프링 MVC 기본 기능 (0) | 2023.05.16 |
---|---|
스프링 MVC 구조 (0) | 2023.05.15 |
MVC 프레임워크 (0) | 2023.05.14 |
Servlet의 한계, 템플릿 엔진, MVC 패턴 (0) | 2023.05.13 |
Spring MVC : 컨테이너 (2) | 2023.05.11 |