서블릿

Single Ko·2023년 5월 31일
0

Spring 강의 정리

목록 보기
9/31

Servlet


스프링 MVC를 사용하기전, 서블릿을 사용하는 방법을 좀 살펴보겠다.

@ServletComponentScan -> servlet 찾아서 자동 등록. main에 붙이자

@WebServlet(name = "서블릿이름", "urlPatterns="path") : 서블릿 클래스로 만들기위한것

extends HttpServlet (서블릿을 사용하려면 이 클래스를 상속받아야됨)

HttpServlet을 상속받으면

@override
protected void service(HttpServletRequest request, 
					   HttpServletResponse response) throws ServletException {

  //쿼리 파라미터를 쉽게 읽을수 있는 방법을 지원함
  String username = request.getParameter("쿼리파라미터이름"); -> 바로 읽을수 있음.

  //응답으로 보낼는 방법들
  response.setContentType("text/pain");
  response.setCharacterEncoding("utf-8");
  response.getWriter().write("hello " + username);  //화면에 띄우는 방법
}

application.yml (properties)에서 http 정보를 로그로 볼 수 있는 설정
운영서버에서는 이렇게 모든 로그를 남기면 성능에 문제가 발생. 개발때만 사용

`loggin.level.org.apache.coyote.http11=debug` (properties)

logging:
  level:
    web: debug  (yml)

HttpServletRequest


HTTP 요청 메시지를 개발자가 직접 파싱해서 하기 매우 불편하다. 서블릿은 HTTP 요청 메시지를 편리하게 사용할 수 있도록 HTTP 요청 메시지를 파싱한다. 그 결과를 HttpServletRequest객체에 담아서 제공.

HTTP 요청 메시지에 대해 쉽게 읽을 수 있도록 가능

부가 기능도 함께 제공.
HTTP 요청이 시작부터 끝날때까지 유지되는 임시 저장소 기능
저장 : request.setAttribute(name, value)
조회 : request.getAttribute(value)

** 세션 관리 : request.getSession(create: true)

중요
Request, Response를 사용할 때 가장 중요한 점은 HTTP 스펙을 잘 이해해야된다는 것이다. 이런 HttpServletRequest, Response는 HTTP 를 편리하게 사용하도록 도와주는 객체라는 점이다.

기능

request.getMethod(); 		// HTTP METHOD
request.getProtocol(); 		// HTTP/1.1
request.getScheme();  	    // http
request.getRequestURL(); 	// http://localhost:8080/path
request.getRequestURI();  	// /path
request.getQueryString();	// 쿼리 파라미터 username=kim
request.isSecure();			// https 사용 유무
request.getHeaderName().asIterator
		.forEachRemaining(headerName -> ...);
        					// 헤더 정보를 전부 받아 올 수 있음.
request.getHeaderName("원하는정보(ex : host)")
 // 이렇게 말고도 헤더의 각각 정보만 빼낼 수 있음
 request.getServerName();
 request.getServerPort();
 request.getLocales();  , request.getLocale();
 request.getCookies(); 
 request.getContentType();
 request.getContentLength();
 request.getCharacterEncoding();

이 외에도 많음. 하지만 사실 이런걸 직접 쳐서 빼낼 일은 요즘은 거의없음(Spring사용하기 때문에)

HTTP 요청

  • GET - 쿼리파라미터, 메시지 바디 없이, URL의 쿼리 파라미터에 데이터를 포함해서 전달

  • POST - HTML Form : application/x-www-form-urlencoded, 메시지 바디에 쿼리 파라미터 형식으로 전달.

  • HTTP message body : HTTP API에서 주로 사용. JSON,XML,TEXT 방식. PUT,PATCH,DELETE, POST 등..

쿼리 파라미터 - 단일 조회, 복수 파라미터도 등의 전송가능. (GET에서 보통 검색, 필터, 페이징등의 방식에서 사용)

HTML FORM - 메시지 바디에 담긴 쿼리 파라미터. x-www-form-urlencoded 형식 사용. 실제 쿼리 파라미터와 동일하게 조회 가능. 클라이언트의 입장에서는 차이가 있지만, 서버의 입장에서는 둘의 형식이 동일. (게시글 등록)

HTTP API - message body에 데이터를 직접 담아서 요청.(데이터형식은 주로 JSON) 스프링 부트로 Spring MVC를 선택하면 기본적으로 Jackson 라이브러리 (ObejctMapper) 제공.

// json 형식
{
	"username": "hello",
    "age": 20
}

HttpServletResponse


응답은 HTTP 스펙에 있는 HTTP 헤더들을 설정하고 받아올수있다. message body도 가능

//[status-line]
response.setStatus()  // 숫자를 직접 넣어도 되지만, 명시된 상수를 사용하는게 좋다.

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

// [header-편의 메서드]
response.setContentType("text/plain");
response.setCharacterEncoding("utf-8);
Cookie cookie = new Cookie("myCookie","good");
cookie.setMaxAge(600); //600초
response.addCookie(cookie)

//redirect
response.sendRedirect("/pathurl");

//message body
PrintWriter writer = response.getWriter();
writer.println("ok");

응답의 데이터 보내는 형식은 3가지
단순 text, HTML, HTTP API
text/plin, text/html, application/json

response.setContentType("application/json");
response.setCharacterEncoding("utf-8");

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

//위의 객체를 json형식으로 parse
String result = objectMapper.writeValueAsString(helloData);
response.getWriter().write(result);

정리

  • 위의 방식은 프레임워크 같은 것과 관련이 없다. 자바가 제공하는 Servlet을 사용한 방식이며, 이 방식만으로도 편리했지만, Spring web을 사용하면 이보다 더 편리하고, 강력하게 사용 할 수 있다.

서블릿으로 간단한 웹페이지 만들기

서블릿을 이용한 자바코드로...

contentType, ChracterEncoding 등을 다 넣어줘야되고,
Body에 HTML을 java 코드로 붙여 줘야된다...

PrintWriter w = response.getWriter();
	w.write("<html>\n" +
    		"<head>\n" +
            " <meta charset=\"UTF-8\">\n" +
            "</head>\n" +
            "<body>\n" +
            "성공\n" +
            "<ul>\n" +
            " <li>id="+member.getId()+"</li>\n" +
            " <li>username="+member.getUsername()+"</li>\n" +
            " <li>age="+member.getAge()+"</li>\n" +
            "</ul>\n" +
            "<a href=\"/index.html\">메인</a>\n" +
            "</body>\n" +
            "</html>");

딱봐도 엄청 혼란스럽지 않은가? 거기다 String"" 형식으로 붙여넣어줘야되서 순간적으로 오타를 내거나 해도 잡아주지도 않고, 따옴표를 쓰기위해선 백슬레쉬를 넣어줘야되는등 엄청나게 귀찮음.
사실 이 위에 것은 그냥 HTML 코드다. html에 list 형식으로 출력해주는 아주 단순한 화면이지만 이 정도의 화면을 만드는 것도 이렇게 오타를 낼 확률이 높거나 귀찮다.

물론 위의 코드를 보시면 중간에 memeber의 이름, 나이, 아이디등을 동적으로 받아올 수 있고 거기다 자바의 반복문이나 조건문등도 다 사용해서 동적으로 화면을 넣을 수 있긴 하다. 하지만 이건 너무 어려움.

이것이 바로 템플릿 엔진이 나온 이유이다. 자바 코드가 아닌 HTML 문서에서 동적으로 변경해야 하는 부분만 자바 코드를 넣기로 바꾸었다.

템플릿 엔진의 종류 : JSP, Thymeleaf,FreeMarker, Velocity등이 있음.

템플릿 엔진을 사용해서...

옛날에는 JSP를 대부분 사용. 하지만 요즘은 JSP는 성능과 기능부분에서 많이 밀려서 점점 사장되는 추세. (이미 업데이트도 멈춘듯. maven repository에선 2015이후 업데이트가 없다..)

최근에는 Thymeleaf를 사용하자. 스프링과 연계된 강력한 기능을 제공한다. 스프링에서 채택한 템플릿 형식. 이 Thymeleaf를 사용하면 .jsp 파일과 다르게 네츄럴 템플릿으로 .html로 그냥 사용 가능.

이 템플릿 엔진에 자바코드와 HTML을 전부 넣어 버리는 형식으로 코드를 짠다.

서블릿과 jsp의 한계

JSP를 사용한 덕분에 뷰를 생성하는 HTML 작업을 깔끔하게 가져갈 수 있었다. 하지만 이렇게 해도 해결되지 않는 문제가 남는다. JSP 코드의 절반은 회원을 저장하기 위한 비지니스 로직이고, 나머지 절반은 HTML로 보여주기 위한 뷰 영역이다.
이런 수백 수천줄이 넘는 코드들이 섞여서 있다. 하나의 jsp 파일이 너무 많은 역할을 해야한다.

MVC 패턴의 등장

비지니스 로직은 서블릿처럼 다른 곳에서 처리, JSP는 목적에 맞게 HTML 화면(view)을 그리는 일에 집중하도록 하는 것이다.

변경의 라이프 사이클
UI를 변경하는 일과 비지니스 로직을 변경하는 일은 라이프 사이클이 다르다. 둘을 수정하는 일은 각각 다르게 발생할 가능성이 매우 높고 대부분 서로에게 영향을 주지 않음. 이렇게 변경의 라이프 사이클이 다른 부분을 하나의 코드로 관리하는 것은 유지보수에 좋지 않다.

Model View Controller

클라이언트의 요청 ---> 비지니스 로직(Controller에서)처리 - Model(데이터전달) ---> View(뷰 로직 처리) ---> 클라이언트에 응답

여기선 간단하게 표현한 것이고 사실 Controller에는 서비스계층과 리포지토리 계층을 붙여서 3Tier Architecture를 짠다. (물론 컨트롤러가 모든것을 담당할 수 있지만 그렇다면 너무 커진다). 컨트롤러는 비지니스 로직을 호출하는 역할을 담당만 한다.

redirect vs forward
리다이렉트는 실제 클라이언트(웹브라우저)에 응답이 나갔다가, 클라이언트가 redirect 경로로 다시 요청한다. 따라서 클라이언트가 인지할 수 있고, URL 경로도 실제로 변경된다.(호출2번)
반면에 포워드는 서버 내부에서 일어나는 호출이기 때문에 클라이언트가 전혀 인지하지 못한다.(호출 한번)

서블릿과 JSP를 이용해서 만든 MVC 패턴의 한계

  • "포워드 중복" : view 로 이동하는 코드가 항상 중복 호출되어야 한다. 이 부분을 공통화 해도 되지만, 해당 메서드도 직접 호출해야 한다.
  • view path 중복
  • 사용하지 않는 코드 (상속받은 HttpServletReuqest, HttpServletResponse)

공통 처리가 어렵다 - 프로젝트가 커질수록공통으로 처리해야 할 부분이 점점 증가. 따로 기능을 메서드로 뽑으면 될거같지만, 해당 메서드를 항상 호출해야하고 호출하는 것 자체도 중복.

Front Controller
이 프론트 컨트롤러 패턴을 도입하면 이런 문제를 해결할 수 있다. 스프링 MVC의 핵심도 이 프론트 컨트롤러에 있다.
이 프론트 컨트롤러 패턴은 다음에 보자..

참고 : 본 글은 김영한님의 스프링 강의를 정리한 것이다.

profile
공부 정리 블로그

0개의 댓글