(책) 자바 웹을 다루는 기술

Chap 8 키워드 정리

EunaSon 2023. 8. 19. 18:47

8장 서블릿 확장 API 사용하기

 

8.1 서블릿 포워드 기능 사용하기

이 장에서는 서블릿 프로그래밍 개발에 사용하는 기능인 포워드, 바인딩, 애너테이션 등 다양한 기능에 대해 살펴보자

- 포워드(forward)

하나의 서블릿에서 다른 서블릿이나 JSP와 연동하는 방법을 말함.

-포워드 주요 사용 용도

요청에 대한 추가 작업을 다른 서블릿에게 수행하게 함

요청에 포함된 정보를 다른 서블릿이나 jsp와 공유할 수 있음

요청에 정보를 포함시켜 다른 서블릿에 전달할 수 있음

모델2(17장) 개발 시 서블릿에서 jsp로 데이터를 전달하는 데 사용됨

=> 포워드 기능은 서블릿에서 다른 서블릿이나 jsp로 요청을 전달하는 역할을 함

 

8.2 서블릿의 여러 가지 포워드 방법

서블릿에서 사용되는 포워드 방법 네 가지

1. redirect 방법

HttpServletResponse 객체의 sendRedirect() 메서드를 이용함

웹 브라우저에 재요청하는 방식

형식 : sendRedirect("포워드할 서블릿 또는 jsp");

2. Refresh 방법

HttpServletResponse 객체의 addHeader() 메서드를 이용함

웹 브라우저에 재요청하는 방식

형식 : response.addHeader("Refresh", "경과시간(초); url=요청할 서블릿 또는 JSP") 

3. location 방법

자바스크립트 location 객체의 href 속성을 이용함

자바스크립트에서 재요청하는 방식

형식 : location.href='요청할 서블릿 또는 jsp'

4. dispatch 방법

일반적으로 포워딩 기능을 지칭함

서블릿이 직접 요청하는 방법

RequestDispatcher 클래스의 forward() 메서드를 이용함

형식 :

RequestDispatcher dis = request.getRequestDispatcher("포워드할 서블릿 또는 jsp");

dis.forward(request, response);

 

1,2,3 방법은 서블릿이 웹 브라우저를 거쳐 다른 서블릿이나 jsp에게 요청하는 방법

4 방법은 서블릿에서 클라이언트를 거치지 않고 바로 다른 서블릿에게 요청하는 방법

 

- 264p redirect를 이용한 포워딩

수행과정

1. 클라이언트의 웹 브라우저에서 서블릿1에 요청함

2. 서블릿1은 sendRedirect() 메서드를 이용해 서블릿2를 웹 브라우저를 통해 요청함

 response.sendResponse("second");

3. 웹 브라우저는 sendRedirect()가 지정한 서블릿2를 다시 요청함

=> 브라우저에서 서블릿1로 요청->브라우저에 표시되는 매핑 이름은 서블릿2의 이름임

: /first로 요청하면 sendRedirect()를 호출해 웹 브라우저가 다시 /second를 요청하는 것

 

- 267p refresh를 이용한 포워딩

수행과정

1. 클라이언트의 웹 브라우저에서 서블릿1에 요청함

2. 서블릿1은 addHeader() 메서드를 이용해 서블릿2를 웹브라우저를 통해 요청함

 response.addHeader("Refresh","1;url=second"); // 웹브라우저에 1초 후 서블릿 second로 재요청함

3. 웹 브라우저는 addHeader() 메서드가 지정한 서블릿2를 다시 요청함

=> 마찬가지로 /first로 요청하면 /second로 재요청함

 

- 268p location을 이용한 포워딩

자바스크립트의 location 객체를 이용함

서블릿1에서 PrintWriter 통해 자바스크립트 코드를 출력해서 서블릿2로 재요청함

out.print("<script>");

out.print("location.href='second';");

out.print("</script>");

 

- 270p redirect 방식으로 다른 서블릿에 데이터 전달하기

서블릿1에서

response.sendRedirect("second?name=lee");

 -> GET 방식을 이용해 이름/값 쌍으로 데이터를 다른 서블릿(second)에 전달함

서블릿2에서는 getParameter() 를 이용해 전달된 값 가져옴

String name = request.getParameter("name"); // 이전 서블릿에서 name으로 전달된 lee를 받아옴

 

8.3 dispatch를 이용한 포워드 방법

dispatch를 이용한 포워딩 과정은 클라이언트의 웹 브라우저를 거치지 않고 서버에서 바로 포워딩이 진행됨. 따라서 웹 브라우저 주소창의 url이 바뀌지 않음. 즉 클라이언트 측에서는 포워드가 진행되었는지 알 수 없음.

 

