๐Ÿ“‹ Spring MVC - 2. ์„œ๋ธ”๋ฆฟ


์˜ˆ์ œ

์Šคํ”„๋ง์„ ์‚ฌ์šฉํ•˜์ง€๋Š” ์•Š์ง€๋งŒ ์Šคํ”„๋ง ๋ถ€ํŠธ ํ”„๋กœ์ ํŠธ๋ฅผ ๋งŒ๋“ ๋‹ค.
์„œ๋ธ”๋ฆฟ์€ ํ†ฐ์บฃ ๊ฐ™์€ WAS๋ฅผ ์ง์ ‘ ์„ค์น˜ํ•˜๊ณ , ๊ทธ ์œ„์— ์„œ๋ธ”๋ฆฟ ์ฝ”๋“œ๋ฅผ ํด๋ž˜์Šค ํŒŒ์ผ๋กœ ๋นŒ๋“œํ•ด์„œ ์˜ฌ๋ฆฐ ๋‹ค์Œ ํ†ฐ์บฃ ์„œ๋ฒ„๋ฅผ ์‹คํ–‰ํ•ด์•ผ ํ–ˆ๋Š”๋ฐ,
์Šคํ”„๋ง ๋ถ€ํŠธ๋Š” ํ†ฐ์บฃ ์„œ๋ฒ„๋ฅผ ๋‚ด์žฅํ•˜๊ณ  ์žˆ์œผ๋‹ˆ, ์ด๋กœ ์ง„ํ–‰ํ•œ๋‹ค.

๋ณดํ†ต์€ Jar๋ฅผ ์„ ํƒํ•˜์ง€๋งŒ, JSP๋ฅผ ๋Œ๋ฆฌ๊ธฐ ์œ„ํ•ด War๋ฅผ ์„ ํƒํ•œ๋‹ค.

HelloServlet

// ์„œ๋ธ”๋ฆฟ์ด ํ˜ธ์ถœ๋˜๋ฉด ์ด service๊ฐ€ ํ˜ธ์ถœ๋œ๋‹ค.
@WebServlet(name = "helloServlet", urlPatterns = "/hello")
public class HelloServlet extends HttpServlet {
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        super.service(req, resp);
        System.out.println("HelloServlet");
        System.out.println("Request : " + req);
        System.out.println("Response : " + resp);

        String name = req.getParameter("name");
        System.out.println(name);
        resp.setCharacterEncoding("utf-8");
        resp.getWriter().write("hello" + name);
    }
}
HelloServlet
Request : org.apache.catalina.connector.RequestFacade@de1a8e6
Response : org.apache.catalina.connector.ResponseFacade@2b3735f6
amazzi
  • @WebServlet : ์„œ๋ธ”๋ฆฟ ์–ด๋…ธํ…Œ์ด์…˜
  • @ServletComponentScan : ์Šคํ”„๋ง์ด ์ž๋™์œผ๋กœ ์„œ๋ธ”๋ฆฟ์„ ์ฐพ์•„ ๋“ฑ๋กํ•ด์ค€๋‹ค.
  • HTTP ์š”์ฒญ์ด ์˜ค๋ฉด ์„œ๋ธ”๋ฆฟ ์ปจํ…Œ์ด๋„ˆ์ธ WAS๊ฐ€ HTTP ์š”์ฒญ, ์‘๋‹ต ๊ฐ์ฒด๋ฅผ ์„œ๋ธ”๋ฆฟ์— ๋˜์ ธ์ค€๋‹ค.
  • req.getParameter() : ์š”์ฒญ์—์„œ ํ•ด๋‹น Parameter๋ฅผ ๊ฐ€์ ธ์˜จ๋‹ค.
  • resp.setCharacterEncoding("utf-8"); : ํ—ค๋”์— CharacterEncoding์„ ์ง€์ •ํ•œ๋‹ค.
  • resp.getWriter().write(); : write() ์— ๋ฐ”๋””์— ๋‹ด์„ ๋ฐ์ดํ„ฐ๋ฅผ ๋„ฃ์–ด์ค€๋‹ค.

๐Ÿค” RequestFacade?

