Web/Spring

SpringMVC (2) - 서블릿

now0204 2023. 10. 2. 11:19

- 서블릿 생성방법, HttpServletRequest와 Response에 대해서 알아보자 

- reqeust는 HTTP 요청 메시지 파싱한 결과 담김 -> 편리하게 조회 

- response는 HTTP 응답 메시지 쉽게 만들도록 함 -> set이 편리 

 

*request는 요청 보내는 거 아님, 받은 요청을 읽는 것 따라서 content-type이나,인코딩 등등은 클라이언트가 요청 메시지 보내면서 잘 만들어서 보내야함 

 

*서블릿은 톰캣 같은 서블릿을 지원하는 애플리케이션 서버를 직접 설치 -> 그 위에 서블릿 클래스 파일을 빌드해서 오린다음 -> 톰캣 서버를 실행함 (스프링 부트는 내장 톰캣 서버를 사용함)

* ex war파일로 프로젝트를 export하고, 외장 톰캣 서버 webapp폴더에 이를 집어넣고,cmd를 통해 서버를 구동시켜야함 

(이때, 수정할때마다 다시 war파일로 export한 뒤, 과정 반복 번거로움 -> 이클립스는 WTP를 통해 외부에서 설치한 톰캣서버에 대한 임시 배치 폴더를 내부에 만들어서 (이클립스 복사본) 이 과정을 쉽게 해결함) 

 

1. Hello 서블릿 

 

- 스프링 부트 환경에서 서블릿을 등록하고 사용

 

1.1 스프링 부트 서블릿 환경 구성 

 

@ServletComponentScan : 스프링 부트에서 서블릿을 직접 등록해서 사용할 수 있도록 위 어노테이션 지원함

                                             서블릿을 자동 등록 

@WebServlet : 서블릿 어노테이션 

                         속성은 name와 urlPatterns

                          HTTP 요청을 통해 매핑된 URL이 호출되면, 서블릿 컨테이너는 service 메서드를 실행함 

 

*서블릿은 톰캣과 같은 WAS(서블릿 컨테이너)를 통해 생명주기가 관리됨 (싱글톤) 

*서블릿을 직접 실행하는게 아니라, WAS를 실행하면, 프로젝트 내에 등록된 서블릿이 WAS를 통해 생성되고 관리됨

 

1.2 HTTP 요청 메시지 로그 확인하기 

 

-application.properties에 다음 설정을 추가하자

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

- 이를 추가하고, 요청을 해보면, 서버가 요청받은 HTTP 메시지 출력함

 

1.3 서블릿 컨테이너 동작 방식 

 

출처: 스프링 MVC (인프런) - 김영한

- 내장 톰캣 서버가 서블릿 생성 -> 요청 들어오면 WAS가 먼저 받아서 HTTP메시지 기반 request,response생성

 

* request,response는 HttpServletRequest,HttpServletResponse의 구현체임 WAS가 구현 객체 만들어서 넣어줌

 

1.3 웰컴페이지 추가

 

- webapp경로에 index.html을 두면, 기본 호출시 이 페이지가 열림 

 

 

2. HttpServletRequest - 상세정보

 

- HTTP 요청 메시지를 파싱해주는 역할을 해준다. (WAS가 파싱해서 위 객체에 담아서 제공함)

- HTTP 요청 메시지를 편리하게 조회 가능 

 

POST /save HTTP/1.1
Host: localhost:8080
Content-Type: application/x-www-form-urlencoded
username=kim&age=20

START LINE(메서드,URL,쿼리,스키마 - 프로토콜), 헤더, 바디 형식

위 내용을 파싱해줌

+ 임시 저장소 기능 ( 요청이 시작하고 끝날 때 까지 유지되는 임시 저장소 기능)

+ 세션 관리 기능 (request.getSession)

 

* HttpServeltRequest와 Response는 HTTP 요청+응답 메시지 편리하게 사용하도록 돕는 객체 따라서 기능에 대한 깊은 이해를 위해서는 HTTP 스펙이 제공하는 요청 응답 메시지를 이해해야함

 

2.1 HttpServletRequest 기본 사용법 

 

// startLine
request.getMethod() 
request.getProtocol()
request.getSchme()
request.getRequestURL() // http://부터 출력
request.getRequestURI() // /path 만 출력
request.getQueryString()
request.isSecure() // https사용여부 검사 

//start-line에 모든 항목 출력가능
//Header정보

request.getHeaderNames().asIterator().forEachRemaining(headerName ->
request.getHeader(headerName))

-> 헤더는 key:value 형식임 Header이름을 얻어서 모든 헤더 값을 출력 

//Header 몇가지 편리하게 조회

request.getServerName() //Host 헤더의 값 조회
request.getServerPort() //Host 헤더의 값

//(Accept - Language 조회)
request.getLocales().asIterarot.forEachRemaining(locale -> ..);
request.getLocale()

//쿠키 조회 
request.getCookies() //-> cookie배열 return -> iter가능

//Content 편의 조회 
request.getContentType()
request.getContentLength()
request.getCharacterEncoding()

*원래는 헤더이름 집어넣고 복잡시럽게 얻어야하는데, 자주 조회되는 헤더는 위와 같이 편리하게 조회하도록 메서드화 함 

 

*기타 정보를 얻을 수 있는데, 이는 HTTP 메시지 정보는 아님

(RemoteHost, RemoteAddr,RemotePort,LocalName,LocalAddr,LocalPort 등)

