
Expression Language는 말 그대로 화면에 값을 표현하는데 특화된 문법입니다.
JSP문서에서 별다른 라이브러리 임포트 없이 바로 사용할 수 있어 사용법이 비교적 간편하고, null값이나 형변환에 관대합니다.
💡 EL은 형변환에 관대하다?
기존 JSP 내 스크립트 요소의 경우 java 문법을 따르기 때문에 형변환 또는 null값 처리에 까다로운 편입니다.
하지만 EL은 값을 표현하는데 특화된 문법 요소이기 때문에 null값이 들어와도 그냥 공백으로 처리해버리고 따로 예외를 발생시키지 않습니다.
또한, 형변환도 마치 JS처럼 알아서 형변환하여 처리하는 식으로 작동합니다.
EL은 별다른 추가 작업 없이 JSP 문서 내 HTML, CSS, JS, JSTL 문법 내, 액션태그 문법 내 어디든 사용할 수 있습니다.
단, <%! %>, <% %>, <%= %>의 스크립트 요소(선언부, 스클립틀릿, 표현식)에서는 사용할 수 없습니다.
- 기본 사용법
${속성명}
- JSTL 문법 내 사용 예시
<c:set var="testVar" value="${pageScope.scopeValue}" />
- 액션 태그 내 사용법 예시
<jsp:forward page="../test/test.jsp" >
<jsp:param name="testParam" value="${pageScope.scopeValue}" />
</jsp:forward>
의 형식으로 사용할 수 있습니다.
EL에서는 JSON 처럼 .접근법 또는 []접근법을 사용할 수 있습니다.
[]접근법 내에서는 "" 또는 ''로 속성명을 감싸서 사용할 수 있습니다.
${param.name}
${param["name"]}
${param['name']}
단, 객체의 속성명에 한글 또는 특수문자 등이 들어갈 경우 .접근법은 사용할 수 없으며 []접근법만 사용할 수 있습니다.
${header.user-agent} (x)
${header["user-agent"]} (O)
${header['user-agent']} (O)
>
${param.한글이름} (x)
${param["한글이름"]} (O)
${param['한글이름']} (O)
💡 EL에서 DTO 객체의 필드에 접근하는법
위에서 봤다시피 EL에서는 객체의 속성명(필드명)으로 바로 객체의 속성에 접근할 수 있습니다.
즉, DTO객체에서 또한객체명.get속성명()의 getter 메서드 없이 바로 필드명으로 접근하여 값을 출력 할 수 있습니다.// dto 객체 page 영역에 저장 <% TestDTO dto = new TestDTO(); pageContext.setAttribute("dto", dto); %> // 1. 스크립트 요소에서 DTO 객체 값 출력 <% TestDTO dto = (TestDTO) pageContext.getAttribute("dto"); String dtoName = dto.getName() out.print("스크립트 요소에서 dtoName 출력 : " + dtoName); %> // 2. EL로 DTO 객체 값 출력 EL로 dtoName 출력 : ${dto.name}
EL은 다음의 값을 표현(출력)하는데 사용될 수 있습니다.
1. JSP의 4가지 영역(Page / Request / Session / Application)에 저정된 속성 값을 출력
2. Request영역에 저장된 Parameter 값을 출력 (post/get 어떤 방식이든)
3. Cookie 값, Http Header 값, web.xml에 설정된 init-Param 값, PageContext 값 출력
4. JSTL 또는 액션태그로 저장된 변수 값 출력
💡 EL로 스클립틀릿 영역에서 저장한 변수를 바로 사용할 수 있나요?
EL의 경우 직접 특정 값을 출력하기 보다 JSP의 4가지 영역에 저장된 값을 갖고와 출력하는 개념입니다.
위 사용범위 4가지 모두 JSP 4가지 영역을 활용한 방식이라는 공통점을 볼 수 있을 것입니다.
따라서, 스크립틀릿<% %>에서 선언한 변수 등을 바로 사용할 수는 없고 해당 변수를 4가지 영역 중 어딘가에 저장한 후 사용할 수 있습니다.
4가지 영역 내 속성에 접근하기 위해서는
1. 영역명 뒤에 Scope로 영역에 접근 후 .접근법 또는 []접근법으로 속성명으로 접근하는 방법
2. 영역명 없이 그냥 바로 속성명으로 접근하는 방법 => 가장 좁은 영역에서부터 해당 속성명을 찾음
(Page 영역 < Request 영역 < Session 영역 < Application 영역)
1. 영역명을 명시하는 방법
Page 영역의 속성 값 = ${pageScope.속성명}
Requesst 영역의 속성 값 = ${requestScope.속성명}
Session 영역의 속성 값 = ${sessionScope.속성명}
Application 영역의 속성 값 = ${applicationScope.속성명}
2. 영역명 없이 사용하는 방법
가장 좁은 영역에서부터 속성명 찾음 = ${속성명}
// 따라서, 동일한 속성명이 각 영역마다 있어도 가장 좁은 영역에서의 해당 속성명의 값만을 가져옵니다.
form으로 또는 쿼리 스트링 등 으로 Request 영역에 저장된 Parameter 값에 접근하여 값을 출력할 수 있습니다.
이 때 요청방식이 get이든 Post이든 상관없이 접근할 수 있습니다.
1. parameter 값이 하나일 경우
${param.파라미터명}
2. parameter 값이 여러개일 경우 (check-box 등의 input 값)
${paramValues.파라미터명}
// String[]로 값을 받아옵니다 출력할 때는 ${paramValues.파라미터명[idx]}로 접근할 수 있습니다.
EL의 경우 4가지 영역에 접근하여 값을 출력할 수 있습니다.
따라서 주로 사용되는 Cookie나 Http 헤더값 등은 특정 키워드로 바로 접근하여 출력하여 사용할 수 있습니다.
1. Cookie 값 출력
${cookie.쿠키명.value}
2. Http 헤더 내 값 출력
// 헤더값이 단일 값일 때
${header.헤더명}
// 헤더값이 여러개 일 때 - Stirng[] 형대로 값을 가져 옴
${headerValues.헤더명}
3. web.xml 에 등록된 init-Param 값 출력
${initParam.파라미터명}
4. PageContext 값 출력 (주로 컨텍스트 루트 경로를 읽을 때 사용)
${pageContext.requeset.contextPath}
JSTL 또는 액션태그로 변수를 저장한 경우도 4가지 영역 내 값을 저장하는 방식이기 때문에 이 또한 EL로 출력할 수 있습니다.
- JSTL로 값 저장
<c:set var="varName" value="test" />
// JSTL c:set의 경우 scope 속성으로 변수를 저장할 영역을 지정할 수 있으며 생략 시 page 영역에 저장됩니다.
- EL로 출력
${varName}
${pageScope.varName}
- 액션태그로 값 저장
<jsp:forward page="../test/test.jsp" >
<jsp:param name="testParam" value="test" />
</jsp:forward>
// 액션태그 <jsp:param>의 경우 <jsp:forward>또는 <jsp:include>와 함께 쓰이며,
// request영역에 Parameter로 저장됩니다.
- EL로 출력
${param.testParam}
EL에서는 여러가지 Java의 문법요소를 더 간단한 형태로 사용할 수 있습니다.
EL 내에서 Collectio 타입의 값을 출력 할 때 비교적 간편히 내부 요소에 접근할 수 있습니다.
- 리스트의 특정 인덱스로 접근
${list[idx]}
- List의 전체 값 출력하기
// JSTL의 코어 태그 활용
<c:forEach var="li" items="${list}">
${li}
</c:forEach>
- Map의 특정 KeyName로 접근
${map["keyName"]}
${map.keyName}
// 단 KeyName에 한글 또는 특수문자가 포함되어있을 경우 []접근법으로만 접근할 수 있습니다.
- Map의 모든 Key의 값을 출력하기
// JSTL의 코어 태그 활용
<c:forEach var="entry" items="${map}">
${entry.key} = ${entry.value}
</c:forEach>
할당 연산자의 경우 EL 3.0 버전부터 사용 가능해진 문법입니다!
${num = 11} - 할당과 동시에 출력
${num = 11;''} - 할당만 하고 출력은 안 함
${num1 + num2} - 덧셈
${num1 - num2} - 뺄셈
${num1 * num2} - 곱셈
${num1 / num2} ${num1 div num2} - 나눗셈
${num1 % num2} ${num1 mod num2} - 나머지
💡 EL 에서
+연산자는 숫자의 더하기에만 사용 가능
Java 문법에 익숙하다보면+연산자로 문자열을 연결시키는게 익숙할 수 있는데,
EL에서+연산자는 오로지 숫자의 더하기에만 사용 됩니다.
단, 문자열 형태의 숫자일 경우 EL이 알아서 형변환하여 연산합니다.${num = 1;''} ${num + 1} => 2 정상 출력 ${num + "1"} => 3 정상 출력 // "1" 문자열 형태의 숫자도 EL이 알아서 형변환 후 연산 함 ${num + "일"} => 에러 발생
${num1 > num2} ${num1 gt num2} - 좌측이 우측보다 크면 ture 아니면 false
${num1 >= num2} ${num1 ge num2} - 최측이 우측보다 커거나 같으면 ture 아니면 false
${num1 < num2} ${num1 lt num2} - 좌측이 우측보다 작으면 ture 아니면 false
${num1 <= num2} ${num1 le num2} - 좌측이 우측보다 작거나 같으면 ture 아니면 false
${num1 == num2} ${num1 eq num2} - 좌측과 우측이 같으면 ture 아니면 false
${num1 != num2} ${num1 ne num2} - 좌측과 우측이 다르면 ture 아니면 false
${조건1 && 조건2} ${조건1 and 조건2} - AND 연산자
${조건1 || 조건2} ${조건1 or 조건2} - OR 연산자
${!조건1} ${not 조건1} - NOT 연산자
EL에서는 empty 연산자를 통해 아래의 경우 true 값을 반환하는 연산자를 사용할 수 있습니다.
${empty 변수명} - 입력된 변수의 값이 null / 빈 문자열 / 길이가 0인 배열 / size가 0인 컬력션일 경우 true 반환
${조건 ? true일 때 결과 : false일 때 결과}
💡 EL에서 null과의 연산
Java 문법의 경우null + 1과 같이 null과의 연산을 실행시킬 경우 따로 예외 처리를 해주지 않는 이상NullPointerExceoption이 발생됩니다.
하지만 EL에서는 null과 연산을 진행하더라도 null이 0으로 취급되기 때문에 에러가 발생되지 않습니다.
단, 정상적으로 출력은 되나, IDEA 상에서 에러로 표시될 수는 있습니다.${null + 10} => 10 정상 출력 ${null > 10} => faule 정상 출력
EL에서는 Java의 클래스로 정의된 메서드를 호출할 수 있습니다.
일반 메서드의 경우 바로 EL에서 사용할 수는 없고 4가지 영역 내 저장 후 저장된 값을 이용해 사용할 수 있습니다.
// 객체 생성해서 page 영역에 저장
<%
TestClass testClass = new TestClass();
pageContext.setAttribute("testClass", testClass);
%>
// EL로 메서드 호출
${testClass.testFunction()}
정적 메서드의 경우, 아래의 두가지 방식으로 사용할 수 있습니다.
클래스명을 통한 사용법
Java에서 처럼 정적 메서드의 경우 객체 생성 없이 바로 클래스명으로 접근해서 사용할 수 있습니다.
${TestClass.testFunction()}
TLD를 활용한 사용법
우선 TLD란, Tag Library Descriptor로 사용자 정의 태그나 JSTL 태그들을 설정하기 위한 XML파일입니다.
TLD를 사용하는 방식은 앞서 설명한 클래스명으로 바로 사용하는 방법이 생기기 전에 사용되던 방식으로 현재는 잘 사용되는 방식은 아니지만 간혹 레거시코드에서 볼 수 있는 방식 입니다.
간단하게만 저리하고 넘어가겠습니다.
[TLD 방식 사용법]
<?xml version="1.0" encoding="UTF-8"?>
<taglib version="2.0"
xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xml="http://www.w3.org/XML/1998/namespace"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-jsptaglibrary_2_0.xsd ">
<tlib-version>1.0</tlib-version>
<!-- 해당 taglib의 버전을 알아서 기입해줍니다. -->
<short-name>myTag</short-name>
<function>
<name>testFunction</name>
<function-class>test.testClass</function-class>
<!-- 작성한 클래스를 패키지명까지 포함해서 작성합니다. -->
<function-signature>void testFunction()</function-signature>
<!--
TLD방식으로는, public static 메서드만 등록할 수 있기 때문에 해당 부분 생략 후 메서드 시그니처 내용을 기입해줍니다.
또한, 리턴타입, 매개변수 부분에서 Java의 기본자료형이 아닌 경우 패키지를 포한한 전체 경로를 입력해야합니다.
-->
</function>
</taglib><%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ page trimDirectiveWhitespaces="true" %>
<%@ tablib prefix="myTag" uri="/WEB-INF/testTLD.tld" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
${myTag:testFunction()}
</body>
</html>성낙현의 JSP 자바 웹 프로그래밍 2판 - 성낙현 지음
위 책을 공부하며 작성하고 있습니다