HttpServletRequest๋Š” ์ธํ„ฐํŽ˜์ด์Šค์ด๋‹ค.
์—ฌ๋Ÿฌ๊ฐ€์ง€ WAS ์„œ๋ฒ„๋“ค์ด ์ด ์ธํ„ฐํŽ˜์ด์Šค์˜ ๊ตฌํ˜„์ฒด๋ฅผ ๊ตฌํ˜„ํ•˜๊ณ  ์žˆ์–ด ๋‹ค์–‘ํ•œ WAS๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ๊ฒƒ์ด๋‹ค.

HTTP ์š”์ฒญ ๋ฉ”์‹œ์ง€ ๋กœ๊ทธ๋กœ ํ™•์ธํ•˜๊ธฐ

application-properties์— ๋‹ค์Œ์„ ์ถ”๊ฐ€ํ•œ๋‹ค.

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

์›น ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์„œ๋ฒ„์˜ ์š”์ฒญ ์‘๋‹ต ๊ตฌ์กฐ


HttpServletRequest

์„œ๋ธ”๋ฆฟ์€ ๊ฐœ๋ฐœ์ž๊ฐ€ HTTP ์š”์ฒญ ๋ฉ”์‹œ์ง€๋ฅผ ํŽธ๋ฆฌํ•˜๊ฒŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก ๊ฐœ๋ฐœ์ž ๋Œ€์‹ ์— HTTP ์š”์ฒญ ๋ฉ”์‹œ์ง€๋ฅผ ํŒŒ์‹ฑํ•œ๋‹ค.
๊ทธ๋ฆฌ๊ณ  ๊ฒฐ๊ณผ๋ฅผ HttpServletRequest ๊ฐ์ฒด์— ๋‹ด์•„์„œ ์ œ๊ณตํ•œ๋‹ค.

  • START LINE
    • HTTP ๋ฉ”์†Œ๋“œ
    • URL
    • ์ฟผ๋ฆฌ ์ŠคํŠธ๋ง
    • ์Šคํ‚ค๋งˆ, ํ”„๋กœํ† ์ฝœ
  • HEADER
    • ํ—ค๋” ์กฐํšŒ
  • BODY
    • form ํŒŒ๋ผ๋ฏธํ„ฐ์˜ ํ˜•์‹ ์กฐํšŒ
    • message body ๋ฐ์ดํ„ฐ ์ง์ ‘ ์กฐํšŒ
  • ๋ถ€๊ฐ€ ๊ธฐ๋Šฅ
    • ์ž„์‹œ ์ €์žฅ์†Œ ๊ธฐ๋Šฅ
      • ํ•ด๋‹น HTTP ์š”์ฒญ์ด ์‹œ์ž‘๋ถ€ํ„ฐ ๋๋‚  ๋•Œ ๊นŒ์ง€ ์œ ์ง€๋˜๋Š” ์ž„์‹œ ์ €์žฅ์†Œ ๊ธฐ๋Šฅ
      • ์ €์žฅ: request.setAttribute(name, value)
      • ์กฐํšŒ: request.getAttribute(name)
    • ์„ธ์…˜ ๊ด€๋ฆฌ ๊ธฐ๋Šฅ
      • request.getSession(create: true)

๊ธฐ๋ณธ ์‚ฌ์šฉ

Start Line

request.getMethod() = GET
request.getProtocal() = HTTP/1.1
request.getScheme() = http
request.getRequestURL() = http://localhost:8080/request-header
request.getRequestURI() = /request-header
request.getQueryString() = username=hello
request.isSecure() = false

ํ—ค๋” ์ •๋ณด

request.getHeaderNames().asIterator()
        .forEachRemaining(headerName -> System.out.println(headerName + ": " +
                request.getHeader(headerName)));
System.out.println("--- Headers - end ---");
System.out.println();

์ด ์™ธ์—๋„ Header ์ •๋ณด๋ฅผ ์ถ”์ถœํ•˜๋Š” ๋ฉ”์„œ๋“œ๋“ค์ด ์žˆ๋‹ค.

  • request.getServerName()
  • request.getServerPort()
  • request.getLocale()
  • request.getCookies()
  • request.getContentType()
  • request.getCharacterEncoding()

HTTP ์š”์ฒญ ๋ฐ์ดํ„ฐ - GET ์ฟผ๋ฆฌ ํŒŒ๋ผ๋ฏธํ„ฐ

