JSTL이란 jsp에서 HTML 코드 내에 java 코드인 스크립틀릿 <%= sample %>을 ${sample}
로, <%=if %>문을 <c:if>
, <%=for %>문을 <c:forEach>
등으로 대체하여 사용하는 라이브러리다.
즉, 자바코드를 html 태그형식으로 간편하게 사용하기 위해 나온 라이브러리이다.
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
JSTL은 라이브러리이기 때문에 반드시 위 코드를 header에 추가해야 한다. 추가하지 않고 사용하려고 하면
위와 같은 경고창(Unknown tag (c:if))을 확인할 수 있다.
태그명 | 설명 |
---|---|
<c:if> | 조건식에 해당하는 블럭과 사용될 scope 설정 |
<c:choose> | java의 switch와 비슷 |
<c:when> | switch문의 case |
<c:otherwise> | switch문의 default |
<c:forEach> | for문(향상된 for문처럼 활용) |
<c:set> | 변수명에 값을 할당 |
<c:url> | url에 자동으로 contextPath를 붙여주는 역할 |
<c:param> | 파라미터를 전달(속성-name:파라미터명/value:값) |
<c:out> | 화면에 출력 |
@Controller
public class JstlController {
@RequestMapping("/jstl1")
public String jstl1(Model model) {
model.addAttribute("memberType", "admin");
return "jstl1";
}
}
>>> 컨트롤러
<h1>jstl1</h1>
<c:if test="${memberType == 'admin'}">
<h2>관리자입니다.</h2>
</c:if>
>>> jsp 파일
↓ 실행결과
@Controller
public class JstlController {
@RequestMapping("/jstl1")
public String jstl1(Model model) {
model.addAttribute("type", "morning");
return "jstl1";
}
}
>>> 컨트롤러
<h1>jstl1</h1>
<c:choose>
<c:when test="${type=='morning'}">
<p>choose 아침</p>
</c:when>
<c:when test="${type=='lunch'}">
<p>choose 점심</p>
</c:when>
<c:otherwise>
<p>아침도 점심도 아니다.</p>
</c:otherwise>
</c:choose>
>>> jsp 파일
↓ 실행결과
<h1>jstl1</h1>
1~10까지 반복
<c:forEach var="i" begin="1" end="10" step="1">
<p>${i}</p>
</c:forEach>
>>> jsp 파일
↓ 실행결과
@Controller
public class JstlController {
@RequestMapping("/jstl1")
public String jstl1(Model model) {
//memberDto 멤버 정보 리스트를 불러왔다~라는 과정이 있다고 가정
List<MemberDto> memberList = new ArrayList<MemberDto>();
memberList.add( new MemberDto("firstid", "pww1", "가멤버") );
memberList.add( new MemberDto("secondid", "pww2", "나멤버") );
memberList.add( new MemberDto("thirdid", "pww3", "다멤버") );
model.addAttribute("memberList", memberList);
return "jstl1";
}
}
>>> 컨트롤러
<h1>jstl1</h1>
<p>멤버 리스트 확인하기</p>
<table>
<thead>
<tr>
<td>아이디</td>
<td>비밀번호</td>
<td>이름</td>
</tr>
</thead>
<tbody>
<c:forEach var="memberItem" items="${memberList}">
<tr>
<td>${memberItem.id}</td>
<td>${memberItem.pw}</td>
<td>${memberItem.name}</td>
</tr>
</c:forEach>
</tbody>
</table>
>>> jsp 파일
↓ 실행결과
jstl2.jsp 파일에서 a태그 링크를 누르면 jstl3.jsp 파일로 이동하는 상황을 만들어보겠다.
<h1>jstl2</h1>
<a href="/jstl3">jstl3페이지로 이동</a>
위와 같은 상황이 있다고 가정해본다. 링크를 클릭하게 되면 아래와 같은 오류를 만난다.
>>> 이는 url 경로에 프로젝트명이 따라오지 않았기 때문이다. 요청 url을 받아오기 위해 <c:set>을 사용한다.
<h1>jstl2</h1>
<c:set var="contextPath" value="${pageContext.request.servletContext.contextPath}"/>
<a href="${contextPath}/jstl3>jstl3페이지로 이동</a>
>>> jsp 파일
↓ 실행결과
<h1>jstl2</h1>
<c:url var="jstl3url" value="/jstl3">
<c:param name="data1" value="abc" />
<c:param name="data2" value="def" />
</c:url>
<a href="${jstl3url}">jstl3페이지로 이동 curl</a>
<!-- <c:url> 태그의 var에서 정한 변수명으로 부름 -->
↓ 실행결과
>>> 요청한 url로 이동하고 파라미터 값도 잘 전달되는 것을 확인할 수 있다. 그런데 url에 ;jsessionid= 값이 따라오는 것을 발견했다.
이는 서버에서 클라이언트에 세션을 유지하기 위해 쿠키를 생성해야 하는데 클라이언트가 쿠키생성을 허용했는지가 불확실하기때문에 ;jsessionid=를 붙여 다니는 것이다.
이는 jstl의 기본 설정 방식이기 때문에 그냥 사용하기로 결정..ㅎㅎ
이 부분이 걸린다면 <c:url> 태그 대신 위에서 사용했던 ${pageContext.request.servletContext.contextPath}
를 변수에 저장해서 경로 앞에 붙이면 된다.
@Controller
public class JstlController {
@RequestMapping("/jstl5")
public String jstl5(Model model) {
model.addAttribute("str2", "<script>alert('경고메시지');</script>");
return "jstl5";
}
}
>>> 컨트롤러
<h1>jstl5</h1>
${str2}
>>> jsp 파일
↓ 실행결과
>>> str2에 들어있는 문자열이 jsp 파일 안에서 스크립트로 인식되어 alert 창이 실행된 것을 볼 수 있다. 문자열 그대로 출력하고 싶을 땐 어떻게 해야 할까? 이럴 때 <c:out> 태그를 사용하면 된다.
<h1>jstl5</h1>
<%-- ${str2} --%>
<c:out value="${str2}"></c:out>
>>> jsp 파일
↓ 실행결과
>>> 원하는 값이 출력됨
❓ <c:out>을 사용하는 이유?
- html이나 스크립트가 실행되어 위험
- 엄격한 태그 규칙을 위해
- 개행문자 파싱의 차이 때문
- 보안성 때문에 사용
- *HTML 특수문자를 탈락시키는 기능 有
*ex)
> -<
< ->
& -&
' -'
'' -"
<c:out value='${값}'/>
에는 디폴트로 escapeXml 옵션이 true로 되어있어 출력할 문자열에 HTML 특수문자가 포함되어 있을 경우 HTML을 해석하지 않고 그대로 출력해준다. escapeXml을 false로 바꾸면 HTML 코드를 그대로 해석해서 내보내게 된다.
결론 : ${}
에는 escape 기능이 지원되지 않아 XSS 공격에 노출될 수 있음!