요청 -> 스레드풀 -> 커넥터(HTTP1.1 ...) -> 엔진 -> 컨텍스트(/project) -> 서블릿
서버(톰캣) -> 서비스(카탈리나) -> 엔진 -> 호스트(여러개 가능) -> 컨텍스트/(/project)
WEB-INF의 web.xml은 서버 설정이고 tomcat 서버와 각 프로젝트마다 서버폴더에 있다
•
톰캣은 공통서버설정, 프로젝트의 서버는 개별서버설정
•
프로젝트는 톰캣의 web.xml 등을 복사해와서 사용하므로 서버마다 다른 설정을 줄 수 있다
@WebServlet은 서블릿에서 사용 / @Controller, @RequestMapping은 스프링에서 사용
•
서블릿을 등록(컨트롤러) , URL 연결(매핑)
프로토콜은 서로 간의 통신을 위한 약속, 규칙으로 주고 받을 데이터의 형식을 정하는 것
•
HTTP(Hyper Text Transfer Protocol)
1.
단순하고 읽기 쉽다 -> 텍스트 기반이므로 바이너리 데이터를 보내는 2가지 방법 (1. MIME 타입쓰고 바이너리 그대로 2.Base64로 텍스트로 인코딩)
2.
상태를 유지하지 않는다 (클라이언트 정보를 저장 X, 요청에 대해 클라이언트를 구별할 수 없다) <- 보완하기 위해 쿠키와 세션을 사용
3.
확장 가능하다 (커스텀 헤더 추가 가능) -> n개 가능
상태코드
•
100번대 : information (클라이언트와 서버간의 정보교류)
•
200번대 : success
•
300번대 : redirect (다른 url로 요청해라!)
•
400번대 : client error
•
500번대 : server error
요청 메시지(메서드)
•
GET /ch2/getYoil?year=2021&month=10&day=1 HTTP/1.1
1.
URL에 쿼리 스트링을 추가해서 보낸다 (소용량)
2.
리소스를 얻어오기 위함 (헤더만 있고 바디가 없음)
3.
URL에 데이터가 노출되므로 보안에 취약, 데이터 공유에 유리
•
POST /ch2/getYoil HTTP/1.1
1.
바디에 쿼리스트링을 추가해서 보낸다 (대용량)
2.
서버에 정보를 제공하거나 쓸 때 사용
3.
데이터를 바디에 담아 전송하므로 보안에 유리, 데이터 공유에 불리
텍스트 파일 : 문자만 있는 저장되어 있는 파일 (숫자는 문자로 변환 후 문자만을 다룬다)
바이너리 파일 : 문자와 숫자가 저장되어 있는 파일 (데이터를 있는 그대로 읽고 쓴다)
MIME(Multipurpose Internet Mail Extensions)
•
텍스트 기반 프로토콜에 바이너리 데이터를 전송하기 위해 고안
•
HTTP의 Content-Type 헤더에 사용하고 데이터 타입을 명시해준다
1.
text : 텍스트를 포함하는 모든 문서 (text/plain, text/html, text/css, text/javascript)
2.
image : 모든 종류의 이미지 (image/bmp, image/webp)
3.
audio : 모든 종류의 오디오 파일 (audio/midi/ audio/mpeg, audio/webm, audio/ogg, audio/wav)
4.
video : 모든 종류의 오디오 파일 (video/webm, video/ogg)
5.
application : 모든 종류의 이진 데이터 (appllication/octestream, application/pkcs12, appllication/vnd.mspowerpoint)
Base64 (64진법)
•
0~9와 A~Z와 a~z와 특수문자(+ , /)를 다 합쳐 모두 64개 (OS 상관 없이 공통으로 인코딩 할 수 있는 것만 모아놓음)
•
바이너리 데이터를 텍스트 데이터로 변환하기 위해 6bit씩 끊어서 변환한다 (변환한 후에는 8bit가 되면서 늘어난다)
•
뒤에 모자란 부분은 패딩(0)으로 채운다
------------------------------------------------------------------------------------------
OOP 5대 설계 원칙 (SOLID)
SRP - 단일 책임의 원칙
•
"하나의 메서드는 하나의 책임(= 관심사, =해야 할 작업)"
•
분리
1.
관심사의 분리
2.
변하는 것, 자주 변하지 않는 것의 분리
3.
공통(중복) 코드의 분리
------------------------------------------------------------------------------------------
JSP
•
JSP를 작성하면 자동으로 서블릿으로 변환된다
•
JSP는 HTML안에 JAVA 코드를 넣은 것
Servelt
•
Servlet은 JAVA 코드 안에 HTML을 넣은 것
•
@WebServlet (= @Controller + @RequestMapping) 을 클래스에 붙인다
•
HttpServelt을 상속 받아야함
SpringMVC 패턴
•
Controller : HttpRequest 대신 파라미터를 전달받고 형변환을 해준다
•
Model : Controller가 작업한 것을 view에게 전달해주기 위해 저장하는 곳
•
View : 요청에 응답할 때 보여주는 곳 (jsp)
1.
반환타입 [String] : return을 통해 view의 이름을 반환한다. 설정을 통해 생략된 확장자명을 붙여준다
2.
반환타입 [void] : 맵핑된 url이 뷰의 이름이라 따로 return이 없다
3.
반환타입 [ModelAndView] : 리턴타입에 ModelAndView를 적고 해당 타입을 갖는 객체를 생성해 view이름을 지정하고 return으로 보내준다
Servlet VS SpringMVC 비교
•
MVC는 @Controller를 클래스에 붙이고 @RequestMapping을 메서드에 붙임으로 클래스를 여러개 만들 필요가 없어졌다
•
MVC는 HttpServelt을 상속받지 않아도 되므로 단일상속에 의한 문제점을 보완했다
•
Servlet은 최초 jsp를 변환, 컴파일하는 과정으로 인해 늦은 초기화(lazy-init)이고 SpringMVC는 early-init이다
------------------------------------------------------------------------------------------
JSP의 호출 과정
1.
.jsp 요청
2.
서블릿 인스턴스 존재 확인
3.
없으면 *.jsp 에서 *_jsp.java 로 변환하고 *_jsp.class 로 컴파일되며 서블릿 클래스 파일이 만들어지고 _jspInit() 호출해서 인스턴스 생성 후 _jspService() 호출
4.
있으면 바로 _jspService() 호출
5.
응답
JSP의 기본 객체
•
서블릿의 service() 메서드에 지역변수들로 JSP→Servlet 변환 시 메서드 영역은 service()에 포함되므로 기본 객체를 다 사용가능
JSP와 서블릿
•
HTTP는 상태를 저장할 수 없기에 접근범위, 생존기간에 따른 4개의 저장소(Map 형태)를 갖는다
◦
pageContext
▪
*.jsp 마다 페이지 안에 지역 변수(기본 객체 등)을 읽고 쓴다 (페이지 개별 저장소)
▪
EL ${} 때문에 사용한다
◦
application
▪
WebApplication 전체에 1개만 존재하며 setAttribute, getAttribute를 사용한다
▪
프로그램 전체에 대한 데이터를 저장하는데 사용한다
◦
session
▪
클라이언트 개별 저장소이며 로그인 할 때 생기며 로그아웃하면 사라진다
▪
사용자 수만큼 객체가 생기므로 서버에 부담이 가장 큰 저장소 → 최소한의 데이터만 빠르게 다룬다
◦
request
▪
페이지에 요청할 때마다 생기며 개별 저장소이다 (다른 페이지로 forwarding해도 유지된다)
•
유효 범위(scope)와 속성(attribute)
◦
유효 범위 : page, request, session, application
◦
기본 객체 : pageContext, request, session, application
서블릿의 생명주기
•
서블릿은 싱글톤으로 1개의 인스턴스만 가지며 요청이 들어올 때마다 재활용한다
1.
요청
2.
Servlet Context의 map(name, servlet) 을 통해 서블릿의 인스턴스 존재 유무 확인
3.
없으면 서블릿 클래스 로딩 & 인스턴스 생성 (init() 호출) / 있으면 service() 호출
4.
응답
5.
서블릿이 종료되면 destroy() 호출
서블릿의 URL 패턴
//@WebSevlet(urlPatterns={"/hello", "/hello/*"}, loadOnStartup=1)
@WebServlet("/hello")
public class HelloServlet extends HttpServlet {
Java
복사
•
loadOnStartup : lazy-init인 서블릿을 early-init처럼 사용할 수 있게 한다 (값은 우선 순위를 부여)
•
URL 패턴은 “/hello” 이 부분을 말하며 우선순위대로 해당 패턴과 일치하는 매핑의 서블릿이 처리하게 된다
•
우선순위는 exact → path → extension → default 순서이다
•
exact, path, extension은 동적 리소스, default는 정적 리소스
•
Servlet Context에 servletMappings이라는 map에 저장되며 요청이 들어왔을 때
key에 URL 패턴을 통해 어떤 servlet이 처리하는지 children map에서 찾아 알려주게 된다
(Spring에선 servlet, jsp를 사용하지 않으므로 모든 요청은 default를 통해 DefaultServlet이 아닌 DisPatcherServlet이 처리한다 → @RequestMapping)
EL(Extension Language)
jsp : <%= %>
EL : ${}
Java
복사
•
jsp는 null을 출력하지만 EL은 null을 출력하지 않는다 (null로 연산할 땐 0으로 계산한다)
•
EL에서의 “1” + 1 → 2 이고 “1” += “1” → 11 이다 (문자와의 연산은 문자를 숫자로 변환한다)
•
“”는 연산에서 0으로 계산한다
•
empty는 null, 빈 컬렉션, 배열인지 확인한다
•
null과 0은 다르다 (null == 0 → false)
•
eq는 equals과 같은 기능이다
•
ne는 eq에 not이 붙은 기능이다
JSTL(JSP Standard Tag Library)
//jsp에서 사용하던 <% ~%> 방식
<%
if(msg != null) {
%>
//jsp 방식을 지양하고자 Servlet에서 사용하는 JSTL 방식
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt"%>
<c:set var="to" value="10"/>
<c:if test="${not empty to}">
Java
복사
•
<%@ taglib prefix="c" ~ : <c:set> , <c:if> 와 같은 태그를 사용하기 위한 라이브러리 선언
•
<%@ taglib prefix="fmt" ~ : <c:set> , <c:if> 와 같은 태그를 사용하기 위한 라이브러리 선언
Filter
•
필터가 여러개인 경우 Filter1 전처리 → Filter2 전처리 → 서블릿 → Filter2 후처리 → Filter1 후처리
@WebFilter(urlPatterns="/*")
public class ServletFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
//초기화 작업
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
//1. 전처리 작업
long startTime = System.currentTimeMillis();
//2. 서블릿 또는 다음 필터를 호출
chain.doFilter(request, response)
//3. 후처리 작업
System.out.print("[" + ((HttpServletRequest) request).getRequestURI() + "]");
System.out.println("소요시간=" + (System.currentTimeMillis() - startTime) + "ms");
}
@Override
public void destory() {
//정리 작업
}
}
Java
복사
•
@WebFilter(urlPatterns=”/*”) : 필터를 적용할 요청의 URL패턴을 지정한다 (/*는 모든 요청)
•
전처리와 후처리는 하나만 입력해도 된다
-----------------------------------------------------------------------------------
@RequestParam
•
매개변수(기본형, String)마다 앞에 붙여줄 수 있다.
•
생략 가능 (아래 선언들 다 가능)
◦
public String main(@RequestParam(name=”year”, required=true) int year)
== public String main(@RequestParam int year)
◦
public String main(@RequestParam(name=”year”, required=false) int year)
== public String main(int year)
•
URI를 통해 매개변수를 입력 받는다.
◦
/requestParam : year = null
◦
/requestParam?year : year = “”
◦
/requestParam?year=2021 : year = 2021
•
required가 false 인 경우엔 defaultValue 로 기본값을 넣어줘야한다.
@ModelAttribute
•
참조형 매개변수에 적용
◦
이 어노테이션이 붙은건 Model에 자동으로 저장된다. (addAttribute 사용 안해도 됨)
◦
@ModelAttribute(”key”) ← key 생략하면 어노테이션이 붙은 대상의 타입 첫 글자를 소문자로 바꾼걸 key로 사용하여 저장한다.
•
컨트롤러 메서드의 반환 타입에 적용
◦
호출 결과를 Model에 저장
@RequestParam VS @ModelAttribute
•
기본형, String VS 참조형
•
둘 다 Model에 값을 저장
•
URI(개별 파라미터) VS URI(바인딩된 파라미터)+컨트롤러 메서드
WebDataBinder
•
URI를 통해 받은 파라미터의 String 값을 참조형 매개변수로 바인딩하는 과정
•
결과&에러는 컨트롤러의 BindingResult를 통해 알 수 있다.
@GetMapping, @PostMapping
•
@RequestMapping(value=”/register/save”, method={RequestMethod.GET, RequestMethod.POST})
→ @GetMapping(”/register/add”)
→ @PostMapping(”/register/save”)
•
Request 시 GET과 POST를 제한하기 위해 사용한다.
•
RequestMethod가 다르면 같은 URL을 매핑해도 에러가 안난다.
•
메서드들이 공통된 @RequestMapping을 갖고 있다면 클래스에 어노테이션을 붙인다.
→ 클래스에 /register를 매핑한 후 각 메서드마다 /add와 같이 GET or POST 매핑을 한다.
<view-controller>
•
servlet-context.xml 에서 설정가능하다.
•
단순히 jsp 페이지만을 보여주는 Mappping을 단순화하기 위해 사용한다.
•
GET 요청만 허용하고 POST 요청은 허용하지 않는다.
URL 인코딩
•
URL에 포함된 non-ASCII 문자를 16진수로 변환해준다
•
URLEncoder.encode(”내용", “UTF-8”);
•
Controller에서 사용하며 예외처리 해줘야한다.
URL 디코딩
•
View에서 받아서 사용할 때 적용해야한다.
•
<%@ page import=”java.net.URLDecoder”%> 를 임포트한 후 사용해야한다.
•
${내용} → ${URLDecoder.decode(내용, “UTF-8”)}
URL 패턴
•
서블릿에선 @WebServlet으로 사용하던걸 스프링에선 @RequestMapping으로 사용
•
exact : /login/hello.do
•
path : /login/*
•
extension : *.do
•
exact → path → extension 순서로 우선순위
•
?는 한 글자, *는 여러 글자, **는 하위 경로 포함
•
배열로 여러 패턴을 지정할 수 있고 모든 패턴으로도 찾지 못하면 404 Not Found가 뜬다.
redirect VS forward
•
redirect (”redirect:/login”)
◦
HTTP 상태코드 300번대를 이용해서 다른 곳으로 재요청.
◦
1번째 요청은 수동이지만 redirect를 통한 요청은 자동이다.
◦
요청 2번 응답 2번
◦
RedirectView
▪
req → DispatcherServlet → Controller → DispatcherServlet (redirect) → RedirectView (redirect 헤더 작성) → res
•
forward (”forward:/login”)
◦
요청을 forward를 통해 다른 곳으로 전달
◦
처음 GET or POST가 그대로 전달된다.
◦
요청 1번 응답 1번
◦
JstlView
▪
req → DispatcherServlet → Controller → DispatcherServlet (jsp 이름) → InternalResourceViewResolver (jsp 경로 반환) → DispatcherServlet → JstlView (jsp 작성) → res
◦
InternalResourceViewResolver
▪
registerForm.jsp 를 받으면 /WEB-INF/views/registerForm.jsp와 같이 경로를 알려준다.
Cookie
•
이름과 값의 쌍으로 구성된 작은 정보
◦
ASCII 문자만 가능하다 (한글은 URL 인코딩 필요)
◦
서버에서 생성 후 전송해서 브라우저에 저장한다. (유효기간 이후 자동 삭제)
◦
서버에 요청 시 domain, path가 일치하는 경우에만 자동 전송
◦
클라이언트 식별 기술
•
쿠키의 생성
•
쿠키의 삭제와 변경
•
쿠키 읽어오기
•
@CookieValue
◦
요청 중에 가져오고 싶은 쿠키를 매개변수에 적어놓고 사용할 수도 있다.
Session
•
기존의 요청들은 독립적이다. 쿠키와 sessionID를 통해 관련된 요청을 묶은 것이다.
•
브라우저마다 개별 저장소(session 객체)를 서버에서 제공 (서버에 저장)
•
session 객체의 생성과 소멸은 StandardManager가 관리한다
•
session=true,false는 세션을 시작할까?에 대한 답
(세션 시작 후 false를 만나도 세션이 끊기지 않는다)
jsp에 <% page session=”true” %> 로 추가한다.
•
세션의 생성
•
세션 객체 얻기
•
세션 관련 메서드
•
세선 종료
Cookie VS Session
•
Cookie
◦
브라우저에 저장
◦
서버 부담 X
◦
보안에 불리 (암호화해서 저장함으로써 보완)
◦
서버 다중화에 유리
•
Session
◦
서버에 저장
◦
서버 부담 O
◦
보안에 유리
◦
서버 다중화에 불리 (서버 다중화 시 동기화가 까다로워 불리하다)