Servlet
웹서버(Server)
클라이언트(Client)
HTML
HTTP Protocol (HyperText Transfer Protocol)
TCP/IP 프로토콜을 기반으로 웹 서버와 클라이언트 간 웹 서비스를 제공하기 위한 통신 규약
요청(Request)
과 응답(Response)
으로 구성됨.
즉, 클라이언트
와 서버
역할이 구분됨.
서버가 클라이언트의 상태를 유지할 수 없는 Stateless Protocol
의 특징을 가진다.
요청마다 서버는 클라이언트와 새로운 접속을 맺고 응답을 전송한다.
서버는 요청에 대한 응답을 전송하면, 해당 클라이언트의 어떠한 상태정보도 유지하지 않는다.
웹 상에서 클라이언트의 상태를 유지하기 위해 Session
, Cookie
를 사용한다.
Cookie & Session
쿠키는 브라우저에서 저장하고, 보안에 취약하다. 중요한 정보는 쿠키에 담으면 안된다.
세션은 서버에서 저장하기에, 중요한 정보를 저장해도 된다.
그럼 쿠키는 나쁜거고, 세션은 좋은거. 이렇게 일반화해도 되는것일까?
네이버 카페
, 네이버 메일
, 네이버 쇼핑몰
.. 이렇게 여러 개의 서비스에서 여러 서비스를 이용할 때마다 로그인을 하지는 않는다. 그럼 카페 서버 / 메일 서버 / 쇼핑몰 서버 가 있을 때, 유저의 정보를 네트워크로 쏠까?
만약 패킷이 스니핑 당한다면 큰일날 것이다.
쿠키
를 통해 이 문제를 해결할 수 있다.
쿠키 정보는 서버
단이 아닌, 도메인
단에서 관리한다.
쿠키는 도메인이 맞으면 통과시킨다.
그렇기에, 한 도메인 내에 여러 개의 서버를 두고 운영하는 서버의 경우에는
세션과 쿠키를 반드시 써야한다. ( 쿠키는 도메인이 같으면 통과됨 )
Host
User-Agent
Encoding 정보
HTTP Header ( A Byte ~ B Byte 까지 인코딩 정보.. X Byte ~ Y Byte 까지 호스트 정보.. 등의 정보들이 미리 규칙으로 잡혀있다. )
HTTP Header는 노출이 됨. Header에 있는 데이터는 아무나 다 볼 수 있다. ( WireShark )
게시글 작성 이런 곳에서 GET
방식으로 쓰면, 주소창에 데이터가 다 보인다.
GET 방식의 한계
보여도 되는 것, 짧은 것에 GET
을 쓴다.
( ex. 회원가입 시 ID/PW는 길이가 짧아서 GET으로 충분히 보낼 수 있는데..?
URL에 데이터가 그대로 노출되기에 보안에 매우 취약 )
SEO
를 위해 노출하면 좋을 정보인데,
데이터 양이 많아서 어쩔 수 없이 POST
를 사용할 수도 있다.
(ex. 남들이 다 봐줬으면 좋겠는 카페에 글 쓰기.. 양이 너무 많아서 POST
로 밖에 전송 못함. )
HTTP Body에 데이터를 담는다.
URL이나 Header에 전송 정보가 노출되지 않는다.
주로 서버에게 특정 데이터를 보내서 어떤 작업을 요청하는 경우에 사용한다.
GET
보다는 보안에서 좋다.
PUT
, PATCH
등의 메소드는 JS 요청 / 서버 - 서버간의 요청 등으로만 가능. ( RestTemplate
, FeignClient
..)초창기 HTTP 1.0 프로토콜은 웹 상에서 HTML
을 전송하기 위한 목적의 프로토콜이었다.
기능이 확장되어 Data
를 보내는 등 API 방식으로 동작 가능하다.
HTML
은 왜 Header로 못보내나요?
- HTTP Protocol Spec 상 Header에 담아 보낼 수 있는 데이터의 양이 제한되기 때문
close
, keep-alive
F5
키에 테이프 꼽고 나가면 메모리 초과로 서버가 누워버렸음.공장과 작업자들의 관계이다.
작업자는 한가지 일만 처리할 수 있다.
크롬 : 프로세스
- 크롬의 키보드 리스너 기능 담당 작업자.( Ctrl + T 누르면 화면 이동, Ctrl + N 누르면 새 창 생성 .. )
프로세스 안에 쓰레드는 엄청나게 많음.
서버에서 실행되는 동적 컨텐츠를 생성하는 자바 기반 웹 컴포넌트
컴포넌트(Component)
-구성요소
라는 의미를 가진다.
바이트 코드로 컴파일된 플랫폼 독립적인 자바 클래스
웹 서비스 개발에 필요한 자바 클래스
서버-사이드 애플릿(Server-Side Applet)
서블릿 컨테이너에 의해 관리된다.
컨테이너
: 서버에서 특정 업무를 담당하는 영역 / 서블릿 코드를 관리하는 영역 / 환경을 마련해준다.
서블릿 컨테이너는 Tomcat (WAS)
이 관리한다.
- 유료 WAS인 Jeus
, WebLogic
또한 있다.
★ WAS
와 JVM
의 관계
- WAS
가 VM
위에 있다.
- Tomcat( WAS )는 VM을 기반으로 해서 동작하고, WAS 안에 Servlet Container가 있다. VM위에 Spring Container가 있다.
HttpServlet라는 추상 클래스를 상속받아 구현하고자 하는 기능을 오버라이딩 하는데 대표적으로 init()
, service()
, destroy()
메소드가 존재한다.
init()
, service()
, destroy()
는 대표적인 쓰레드의 메소드이다.
즉, 서블릿은 쓰레드
이다.
단일 프로세스에, 요청이 들어올 때마다 프로세스 내에서 쓰레드를 생성하는
멀티 쓰레드 방식으로 동작한다.
아무리 과도하게 호출 요청을 해도 OS가 누울 일이 절대 없다는 것이 장점.
쓰레드를 기반으로 하므로, Web Application 운영에 효율적이다.
자바를 기반으로 하므로 모든 Java API를 사용할 수 있다.
웹 어플리케이션에서 효율적인 자료 공유 방법을 제공한다.
요청이 들어올 때마다 Servlet Thread가 init
되어 생성된다.
JSP는 결국 HTML이다.
JSP 내에 Java Code를 넣을 수 있다.
서블릿은 Java Code에 HTML
을 넣었다면, JSP
는 HTML 코드에 Java Code를 넣는 방식으로 동작한다.
JSP
는 결국 Servlet Container에 의해 컴파일 되어 Servlet으로 변환된다. ( JSP
-> Servlet
)
<%@ %>
: 페이지 지시자 / JSP가 서블릿으로 변환될 때, 어떻게 변환되어야 하는지 컨테이너에 알려주는 역할을 한다.
<% %>
: Scriptize : HTML 안에 Java 코드를 사용한다.
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<% for(int i = 0; i < 3; i++){
out.println(i);
System.out.println(i);
}
%>
</body>
</html>
out
은 jspWriter로 JSP 자체의 내장 객체
이다.jspWriter
타입(PrintWriter
)이 내부적으로 미리 선언되어 있다.web.xml
설정을 참고하여, 이 요청을 처리할 Servlet 코드를 실행할 쓰레드를 할당하려 한다.response.getWriter().append
...)또한, 서블릿에서 요청을 받고, 비즈니스 로직 실행 후 뷰까지 렌더링하는, 너무 많은 책임을 가지고 있었다.
비즈니스 로직과 View
를 분리한 JSP를 도입하고, 뷰 단에 넘겨줘야할 데이터를 Model
에 담음으로써 역할 분리를 이뤄냈다.
JSP
의 한계 또한 존재했는데, 컨텐츠 자체와 비즈니스 로직이 분리되지 않았다. ( 과도한 책임 - 단일 책임 원칙 위배 )
어플리케이션을 구성 요소 단위로 분리하여 역할 분담을 이뤄냈다.
Model
& Business Logic : Java Class ( VO, DAO, DTO )
View
: JSP, JSTL
Controller
: 서블릿
서블릿의 개발
과 실행
을 가능하게 하는 인터페이스와 클래스들의 모임
J2EE에서 추상화된 개념
HTTP에 특화된 하부 클래스들을 제공함. ( cf. GenericServlet
)
일반적인 서블릿은 HttpServlet 클래스로부터 파생됨.
- HTTP에 특화된 요청 핸들러 doGet(), doPost() 등을 제공함.
HttpServletRequest
, HttpServletResponse
)Session
, ServletContext
, init params
)상속 계층도에서 HttpServlet
보다 상위에 있는 GenericServlet
의 경우, FTP
/ SMTP
등의 요청도 수용한다.
HttpServlet class의 코드에서 파라미터가 ServletRequest
, ServletResponse
인데, 이것을 (HttpServletRequest
), (HttpServletResponse
) 로 다운캐스팅 하는 이유가 바로 이 이유이다.
서블릿은 서버에서 실행되는 동적 컨텐츠를 생성하는 자바 기반 웹 컴포넌트
이지, HTTP만을 위한 컴포넌트가 아니다. 자주 사용되는 것이 HTTP 프로토콜일 뿐이다.
GenericServlet
은 모든 프로토콜을 수용한다.
인터페이스는 공통의 기능이 없다.
또한, 구현 메서드 사이사이에 특정 메서드 호출을 강제하지 못한다.
서블릿이라면 가지고 있어야할 스펙인
init()
, doGet()
, doPost()
, destroy()
등의
공통된 기본 기능을 주고 관리해야하기에 사용한다.
/**
* Servlet implementation class BoardServlet
*/
@WebServlet("/board_servlet_url")
public class BoardServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
/**
* Default constructor.
*/
public BoardServlet() {
// TODO Auto-generated constructor stub
}
/**
* @see Servlet#init(ServletConfig)
*/
public void init(ServletConfig config) throws ServletException {
System.out.println("init called");
// TODO Auto-generated method stub
}
/**
* @see Servlet#destroy()
*/
public void destroy() {
// TODO Auto-generated method stub
}
/**
* @see HttpServlet#service(HttpServletRequest request, HttpServletResponse response)
*/
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String method = request.getMethod();
System.out.println(method);
if(method.equals("POST")) {
doPost(request, response);
} else if(method.equals("GET")) {
doGet(request, response);
}
}
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
response.getWriter().write(1);
// response.sendRedirect("lec_servlet_call.jsp");// response.sendRedirect("index.html");
}
/**
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String vUserId = request.getParameter("userid");
String vUserPw = request.getParameter("userpw");
String vGen = request.getParameter("gen");
String vSubject = request.getParameter("subject");
String vUserfile = request.getParameter("userfile");
String vSsn = request.getParameter("ssn");
String vContents = request.getParameter("contents");
String[] vHabits = request.getParameterValues("habit");
System.out.println(vUserId);
System.out.println(vUserPw);
System.out.println(vGen);
System.out.println(vSubject);
System.out.println(vUserfile);
System.out.println(vSsn);
System.out.println(vContents);
System.out.println(vHabits);
}
}
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
GET 호출
<!-- <a href="localhost:8081/board_servlet_url">서블릿 GET 방식 요청</a> -->
<a href="/board_servlet_url">서블릿 GET 방식 호출</a>
<form method="get" action="/board_servlet_url">
<input type="submit" value="서블릿 GET 방식 호출">
</form>
<form method="post" action="/board_servlet_url">
</form>
<form method="post" action="/board_servlet_url">
<input name="userid" type="text"><br>
<input name="userpw" type="password"><br>
<input name="gen" value="m" type="radio">남
<input name="gen" value="f" type="radio">여 <br>
<input name="habit" value="habit" type="checkbox">낚시<br>
<input name="habit" value="habit" type="checkbox">드럼<br>
<input name="habit" value="habit" type="checkbox">노래<br>
<input name="habit" value="habit" type="checkbox">독서<br>
<select name="">
<option value="kor">국어</option>
<option value="eng">영어</option>
<option>수학</option>
</select><br>
<input type="file" name="userfile">파일 선택 <br>
<input type="hidden" name="secret" value="12345"><br>
<!-- 게시판에서 서버로 넘겨야하긴 하는데, 사용자에게 입력 안받는 것? (Seq) -->
<textarea name="contents" rows=10 cols=50>
</textarea> <br>
<input type="submit" value="서블릿 POST 방식 호출">
</form>
</body>
</html>
직렬화 ( 객체 → 바이트 )
인코딩
하는 것이 직렬화디코딩
하는 것이다.