요청을 하고 그에대한 응답을 보낼 때, 응답에 대해 동적으로 처리되는 내용들을 request 의 Attribute 내에 담아 화면상에 출력하고자 할 것이다.
위임된 JSP에서 출력하고자 하는 내용을 request 내장객체 내 setAttribute를 이용해서 담는다.
문자값, 숫자값을 담은 뒤 ArrayList 배열도 생성한다. 이 배열역시 request에 담는다.
items를 request에 setAttribute 하여 담아준다.
attribute는 Object 타입이므로 담길 수 있다.
ServletRequest를 통해서 RequestDispatcher 얻는 법 서블릿 클래스에서는 service() 메서드나 doGet() doPost() 등에서 ServletRequest의 하위 클래스인 HttpServletRequest를 매개변수로 받기 때문에 이것을 이용하여 RequestDispatcher를 얻을 수 있습니다. HttpServletRequest에서는 URL 경로를 통해서 대상을 지정하는 한가지 방법만을 제공합니다. 그러나 ServletContext를 통해서 대상을 지정할때와는 다르게 절대경로 및 상대경로 모두 지정이 가능합니다. JSP 페이지에서도 ServletRequest의 인스턴스인 request 기본객체가 있으므로 쉽게 얻을 수 있습니다.
출처: https://dololak.tistory.com/502
다 담아줬다면 위임, 즉 forward 하여 jsp로 보내도록 한다.
보내기 위해 RequestDispatcher 객체가 필요하다.
* * * RequestDispatcher란? RequestDispatcher는 클라이언트로부터 최초에 들어온 요청을 JSP/Servlet 내에서 원하는 자원으로 요청을 넘기는(보내는) 역할을 수행하거나, 특정 자원에 처리를 요청하고 처리 결과를 얻어오는 기능을 수행하는 클래스입니다. 즉 /a.jsp 로 들어온 요청을 /a.jsp 내에서 RequestDispatcher를 사용하여 b.jsp로 요청을 보낼 수 있습니다. 또는 a.jsp에서 b.jsp로 처리를 요청하고 b.jsp에서 처리한 결과 내용을 a.jsp의 결과에 포함시킬 수 있습니다.
요청을 보내는 방법으로는 (1) RequestDispatcher#forward()와 (2) RequestDispatcher#include() 두 가지 방법이 있습니다.
출처 : https://dololak.tistory.com/502
경로를 지정한뒤 해당경로로 위임시키는 forward를 호출한다.
request 와 response를 다 넘겨야 해당페이지에서도 담았던 값들을 모두 사용할 수 있다.
위임될 대상인 JSP ("views/el/testEl1.jsp")를 경로에 맞게 작성한다.
testEl1.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8" import="java.util.*"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<h2>전달 된 request 객체에서 저장된 정보 출력하기</h2>
<%-- <%
String name = (String)request.getAttribute("name");
int age = (Integer)request.getAttribute("age");
String phone = (String)request.getAttribute("phone");
%>
name : <%= name %> <br>
age : <%= age %> <br>
phone : <%= phone %> <br> --%>
<!-- EL 표현식으로 출력하기 -->
name : ${ requestScope.name } <br>
age : ${ requestScope.age } <br>
phone : ${ requestScope.phone } <br>
<!-- 스코프 범위 생략 가능함(알아서 찾음) -->
name : ${ name } <br>
age : ${ age } <br>
phone : ${ phone } <br>
<br>
<h2>items 이름으로 저장 된 리스트 정보 출력하기</h2>
<%-- <%
ArrayList items = (ArrayList)request.getAttribute("items");
%>
<% for(int i = 0; i < items.size(); i++) { %>
<%= i %> : <%= items.get(i) %> <br>
<% } %> --%>
0 : ${ requestScope.items[0] } <br>
1 : ${ requestScope.items[1] } <br>
2 : ${ requestScope.items[2] } <br>
0 : ${ items[0] } <br>
1 : ${ items[1] } <br>
2 : ${ items[2] } <br>
</body>
</html>
전달 된 request 객체에서 저장된 정보 출력하기
스크립틀릿과 익스프레션 태그를 이용해서 먼저 출력해본다.
request에서 setAttribute 해주었던 내용을 getAttribute 해온다.
스크립틀릿(<% %>) 내에선 순수하게 '꺼내왔다'고만 할 수 있으나 이걸 화면상에서 표현하고자 한다면
익스프레션(<%= %>) 태그를 이용해 주면 된다.
화면에 잘 반영되는지 확인해보자.
아까전 jsp 파일에 /test1으로 경로를 지정해서 연결해주었다.
1) test1으로 요청이 되어서 서블릿과 매핑이 되고
2) 서블릿에서는 jsp로 위임한 것이 화면에 출력된 것이다.
하지만 위임에 대해서는 경로에 드러나지 않는다. 내부적으로 위임이 되어 jsp 에서 처리를 해주는 것이다.
EL 표현식으로 출력하기
지금까지 태그를 이용해서 (위와같이) 꺼내오고 출력하는 모습을 확인했다.
이렇게 꺼내오는 과정의 번거로움을 줄이기 위해 나타난 것이 el표현식이다.
특징은 다음과 같다. ${ } 를 활용하며, requestScope 라는 내장객체를 이용해, 속성을 가져온다.
requestScope란, request 영역을 의미한다. el문법안에서 사용할 수 있는 el 내장객체이다.
requestScope 뒤에 점을 찍어 영역의 속성을 가져오는 것이다.
jsp내장객체이기에 request를 그냥 쓸 수 있듯 requestScope 역시 el 문법의 내장객체이기에 별도의 처리 없이 사용할 수 있다. 약속된 용어이다.
el문법에서 내장하고있는 객체, 즉 requstScope 는 생략이 가능하다.
JSP 태그를 사용하면 저장(setAttribute)하고 꺼내와야(getAttribute)하지만
el문법에서 내장하고있는 객체는 ${ } 즉, 달러와 중괄호 내에 작성하기만 하면 알아서 잘 찾아온다는 특징을 가지고 있으므로 훨씬 간결하고, 편리한 면이 있다.
items 이름으로 저장 된 리스트 정보 출력하기
request 객체의 속성은 Object로 리턴되므로 ArrayList에 담기위해서 다운 캐스팅이 필요하다.
Attribute는 Object에 속한탓이다.
다운캐스팅을 해주어도 여전히 에러줄이 사라지지않는다면 맨 위 지시자 태그내에 import 처리가 되어있는지 확인한다.
배열이므로 출력을 위해선 반복문의 사용이 필요하다.
단순히 화면에 출력되기 위해 반복문을 출력줄 것이다.
겉, 즉 위아래로 반복문의 범위를 스크립틀릿으로 잡아주고
내부에선 익스프레션 태그를 이용해 반복되는 만큼 화면에 출력해줄 것이다.
<%
ArrayList items = (ArrayList)request.getAttribute("items");
%>
<% for(int i = 0; i < items.size(); i++) { %>
<%= i %> : <%= items.get(i) %> <br>
<% } %>
리스트 정보 el문법을 이용해 출력하기
list 이므로 배열 인덱스 하나하나 값으로 접근시, 잘 출력된다.
역시 내장객체인 requestScope 의 사용은 생략 가능하다.
이와같이 인덱스로 하나하나 접근하는게 아닌 반복문은 나중에 배울 jstl을 이용하면 된다.
java.util.function패키지에 일반적으로 자주 쓰이는 형식의 메서드를 함수형 인터페이스로 미리 정의해 놓았다.
매개변수와 반환값의 유무에 따라 4개의 함수형 인터페이스가 정의되어 있고, Function 의 변형으로 Predicate가 있다.
Runnable : 매개변수도 없고, 반환값도 없음
Supplier<T> : 매개변수는 없고 반환값만 있는 공급자
Consumer<T> : 매개변수만 있고, 반환값은 없는 소비자
Function<T,R> : 하나의 매개변수와 하나의 결과를 반환하는 일반적인 함수
Predicate<T> : 조건식을 표현하는데 사용, 하나의 매개변수와 boolean 타입의 반환값
Predicate는 반환값이 boolean이라는 것만 제외하면 Function과 동일하다.
Predicate는 조건식을 함수로 표현히는데 시용된다.
Predicate는 Function의 변형으로, 반환타입이 boolean이라는 것만 다르다. Predicate 는 조건식을 람다식(함수)으로 표현하는데 사용된다
java.util.function 패키지 Quiz
1~100 범위의 숫자를 반환만 하므로 공급자 > Supplier<Integer>
매개변수만 있고 반환값을 없으므로 수요자 > Consumer<Integer>
조건식이 있으므로 Predicate<Integer, Boolean>
매개변수 하나와 반환값이 있으므로 Function<Integer, Integer>
매개변수가 2개인 함수형 인터페이스
매개변수의 개수가 2개인 함수형 인터페이스는 이름 앞에 접두사 "Bi’가 붙는다
BiSupplier 는없다. 함수의 반환값은 0개 혹은 1개만 가능하기 때문이다. 반환값이 2개일 수는 없다.
람다식의 도입으로 인해, 이제 자바는 객체지향언어(OOP)인 동시에 함수형 언어가 되었다.
람다식(Lambda expression)은 메서드를 하나의 ‘식(expression)’으로 표현한 것이다.
메서드를 람다식으로 표현하면 메서드의 이름과 반환값이 없어지므로, 람다식을 ‘익명 함수(anonymous function)’이라고도 한다.
모든 메서드는 클래스에 포함되어야 하므로 클래스도 새로 만들어야 하고, 객체도 생성해야만 비로소 이 메서드를 호출할 수 있다.
그러나 람다식은 이 모든 과정없이 오직 람다식 자체만으로도 이 메서드의 역할을 대신할 수 있다.
람다식은 메서드의 매개변수로 전달되어지는 것이 가능하고, 메서드의 결과로 반환될 수도 있다.
람다식으로 인해 메서드를 변수처럼 다루는 것이 가능해진 것이다.
Q. 메서드와 함수의 차이
A. 전통적으로 프로그래밍에서 함수라는 이름은 수학에서 따온 것입니다. 수학의 함수와 개
념이 유사하기 때문이죠. 그러나 객체지향개념에서는 함수(function)대신 객체의 행위나 동
작을 의미하는 메서드(method)라는 용어를 사용합니다. 메서드는 함수와 같은 의미이지만,
특정 클래스에 반드시 속해야 한다는 제약이 있기 때문에 기존의 함수와 같은 의미의 다른
용어를 선택해서 사용한 것입니다. 그러나 이제 다시 람다식을 통해 메서드가 하나의 독립적
인 기능을 하기 때문에 함수라는 용어를 사용하게 되었습니다.
즉 함수는 클래스에 독립적이나 메서드는 반드시 클래스에 작성해야하므로 종속적이다.
람다식 작성하기
람다식은 메서드에서 이름과 반환타입을 제거하고
매개변수 선언부와 몸 통{ } 사이에
‘ -> ’를 추가 한다.
이때는 ‘문장(statement)’이 아닌 ‘식’이므로 끝에 ‘;’을 붙이지 않는다.
람다식에 선언된 매개변수의 타입은 추론이 가능한 경우는 생략할 수 있는데, 대부분의 경우에 생략가능하다.
람다식에 반환타입이 없는 이유도 항상 추론이 가능하기 때문이다.
‘(int a. b) -> a > b ? a : b’와 같이 두 매개변수 중 어느 하나의 타입만 생략하는 것은 허용되지 않는다.
선언된 매개변수가 하나뿐인 경우에는 괄호( ) 를 생략할 수 있다.
단, 매개변수의 타입이 있으면 괄호()를 생략할 수 없다.
괄호{ } 안의 문장이 하나일 때는 괄호{ }를 생략할 수 있다.
이 때 문장의 끝에 ';'(세미콜론) 을 붙이지 않아야 한다는 것에 주의한다.
그러나 괄호{ } 안의 문장이 return문일 경우 괄호를 생략할 수 없다.
익명객체 람다식
자바에서 모든 메서드는 클래스내에 포함되어야 한다.
람다식이 메서드와 동등한 것처럼 설명했지만, 사실 람다식은 익명 클래스의 객체와 동등하다.
람다식으로 정의된 익명 객체의 메서드를 어떻게 호출할 수 있을 것인가? 이미 알고 있는 것 처럼 참조변수가 있어야 객체의 메서드를 호출 할 수 있으니 이 익명 객체의 주소를 f라는 참조변수에 저장해 본다.
타입 f = (int a,int b) -> a>b ? a:b;
참조변수 f의 타입은 어떤 것이어야 할까?
참조형이니까 클래스 또는 인터페이스 가 가능하다.
그리고 람다식과 동등한 메서드가 정의되어 있는 것이어야 한다.
그래야만 참조변수로 익명 객체(람다식)의 메서드를 호출할 수 있기 때문이다.
아래와 같이 max()라는 메서드가 정의된 MyFunction인터페이스가 정의되어 있다고 가정하자
이 인터페이스를 구현한 익명 클래스의 객체는 다음과 같이 생성할 수 있다.
MyFunction인터페이스에 정의된 메서드 max()는 람다식 ‘(int a, int b) -〉a 〉b ? a : b’과 메서드의 선언부가 일치한다. 그래서 위 코드의 익명 객체를 람다식으로 아래와 같이 대체할 수 있다
MyFunction f = (int a,int b) -> a>b ? a:b;
int big = f.max(5,3);
MyFunction인터페이스를 구현한 익명 객체를 람다식으로 대체가 가능한 이유는
MyFunction인터페이스를 구현한 익명 객체의 메서드 max()와
람다식의 매개변수의 타입과 개수 그리고 반환값이 일치하기 때문이다
그러므로 람다식을 다루기 위한 인터페이스를 ‘함수형 인터페이스(functional interface)’라고 한다.