클래스에 맵핑하기 때문에 클래스에 속한 모든 메서드에 일일이 애노테이션을 붙일 필요가 없다
@WebServlet("hello")
public class HelloServlet extends HttpServlet {
@Override
public void init() throws ServletException {
//서블릿이 초기화될 때 자동 호출되는 메서드
//1. 서블릿의 초기화 담당
System.out.println("[HelloServlet] init() is called");
}
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//1. 입력
//2. 처리
//3. 출력
System.out.println("[HelloServlet] service() is called");
}
@Override
public void destroy() {
System.out.println("[HelloServlet] destroy() is called");
}
}
여러번 호출할 경우 init()은 사용되지 않고 service()만 계속 사용된다
등록된 서블릿들이 Servlet Context에 Map 형태로 저장되어 있어서 요청이 들어오면 Servlet Context 에서 확인한다
서블릿은 기본적으로 싱글톤(1개의 인스턴스 재활용)이다
<%@ page contentType="text/html;charset=utf-8"%>
<%@ page import="java.util.Random" %>
<%-- <%! 클래스 영역 %> --%>
<%!
int getRandomInt(int range){
return new Random().nextInt(range)+1;
}
%>
<%-- <% 메서드 영역 - service()의 내부 %> --%>
<%
int idx1 = getRandomInt(6);
int idx2 = getRandomInt(6);
%>
<html>
<head>
<title>twoDice.jsp</title>
</head>
<body>
<img src='resources/img/dice<%=idx1%>.jpg'>
<img src='resources/img/dice<%=idx2%>.jpg'>
</body>
</html>
- 서블릿은 lazt-init (늦은 초기화)
- Spring은 이를 개선하기 위해 early-init
요청이 오지 않아도 미리 객체를 만들어두고 초기화 하는 방법을 사용
- 기본 객체와 lv를 저장하는 저장소
- 페이지 안에서만 접근(읽기, 쓰기)할 수 있음
- EL ${}에서 사용하기 위해, 저장소에 저장된 변수만 EL에 사용할 수 있음
- 위 그림에서 login.jsp페이지에서만 pageContext에 접근할 수 있다
- WebApp 전체에서 접근할 수 있는 공통 저장소
- 위 그림에서 login.jsp와 write.jsp에서 모두 접근할 수 있다
- 전체 애플리케이션에서 공유하는 저장소이기 때문에 로그인에서 사용하는 아이디나 비밀번호 같은 정보를 저장하기에 올바르지 않다
- 클라이언트마다 존재하는 개별 저장소
- 로그인하게 되면 세션에 아이디와 비밀번호가 저장되어 다음 요청을 했을 때 저장되어 있는 아이디를 사용할 수 있으며 요청마다 로그인을 새로 할 필요가 없어진다
- 로그아웃하면 개별 저장소가 사라진다
- 아이디, 장바구니 등 클라이언트마다 가지고 있는 정보들을 저장
- 사용자의 수만큼 세션 객체가 생기기 때문에 최소한의 데이터만 저장한다
그래서 서버 부담이 가장 큰 저장소이다- 가장 쉬운 저장소
- 요청할 때마다 생기는 저장소 요청마다 서로 독립적이다
- 하나의 jsp파일이 담당한다
- jsp파일 안에서 request 객체를 사용한다
- 데이터도 저장할 수 있다
- 한 jsp파일에서 사용할 수 있고 여러 jsp파일을 거쳐 사용될 수 있다(다른 jsp파일로 넘김)
- 가장 부담이 적은 객체
- 만약 요청이 /hello로 들어왔다면 servletMappings 에서 일치하는 key를 찾아 value에 해당하는 서블릿으로 이동한다
- 이 경우 HelloServlet이라는 서블릿이 있기 때문에 그 서블릿을 children 에서 찾는다
- HelloServlet이 있기 때문에 요청을 처리한다
- 만약 요청 url이 존재하지 않는다면 default 서블릿에 맵핑되어 default 서블릿이 요청을 처리한다 = 우선순위가 가장 낮다
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> 2출력, ""안의 숫자를 숫자로 변환함
"1"+="1" = ${"1"+="1"} <br> 11출력
"2">1 = ${"2">1} <br> true
null = ${null}<br> null 출력 안함
null+1 = ${null+1} <br> 1
null+null = ${null+null} <br> 0
"" + null = ${""+null} <br> 0
""-1 = ${""-1} <br> -1
empty null=${empty null} <br> true
empty list=${empty list} <br> true
null==0 = ${null==0} <br> false
null eq 0 = ${null eq 0} <br> false
name == "남궁성"=${name=="남궁성"} <br>
name != "남궁성"=${name!="남궁성"} <br>
name eq "남궁성"=${name eq "남궁성"} <br>
name ne "남궁성"=${name ne "남궁성"} <br> ne는 not equal
name.equals("남궁성")=${name.equals("남궁성")} <br>
<%@ 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"/> //EL은 lv를 사용할 수 없기 때문에 저장소에 우선 저장하는 것이다
<c:set var="arr" value="10,20,30,40,50,60,70"/>
<c:forEach var="i" begin="1" end="${to}"> //1부터 10까지 출력
${i}
</c:forEach>
<br>
<c:if test="${not empty arr}"> //배열이 비어있지 않으면
<c:forEach var="elem" items="${arr}" varStatus="status"> //배열의 값들을 elem에 하나씩 넣어서 출력
//status에는 count와 index가 있는데 count는 1부터 시작, index는 0부터 시작.
//아래 출력문에 포함해서 출력
${status.count}. arr[${status.index}]=${elem}<BR>
</c:forEach>
</c:if>
<c:if test="${param.msg != null}"> //url로 호출할 때 msg 파라미터에 값이 입력되었는지 확인하고
msg=${param.msg} //있으면 출력하는데 태그가 있다면 태그가 해석되어 적용되어 출력되고
msg=<c:out value="${param.msg}"/> //out은 만약 태그와 함께 입력되었다면 태그를 무시하고 문자로 출력한다
</c:if>
<br>
<c:if test="${param.msg == null}">메시지가 없습니다.<br></c:if> //msg가 없으면
<c:set var="age" value="${param.age}"/> //저장소에 저장하고
<c:choose>
<c:when test="${age >= 19}">성인입니다.</c:when> //위에 저장된 age의 값 비교
<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>
공통적인 요청 전처리와 응답 후 처리에 사용
로깅, 인코딩 등
서블릿들이 있을 때 모든 서블릿에 공통으로
- 전처리
- 처리
- 후처리
과정이 반복된다
처리 부분만 각 서블릿이 상이하고 전처리와 후처리가 중복될 경우 따로 하나로 묶어서 관리한다
- 서블릿의 코드가 간결해지고 중복이 제거된다
- filter -> servlet -> filter
filter를 여러 개 적용할 수 있다
filter1 전처리 -> filter2 전처리 -> servlet 처리 -> filter2 후처리 -> filter1 후처리
@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() {
// 정리 작업
}
}