JSP와 서블릿은 거의 유사하며, 이를 발전시킨 형태가 Spring이라고 보면 됨.
Spring역시 서블릿을 통해 동작함.
java는 단일상속이므로 되도록이면 상속을 하지않고 구현하는게 좋음.(여지를 남겨둔다고 생각하면 편함)
controller는 서블릿보다 더욱 발전된 형태임.
서블릿
@WebServlet("/rollDice2")
public class TwoDiceServlet extends HttpServlet {
int getRandomInt(int range) {
return new Random().nextInt(range)+1;
}
public void service(HttpServletRequest request, HttpServletResponse response) throws IOException {
int idx1 = getRandomInt(6);
int idx2 = getRandomInt(6);
response.setContentType("text/html");
response.setCharacterEncoding("utf-8");
PrintWriter out = response.getWriter();
// 이하생략
}
}
컨트롤러
@Controller // ctrl + shift + o => 자동 import
public class TwoDice {
@RequestMapping("/rollDice")
public static void main(HttpServletResponse response) throws IOException {
int idx1 = (int)(Math.random()*6)+1;
int idx2 = (int)(Math.random()*6)+1;
response.setContentType("text/html");
response.setCharacterEncoding("utf-8");
PrintWriter out = response.getWriter();
// 이하생략
}
}
위 두 클래스는 같은 기능을 함.
서블릿을 사용할때는 HttpServlet
의 상속이 필요.
요청이 왔을때 서블릿 인스턴스가 존재하면 init()과정을 생략.
존재하지 않을 경우 서블릿 클래스 로딩 & 인스턴스 생성
init()
service()
응답
서블릿이 메모리에서 내려갈때 destroy()
실행
서블릿은 기본적으로 싱글톤 구조로, 1개의 인스턴스만을 가진다.
=> 하나의 객체를 요청마다 재활용하는 형태.
<%! 내용 %>
: 클래스 영역
<% 내용 %>
: service 메서드 영역
JSP에는 생성하지 않아도 사용할 수 있는 기본객체가 존재.
예) request, response, session ...
-towDice.jsp-
<%@ 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>
servlet으로 만든 twoDice와 비교한 사진.
서블릿과 Spring은 동일하게 싱글톤 디자인패턴을 가지지만 초기화에 있어서는 약간 다름.
서블릿
: lazy - init (지연된 초기화)
Spring
: early - init (요청이 오지 않아도 미리 객체를 만들어두고 초기화를 해두도록 개선)
둘 다 장/단점이 있음.
서블릿역시 Spring처럼 미리 초기화하는 방법이 있음. 위는 기본값 이야기임.
HTTP의 특징
저장소의 종류
1)pageContext
: 같은 페이지내에서만 참조가능. 보통 EL${}
때문에 사용.
2)application
: WebApp전체에서 접근가능. 저장은 하나만 가능. 공통저장소.
3)session
: 클라이언트마다 하나씩 있는 개별저장소.
4)request
: 요청이 처리되는 동안만 유지되는 객체.
forward
(데이터를 다른 페이지로 전달시키는 것)시 가장 먼저 고려해볼 저장소.
session
은 클라이언트의 숫자대로 객체를 생성하므로 최대한 적은 값을 저장하는게 좋음.
4개의 저장소 중 가장 서버 메모리 부담이 높다.
보통은 jsp페이지 하나가 요청받은 값을 출력하지만 간혹 필요한 jsp페이지간에 데이터를 옮겨주는 작업을 forward
라고 함.
@WebServlet
으로 서블릿을 URL
에 맵핑할때 사용
우선순위. 종류 | URL pattern | 매칭URL |
---|---|---|
1. exact mapping 정확한 주소로 매핑 | /login/hello.do | http://localhost/ch2/login/hello.do |
2. path mapping 경로로 매핑 | /login/* | http://localhost/ch2/login/ |
3. extension mapping 확장자 매핑 | *.do | http://localhost/ch2/hi.do |
4. default mapping 모든주소와 매핑되는 기본형 | / | http://localhost/ch2/ |
/는 모든 요청을 받지만 우선순위가 가장 낮음
=> Spring에서는 @RequestMapping
을 사용.
Spring에서도 마찬가지로 URL패턴이 존재함.
이에 대해서는 추후 강의내용에서 공부예정.
Spring에서는 서블릿에서 사용하는 1, 2, 3번패턴을 사용하지 않기때문에 DispatcherServlet
이 모든요청을 받아 내부적으로 각 유형별 분배를 하게 됨.
servlet은 요청에 따라 서블릿이 분류를 진행하는것과 차이가 있음.
Expression Language
쉽게 말하자면 <%=값%>
=> ${}
로 간단히 사용하는 방법.
지역변수(lv)는 바로 사용할 수 없으며, 저장 후 사용해야한다.
EL은 null을 출력하지 않음.
EL의 경우 "1" + 1의 결과가 2이니 주의.
계산 시 null은 0으로 취급됨.
empty
=> null 또는 빈 컬렉션배열일때 true, 아닐때 false를 반환. 피연산자가 비었는지를 체크함.
단, 그렇다고해서 null과 빈 컬렉션배열이 같은것은 아님.
자동으로 생성된 class파일 및 src파일을 삭제.
컴파일 과정에서 문제가 생길 경우 해준 뒤 다시 실행해주면 됨.
-Person.class-
public class Person {
private Car car = new Car();
public Car getCar() { return car; }
}
-Car.class-
public class Car {
private String color = "red";
public String getColor() { return color; }
}
-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>
JSP Standard Tag Library
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
위 두 태그를 추가하여 라이브러리를 추가해야 함.
prefix="c"
는 코어 라이브러리, prefix="fmt"
은 포멧라이브러리
<%=값%>
=> ${}
(EL)
<%코드%>
=> JSTL
-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>
공통적인 요청 전처리와 응답 후처리에 사용됨.
로깅, 인코딩 등.
-PerformanceFilter.java-
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() {
// 정리 작업
}
}
각각
http://localhost:8090/ch2/
http://localhost:8090/ch2/jstl.jsp
http://localhost:8090/ch2/el.jsp
페이지를 차례로 실행시켰을때의 결과.
필터를 이용해 페이지 로드에 걸리는 소요시간을 보는 예제클래스.