본문 바로가기
Spring/스프링 MVC 기본

#2 서블릿

by 히포파타마스 2021. 6. 23.

서블릿

 

1. 서블릿 환경 구성(스프링 부트)

스프링 부트는 서블릿을 직접 등록해서 사용할 수 있도록 @ServletComponentScan을 지원한다.

 

 

[@ServletComponentScan]

@ServletComponentScan //서블릿 자동 등록
@SpringBootApplication
public class ServletApplication {

	public static void main(String[] args) {
		SpringApplication.run(ServletApplication.class, args);
	}
}

 

 

[서블릿 예제]

@WebServlet(name = "helloServlet", urlPatterns = "/hello")
public class HelloServlet extends HttpServlet {

    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) 
    throws ServletException, IOException {

        String username = req.getParameter("username");
        System.out.println("username = " + username);

        resp.setContentType("text/plain");
        resp.setCharacterEncoding("utf-8");
        resp.getWriter().write("hello " + username);
    }
}

서블릿 객체는 @WebServlet으로 지정할 수 있다.

 

urlPatterns의 URL으로 HTTP 요청을 하면 서블릿 컨테이너는 service 메서드를 실행한다.

 

HttpServletRequest와 HttpServletResponse를 이용해 HTTP 요청과 응답을 손쉽게 처리할 수 있다.

 

 

[로그 확인 설정]

logging.level.org.apache.coyote.http11=debug

application.properties에 위의 코드를 추가하면 서버가 받은 HTTP 요청 메시지가 출력된다.

 

 

2. HTTP 요청 메시지_HttpServletRequest

HttpServletRequest 객체에는 HTTP 요청 메시지에 관련된 정보가 제공된다.

 

또한 해당 HTTP 요청이 시작될 때 부터 끝날 때 까지 유지되는 임시 저장소 기능을 하기도 한다.

- 저장: request.setAttribute(name, value)

- 조회: request.getAttribute(name)

 

■ HttpServletRequest 제공 기능

 

 □ start-line

 

 · request.getMethod() : HTTP 메서드

 

 · request.getProtocal() : 사용 프로토콜

 

 · request.getScheme() : Scheme

 

 · request.getRequestURL() : URL

 

 · request.getQueryString() : 쿼리문  

 

 □ header

 

 · request.getHeaderNames() : 헤더들을 리스트로 반환

 

 · request.getServerName() : 서버 이름

 

 · request.getServerPort() : 서버 포트

 

 · request.getLocales() :  Accept-Language 리스트로 반환

 

 · request.getCookies() : 쿠키들을 리스트로 반환

 

 · request.getContentType() : 메시지 바디 타입

 

 · request.getContentLength() : 메시지 바디 길이

 

 · rquest.getCharacterEncoding() : 메시지 바디 인코딩 타입

 

 □부가 기능

 

 · request.getRemoteHost() : RemoteHost

 

 · requesst.getLocalName() : 로컬 이름

 

 

3. HTTP 요청 데이터 처리

HTTP 요청 메시지를 서버로 전달하는 방식은 크게 세가지가 있다.

 

■ GET - 쿼리 파라미터

 

메시지 바디 없이 쿼리 파라미터를 통해 전달하는 방법

 

쿼리 파라미터는 URL에 ?를 시작으로 보낼수있다. 추가 파라미터는 &로 구분한다.

 

 

[쿼리 파라미터 예제]

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

 

 

[쿼리 파라미터 사용]

@WebServlet(name = "requestParamServlet", urlPatterns = "/request-param")
public class RequestParamServlet extends HttpServlet {

    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) 
    throws ServletException, IOException {

        System.out.println("[전체 파라미터 조회] - start");

        req.getParameterNames().asIterator()
                .forEachRemaining(paramName -> System.out.println(paramName + "=" 
                + req.getParameter(paramName)));
        System.out.println("[전 파라미터 조회] - end");
        System.out.println();

        System.out.println("[단일 파라미터 조회]");
        String username = req.getParameter("username");
        String age = req.getParameter("age");

        System.out.println("username = " + username);
        System.out.println("age = " + age);

        System.out.println("[이름이 같은 복수 파라미터 조회");
        String[] usernames = req.getParameterValues("username");
        for (String name : usernames) {
            System.out.println("username = " + name);
        }

        resp.getWriter().write("ok man");
    }
}

req.getParameterNames()은 쿼리 파라미터의 키값을 리스트로 반환한다.

 

req.getParameter(키 값)은 쿼리 파라미터의 키에 해당하는 값을 반환한다. 단, 하나의 파라미터 키에 대해 단 하나의 값만 있을 때 사용해야 한다.

 

하나의 키에 값이 중복될 경우 req.getParameterValues(키 값)을 이용해 복수의 값을 반환받을 수 있다.

 

※값이 다수 일경우 getParameter()를 사용하면 getParameterValues()의 첫 번째 값을 반환한다.

 

■ POST - HTML Form

 

HTML로 메시지 바디에 쿼리 파라미터 형식으로 데이터를 전달한다.

 

이 경우, HTTP 요청에서 content-type은 application/x-www-form-urlencoded 이고 message body는 쿼리 파라미터의 형태가 된다.

 