271p dispatch를 이용한 포워딩 수행 과정

1. 클라이언트의 웹 브라우저에서 첫 번째 서블릿에 요청함

2. 첫 번째 서블릿은 RequestDispatcher를 이용해 두번째 서블릿으로 포워드함

RequestDspatcher dispatch = request.getRequestDispatcher("second");

dispatch.forward(request, response);

 

* dispatcher 방법은 17장의 모델2 방식이나 스트럿츠, 스프링 프레임워크에서 포워딩할 때 사용함

 

dispatcher 이용해 GET 방식으로 데이터 전송

RequestDispatcher dispatch = request.getRequestDispatcher("second?name=lee");

=>

서블릿2에서

String name = request.getParameter("name"); 으로 lee 가져옴

url 변하지 않음을 확인할 수 있음

 

8.4 바인딩

앞에서는 GET 방식으로 데이터 전달했음

데이터의 양이 적을 때는 GET 방식이 편리하지만 대량의 상품 정보 등 대량의 데이터를 공유하거나 전달할 때에는 바인딩(binding) 기능을 사용함

 

275p

바인딩 : '두 개를 하나로 묶는다' 는 의미.

웹 프로그램 실행시 자원(데이터)을 서블릿 관련 객체에 저장하는 방법으로, 주로 HttpServletRequest, HttpSession, ServletContext 객체에서 사용됨. 저장된 자원(데이터)은 프로그램 실행 시 서블릿이나 jsp에서 공유하여 사용함.

모델2, 스트럿츠, 스프링 프레임워크로 구현하는 웹 프로그램은 바인딩 기능을 이용해 서블릿이나 jsp간 데이터를 전달, 공유함

 

-서블릿 관련 객체에서 바인딩 관련 기능을 제공하는 메서드들

setAttribute(String name. Object obj) : 자원(데이터)을 각 객체에 바인딩함

getAttribute(String name) : 각 객체에 바인딩된 자원(데이터)을 name으로 가져옴

removeAttribute(String name) : 각 객체에 바인딩된 자원(데이터)을 name으로 제거함

 

-276p HttpServletRequest를 이용한 redirect 포워딩 시 바인딩

<첫번째 서블릿>

request.setAttribute("address", "서울시 성북구"); // 웹 브라우저에서 요청한 request 객체에 address의 값으로 "서울시 성북구"를 바인딩함

response.sendRedirect("second"); // 두번째 서블릿 호출

<두번째 서블릿>

String address = (String)request.getAttribute("address"); // 전달된 reqeust에서 getAttribute()를 이용해 address의 값을 가져옴

=> address에 '서울시 성북구'가 들어가지 않고 null이 출력됨

첫번째 request(1단계에서 웹브라우저->첫번째 서블릿에 전달되는 요청)와 두번째 request(3단계에서 웹브라우저->두번째 서블릿에 재요청)가 서로다른 요청이기 때문임

=> redirect 방식에는 다량의 데이터 전송에 문제가 있음

 

-278p HttpServletRequest를 이용한 dispatch 포워딩 시 바인딩 

<첫번째 서블릿> 브라우저에서 전달된 request에 주소를 바인딩 후 dispatch 방법으로 포워딩

request.setAttribute("address", "서울시 성북구");

RequestDispatcher dispatch = request.getRequestDispatcher("second");

dispatch.forward(request, response);

<두번째 서블릿>

위의 예제와 동일

 

=> 화면에 정상적으로 address가 '서울시 성북구'로 출력됨

: 첫번째 서블릿에서 두번째 서블릿으로 전달되는 request가 브라우저를 거치지 않고 바로 전달되었음. 따라서 첫번째 서블릿의 request에 바인딩된 데이터가 그대로 전달된 것.

따라서 모델2, 스트럿츠, 스프링 프레임워크로 개발할 때는 dispatch 방식으로 바인딩된 데이터를 전달함

 

8.5 ServletContext와 ServletConfig 사용법

-282p ServletContext 클래스

톰캣 컨테이너 실행 시 각 컨텍스트(웹 애플리케이션) 마다 1개의 ServletContext 객체를 생성함

톰캣 컨테이너 종료시 ServleetContext 객체 역시 소멸됨

ServletContext 객체는 웹 애플리케이션이 실행되면서 애플리케이션 전체의 공통 자원이나 정보를 미리 바인딩해서 서블릿들이 공유하여 사용함

 

-ServletContext 클래스의 특징

javax.servlet.ServletContext로 정의되어있음

서블릿과 컨테이너 간의 연동을 위해 사용함

