Backend

서블릿, HTTP Request, HTTP Response, ObjectMapper

연_우리 2021. 11. 24. 18:19
반응형

목차

     

    서블릿 클래스 만들기

    서블릿 클래스는 HttpServlet을 반드시 상속받아야하며

    @WebServlet 애노테이션을 작성해서 스프링에게 이 클래스가 웹 서블릿 클래스 라는 것을 알려주어야 한다.

    그래야 ServletApplication의 @ComponentScan이 HelloServlet클래스를 서블릿으로 가져올 수 있다.

    HttpServlet 클래스를 실행하면 자동으로 service메서드가 실행된다.

    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.boot.web.servlet.ServletComponentScan;
    
    @ServletComponentScan //hello.servlet 하위의 서블릿을 모두 스프링컨테이너에 등록한다 : 서블릿 자동등록
    @SpringBootApplication
    public class ServletApplication {
    
    	public static void main(String[] args) {
    		SpringApplication.run(ServletApplication.class, args);
    	}
    
    }

     

    @WebServlet(name="서블릿명", urlPatterns="/요청받을 경로")

    http://localhost:8080/hello를 주소창에 입력하면 helloServlet 서블릿이 실행된다.

    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 {
    
            
        }
    
    }

     

     

    서블릿에서 HTTP 요청받기

    HttpServletRequest, HttpServletResponse는 interface이다.

    여러 WAS(tomcat, jetty,...)들이 HttpServletRequest, HttpServletResponse interface를 구현한다.

    그 구현체가 org.apache.catalina.connector.~~ 이다.

     

    Query Parameter

    주소창에 localhost:8080/hello?username=kim 입력 시 ?username=kim 이것을 query parameter라고 한다.
    query parameter는 request.getParameter(String name); 으로 값을 읽어온다.

    @WebServlet(name="helloServlet", urlPatterns = "/hello")
    public class HelloServlet extends HttpServlet {
    
        @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);
    	//HelloServlet.service
    	//request = org.apache.catalina.connector.RequestFacade@cbe2520
    	//response = org.apache.catalina.connector.ResponseFacade@a23bd9c
    
            String username = request.getParameter("username");
            System.out.println(username);
            //username = kim
    
        }
    
    }

     

     

    서블릿에서 HTTP 응답하기

    @WebServlet(name="helloServlet", urlPatterns = "/hello")
    public class HelloServlet extends HttpServlet {
    
        @Override
        protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    
            response.setContentType("text/plain"); 
            //HTML HEADER부분에 응답메시지를 단순 문자열로 보낸다고 알려준다.
            
            response.setCharacterEncoding("utf-8"); 
            //HTML HEADER부분에 응답메시지의 인코딩 방식을 알려준다.
            
            response.getWriter().write("hello "+username); 
            //HTML BODY부분에 응답메시지로 출력하는 내용을 알려준다.
    
        }
    
    }

    localhost:8080/hello?username=Myname 입력 시 아래와 같이 출력된다.

     

    HttpServletRequest

    HTTP 요청 메시지를 개발자가 직접 파싱해서 사용해도 되지만, 매우 불편할 것이다.

    서블릿은 개발자가 HTTP 요청 메시지를 편리하게 사용할 수 있도록 개발자 대신에 HTTP 요청 메시지를 파싱한다.

    그리고 그 결과를 HttpServletRequest 객체에 담아서 제공한다.

     

    HTTP 요청 메시지의 주소정보 출력하기

    @WebServlet(name = "requestHeaderServlet", urlPatterns = "/request-header")
    public class RequestHeaderServlet extends HttpServlet {
        @Override
        protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            /*
            localhost:8080/request-header?username=hello 입력 시
            
            request.getMethod() = GET
            request.getProtocal() = HTTP/1.1
            request.getRequestURL() = http://localhost:8080/request-header
            request.getScheme() = http
            request.getServerName() = localhost
            request.getServerPort() = 8080
            request.getRequestURI() = /request-header 
            request.getQueryString() = username=hello
            */
        }
    
    }

     

     

    HTTP 요청 메시지의 데이터 출력하기

    클라이언트에서 서버로 데이터를 전달하는 방법은 3가지가 있다.

    content-type은 HTTP 메시지 BODY의 데이터 형식을나타낸다.

    GET방식 쿼리 파라미터 사용

    /url?username=hello&age=20
    메시지 BODY 없이 URL의 쿼리파라미터에 데이터를 포함해서 전달한다.

    content-type : 
    GET방식에서는 BODY를 사용하지 않으니 비어있는 것으로 출력된다.

    EX) 검색, 필터, 페이징 등에서 많이 사용한다.
    POST방식 HTML FORM태그 사용

    <form method="post" action="/전달주소">
      <input type="text" name="username" />
      <button type="submit">전송</button>
    </form>
    메시지 BODY에 쿼리파라미터 형식으로 전달한다.

    content-type : application/x-www-form-urlencoded
    content-type을 출력했을 때 위에처럼 나오면 POST방식으로 출력된 것이다.

    EX) 회원가입, 상품주문 등에서 많이 사용한다.
    HTTP Message Body에 데이터를 직접 담아서 요청 메시지 BODY 없이 URL의 쿼리파라미터 없이 데이터만 전달한다.

    JSON, XML, TEXT 등으로 데이터만 전달된다.

     

     

    GET 방식 : 쿼리파라미터 사용

    쿼리파라미터는 URL 맨 끝에서 "?"로 시작하고, "&"로 각각을 연결한다.

     

    http://localhost:8080/request-param?username=hello&age=20

     

    파라미터 키로 값 조회 : String username = request.getParameter("username")

    파라미터명 모두 조회 : Enumeration<String> parameterNames = request.getParameterNames();

    @WebServlet(name = "requestParamServlet", urlPatterns = "/request-param")
    public class RequestParamServlet extends HttpServlet {
        @Override
        protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    
            String username = request.getParameter("username");
            System.out.println("username = " + username);
            //단일 파라미터 조회
            //username = hello
    
            Enumeration<String> parameterNames = request.getParameterNames();
            parameterNames.asIterator().forEachRemaining(paramName ->
                  System.out.println(paramName + "=" + request.getParameter(paramName)));
            //파라미터 모두 조회
            //username=hello
            //age=20
        }
    
    }

     

    http://localhost:8080/request-param?username=hello&age=20&username=hello2

     

    파라미터 키에 값이 2개인 경우 : String[] usernames = request.getParameterValues("username")

    @WebServlet(name = "requestParamServlet", urlPatterns = "/request-param")
    public class RequestParamServlet extends HttpServlet {
        @Override
        protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    
            String[] usernames = request.getParameterValues("username");
            for (String s : usernames) {
                System.out.println("usernames = " + s);
            }
            //복수 파라미터 조회
            //username = hello
            //username = hello2
        }
    
    }

     

     

    POST 방식 : FORM태그 사용

    form태그의 method값에 post를 작성하면 post방식으로 서버에 값이 전달된다.

    (method에 get이라고 작성할수도 있다. 그러면 get방식으로 값이 전달된다.)

     

    <form action="/request-param"> 이면 @WebServlet(urlPatterns = "/request-param") 메서드로 값이 전달된다.

     

    http://localhost:8080/basic/hello-form.html

    <!DOCTYPE html>
    <html lang="en">
    <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>
    @WebServlet(name = "requestParamServlet", urlPatterns = "/request-param")
    public class RequestParamServlet extends HttpServlet {
        @Override
        protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    
            String age = request.getParameter("age");
            //System.out.println("age = " + age);
            //age = 22
            //단일 파라미터 조회
        }
    }

     

     

    HTTP Message Body에 데이터를 직접 담아서 요청 - 단순 데이터 출력

     

    ServletInputStream inputStream = request.getInputStream(); 

    //데이터를 Stream형식으로 가져온다.


    String messageBody = StreamUtils.copyToString(inputStream, StandardCharsets.UTF_8);

    //Stream형식을 UTF-8로 인코딩하여 문자열로 변경한다.

     

    postman으로 테스트 작성

    @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);
            //messageBOdy = plain text!
        }
    }

     

     

    HTTP Message Body에 데이터를 직접 담아서 요청 - JSON 형식

     

    JSON(JavaScript Object Notation)은 텍스트 기반의 데이터 교환 표준이다.

    JSON
    데이터
    "데이터이름" : 값 "name" : "kim"
    JSON
    객체
    {
       "속성명" : 값,
       "속성명" : 값,
       "속성명" : 값...
    }
    {
        "name""식빵",
        "age"1,
        "weight"2.14
    }
    JSON
    배열
    "배열명" : [
      {  "속성명" : 값,  "속성명" : 값,  "속성명" : 값,  ... }
      {  "속성명" : 값,  "속성명" : 값,  "속성명" : 값,  ... }
      {  "속성명" : 값,  "속성명" : 값,  "속성명" : 값,  ... }
    ]
    "dog"[
        {"name""식빵", "age"1"weight"2.14},
        {"name""콩콩", "age"3"weight"2.5},
        {"name""젤리", "age"7"weight"3.1}
    ]

     

    private ObjectMapper objectMapper = new ObjectMapper();

    HelloData helloData = objectMapper.readValue(messageBody, HelloData.class);

    // Jackson라이브러리가 json문자열을 HelloData 클래스 객체로 변경해주었다.

     

    postman으로 테스트 작성

    import lombok.Getter;
    import lombok.Setter;
    
    @Getter  @Setter
    public class HelloData {
        private String username;
        private int age;
    }
    import com.fasterxml.jackson.databind.ObjectMapper;
    import hello.servlet.basic.HelloData;
    import org.springframework.util.StreamUtils;
    
    @WebServlet(name="requestBodyJsonServlet", urlPatterns = "/request-body-json")
    public class RequestBodyJsonServlet extends HttpServlet {
    
        //스프링부트에 기본으로 포함되어있는 jackson 라이브러리
        //json 문자열을 클래스 객체로 변경할 수 있다.
        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);
            //messageBody = {"username" : "kim", "age" : 20}
    
            HelloData helloData = objectMapper.readValue(messageBody, HelloData.class);
            System.out.println("helloData.username = " + helloData.getUsername());
            System.out.println("helloData.age = " + helloData.getAge());
            //helloData.username = kim
            //helloData.age = 20
        }
    }

     

     

    HttpServletResponse

    HTTP 응답 메시지를 생성하는 역할을한다.

    @WebServlet(name = "responseHeaderServlet", urlPatterns = "/response-header")
    public class ResponseHeaderServlet extends HttpServlet {
        @Override
        protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        
            response.setStatus(200);  //성공
            response.setStatus(HttpServletResponse.SC_OK);  //200과 같음. 성공
    
            response.setHeader("Content-Type", "text/plain;charset=utf-8");
            // = response.setContentType("text/plain");
            // = response.setCharacterEncoding("utf-8");
            //응답데이터의 데이터타입, 인코딩방법 설정
    
            response.setHeader("my-header", "hello");
            //임의의 header설정
    
            response.sendRedirect("/basic/hello-form.html");
            //페이지 이동
    
            response.getWriter().write("ok");
            //"ok"로 HTML BODY에 출력한다.
        }
    
    }

     

     

    HTTP 응답 메시지 데이터 보내기

    서버에서 클라이언트로 데이터를 전달하는 방법은 3가지가 있다.

    단순 텍스트 응답 response.getWriter().write("OK");
    HTML 응답 response.setContentType("text/html");
    response.getWriter().println("<html><body>");
    response.getWriter().println("<div>안녕?</div>");
    response.getWriter().println("</body></html>");
    HTTP Message Body에 데이터를 직접 담아서 응답 메시지 BODY 없이 URL의 쿼리파라미터 없이 데이터만 전달한다.

    JSON, XML, TEXT 등으로 데이터만 전달된다.

     

     

    단순 텍스트 응답, HTML 응답

    HTML로 응답할 땐 setContentType을 반드시 "text/html" 로 지정해야한다.

    @WebServlet(name = "responseHtmlServlet", urlPatterns = "/response-html")
    public class ResponseHtmlServlet extends HttpServlet {
        @Override
        protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            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>");
        }
    }

     

     

    HTTP Message Body에 데이터를 직접 담아서 응답 - JSON형식

    JSON으로 응답할 땐 setContentType을 반드시 "application/json" 로 지정해야한다.

     

    private ObjectMapper objectMapper = new ObjectMapper();

    String

     result = objectMapper.writeValueAsString(helloData);

    // Jackson라이브러리가 HelloData클래스 객체를 json문자열로 변경해주었다.

     

    @WebServlet(name="responseJsonServlet", urlPatterns = "/response-json")
    public class ResponseJsonServlet extends HttpServlet {
    
        private ObjectMapper objectMapper = new ObjectMapper();
        //클래스 객체를 Json데이터 형식으로 변환해준다.
    
        @Override
        protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            response.setContentType("application/json");
            response.setCharacterEncoding("utf-8");
    
            HelloData helloData = new HelloData();
            helloData.setUsername("kim");
            helloData.setAge(30);
    
            String result = objectMapper.writeValueAsString(helloData);
            response.getWriter().write(result);
    
        }
    }

     

     

    정리

    서블릿 클래스

    @WebServlet(name="서블릿명", urlPatterns = "/요청받을 경로")
    public class HelloServlet extends HttpServlet {
        @Override
        protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            
        }
    }

     

    Request객체

    파라미터 키로 값 조회 : String username = request.getParameter("username")
    파라미터 키에 값이 2개인 경우 : String[] usernames = request.getParameterValues("username")
    파라미터명 모두 조회 : Enumeration<String> parameterNames = request.getParameterNames();

     

    Response객체

    응답상태 설정 : response.setStatus(HttpServletResponse.SC_OK);
    페이지 이동 : response.sendRedirect("/basic/hello-form.html");

     

    요청받기&응답하기

     

    요청받기 GET 방식 Query Parameter 사용
    ?username=kim&age=20
    POST 방식 FORM태그 사용
    <form method="post" action="/전달주소">
    JSON 데이터 ServletInputStream inputStream = request.getInputStream(); 
    String messageBody = StreamUtils.copyToString(inputStream, StandardCharsets.UTF_8);

    private ObjectMapper objectMapper = new ObjectMapper();
    HelloData helloData = objectMapper.readValue(messageBody, HelloData.class);
    응답하기 단순텍스트 응답 response.getWriter().write("OK");
    HTML 응답 response.setContentType("text/html");
    response.getWriter().println("<html><body>");
    response.getWriter().println("<div>안녕?</div>");
    response.getWriter().println("</body></html>");
    JSON 데이터 response.setContentType("application/json");

    HelloData helloData = new HelloData();
    helloData.setUsername("kim");
    helloData.setAge(30);

    private ObjectMapper objectMapper = new ObjectMapper();
    String result = objectMapper.writeValueAsString(helloData);
    response.getWriter().write(result);

     

     

     

     

    인프런 - 스프링MVC 백엔드 웹개발 핵심기술

     

    반응형
    • 네이버 블러그 공유하기
    • 페이스북 공유하기
    • 트위터 공유하기
    • 구글 플러스 공유하기
    • 카카오톡 공유하기