HTML From방식은 앞의 GET 쿼리 파라미터 형식과 같다.

 

때문에 동일한 쿼리 파라미터 메서드를 사용한다.

 

■ HTTP 메시지 바디에 데이터를 직접 담아서 요청

 

 □단순 텍스트

 

 

 [단순 텍스트 읽기]

@WebServlet(name = "requestBodyStringServlet", urlPatterns = "/request-body-string")
public class RequestBodyStringServlet extends HttpServlet {

    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        ServletInputStream inputStream = req.getInputStream();
        String messageBody = StreamUtils.copyToString(inputStream, StandardCharsets.UTF_8);

        System.out.println("messageBody = " + messageBody);

        resp.getWriter().write("ok");
    }
}

메시지 바디의 데이터는 InputStream(getInputStream())을 이용해서 직접 읽을 수 있다.

 

inputStream은 byte코드를 반환한다. StreamUtils.copyToString(InputStream, Charset)은 지정된 Charset으로 InputStream을 String으로 변환한다.

 

 □ JSON 

 

메시지 바디에 데이터를 JSON형식으로 전달한다.

 

JSON 형식의 데이터를 읽기 위해서는 파싱할 수 있는 객체가 필요하다.

 

 

[JSON 형식 파싱 추가]

@Getter @Setter
public class HelloData {

    private String username;
    private int age;

}

롬 북의 @Getter, @Setter 에노테이션으로 Getter와 Setter가 생략되었다.

 

 

[JSON 형식 데이터 읽기]

@WebServlet(name = "requestBodyJsonSevlet", urlPatterns = "/request-body-json")
public class RequestBodyJsonSevlet extends HttpServlet {

    private ObjectMapper objectMapper = new ObjectMapper();

    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) 
    throws ServletException, IOException {
        ServletInputStream inputStream = req.getInputStream();
        String messageBody = StreamUtils.copyToString(inputStream, StandardCharsets.UTF_8);

        System.out.println("messageBody = " + messageBody);

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

        System.out.println("helloData.username = " + helloData.getUsername());
        System.out.println("helloData.age = " + helloData.getAge());

        resp.getWriter().write("ok");
    }
}

objectMapper.readValue(JSON 텍스트, JSON 객체)는 JSON 형식의 텍스트를 JSON 객체 형식으로 반환한다.

 

 

4. HTTP 응답

HttpServletResponse 객체를 이용해 HTTP 응답 메시지를 생성할 수 있다.

 

 

[HttpServletResponse 예시]

@WebServlet(name = "responseHeaderServlet", urlPatterns = "/response-header")
public class ResponseHeaderServlet extends HttpServlet {

    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.setStatus(HttpServletResponse.SC_OK);

        resp.setHeader("Content-Type", "text/plain;charset=utf-8");
        resp.setHeader("Cache-Control", "no-store, must-revalidate");
        resp.setHeader("Pragma", "no-cache");
        resp.setHeader("my-header", "hello");

        PrintWriter writer = resp.getWriter();
        writer.println("ok");
    }
}

· setHeader(이름, 내용) : [이름 : 내용]의 해더를 추가한다.

· response.getWriter() : 메시지 바디에 내용을 추가할 수 있는 객체를 반환한다.

· println(내용) : 내용을 메시지 바디에 추가한다.

 

■ HTTP 응답_HTML

 

 

[HTML로 응답 메시지 작성]

@WebServlet(name = "responseHtmlServlet", urlPatterns = "/response-html")
public class ResponseHtmlServlet extends HttpServlet {

    @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>");
    }
}

println으로 HTML문법을 작성한다.

 

HTML 형식을 사용할 때는 setContentType()으로 ContentType을 "text/html"로 지정해주어야 한다.

 

■ HTTP 응답_JSON

 

 

[JSON으로 응답 메시지 작성]

@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.setHeader("content-type", "application/json");
        response.setCharacterEncoding("utf-8");
        
        HelloData data = new HelloData();
        data.setUsername("kim");
        data.setAge(20);
        
//{"username":"kim","age":20}
        String result = objectMapper.writeValueAsString(data);
        response.getWriter().write(result);
    }
}

메시지 바디에 JSON 형식으로 데이터를 작성하려면 JSON 객체에 데이터를 넣고 JSON 형식으로 변환해서 메시지 바디에 JSON 형식의 텍스트를 기입하면 된다.

 

objectMapper.writeValueAsString(JSON 객체)는 JSON 객체를 JSON 형식의 String으로 변환해서 반환한다.

 

JSON 형식의 데이터를 메시지 바디에 사용하려면 setHeader()를 사용해 content-type을 application/json으로 지정해주어야 한다.

 

'Spring > 스프링 MVC 기본' 카테고리의 다른 글

#6 스프링 MVC 기본 기능  (0) 2021.07.07
#5 스프링 MVC 구조 이해  (0) 2021.06.30
#4 MVC 프레임워크  (0) 2021.06.29
#3 JSP & MVC 패턴 적용  (0) 2021.06.28
#1 스프링 웹 애플리케이션 이해  (0) 2021.06.23

댓글