- 서블릿과 JSP
1. 서블릿과 컨트롤러의 비교
@WebServlet 애너테이션 = @Controller + @RequestMapping
서블릿은 HttpServlet을 상속받아야 함.
작업하는 메소드의 이름은 오직 service 이어야 하며, 매개변수로 HttpServletRequest 타입의 참조변수와 HttpServletResponse 타입의 참조변수를 받는다.
서블릿은 클래스에 Mapping을 하기 때문에 클래스들을 많이 생성해야 하지만
컨트롤러는 메소드에 Mapping을 하기 때문에 메소드만 만들면 된다.
(둘은 비슷하지만 컨트롤러가 좀 더 발전된 형태를 가지고 있다)
2. 서블릿의 생명주기
클래스 안에는 서블릿을 초기화 하는 init 메소드, 작업을 하는 service 메소드, 뒷정리 작업을 하는 destroy 메소드가 있다.
프로그램이 처음 시작될 때 init 메소드가 호출되고
요청이 들어오면 service 메소드가 호출되며
프로그램이 변경되거나 종료될 때 destroy 메소드가 호출된다.

Servlet과 Spring은 1개의 인스턴스만 계속 재활용함(Singleton)
Servlet Context 안에는 children이라는 멤버가 있음.
Map 형태로 서블릿을 등록해놓음.
요청이 왔을 때 서블릿 객체가 존재하는지 children에서 확인함.
3. JSP(Java Server Pages)란?
HTML 안에 Java코드가 들어가 있는 것.
4. JSP와 서블릿의 비교
-> 서블릿과 거의 유사
JSP는 서블릿으로 자동 변환이 됨.
jsp 파일은 src->main->webapp 폴더에 저장한다.
URL은 http://localhost/ch2/twoDice.jsp
이다.
클라이언트에서 요청이 오면 jsp 파일이 서블릿 파일로 변환이 됨.
5. JSP 호출과정

확장자가 jsp인 파일이 요청이 들어오면 JspServlet이 서블릿 인스턴스가 존재하는지 확인함.
인스턴스가 존재하지 않으면 twoDice.jsp를 서블릿으로 변환함.
컴파일 후 인스턴스를 생성함.
생성하면서 init 메소드를 호출하고, 작업을 하기 위해 service 메소드를 호출하여 응답함.
첫 번째 호출시에는 jsp 파일을 서블릿 소스파일로 변환해야 하기 때문에 시간이 지연됨.
두 번째 호출부터는 이미 존재하는 인스턴스를 이용하면 되므로 응답이 빨라짐.
jsp 파일이 변경되면 다시 새로 서블릿 소스파일로 변환 한다.
Servlet : lazy – init (늦은 초기화)
Spring : early – init (미리 객체를 만들어놓고 초기화)
서블릿과 스프링 둘 다 싱글톤을 사용하지만 초기화 방법이 다르다.
6. JSP와 서블릿으로 변환된 JSP의 비교
twoDice.jsp -> 변환 -> twoDice_jsp.java (서블릿)
7. JSP의 기본 객체
생성없이 사용할 수 있는 객체가 존재함
8. 유효 범위(scope)와 속성(attribute)
HTTP 프로토콜의 특징 – 상태정보를 저장하지 않는다(stateless) <-> 상태정보저장(stateful)
따라서 따로 저장소가 필요함
4개의 저장소(Map 형태) - 데이터를 저장
사용 목적에 따라 접근 범위, 생존 기간이 다름.
pageContext 저장소 – lv를 저장, 기본객체도 저장(request, response 등)
해당 페이지에서만 저장소에 접근 가능(읽기 쓰기 가능)
다른 페이지에서 접근 불가능
EL( ${ } )에서 사용하기 위해 쓰는 저장소.
application 저장소 – WebApp 전체에서 접근 가능. 전체에서 단 1개만 존재. 모두가 공유하는 공통 저장소. 프로그램 전체에서 쓰는 데이터를 저장할 때 사용.
session 저장소 – 클라이언트마다 1개씩 존재하는 개별 저장소.
ex) id, 장바구니 등 개별적인 속성(attribute)을 저장함.
사용자수마다 1개씩 있어야 하므로 서버에 부담이 제일 큼.
클라이언트가 접근하는 페이지에서 모두 접근이 가능.
그러나 메모리 부담이 크기 때문에 사용을 최소화 하는게 좋고 쓰더라도 잠깐 저장했다가 삭제하는 식으로 사용하는게 좋음.
request 저장소 – 요청할 때마다 1개씩 생김. 요청이 끝나면 사라지기 때문에 부담이 적으며 데이터를 다른 페이지로 전달할 때 가장 먼저 고려하는 저장소.(여기에 저장해서 줄 수 없는지)

9. URL 패턴

@WebServlet(urlPatterns={"/hello", "/hello/*}, loadOnStartup=1)
loadOnStartup은 미리 초기화 할 수 있게 해줌. 1은 우선순위
1) exact mapping
정확히 일치하는 URL pattern. 우선순위 가장 높음
2) path mapping
경로 mapping.
3) extension mapping
확장자 mapping
4) default mapping
디폴트 mapping. 모든 주소
(Spring도 URL 패턴이 있음)
-> 요청이 들어오면 해당 URL 패턴에 맞는 서블릿으로 연결이 됨.
* Spring에서는 DispatcherServlet이 내부적으로 이 요청을 전부 다 처리함

