프로젝트 생성
사전 준비
- Java 17 이상 설치
- IDE : IntelliJ 또는 Eclipse 설치
스프링 부트 스타터로 이동해 스프링 프로젝트를 생성한다.
설정은 사진을 참고해 작성하면된다. 주의할 점은 Packaging 부분! JSP를 실행하기 위해서 War
로 선택해야 한다.
이제 스프링 부트 환경에서 서블릿을 등록하고 사용해보자.
참고로 서블릿은 톰캣 같은 웹 애플리케이션 서버를 직접 설치하고, 그 위에 서블릿 코드를 클래스 파일로 빌드해서 올린 다음, 톰캣 서버를 실행하면 된다. 이 과정이 매우 번거롭다.
스프링 부트는 톰캣 서버를 내장하고 있으므로, 톰캣 서버 설치 없이 편리하게 서블릿 코드를 실행할 수 있다.
Hello Servlet
스프링 부트 서블릿 환경 구성
@ServletComponentScan
어노테이션을 사용해 서블릿을 직접 등록해 사용할 수 있다.
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);
}
}
이제 실제 동작하는 서블릿 코드를 작성해본다.
package hello.servlet.basic;
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebServlet(name = "helloServlet", urlPatterns = "/hello")
public class HelloServlet extends HttpServlet {
// ctrl + o를 통해 상속받는 클래스의 메서드를 쉽게 생성가능
@Override
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
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");
response.getWriter().write("hello " + username);
}
}
서블릿에서는 request 객체로 쿼리 파라미터를 굉장히 편하게 읽는 기능을 제공한다. request.getParameter()
@WebServlet
서블릿 어노테이션
- name : 서블릿 이름
- urlPatterns : URL 매핑
참고로 서블릿 이름이나 URL 매핑은 중복되면 안된다.
HTTP 요청을 통해 매핑된 URL이 호출되면 서블릿 컨테이너는 service()
메서드를 실행한다.
HTTP 요청 메시지 로그로 확인하기
application.properties
파일에 아래의 설정을 추가한다.
logging.level.org.apache.coyote.http11=debug
해당 설정을 추가하고 요청시에는 콘솔에 서버가 받은 HTTP 요청 메시지를 출력한다. 그러나 운영 서버에 해당 설정을 할경우, 성능저하가 발생할 수 있으므로 개발시에만 적용하는 것이 좋다.
웰컴 페이지 설정
이제 내 도메인에 왔을 때 첫 화면인 웰컴페이지를 설정한다. main 바로 아래에 하위 폴더로 webapp 폴더를 생성한다. 그리고 index.html 파일을 생성한다. 그러면 아래 사진과 같이 내 도메인에 접속시 보이는 첫화면으로 설정이 가능하다.
HttpServletRequest
HttpServletRequest
는 개발자가 HTTP 요청 메시지를 편리하게 사용할 수 있도록 HTTP 요청 메시지를 파싱해 이 결과를 HttpServletRequest 객체에 담아 제공
한다.
추가로 여러가지 부가기능도 함께 제공한다.
임시 저장소 기능 : 해당 HTTP 요청이 시작부터 끝날 때 까지 유지되는 임시 저장소 기능
- 저장 :
request.setAttribute(name, value)
- 조회 :
request.getAttribute(name)
세션 관리 기능
request.getSession(create:true)
다양한 메서드가 존재하는데 여기를 클릭해 확인할 수 있다.
HTTP 요청 데이터
HTTP 요청 메시지를 통해 클라이언트에서 서버로 데이터를 전달하는 방법은 주로 아래의 3가지 방법을 사용한다.
- GET - 쿼리 파라미터
- /url?username=syong&age=20
- HTTP 메시지 바디 없이, URL의 쿼리 파라미터에 데이터를 포함해서 전달
- 검색, 필터, 페이징등에서 많이 사용하는 방식
- POST - HTML Form
- content-type : application/x-www-form-urlencoded
- HTTP 메시지 바디에 쿼리 파라미터 형식으로 전달 : username=syong&age=20
- 회원 가입, 상품 주문, HTML Form 사용
- HTTP message body에 데이터를 직접 담아 요청
- HTTP API에서 주로 사용. JSON, XML, TEXT
- 주로 사용하는 데이터 형식은 JSON
- POST, PUT, PATCH
GET 쿼리 파라미터
GET 쿼리 파라미터 방식은 검색, 필터, 페이징 등에서 많이 사용되는 방식이다. 쿼리 파라미터는 URL에 ?
를 시작으로 추가 파라미터는 &
로 구분한다. http://localhost:8080/request-param?username=syong&age=20
아래의 데이터를 클라이언트에서 서버로 전송해본다.
- username=syong
- age=20
서버에서는 HttpServeltRequest가 제공하는 다음 메서드를 통해 쿼리 파라미터를 편리하게 조회할 수 있다.
package hello.servlet.basic.request;
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
/*
* 1. 파라미터 전송 기능
* http://localhost:8080/request-param?username=syong&age=20
* */
@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)));
System.out.println("[전체 파라미터 조회] - end");
System.out.println();
System.out.println("[단일 파라미터 조회]");
String username = request.getParameter("username");
String age = request.getParameter("age");
System.out.println("username = " + username);
System.out.println("age = " + age);
System.out.println("[단일 파라미터 조회] - end");
System.out.println();
System.out.println("[이름이 같은 복수 파라미터 조회]");
System.out.println("request.getParameterValues(username)");
String[] usernames = request.getParameterValues("username");
for (String name : usernames) {
System.out.println("username=" + name);
}
response.getWriter().write("ok");
}
}
POST HTML Form
이번에는 회원가입, 상품 주문 등에서 사용하는 방식인 HTML의 Form을 사용해 클라이언트에서 서버로 데이터를 전송해본다.
POST의 HTML Form을 전송하면 아래의 형식으로 HTTP 메시지를 만든다.
- content-type :
application/x-www-form-urlencoded
- message body: username=syong&age=20
application/x-www-form-urlencoded 형식은 GET의 쿼리 파라미터 형식과 같아 쿼리 파라미터 조회 메서드를 그대로 사용하면 된다. (= request.getParameter() 메서드는 GET URL 쿼리 파라미터 형식도 지원, POST HTML Form 형식도 지원한다)
API 메시지 바디
API 메시지 바디 형식은 HTTP message body
에 데이터를 직접 담아서 요청하고, 주로 HTTP API
에서 사용한다. 주 데이터 형식은 JSON
을 사용하며, POST, PUT, PATCH
에서 사용한다.
단순 텍스트 전송
package hello.servlet.basic.request;
import jakarta.servlet.ServletException;
import jakarta.servlet.ServletInputStream;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.util.StreamUtils;
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();
String messageBody = StreamUtils.copyToString(inputStream, StandardCharsets.UTF_8);
System.out.println("messageBody = " + messageBody);
response.getWriter().write("ok");
}
}
inputStream은 byte 코드를 반환한다. 이러한 byte 코드를 우리가 읽을 수 있는 문자(String)으로 보기 위해 Charset을 지정해주었다. (UTF_8)
Postman을 사용해 테스트 해보자.
- url : http://localhost:8080/request-body-string
- content-type : text/plain
- message body : hello
JSON 전송
이번에는 HTTP API에서 주로 사용하는 JSON 형식으로 데이터를 전달해본다.
JSON 형식의 데이터 전송은 아래의 설정으로 진행한다.
- POST : http://localhost:8080/request-body-json
- content-type :
application/json
- message body :
{"username":"syong", "age":"20"}
JSON 형식의 데이터를 파싱하기 위해선 객체가 필요하다.
package hello.servlet.basic;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
public class HelloData {
private String username;
private int age;
}
lombok이 제공하는 @Getter, @Setter
로 게터와 세터가 자동으로 생성된다. 만일 잘 동작하지 않는다면 프로젝트 생성의 롬복 부분을 다시 확인한다. (아래사진참고)
JSON 결과를 파싱해서 사용할 수 있는 자바 객체로 변환하기 위해선 Jackson, Gson과 같은 JSON 변환 라이브러리를 추가해 사용해야 한다. 스프링 부트로 Spring MVC를 선택하면 기본으로 Jackson 라이브러리(ObjectMapper)
를 함께 제공한다.
HttpServletResponse
HttpServletResponse의 역할은 아래와 같다.
- HTTP 응답 메시지를 생성한다
- HTTP 응답코드 지정
- 헤더 생성
- 바디 생성
- 편의 기능 제공 : Content-Type, 쿠키, Redirect
기본 사용법
@Override
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// [status-line]
response.setStatus(HttpServletResponse.SC_OK);
// [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");
}
이렇게 하나하나 타이핑을 하니 매우 번거롭다. 그래서 편의 메서드를 제공한다.
private void content(HttpServletResponse response) {
response.setContentType("text/plain");
response.setCharacterEncoding("utf-8");
//response.setContentLength(2); //(생략시 자동 생성)
}
Cookie 편의 메서드
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);
}
Redirect 편의 메서드
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");
}
HTTP 응답 데이터
HTTP 응답 메시지는 주로 아래의 내용을 담아 전달한다.
- 단순 텍스트 :
response.getWriter().write("ok");
- HTML
- HTTP API - MessageBody JSON 응답
HTML 반환시에는 content-type을 text/html
로 지정해야한다.
@Override
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// Content-Type : text/html;charset=utf-8
response.setContentType("text/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>");
}
JSON으로 응답하기 위해선 content-type을 application/json
으로 지정해야한다.
@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("syong");
helloData.setAge(20);
String result = objectMapper.writeValueAsString(helloData);
response.getWriter().write(result);
}
위 글은 김영한 스프링 MVC 1편 - 백엔드 웹 개발 핵심 기술의 일부 내용을 정리한 것입니다.
'Backend > Spring' 카테고리의 다른 글
[Spring] 스프링 MVC 1편 - 백엔드 웹 개발 핵심 기술 #4 MVC 프레임워크 (0) | 2024.07.10 |
---|---|
[Spring] 스프링 MVC 1편 - 백엔드 웹 개발 핵심 기술 #3 서블릿, JSP, MVC 패턴 (0) | 2024.06.25 |
[Spring] 스프링 MVC 1편 - 백엔드 웹 개발 핵심 기술 #1 웹 애플리케이션 이해 (0) | 2024.06.17 |
[Spring] 스프링 입문 - 코드로 배우는 스프링 부트 #7 AOP (0) | 2024.06.16 |
[Spring] 스프링 입문 - 코드로 배우는 스프링 부트 #6 스프링 DB 접근 기술 (0) | 2024.06.16 |