컨텍스트(웹 애플리케이션)마다 하나의 ServletContext가 생성됨

서블릿끼리 자원(데이터)을 공유하는데에 사용함

컨테이너 실행시 생성되고 컨테이너 종료시 소멸됨

 

-ServletContext가 제공하는 기능

서블릿에서 파일 접근 기능

자원 바인딩 기능

로그 파일 기능

컨텍스트에서 제공하는 설정 정보 제공 기능

 

ServletContext는 컨텍스트당 생성되는 반면, ServletConfig는 각 서블릿에 대해 생성됨

 

-285p ServletContext 바인딩 기능

[ SetServletContext 클래스 ]

: getServletContext() 메서드를 이용해 ServletContext 객체에 접근단 다음 ArrayList에 이름과 나이를 저장한 후 다시 ServletContext 객체에 setAttribute() 메서드로 바인딩함 

 

1. ServletContext context = getServletContext(); // ServletContext 객체를 가져옴


* 일반적으로는 이 방식으로 getServletContext()를 사용하면 되지만

모델2방식(MVC)에서는 컨트롤러 인터페이스를 상속받아 처리하게 되는데 이때는 위의 방식으로 사용할수 없음

=> ServletContext context = request.getSession().getServletContext(); 로 사용하여 웹애플리케이션 상의 절대경로를 구할 수 있는 ServletContext를 구할 수 있다

절대경로는 String realFolder = context.getRealPath("upload"); 이런 식으로 업로드의 절대경로를 구하면 된다

출처 https://wowstudy.tistory.com/17


2. 

List member = new ArrayList();

member.add("이순신");

member.add(30); // ArrayList에 이름, 나이 저장

 

3. context.setAttribute("member", member); // ServletContext 객체에 데이터를 바인딩함

 

[ GetServletContext 클래스]

: getServletContext() 메서드를 이용해 ServletContext 객체에 접근함, getAttribute() 로 다른 서블릿에서 바인딩한 ArrayList를 가져와 회원정보를 출력함

 

1. ServletContext context = getServletContext(); // ServletContext 객체를 가져옴

2. List member = (ArrayList)context.getAttribute("member"); // ServletContext에 member로 바인딩된 정보를 가져옴

 

=>

ServletContext를 이용한 바인딩

= 서블릿1이 ServletContext에 setAttribute()로 데이터 바인딩, 서블릿2는 getAttribute()로 ServletContext에서 바인딩된 데이터 가져옴.. ServletContext를 매개로 한 애플리케이션 내의 서블릿들이 데이터를 서로 바인딩하고, 가져오는 것임.

ServletContext에 바인딩된 데이터는 모든 사용자(서블릿들)가 접근할 수 있으므로, 웹 애플리케이션에서 모든 사용자가 공통으로 사용하는 데이터는 ServletContext에 바인딩해놓고 사용하면 편리함

 

-287p ServletContext의 매개변수(parameter) 설정 기능

대부분의 웹 애플리케이션에서 공통으로 사용하는 '메뉴' 같은 기능은 web.xml에 설정해놓고, 프로그램 시작 시 초기화할 때 가져와서 사용하면 편리함. '메뉴'는 ContextServlet 객체를 통해 접근하므로 모든 웹브라우저에서 공유하면서 접근할 수 있음(크롬, IE 등에서 모두 똑같은 메뉴를 출력함)

 

[ web.xml ] : 메뉴항목을 설정함

<context-param> 태그 안에  <param-name> 태그와 <param-value> 태그를 이용해 메뉴에 대한 하위 메뉴 항목을 설정함

<web-app>

  <context-param>

    <param-name>menu_member</param-name>

    <param-value>회원등록  회원조회  회원수정</param-value>

  </context-param>

  <context-param>

    <param-name>menu_order</param-name>

    <param-value>주문조회  주문등록  주문수정  주문최소</param-value>

  </context-param>

  <context-param>

    <param-name>menu_goods</param-name>

    <param-value>상품조회  상품등록  상품수정  상품삭제</param-value>

  </context-param>

...

</web-app>

 

[ ContextParamServlet 클래스 ]

: getServletContext() 로 ServletContext 객체에 접근함, getInitParameter() 메서드의 인자로 각각의 메뉴 이름을 전달한 후 메뉴 항목들을 가져와 이를 브라우저로 출력함

 

ServletContext context = getServletContext(); // ServletContext 객체를 가져옴

 

String menu_member = context.getInitParameter("menu-member");

String menu_order = context.getInitParameter("menu-order");

String menu_goods = context.getInitParameter("menu-goods");