๋ฉ”์‹œ์ง€ ๋ฐ”๋”” ์—†์ด, URL์˜ ์ฟผ๋ฆฌ ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ์‚ฌ์šฉํ•ด์„œ ๋ฐ์ดํ„ฐ๋ฅผ ์ „๋‹ฌํ•˜๋Š” ๋ฐฉ๋ฒ•.
์˜ˆ) ๊ฒ€์ƒ‰, ํ•„ํ„ฐ, ํŽ˜์ด์ง•๋“ฑ์—์„œ ๋งŽ์ด ์‚ฌ์šฉ

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

์ฟผ๋ฆฌํŒŒ๋ผ๋ฏธํ„ฐ๋Š”URL์—๋‹ค์Œ๊ณผ๊ฐ™์ด ?๋ฅผ์‹œ์ž‘์œผ๋กœ๋ณด๋‚ผ์ˆ˜์žˆ๋‹ค.์ถ”๊ฐ€ํŒŒ๋ผ๋ฏธํ„ฐ๋Š” &๋กœ๊ตฌ๋ถ„ํ•˜๋ฉด๋œ๋‹ค.

RequestParamServlet

/**
 * ํŒŒ๋ผ๋ฏธํ„ฐ ์ „์†ก ๊ธฐ๋Šฅ
 * 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("1. ์ „์ฒด ํŒŒ๋ผ๋ฏธํ„ฐ ์กฐํšŒ");
        req.getParameterNames()
                .asIterator()
                .forEachRemaining(paramName ->
                        System.out.println(paramName + "=" + req.getParameter(paramName)));

        System.out.println("2. ๋‹จ์ผ ํŒŒ๋ผ๋ฏธํ„ฐ ์กฐํšŒ (๋” ๋งŽ์ด ์“ฐ๋Š” ๋ฐฉ์‹)");
        String username = req.getParameter("username");
        System.out.println(username);

        System.out.println("3. ํŒŒ๋ผ๋ฏธํ„ฐ ์ด๋ฆ„์ด ๊ฐ™์€ ์—ฌ๋Ÿฌ๊ฐœ ๊ฐ’์ด ์žˆ์„ ๊ฒฝ์šฐ");
        String[] usernames = req.getParameterValues("username");
    }
}

HTTP ์š”์ฒญ ๋ฐ์ดํ„ฐ - POST HTML Form

๋ฉ”์‹œ์ง€ ๋ฐ”๋””์— ๋ฐ์ดํ„ฐ๊ฐ€ ๋“ค์–ด๊ฐ€๊ธฐ ๋•Œ๋ฌธ์— content-type์ด ์žˆ๋‹ค.
content-type : application/x-www-form-urlencoded
๋ฐ”๋””์— ์ฟผ๋ฆฌ ํŒŒ๋ฆฌ๋ฏธํ„ฐ ํ˜•์‹์œผ๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ์ „๋‹ฌํ•œ๋‹ค. username=hello&age=20

hello-form.html ์ผ๋ถ€

<form action="/request-param" method="post">
    username: <input type="text" name="username"/> age: <input type="text" name="age"/>
    <button type="submit">์ „์†ก</button>
</form>

์ด์ „์— ๋งŒ๋“ค์—ˆ๋˜ requestParamServlet์— ์š”์ฒญ์„ ๋ณด๋‚ด๋ฉด,

๋‹ค์Œ๊ณผ ๊ฐ™์€ ๊ฒฐ๊ณผ๋ฅผ ์–ป๋Š”๋‹ค!
๊ทธ๋Ÿฐ๋ฐ requestParamServlet๋Š” ์ฟผ๋ฆฌ ํŒŒ๋ผ๋ฏธํ„ฐ๋งŒ ์กฐํšŒํ•˜๋Š”๋ฐ ?

application/x-www-form-urlencoded ํ˜•์‹์€ ์ฟผ๋ฆฌ ํŒŒ๋ผ๋ฏธํ„ฐ ํ˜•์‹๊ณผ ๊ฐ™๋‹ค.
๋”ฐ๋ผ์„œ ์ฟผ๋ฆฌ ํŒŒ๋ผ๋ฏธํ„ฐ ์กฐํšŒ ๋ฉ”์„œ๋“œ๋ฅผ ๊ทธ๋Œ€๋กœ ์‚ฌ์šฉํ•˜๋ฉด ๋œ๋‹ค. ์„œ๋ฒ„ ์ž…์žฅ์—์„œ๋Š” ๋‘˜์˜ ํ˜•์‹์ด ๋™์ผํ•˜๋ฏ€๋กœ, request.getParameter() ๋กœ ํŽธ๋ฆฌํ•˜๊ฒŒ ๊ตฌ๋ถ„์—†์ด ์กฐํšŒํ•  ์ˆ˜ ์žˆ๋‹ค.

request.getParameter() ๋Š” GET URL ์ฟผ๋ฆฌ ํŒŒ๋ผ๋ฏธํ„ฐ ํ˜•์‹๋„ ์ง€์›ํ•˜๊ณ , POST HTML Form ํ˜•์‹๋„ ๋‘˜ ๋‹ค ์ง€์›ํ•œ๋‹ค.

๐Ÿ’ก POSTMAN์œผ๋กœ ํ…Œ์ŠคํŠธํ•  ๊ฒฝ์šฐ

Form ๋ฐ์ดํ„ฐ๋ฅผ ์ž…๋ ฅํ•˜๊ธฐ ๊ท€์ฐฎ์€๋ฐ, ์ด๋•Œ Content-type์„ application/x-www-form-urlencoded ๋กœ ์„ค์ •ํ•œ๋‹ค.


HTTP ์š”์ฒญ ๋ฐ์ดํ„ฐ - API ๋ฉ”์‹œ์ง€ ๋ฐ”๋””

HTTP message body์— ๋ฐ์ดํ„ฐ๋ฅผ ์ง์ ‘ ๋‹ด์•„์„œ ์š”์ฒญํ•œ๋‹ค.
HTTP API์—์„œ ์ฃผ๋กœ JSON์„ ์‚ฌ์šฉํ•œ๋‹ค.

๋‹จ์ˆœ ํ…์ŠคํŠธ

RequestBodyStringServlet - Rawํ•œ String

@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(); // byte ์ฝ”๋“œ๋ฅผ ์–ป์Œ
        String messageBody = StreamUtils.copyToString(inputStream, StandardCharsets.UTF_8); // ์Šคํ”„๋ง์ด ์ œ๊ณตํ•˜๋Š” ์œ ํ‹ธ๋ฆฌํ‹ฐ
    }
}

HTML form๋„ ์ด๋ ‡๊ฒŒ ์กฐํšŒํ•  ์ˆ˜ ์žˆ์ง€๋งŒ ๋ฒˆ๊ฑฐ๋กœ์šฐ๋‹ˆ ์ฟผ๋ฆฌ ํŒŒ๋ผ๋ฏธํ„ฐ ์กฐํšŒ๋ฅผ ์‚ฌ์šฉํ•˜์ž!

JSON

  • content-type: application/json

HelloData

@Getter
@Setter
public class HelloData {
    private String userName;
    private int age;
}

RequestBodyJsonServlet

@WebServlet(name = "requestBodyJsonServlet", urlPatterns = "/request-body-json")
public class RequestBodyJsonServlet extends HttpServlet {
    private ObjectMapper objectMapper = new ObjectMapper();
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        ServletInputStream inputStream = req.getInputStream(); // byte ์ฝ”๋“œ๋ฅผ ์–ป์Œ
        String messageBody = StreamUtils.copyToString(inputStream, StandardCharsets.UTF_8); // ์Šคํ”„๋ง์ด ์ œ๊ณตํ•˜๋Š” ์œ ํ‹ธ๋ฆฌํ‹ฐ

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

JSON ๊ฒฐ๊ณผ๋ฅผ ํŒŒ์‹ฑํ•ด์„œ ๊ฐ์ฒด๋กœ ๋ณ€ํ™˜ํ•˜๋ ค๋ฉด Jackson, Gson ๊ฐ™์€ JSON ๋ณ€ํ™˜ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์ถ”๊ฐ€ํ•ด์„œ ์‚ฌ์šฉํ•ด์•ผ ํ•œ๋‹ค.
์Šคํ”„๋ง ๋ถ€ํŠธ๋กœ Spring MVC๋ฅผ ์„ ํƒํ•˜๋ฉด ๊ธฐ๋ณธ์œผ๋กœ Jackson ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ( ObjectMapper)๋ฅผ ์ œ๊ณตํ•œ๋‹ค.


HTTPServletResponse - ๊ธฐ๋ณธ ์‚ฌ์šฉ๋ฒ•

๊ฐœ๋ฐœ์ž๊ฐ€ ์ง์ ‘ ์‘๋‹ต ๊ฐ์ฒด๋ฅผ ๋งŒ๋“ค๊ธฐ๋Š” ๋ฒˆ๊ฑฐ๋กญ์ง€ ์•Š๊ฒŒ ์„œ๋ธ”๋ฆฟ์ด ์ œ๊ณตํ•ด์ค€๋‹ค!

  • HTTP ์‘๋‹ต์ฝ”๋“œ ์ง€์ •
  • ํ—ค๋” ์ƒ์„ฑ
  • ๋ฐ”๋”” ์ƒ์„ฑ ๋“ฑ๋“ฑโ€ฆ

ResponseHeaderServlet

@WebServlet(name = "responseHeaderServlet", urlPatterns = "/response-header")
public class ResponseHeaderServlet extends HttpServlet {
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //[status-line] ์ƒํƒœ์ฝ”๋“œ ์ง€์ •
        resp.setStatus(HttpServletResponse.SC_OK); //200
        //[response-headers] ์‘๋‹ต ํ—ค๋” ์ง€์ •
        resp.setHeader("Content-Type", "text/plain;charset=utf-8");
        resp.setHeader("Cache-Control", "no-cache, no-store, must-revalidate");
        resp.setHeader("Pragma", "no-cache");
        resp.setHeader("my-header", "hello");
        //[Header ํŽธ์˜ ๋ฉ”์„œ๋“œ] content(response); cookie(response); redirect(response);
        //[message body] ์‘๋‹ต ๋ฐ”๋”” ์ง€์ •
        PrintWriter writer = resp.getWriter();
        writer.println("ok");

        //Content-Type: text/plain;charset=utf-8
        //Content-Length: 2
        //response.setHeader("Content-Type", "text/plain;charset=utf-8");
        resp.setContentType("text/plain"); 
        resp.setCharacterEncoding("utf-8"); 
        //response.setContentLength(2); //(์ƒ๋žต์‹œ ์ž๋™ ์ƒ์„ฑ)
    }
}

์ฟ ํ‚ค ์„ค์ •ํ•˜๊ธฐ

//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 ์„ค์ •ํ•˜๊ธฐ

//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 ์š”์ฒญ ๋ฐ์ดํ„ฐ

๋‹จ์ˆœ ํ…์ŠคํŠธ, HTML

HttpServletResponse

@WebServlet(name = "responseHtmlServlet", urlPatterns = "/response-html")
public class HttpServletResponse extends HttpServlet {
    @Override
    protected void service(HttpServletRequest req, javax.servlet.http.HttpServletResponse resp) throws ServletException, IOException {
        // Content-Type: text:html; charset=utf-8
        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์„ ์ผ์ผํžˆ ์ž‘์„ฑํ•ด์ฃผ์–ด์•ผ ํ•œ๋‹ค?

API JSON

ResponseJsonServlet

@WebServlet(name = "responseJsonServlet", urlPatterns = "/response-json")
public class ResponseJsonServlet extends HttpServlet {
    private final ObjectMapper objectMapper = new ObjectMapper();
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //Content-Type: application/json
        resp.setHeader("content-type", "application/json");
        resp.setCharacterEncoding("utf-8");
        HelloData data = new HelloData();
        data.setUserName("mazzi");
        data.setAge(100);
        
        // JSON์œผ๋กœ ๋ณ€ํ™˜
        String result = objectMapper.writeValueAsString(data);
        resp.getWriter().write(result);
    }
}

(์‚ฌ์‹ค ์Šคํ”„๋ง ์“ฐ๋ฉด ์ด๋ ‡๊ฒŒ ๊ธธ์–ด์ง€์ง€๋„ ์•Š๋Š”๋‹ค.)


โœ๏ธ ๊น€์˜๋‹˜์˜ ์Šคํ”„๋ง MVC 1ํŽธ - ๋ฐฑ์—”๋“œ ์›น ๊ฐœ๋ฐœ ํ•ต์‹ฌ ๊ธฐ์ˆ  ๊ฐ•์˜ ๋…ธํŠธ โœ๏ธ