Servlet (2일차) - (Redirect & Forward)

지환·2023년 12월 1일
0

Jsp & Servlet

목록 보기
4/21
post-thumbnail

참고 | https://kbj96.tistory.com/39

Forward 개념정리

간단한 예시

  1. 고객이 고객센터로 상담원에게 100번으로 전화를 건다.

  2. 상담원은 해당문의 사항에 대해서 전문적인 지식을 갖춘 상담원에게 문의해 답을 얻는다.
    (여기서 connect가 끊어지는 것이 아니라 (req,res)가 살아있음

  3. 상담원은 고객에게 문의사항을 처리해준다.

해당 부분을 이해하면 전반적인 인사이트를 얻을 수 있다.


package com.example.demo.ch5;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import jakarta.servlet.RequestDispatcher;
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;

@WebServlet("/hello")
public class HelloServlet extends HttpServlet {

	private static final long serialVersionUID = 1L;

	@Override
	public void init() throws ServletException {
		//서블릿 초기화 -  서블릿이 생성 또는 리로딩때 단 한번한 수행됨
		//서블릿이 초기화 될 때 자동 호출되는 메소드 - 개발자가 신경쓰지 않아도 된다
		System.out.println("init호출");
	}
	//브라우저 새로고침을 누르면 service메소드만 호출되고 처리된다.
	//호출될 때마다 반복적으로 수행됨
	@Override
	protected void service(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException{
		//service메소드 호출
		System.out.println("service호출");
		//res.sendRedirect("./index.jsp");
		
		//요청이 계속 유지되는 것처럼 트릭을 쓸 수 있다.
		//forward로 페이지를 요청하면 url이 바뀌지 않는다.
		// 요청이 유지되고 있는것으로 판단
		List<Map<String,Object>> list = new ArrayList<>();
		Map<String,Object> rmap = new HashMap<>();
		rmap.put("mem_id", "kiwi");
		rmap.put("mem_pw", 123);
		list.add(rmap);
		req.setAttribute("list", list); 
		// list의 주소를 참조하여 보낸다. forward를 똑겉아 요청이 일어난다면
		// 자바에서 사용하고  있는 정보를 jsp에서 사용 가능하다.
		RequestDispatcher view = req.getRequestDispatcher("./index.jsp");
		view.forward(req, res);

	}
	@Override
	public void destroy() {
		//서블릿이 제거될 때 단 한번만 수행됨
	   //서블릿이 메모리에서 내려올 때
	   //어플리케이션 종료
	   //주석이라도 수정 후 저장하면 다시 리로딩
		System.out.println("destroy호출");
	}  

}

RequestDispatcher view = req.getRequestDispatcher("./index.jsp");
view.forward(req, res);

Foward를 사용하면,

hello 요청이 클라이언트로부터 들어왔을 때 -> 서버(서블릿) 내부동작과정에서는 서블릿이 view로 Forward한다.(넘긴다)

그래서 View는 index.jsp파일을 렌더링한 페이지를 클라이언트에게 넘긴다.

그렇다면, index.jsp를 직접호출하는 부분은 어딜까?

		req.setAttribute("list", list); 
		RequestDispatcher view = req.getRequestDispatcher("./index.jsp");
		view.forward(req, res);
        
     ============================================================
     
view.forward(req, res); --> 이 부분이 View에 넘겨주는 부분
 어떻게 넘겨줄까? 
 
setAttribute("list",list);에서는 VO에 대한 정보를 req에 담고 

forward()는 제어가 넘어간 이후 다지 이전의 자원으로 제어가 돌아가지 않으므로 

호출하는쪽의 처리를 모두 완료한 후 제어를 넘겨야한다. 그래서 

setAttribute으로 값을 먼저 담았다.

===================================================================

RequestDispatcher view = req.getRequestDispatcher("./index.jsp");

getRequestDispatcher 메소드의 인자로 전달된 문자열은 

포워드할 **리소스의 경로**를 나타낸다.

포워드 하겠다 = 뷰에 넘기겠다. 뷰에 넘길 주소를 인자에 넣는다.

를 통해서 경로에 대한 값을 View 변수에 할당한다
==================================================================
그리고 View.forward(req,res); 해당 
        

RequestDispatcher에 대해 살펴보자.

  • RequestDispatcher는 클라이언트로부터 최초에 들어온 요청을 JSP/Servlet 내에서 원하는 자원으로 요청을 넘기는(보내는) 역할을 수행한다.

  • 특정 자원에 처리를 요청하고 처리 결과를 얻어오는 기능을 수행하는 클래스이다.

  • 즉 /a.jsp 로 들어온 요청을 /a.jsp 내에서 RequestDispatcher를 사용하여 b.jsp로 요청을 보낼 수 있다.

    • forward() 메서드는 대상 자원으로 제어를 넘기는 역할을 한다.

    • 브라우저에서 /a.jsp로 요청했을 때 /a.jsp에서 forward()를 실행하여 /b.jsp로 제어를 넘길 수 있다.

    • 제어를 넘겨받은 /b.jsp는 처리 결과를 최종적으로 브라우저에게 출력한다.

    • 브라우저 입장에서는 /a.jsp를 요청했지만 받은 결과는 /b.jsp의 결과이다.

  • forward()는 제어가 넘어간 이후 다지 이전의 자원으로 제어가 돌아가지 않으므로 호출하는쪽의 처리를 모두 완료한 후 제어를 넘겨야한다. (그래서 선처리가 중요하다)
  • forward() 실행시에는 HttpServletRequest
    와 HttpServletResponse 객체를 같이 넘겨주기 때문에 호출한 쪽과 호출당한 쪽에서 이 두 가지의 객체를 공유한다.
  public class DispatchTest extends HttpServlet { 
     @Override 
     protected void service(HttpServletRequest request, HttpServletResponse response) 
                                                    throws ServletException, IOException { 
           request.setCharacterEncoding("UTF-8"); 
           request.setAttribute("name", "doloak"); //사전처리 
           
           RequestDispatcher dispatcher = request.getRequestDispatcher("/hello"); 
           dispatcher.forward(request, response); 
     }
}
HelloServlet/hello에 맵핑되어있는 서블릿이다.
/dispatch로 호출된 DispatchTest 서블릿에서 forward()를 통해 제어가 넘어온다.

위 코드를(바로 위 말고 main) 보면,

원래는 init과 service 가 호출되었는데, 호출되지 않는다.

우리는 Service라는 메소드를 직접 호출한 적이 없다.(콜백함수)

파라미터 자리는 톰캣 서버가 객체주입을 해준다.(지역변수)

메소드 파라미터 자리는 선언만 - NullPointException이 발동하지 않는다. 왜? 객체주입을 하기 때문이다.

setAttribute : 저장하기(index.jsp에서 꺼낼 땐 list이름을 사용한다.)

request 객체는 저장소의 역할도 가능하다(SELECT-조회)

.java가 쥐고 있는 주소번지를 jsp가 어떻게 사용할 수 있을까?

<%>에서

주입받는다.

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>

<%@ page import = "java.util.*"%>
    
<% // 스크립트릿 -- 지역변수로 선언된다.
	List<Map<String,Object>> list = (List)request.getAttribute("list");
	//localhost:8000/index.jsp -  null이 출력된다. -> HelloServlet을 경유하지 않았잖아
	//localhost:8000/hello (주소는 hello인데 출력페이지는 index.jsp보임??) - 값이 출력된다.
	
	
%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
hello 서블릿
</body>
</html>
List<Map<String,Object>> list = (List)request.getAttribute("list");
  • 이 코드를 분석하자면 위에서 list형태로 setAttribute("list",list);주입한 객체를 스크립트릿을 통해서 받아온다. (해당 부분은 localStroage)와 동일하다.

  • request 반환타입이 Object이기 때문에 (List) 캐스팅 연산자를 작성해야된다.

localhost:8000/index.jsp을 호출하고 Redirection으로 진행했을 떈 init/service/destory가 찍혔지만, forward는 찍히지 않는다. 왜 그런것일까?

10번을 새로고침해도 변동이 없다. 만약에 @WebServlet("/hello")매핑을 했는데, url을 hello을 호출한다면?

두 개가 다른 url로서 작동하는데 forward를 통해서 객체간의 연동이 되어 있다.(스레드 연결이 끊어지지 않음)

검증



만약에 forward를 제거하고 redirect로 호출한다면?

package com.example.demo.ch5;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import jakarta.servlet.RequestDispatcher;
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;

@WebServlet("/hello")
public class HelloServlet extends HttpServlet {

	private static final long serialVersionUID = 1L;

	@Override
	public void init() throws ServletException {
		//서블릿 초기화 -  서블릿이 생성 또는 리로딩때 단 한번한 수행됨
		//서블릿이 초기화 될 때 자동 호출되는 메소드 - 개발자가 신경쓰지 않아도 된다
		System.out.println("init호출");
	}
	//브라우저 새로고침을 누르면 service메소드만 호출되고 처리된다.
	//호출될 때마다 반복적으로 수행됨
	@Override
	protected void service(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException{
		//service메소드 호출
		System.out.println("service호출");
		
		
		//요청이 계속 유지되는 것처럼 트릭을 쓸 수 있다.
		//forward로 페이지를 요청하면 url이 바뀌지 않는다.
		// 요청이 유지되고 있는것으로 판단
		List<Map<String,Object>> list = new ArrayList<>();
		Map<String,Object> rmap = new HashMap<>();
		rmap.put("mem_id", "kiwi");
		rmap.put("mem_pw", 123);
		list.add(rmap);
		req.setAttribute("list", list); 
		res.sendRedirect("./index.jsp");
		// list의 주소를 참조하여 보낸다. forward를 똑겉아 요청이 일어난다면
		// 자바에서 사용하고  있는 정보를 jsp에서 사용 가능하다.
//		RequestDispatcher view = req.getRequestDispatcher("./index.jsp");
//		view.forward(req, res);
		//index.jsp를 직접호춣하면 서블릿을 경유하는것 아니라 그 url에 매핑되어 매칭돤다.
		//helloServlet을 호출하지 않는다. = Service을 찍지 않는다.
		//원래는 init과 service 가 호출되었는데, 호출되지 않는다.
		//List를 담아서 setAttribute로 저장했다고 보면된다.
		//우리는 Service라는 메소드를 직접 호출한 적이 없다.(콜백함수)
		//파라미터 자리는 톰캣 서버가 객체주입을 해준다.
	}
	@Override
	public void destroy() {
		//서블릿이 제거될 때 단 한번만 수행됨
	   //서블릿이 메모리에서 내려올 때
	   //어플리케이션 종료
	   //주석이라도 수정 후 저장하면 다시 리로딩
		System.out.println("destroy호출");
	}  

}

  • 이렇게 호출하면 url에 이렇게 찍힌다.

http://localhost:8000/hello 를 해도

http://localhost:8000/index.jsp 로 출력된다.

hello도 같이 찍혀서 나온다 즉, 경유했다는 얘기다.

그 접속을 끊고(req,res) 스레드를 회수해간다(톰캣) sendRedirect 할 때 다시 (req,res)가 생성된다.

302번이면 한번 요청한 url을 get방식으로 또 요청 했을 때 발생하는 Status이다. 서버까지 전달이 안되고, 브라우저가 가로챈다.


redirect

protected void service(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException{

		System.out.println("service호출");
		res.sendRedirect("./index.jsp");
		

	}

이렇게 설정되어 있다. 그리고 이것을 호출 했을 떄 동작원리를 살펴보자.

간단한 예시를 보자.

  1. 고객이 고객센터로 상담원에게 100번으로 전화를 건다. @WebServlet(/hello)
    업로드중..

  2. 상담원은 고객에게 다음과 같이 이야기한다. "고객님 해당 문의 사항은 200번으로 다시 문의해주세요" res.sendRedirect("./index.jsp");로 해주세요

  3. 고객은 다시 200번으로 문의해 일을 처리한다.

업로드중..

  • req, res는 톰캣 내장객체가 객체를 주입해준다.

  • res(응답).sendRedirct("./index.jsp")는 해당 경로로 이동한다. 그렇다면 위의 동작원리를 보면 @WebServlet("/hello")을 경유하고 가는가?

    • 경유하고 가는데 hello를 들렸다가 요청을 끊어버리고 index.js로 이동했다(새로운 요청이 들어온다) - 이 말은 유지되는 것으로 판단하지 않는다.
      업로드중..

정리

SELECT - FORWARD
나머지 SendRedirect

[서버오류정리]
1. 200 - ok
2. 303 - url 오타
3. 405 - restFul 오타
4. 500 - Exception - 런타임에러 - 트러블슈팅
5. 403

url로 호출할 수 있는 메소드는 doGet뿐이다.
그럼 doPost는 PostMan으로 확인하자.

profile
아는만큼보인다.

0개의 댓글