// web.xml의 <param-name> 태그의 이름으로 <param-value> 태그의 값인 메뉴이름들을 받아옴

 

* getInitParameter(String name)

: name에 해당되는 매개변수의 초기화 값을 반환함(name에 해당하는 매개변수가 없으면 null 반환)

 

=> Context Init Parameter 선언 및 사용 방법

: web.xml에서 context parameter를 선언함

<param-name>에 매개변수 이름을, <param-value>에 매개변수 값을 설정함

사용할때는 ServletContext 객체를 가져와서 getInitParameter()를 호출한다

즉, 여러 서블릿에서 공통으로 참조하는 값이 있을 경우(위의 '메뉴'와 같이) context parameter로 정의하면 유지보수가 쉬워진다

 

-289p ServletContext의 파일 입출력 기능

ServletContext의 파일에서 데이터를 읽어오는 기능을 알아보자

/WEB-INF/bin 폴더에 init.text 파일을 생성 후 메뉴 항목을 입력하고 저장함,

[ init.txt ]

회원등록 회원조회 회원수정, 주문조회 주문수정 주문취소, 상품조회 상품등록 상품수정 상품삭제

 

이 init.txt 에서 메뉴 데이터를 읽어와 출력하는 기능을 구현해보자

[ ContextFileServlet 클래스 ]

1. ServletContext context = getServletContext(); // ServletContext에 접근

 

2. InputSteam is = context.getResourceAsStream("/WEB-INF/bin/init.txt"); // 해당 위치의 파일을 읽어들임

BufferedReader buffer = new BufferedReader(new InputStreamReader(is));

 

3. String menu, String menu_member, String menu_order, String menu_goods를 만들고 null을 저장

 

4. buffer.readLine()으로 buffer 내용을 가져와서 menu에 저장 후, null이 아니면

->

StringTokenizer tokens = new StringTokenizer(menu, ","); // 콤마를 구분자로 하여 내용을 분리함

menu_member = tokens.nextToken(); 

menu_order = tokens.nextToken();

menu_goods = tokens.nextToken(); // 분리된 항목을 각각의 String에 대입함


StringTokenizer 클래스는 우리가 지정한 구분자로 문자열을 쪼개주는 클래스, 쪼개어진 문자열을 토큰이라 부름

토큰 반환시 nextElement()는 Object로 반환하고, nextToken()은 String으로 반환함

출처 https://reakwon.tistory.com/90


-293p ServletConfig

 서블릿 확장 API임

 각 Servlet 객체에 대해 생성됨

 ServletConfig 인터페이스는 GenericServlet 클래스가 실제로 구현하고 있음

 ServletConfig에서 제공하는 여러 메서드를 이용해 서블릿에 관련된 기능을 사용할 수 있음. 대표적인 기능이 ServletContext 객체를 가져오는 기능임( getServletContext() )

 javax.servlet 패키지에 선언되어 있음

 서블릿과 동일하게 생성되고 서블릿에 소멸되면 같이 소멸됨

 

-ServletConfig가 제공하는기능

 ServletContext 객체를 얻는 기능

 서블릿에 대한 초기화 작업 기능

 

-ServletContig - 서블릿에서 사용할 설정정보를 읽어와 초기화하는 기능

1. @WebServlet 애너테이션을 이용하는 방법

2. web.xml에 설정하는 방법

 

1. 294p @WebServleet 애너테이션을 이용한 서블릿 설정

-@WebServlet의 중요한 구성요소

urlPatterns : 웹 브라우저에서 서블릿 요청 시 사용하는 매핑 이름

name : 서블릿 이름

loadStartup : 컨테이너 실행 시 서블릿이 로드되는 순서 지정

initParams : @WebInitParam 애너테이션 이용해서 매개변수를 추가하는 기능

description : 서블릿에 대한 설명

 

-서블릿 생성 시 @WebServlet의 매개변수와 같은 값들 설정하는 방법

1. 패키지 생성 > 패키지 우클릭 > New > Servlet

2. 클래스 이름 입력 후 'Next' 클릭

3. 'Initialization parameters'(파라미터 초기화) 항목의 'Add' 클릭

4. 추가할 파라미터의 Name과 Value를 각각 입력 후 ok

5. 다시 Add 클릭 후 name, value 입력, ok.... -> 총 2개의 서블릿 파라미터가 추가되었음

6. 'URL mappings'의 '/InitParamServlet'을 선택 후 'Remove' 클릭해 삭제 후 'Add' 눌러서 /sInit, /sInit2 입력, 각각 ok 눌러서 2개의 서블릿 매핑 이름이 추가된 것 확인 후 next

