Search

JSP, Servlet

요청 -> 스레드풀 -> 커넥터(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
보안에 유리
서버 다중화에 불리 (서버 다중화 시 동기화가 까다로워 불리하다)