(IPv4정보를 얻고 싶으면, VM options 뭐 추가해주면됨 (PDF참조)

 

3. HTTP 요청 데이터 - 개요

 

- HTTP 요청 메시지는 클라이언트가 서버로 데이터를 전달하는 방법이다.

- 주로 3가지를 사용한다.

 

-  쿼리 파라미터 사용(GET) : 메시지 바디 x URL에 데이터 포함해서 전달 (검색,필터,페이징) 

 

-  HTML FORM (POST) :  메시지 바디에 쿼리 파라미터를 전달 

                                         (요청헤더) content-type:application/x-www-form-urlencoded 

                                         (회원가입,상품주문 등)

 

- HTTP message body (HTTP API에서 주로 사용 JSON,XML)

 

*HTTP message body를 사용하는 방법은 마치 웹브라우저 도움 없이 요청을 날리는 느낌 

HTTP 스펙을 맞추기 위해 요청url,메서드 등등 하나씩 지정해서 요청 날리면 결과 받음 

받은 결과는 json형식으로 데이터 넘어옴 -> 파싱해서 사용하면 됨 

 

3.1 쿼리 파라미터 GET

 

- 쿼리 파라미터 형식으로 데이터가 넘어오면, request.getParameter를 사용해서 간단하게 조회 가능 

Enumeration<String> prameterNames = request.getParameterNames() // 이름 모두 조회
Map<String,String[]> paramterMap = request.getParamterMap() // Map으로 모두 조회
String[] values = request.getParameterValues("name") // 같은 key로 여러 값이 넘어 올때
String value = request.getParameter("name") // key - value 형태일 때

 

* 파라미터 이름은 하나 일때 값이 여러개 넘어올 때 getParameter()를 사용하면, getParameterValues중 첫번째 값만 넘어옴

 

3.2 HTML Form (POST)

 

- 폼을 통해 넘어온 데이터를 조회하는 방법을 알아보자 

- content-type : application/x-www-form-urlencoded

- message body : 쿼리스트링 처럼 넘어옴 

- 폼을 통해 넘어온 데이터는 쿼리스트링처럼 동일하게 사용가능함 

 

* 쿼리 스트링 방식은 content-type 헤더가 없음 (바디 사용 안해서)

   폼 형식바디를 사용하므로, 요청시 content-type을 꼭 지정해야함 (메시지에 지정해서 보내야함)

 

3.3 HTTP 요청 데이터 (HTTP API)

 

- 단순히 text를 바디에 담아서 전송하고, 읽어보자 

- HTTP 메시지 바디의 데이터를 InputStream을 사용해서 읽을 수 있음! 

ServletInputStream is = request.getInputStream();
String messageBody = StreamUtils.copyToString(is,StandardCharsets.UTF-8);

*InputStream은 byte코드 반환 -> 문자로 바꾸려면 문자표(Charset)을 지정해 줘야함 

*InputStream을 열고, StreamUtils를 통해 안에 내용을 String으로 복사 

 원래라면 read()같은 메서드가 -1 반환안할 때 까지 읽어줘야..

 

3.4 HTTP 요청 데이터 - JSON

 

- json 타입을 메시지 바디에 사용하는 경우 content-type은 application/json

- String으로 읽는 부분까지는 동일 ObjectMapper추가 

 

*ObjectMapper는 Json to 객체 해줌

 

ServletInputStream is = request.getInputStream();
String messageBody = StreamUtils.copyToString(is,StanderdCharsets.UTF_8);

HelloData hd = ObjectMapper.readValue(messageBody,HelloData.class);

* JSON 파싱해서 객체 변환하려면, 변환 라이브러리가 필요한디 스프링 부트는 Spring MVC를 선택시 Jackson라이브러리 제공함

 

 

4. HttpServletResponse - 사용법

 

- 응답메시지는: 응답코드,헤더,바디를 생성해서 응답해야함 (이런 기능 제공)

- 편의기능 : Content-Type, 쿠키 , Redirect

 

response.setStatus() // 요청 상태
request.setHeader("헤더명","value");

//message body
respnse.getWriter() //String으로 응답
//contentType

response.setContentType("text/plain");
response.setCharacterEncoding("utf-8");

//Cookie

//원래는 응답헤더에 포함해야해서 복잡 귀찮음 
Cookie cookie = new Cookie("myCookie", "good");
cookie.setMaxAge();
response.addCookie();

/redirect

response.sendRedirect("path");
//원래는 setStatus,SetHeader("Location","path") 해야함 귀찮

 

4.1 HTTP 응답 데이터 - 텍스트 or HTML

 

- HTML응답은 contextType을 text/html, 인코딩을 utf-8로 한다음 getWriter를 얻어서 html문서 만들어서 보내면 됨

- Json은 content Type을 application/json으로 설정 인코딩 utf-8

- json으로 만들어서 넘길 객체를 ObjectMapper를 사용해서 넘김 

 

HelloData data = new HelloData();
dara.setUsername();
data.setAge();


String result = objectMapper.writerValueAsString(data);
response.getWriter().writer(result);

* content-type이 application/json이면, utf-8형식 사용하도록 정의됨 따라서 

chatset=utf-8 등 추가 파라미터 지원 안함 

content-type쓸때 application/json;charset=utf-8 하면 의미없는 파라미터 추가된 것 

response.getWriter()를 사용하면, 추가 파라미터를 자동으로 추가하고, getOutputStream()사용하면 그런 문제 없다.

 

 

 

참고자료: 

https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81-mvc-1

 

스프링 MVC 1편 - 백엔드 웹 개발 핵심 기술 - 인프런 | 강의

웹 애플리케이션을 개발할 때 필요한 모든 웹 기술을 기초부터 이해하고, 완성할 수 있습니다. 스프링 MVC의 핵심 원리와 구조를 이해하고, 더 깊이있는 백엔드 개발자로 성장할 수 있습니다., 원

www.inflearn.com