7. 'Inherited abstract methods', 'doGet' 옵션 체크한 후 finish

=>

설정한대로 @WebServlet이 표시됨을 확인

@WebServlet (

  urlPatterns = { "/sInit", "/sInit2" },

 initParams = { @WebInitParam(name="email", value="admin@jweb.com"),

                        @WebInitParam(name="tel", value="010-1111-2222")} )

8. getInitParameter() 메서드를 이용하여 애너테이션으로 매개변수로 설정한 email과 tel의 value를 가져와 저장함 

String email = getInitParameter("email");

String tel = getInitParameter("tel");

 

9.브라우저에서 각각 매핑이름을 sInit, sInit2로 요청하면 동일한 결과가 출력됨

 

2. 300p web.xml을 이용한 매개변수 설정 방법

<web-app>
    <servlet>
        <servlet-name>sinit</servlet-name>
        <servlet-class>sec06.ex01.initParamServlet</servlet-class>
        <init-param>
            <param-name>email</param-name>
            <param-value>admin@jweb.com</param-value>
        </init-param>
        <init-param>
            <param-name>tel</param-name>
            <param-value>010-1111-2222</param-value>
        </init-param>
    </servlet>
    <servlet-mapping>
        <servlet-name>sinit</servlet-name>
        <url-pattern>/first</url-pattern>
    </servlet-mapping>
</web-app>

<servlet-name> : 아래 <servlet-mapping> 태그 아래 <servlet-name>과 동일해야함

<servlet-class> : '패키지이름.서블릿클래스이름' 형식으로, 실제 클래스 이름을 작성해줌

<init-param> 태그 안에 매개변수 설정

<url-pattern> : url을 서블릿 이름에 연결함. 브라우저의 요청 url에서 앱 이름 뒤에 오는 부분, / 로 시작해야함

 참고) 클라이언트가 요청하는 url 정보

요청을 보낼 서버의 ip 주소 : 포트번호 / app 이름 / 달라고 요청하는 html

 

8.6 load-on-startup 기능 사용하기

서블릿 - 브라우저에서 최초 요청시 init() 메서드를 실행 > 메모리에 로드됨 > 기능 수행

=> 최초 요청에 대해서는 실행 시간이 길어질 수밖에 없음 : load-on-starup 기능 이용

 

- 301p load-on-startup의 특징

톰캣 컨테이너가 실행되면서 미리 서블릿을 실행함

지정한 숫자(우선순위)가 0보다 크면 톰캣 컨테이너가 실행되면서 서블릿이 초기화됨

지정한 숫자가 작은 것부터 먼저 초기화됨

 

-load-on-startup 구현 방법 : 애너테이션 이용 / web.xml에 설정

301p 1. 애너테이션을 이용한 load-on-startup 구현

패키지 생성 후 우클릭 > New > Servlet > 클래스 이름으로 LoadAppConfig 입력, Next > Name을 loadConfig, URL mappings를 /loadConfig로 변경함, Next > Inherited abstract methods, init, doGet에 옵션 체크 후 Finish

[ LoadAppConfig 클래스 ]

애너테이션(@WebServlet)으로 설정한 매개변수에 loadOnStartup 속성을 추가한 후 우선순위를 1로 설정

@WebServlet(name="loadConfig", urlPatterns={"/loadConfig"}, loadOnStartup=1)

 

private ServletContext context; // 변수 context를 멤버변수로 선언함

 

init() 메서드에서

ServletContext객체 얻음

getInitParameter() 메서드로 web.xml의 메뉴정보 읽어와 ServletContext 객체에 바인딩함

<- 원래 doGet에서 다 했었음

 

doGet() 메서드에서

ServletContext 객체 얻어오는 부분 주석처리

브라우저에서 요청 시 ServletContext 객체에 바인딩된 메뉴 항목을 가져옴

 

톰캣 실행 > init() 메서드 호출하면 getIitParameter() 메서드 이용해 web.xml의 메뉴정보 읽어와 다시 ServletContext 객체에 setAttribute() 메서드로 바인딩 함. 브라우저에서 요청하면 web.xml이 아니라 ServletContext 객체에서 데이터 가져와 출력하므로 파일에서 읽어와 출력하는 것보다 빠름.

 

305p 2. web.xml에 load-on-startup  구현

<servlet> 태그에서

 <servlet-name> 태그의 값은 서블릿 생성할때 지정한 name으로 설정함(loadConfig)

 <load-on-startup> 태그의 값으로 우선순위를 설정함

 

톰캣 재실행 후 브라우저에서 /loadConfig로 요청하면 1의 방법과 같은 결과 확인할 수 있음