10. EL (Expression Language)
<%=값%> => ${값}
ex) el.jsp
<%@ page contentType="text/html;charset=utf-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
<%@ page import="com.fastcampus.ch2.*" %>
<%
Person person = new Person();
request.setAttribute("person", person);
request.setAttribute("name", "남궁성");
request.setAttribute("list", new java.util.ArrayList());
%>
<html>
<head>
<title>EL</title>
</head>
<body>
person.getCar().getColor()=<%=person.getCar().getColor()%> <br>
person.getCar().getColor()=${person.getCar().getColor()} <br>
person.getCar().getColor()=${person.car.color} <br>
name=<%=request.getAttribute("name")%> <br>
name=${requestScope.name} <br>
name=${name} <br>
id=<%=request.getParameter("id")%> <br>
id=${pageContext.request.getParameter("id")} <br>
id=${param.id} <br>
"1"+1 = ${"1"+1} <br>
"1"+="1" = ${"1"+="1"} <br>
"2">1 = ${"2">1} <br>
null = ${null}<br>
null+1 = ${null+1} <br>
null+null = ${null+null} <br>
"" + null = ${""+null} <br>
""-1 = ${""-1} <br>
empty null=${empty null} <br>
empty list=${empty list} <br>
null==0 = ${null==0} <br>
null eq 0 = ${null eq 0} <br>
name == "남궁성"=${name=="남궁성"} <br>
name != "남궁성"=${name!="남궁성"} <br>
name eq "남궁성"=${name eq "남궁성"} <br>
name ne "남궁성"=${name ne "남궁성"} <br>
name.equals("남궁성")=${name.equals("남궁성")} <br>
</body>
</html>
el의 사용 예를 보여주는 jsp 파일이다.
문법적인 내용이므로, 참고하여 필요할 때 사용해보기로 한다.
11. JSTL (JSP Standard Tag Library)
ex) jstl.jsp
<%@ page contentType="text/html;charset=utf-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
<html>
<head>
<title>JSTL</title>
</head>
<body>
<c:set var="to" value="10"/>
<c:set var="arr" value="10,20,30,40,50,60,70"/>
<c:forEach var="i" begin="1" end="${to}">
${i}
</c:forEach>
<br>
<c:if test="${not empty arr}">
<c:forEach var="elem" items="${arr}" varStatus="status">
${status.count}. arr[${status.index}]=${elem}<BR>
</c:forEach>
</c:if>
<c:if test="${param.msg != null}">
msg=${param.msg}
msg=<c:out value="${param.msg}"/>
</c:if>
<br>
<c:if test="${param.msg == null}">메시지가 없습니다.<br></c:if>
<c:set var="age" value="${param.age}"/>
<c:choose>
<c:when test="${age >= 19}">성인입니다.</c:when>
<c:when test="${0 <= age && age < 19}">성인이 아닙니다.</c:when>
<c:otherwise>값이 유효하지 않습니다.</c:otherwise>
</c:choose>
<br>
<c:set var="now" value="<%=new java.util.Date() %>"/>
Server time is <fmt:formatDate value="${now}" type="both" pattern="yyyy/MM/dd HH:mm:ss"/>
</body>
</html>
태그 라이브러리에 대한 사용 방법인데
역시 문법적인 내용이므로 어떻게 사용하는지 참고하도록 한다.
12. Filter
공통적인 요청 전처리와 응답 후처리에 사용. 로깅, 인코딩 등
요청->Filter에서 전처리->서블릿 호출->서블릿에서 처리 후 Filter로 반환->후처리->응답
ex)
package com.fastcampus.ch2;
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
// 필터를 적용할 요청의 패턴 지정 - 모든 요청에 필터를 적용.
@WebFilter(urlPatterns="/*")
public class PerformanceFilter 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 destroy() {
// 정리 작업
}
}
urlPatterns 를 /* 로 했기 때문에 모든 URL에 이 필터가 적용이 된다.
그래서 Console에 작업 소요시간이 출력된다.
doFilter 메소드를 오버라이딩 한 후
서블릿을 호출하는 코드를 제외하고
전처리, 후처리 작업 코드만 사용하려는 용도에 맞게 작성하면 된다.
출처 : 스프링의 정석 : 남궁성과 끝까지 간다
'Spring & SpringBoot > Spring' 카테고리의 다른 글
220427 Spring - Chapter 2. Spring MVC (Part 6) (0) | 2022.04.27 |
---|---|
220426 Spring - Chapter 2. Spring MVC (Part 5) (0) | 2022.04.26 |
220425 Spring - Chapter 2. Spring MVC (Part 4) (0) | 2022.04.25 |
220422 Spring - Chapter 2. Spring MVC (Part 2) (0) | 2022.04.23 |
220421 Spring - Chapter 2. Spring MVC (0) | 2022.04.22 |