[JSP] 서버 사이드 렌더링 방식인 JSP의 기본 문법과 더 쉽게 사용하기 위한 EL & JSTL
서버 사이드 렌더링 vs 클라이언트 사이드 렌더링
서버는 사용자의 요청에 응답하기 위해 페이지를 동적으로 생성하며,
클라이언트에서 실행되는 브라우저에 의해 페이지는 단순히 표시될 뿐이다.
따라서, 사용자가 보는 페이지는 서버에서 처리된 결과물이다.
서버에서 완전히 렌더링된 페이지를 제공하기 때문에 검색엔진이 페이지 콘텐츠를
더 쉽게 크롤링하고, 인덱싱할 수 있다. SEO 최적화
사용자가 처음 페이지를 요청할 때, 서버에서 이미 렌더링된 페이지를 전송하기 때문에
초기 로딩 시간이 짧다. 하지만 다른 페이지로 이동할 때마다, 서버에서 새로운 페이지를 렌더링하고 전송해야 하므로
페이지 전환 시, 지연이 발생할 수 있다. 또한, 모든 사용자 요청에 대해 서버에서 페이지를 렌더링해야 하므로
많은 트래픽이 발생할 경우 서버에 부하가 증가할 수 있다.
클라이언트(브라우저)에서 동적으로 페이지를 렌더링하므로, 사용자와의 인터렉션이 풍부한 웹 애플리케이션을 구현할 수 있다.
또한, 초기 로딩 후에는 클라이언트에서 대부분 렌더링 작업을 처리하기 때문에 서버 부하를 줄일 수 있다.
때문에 처음 페이지 로딩 후에는, 사용자 페이지 전환 요청을 클라이언트에서 처리할 수 있어 페이지 전환이 빠르다.
단, 클라이언트에서 동적으로 콘텐츠를 렌더링하기 때문에 검색엔진이 페이지의 콘텐츠를 제대로 크롤링하고 인덱싱하는데 어려움이 있을 수 있다.
또한, 초기 로딩은 자바스크립트 코드를 모두 다운로드하고 실행한 후에야 콘텐츠를 볼 수 있기 때문에, 초기 로딩 시간은 길어질 수 있다.
⚠️ SSR과 CSR의 장점을 결합한 하이브리드 접근 방식 (Next.js Nuxt.js)도 있다.
JSP (Java Server Page)
JSP는 동적인 웹페이지를 생성하기 위해 사용되는 자바 기반의 템플릿 엔진이다.
다양한 형식의 문서를 가지고 결과물을 생성하는 소프트웨어를 뜻한다
Java 코드를 사용하여 동적인 콘텐츠를 생성하고, HTTP 응답의 본문에 포함될 문자열을 작성하는 방식으로 동작한다.
HTML에는 데이터를 전송하는 기능은 있지만, 받는 기능은 없다.
동적인 콘텐츠 생성을 위해, 데이터를 받을 변수의 개념이 필요한데, JSP에는 변수의 개념이 있다.
서버에서 페이지를 생성해서 클라이언트에 전달하고, 브라우저에서 실행시키면
내부적으로는 * 서블릿이 돌아간다.
웹브라우저에서 동작하는 자바 프로그램을 뜻한다.
서블릿은 자바 기반의 강화된 CGI라 할 수 있다.
서버와 서드 파티 간 데이터 전송을 위한 통신 규약을 뜻한다.
CGI의 단점은 자원 사용의 비효율성에 있다.
자바 기반의 CGI는 매 요청마다 새로운 JVM을 시작하고 요청을 처리한 뒤, 종료한다.
이 과정은 상당한 오버헤드를 발생시키고 성능저하로 이어질 수 있다. 또한, 시스템 자원을 비효율적으로 사용하게 된다.
때문에 FastCGI는 스레드 풀⛱️을 이용한다. 스레드 풀에 프로세스를 미리 실행시켜 놓고, 요청이 들어올 때마다 프로세스에 토스하고 요청이 끝나면 잠들게 한다.
⚠️ 서블릿은 자바기반의 CGI 강화ver.으로, 스레드 풀 개념이 녹아있다.
JSP는 요청을 받을 때마다, 이미 실행중인 서버 프로세스 내에서 JSP 페이지를 처리한다.
JSP 페이지는 첫 요청 시, 자바 서블릿으로 변환되고 컴파일된다.
이후의 요청들은 이미 컴파일된 서블릿 코드를 재사용하여 처리속도가 빠르다.
JSP와 CGI는 같은 목적을 가지고 있지만, 실행방식, 성능, 자원관리 측면에서 차이가 난다.
JSP 기본 문법 및 내장 객체
<% %>
: 스크립트릿, ☕Java코드
로 데이터 처리 및 로직 구현
<%@ %>
: page 지시어 or taglib 선언
<%! %>
: 전역변수 or 메서드 선언
<%= %>
: 마크업 중심으로 코딩하다가, 변수나 메서드를 출력해야할 때
<%-- --%>
: 주석
- 🍪 html 주석
<!-- -->
과 다른 점 - html 주석문은 html tag의 일종이므로, JSP 컨테이너에 의해 아무런 영향을 받지 않는다.📕 JSP 컨테이너란
JSP 페이지를 해석하고 실행하는 환경을 제공하는 소프트웨어로써,
웹서버에 내장되어 잇거나, 웹 애플리케이션 서버에 포함되어 있다.
JSP 페이지를 해석해서 해당 페이지를 Java 서블릿으로 변환한다
이 과정에서 스크립트 릿을 해석하여 서블릿 코드로 변환하고,
변환된 서블릿을 서블릿 컨테이너에게 제공한다.
그러면 서블릿 컨테이너는 해당 서블릿을 컴파일해서 실행가능한 형태로 만든다.즉, JSP 페이지에 html tag를 쓰면 JSP 컨테이너가 이를 해석하지 않고, 브라우저에 넘겨 그대로 개발자 도구 element tab에 노출시킨다.
반면 JSP 주석문은 JSP 컨테이너에 의해 주석문으로 해석되므로,
브라우저의 개발자 도구에서 노출시키지 않는다. - 🚀 JSP 내장 객체 🚀
- 자주 사용하는 객체를 미리 만들어 레퍼런스로 제공
request
: HttpServletRequest
response
: HttpServletResponse
session
: HttpSession
application
: ServletContext
out
: PrintWriter
표현언어, EL
속성값(웹 애플리케이션 데이터)을 쉽게 사용하기 위한 표현언어를 뜻한다.
속성값은 다양한 범위(scope)에 저장될 수 있는데,
주로 요청 request 세션 session 애플리케이션 application 및 페이지 page 범위에
저장되는 데이터를 말한다.
EL을 사용하면 이런 속성값에 쉽게 접근할 수 있다.
ex. 세션범위에 저장된 사용자 이름에 접근하려면
EL표현식 ${ }
을 사용하여 ${sessionScope.username}
과 같이 속성값을 쉽게 표현할 수 있다.
EL 내장객체는 생략 가능하지만, 생략했을 시, 속성값을 좁은 범위부터 찾기 시작한다.
pageScope: 현재 페이지에만 적용되는 속성값
requestScope: Http 요청이 처리되는 동안만 적용되는 속성값
sessionScope: 사용자 브라우저(사용자 세션)과 상호작용하는 동안만 적용되는 속성값
applicationScope: 애플리케이션이 시작될 때, 생성되어 종료될때까지 적용되는 속성값
⚠️ 내장 메서드 setAttribute() / getAttribute() 이용
☄️ EL 문법 ex
1
2
3
${empty param.id ? "Guest님" : param.id.concat("님")}<br>
${not empty param id ? param.id.concat("님") : "Guest님"}<br>
${param.id == null ? "Guest님" : param.id.concat("님")}<br>
표준 태그 라이브러리, JSTL
1
2
3
4
5
6
7
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="fm" uri="http://java.sun.com/jsp/jstl/fmt" %>
<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>
<c:out value="exVal" escapeXml="false" /> <%-- 문자 그대로 출력 --%>
<c:set var="exVar" value="exVal" scope="page" />
<fmt:formatNumber value="${price}" />원
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
<%
MemberDao dao = new MemberDaoImpl();
List<Member> members = dao.selectAll();
request.setAttribute("members", members);
%>
<table>
<tr>
<th>번호</th>
<th>이메일</th>
<th>이름</th>
<th>나이</th>
<th>주소</th>
</tr>
<c:choose>
<c:when test="${empty requestScope.members || members.size() == 0}">
<tr>
<th colspan="5">검색된 정보가 없습니다.</th>
</tr>
</c:when>
<c:otherwise>
<c:forEach items="${members}" var="mem" varStatus="status">
<tr>
<td>${state.count} / ${state.index}</td>
<td>${mem.email}</td>
<td>${mem.name}</td>
<td>${mem.age}</td>
<td>${mem.addr}</td>
</tr>
</c:forEach>
</c:otherwise>
</c:choose>
</table>
정적 include vs 동적 include
⚠️ include 하는 JSP파일
과 include 되는 JSP파일
을 부모-자식 관계로는 해석하지 않는다.
🌵 정적 include - 스크립트 태그
<%@ include file=" " %>
JSP 컨테이너가 JSP 파일을 컴파일할 때, include하는 JSP파일 내에 복사되어 같이 컴파일된다.
include하는 JSP 파일
내의 전역변수를 include되는 JSP 파일
내에서 사용할 수 있다.
include되는 JSP 파일
내의 전역변수를 include하는 JSP 파일
내에서 사용할 수 있다.
즉, 서블릿 문서가 하나만 만들어져 변수를 공유한다.
🚀 동적 include - 액션 태그
<jsp:include page=" " />
JSP 페이지에 접근하여 JSP가 실행될 때, 해당 include문이 실행되어 동적으로 파일의 내용이 포함된다.
즉, 사용자의 요청에 따라 다른 내용을 동적으로 포함할 수 있다.
단, include되는 JSP 파일
의 출력결과(HTML)만 포함하므로, include되는 JSP 파일
의 변수를 include하는 JSP 파일
내에서 사용할 수 없다.
즉, 서블릿 문서가 각각 독립적으로 만들어져 결과만 전달한다.
⚠️ <jsp:param>
태그로 값을 전송할 수 있다.
🚀 동적 include - JSTL
<c:import url=" " />
액션 태그와 실행시점과 출력결과가 동일하지만, 주로 외부의 리소스를 가져오는데 사용한다.
ex. html 페이지, JSP 페이지, 이미지, CSS파일 …