-
SpringMVC (2) - 서블릿Web/Spring 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 서블릿 컨테이너 동작 방식
- 내장 톰캣 서버가 서블릿 생성 -> 요청 들어오면 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
'Web > Spring' 카테고리의 다른 글
SpringMVC (4) - MVC 프레임워크 만들기 [중요] (0) 2023.10.02 Spring MVC (3) - 서블릿, JSP, MVC 패턴 (0) 2023.10.02 스프링 MVC (1) 웹 애플리케이션 이해 (0) 2023.09.04 스프링 핵심 원리 (5) - 빈 생명주기 (0) 2023.08.22 스프링 핵심 원리 (4) - 컴포넌트 스캔 (0) 2023.08.18