IT 강의 정리/윤재성의 스프링 MVC5

[섹션2][Spring MVC에서의 Bean관리] 20~26강

Nellie Kim 2022. 10. 24. 20:44
728x90

20. RequestScope

브라우저에서 새로운 요청이 발생하면, 브라우저는 서버에 요청에 관련된 정보를 전송한다.

이를 받은 서버는 브라우저가 보낸 요청 정보들을 보관하기 위해 HttpServletRequest객체를 생성해 요청 정보들을 담아둔다.그 요청정보가 담겨있는 HttpServletRequest객체는 응답결과가 브라우저로 전송될 때까지 유지되며 사용이 가능하다.새로운 요청이 발생해 응답결과가 브라우저로 전달 될 때까지요청정보가 담겨있는 Request객체를 사용할 수 있는데, 이 사용 범위를 RequestScope라고 부른다.

이 HttpServletRequest객체는 서버개발자가 필요에 의해 데이터나 객체를 저장할 수 있고 RequestScope내에서 사용이 가능하다.

하나씩 살펴보자.

 

1. request 주입받기

만약에, redirect로 데이터를 넘겼을 때는 Request객체에 요청정보가 담겨있을까? 아래를 보자.

request객체를 주입받고 setAttribute로 데이터를 넣어주고 result1으로 redirect시켜준다.

19강에서 배웠듯 Redirect는 새로운 요청이 발생하는 것이므로 Request객체는 소멸 되며, 19번줄에서 다시 요청하게되면 Request객체가 새롭게 생성된다. 그렇게 되면 14줄에서 넣은 데이터가 사라지기 때문에 이 코드는 null값이 나온다.

 

그래서 이럴때는 redirect를 쓰면 안되고 forward를 쓰자.

forward를 쓰면 응답결과가 브라우저에 전달되지 않고, 20번줄로 데이터의 흐름이 이동하게 된다. 아직 응답결과가 브라우저에 전달되지 않았기 때문에 16줄에서 사용한 request객체가 그대로 20번줄로 들어오게 된다. 정상 출력 된다.

이렇게 Request객체의 사용목적은 2가지로 볼 수 있다.

1. JSP에서 해당 데이터를 사용하게 하는 목적

2. 포워딩했을 때 다른 메서드로 코드흐름이 이동하며 해당데이터를 가져가게 하는 목적

 

2. Model 주입받기

이번에는 Request객체 말고 Model을 주입해보자. 그런데 아래 왼쪽과 같이 실행하면 null값이 나온다. 왜그럴까?

28번줄에서 Model을 주입받고 addAttribute로 데이터를 저장해주면 Request객체에 저장이 된다. 그 객체를 받기위해 36번줄에서 또 Model을 주입받았다. 그러나 Model은 전달되지 않는다. ModelAttribute를 하면 Model에 저장되는게 아니라 Request에 저장되기 때문이다. 그래서 아래와 같이 Model을 주입받게 되면 데이터가 null값이 나오는 것이다.

그래서 36번줄에서 Model을 주입받는게 아니라 request객체를 주입받아야 데이터를 가져올 수 있다.

jsp파일에서 출력할 때는 아래와 같이 ${requestScope.data1} 이렇게 작성하여 출력한다.

 

3. ModelAndView 주입받기

ModelAndView를 사용해도 마찬가지로 request로 받아와야 한다.

4. 객체 주입받기 - model사용

이번에는 고전적인 방법으로 객체를 저장해서 사용해보자.

데이터정보를 담을 DataBean1 클래스를 만들고, 컨트롤러 클래스에 Model을 주입받고 model.addAttribute로 만든 bean을 저장하고 포워딩으로 코드의 흐름이 76번줄에 있는 request객체로 이동되면서 request객체를 주입받는다.

5. 객체 주입받기 - @ModelAttribute사용

이번에는 @ModelAttribute를 사용하여 객체를 주입 받아보자.

@ModelAttribute로 주입받은 객체는 자동으로 request영역에 저장이 된다. 아래와 같이 작성해서 사용한다.

87번줄에서 bean1이란 이름으로 객체가 주입이 될 때, request영역에 bean1이 저장된다.

그리고 forward를 통해서 95번째줄로 이동이 되는데 이때, 새로운 bean객체가 생성되어 bean1 이름으로 저장이 된다.

즉, forward되긴 했지만 87, 95번째줄 둘다 ModelAttribute여서 각각 새로운 객체가 생성이 된 것이다.

결국 덮어쓰기를 한 셈이다. 그래서 null값이 나오게 된다.

그래서 ModelAttribute대신에 HttpServletRequest로 주입받아서 사용해야 아래와 같이 정상출력된다.

요약 )  객체에 저장을 할 때, request/ model/ modelAndView를 주입받아서 데이터를 저장할 수 있다.

하지만 forward해서 이동 후에 추출할 때는 HttpServletRequest를 주입받아서 데이터를 추출해야한다.

21. RequestScope 빈 주입

지난시간에 request객체에 빈을 저장한 후, forwarding한 쪽에서 가져와서 사용을 했다.

이번에는 @Autowired를 활용하여 Bean을 자동 주입 받아보자.

 

스프링에서는 prototype과 singleton이 있었는데 Spring MVC에서는 추가로 request, session, application을 제공하고 있다. scope에 이걸 넣어주면 해당 빈이 주입받는 시기가 달라지며, 그에 맞춰서 적당한 곳에 사용을 해주면 된다.

 

Request scope로 정의하면 요청이 발생할 때마다 Bean객체가 생성되어 자동으로 주입된다.

자바방식은 @RequestScope사용 , xml방식은 scope="request" 사용

주입된 Bean은 요청발생시 주입만 이루어지고 request영역에 저장되지는 않는다. 저장을 하고싶으면 model객체를 쓰자.

 

1. 타입을 통한 빈주입 - 자바방식

①  @Autowired라고 했기 때문에 그냥 타입을 통한 주입을 받게된다. 

②  RootAppContext에가서 정의된 빈 중에서 DataBean1타입을 찾아본다.

③  @RequestScope라고 정의되어있다. 이 빈이 주입되는 시점은 새로운 요청이 발생됐을때,

dataBean1()메소드가 호출되고 new DataBean1 얘가 생성하는 빈 객체를 requestBean1에 주입하게 된다.

④  그런데 forward:/result1으로 이동하는 것은 새로운 요청이 발생되는게 아니기때문에 새로운객체가 주입되지 않고, 

requestBean1에 들어있는 객체를 그대로 이용하게 된다.

결과는 콘솔창에는 잘 출력이 되는데, 브라우저에는 출력이 되지 않았다. 

정상적으로 출력을 받기위해 아래와 같이 model객체를 써서 request영역에 저장후 실행해야 한다. 정상 작동 된다.

2. 타입을 통한 빈주입 - xml 방식

빈을 정의하는 방식만 달라지고 나머지는 동일하다.

왼쪽이 자바방식, 오른쪽이 xml방식이다

그냥 실행시키면 500오류가 난다. 원래 requestScope는 브라우저가 새로운 요청을 발생시켰을 때 주입이 되는데,

xml은 서버가 가동이 될 때 얘를 무조건 주입하려고 시도한다.

그런데 scope가 request로 되어있기때문에 주입에 실패하고 오류가 발생하는 것이다. 쌤의 방법은 @Lazy를 붙여주는것!

3. 이름을 통한 빈주입 - 자바방식

4. 이름을 통한 빈주입 - xml방식

root-context.xml 파일만 다르고, 나머지 코드는 동일하다.  그리고 이 때는, model객체로 저장해주지 않아도 된다.

Xml로 bean을 설정하고 byName으로 주입 받았을 경우에만 request영역에 자동저장된다.

5. 컴포넌트를 사용한 빈주입 (타입/ 이름) - 자바방식

컴포넌트를 사용하여 타입 및 이름을 통한 빈 주입방식으로 동시에 실행해보자. 

빈클래스에 @Component를 지정하여 타입을 통한 주입을 선언해주고, @Component(value="requestBean4")로 이름을 통한 주입을 선언해준다.

컴포넌트를 사용하려면 ServletAppContext에 @ComponentScan이 꼭 있어야 한다.

컨트롤러에서는 @Autowired로 타입을 통한 주입, @Resource(name="requestBean4")으로 이름을 통한 주입을 받는다.

6. 컴포넌트를 사용한 빈주입 (타입/ 이름) - xml방식

servlet-context.xml 파일에서 컴포넌트 스캔부분만 아래와 같이 하고, 나머지는 동일하다.

22. SessionScope

Session

브라우저가 최초로 서버에 요청을 하게 되면 브라우저당 하나씩 메모리 공간(session)서버에서 할당하게 된다.

이 메모리 영역은 브라우저당 하나씩 지정되며 요청이 새롭게 발생하더라도 같은 메모리 공간을 사용하게 된다.

이 공간을 session이라고 부르며, 브라우저를 종료할 때까지 서버에서 사용할 수 있다.

 

SessionScope

브라우저가 최초의 요청을 발생시키고 브라우저를 닫을 때 까지를 SessionScope이라고 부른다.

SessionScope에서는 session영역에 저장되어 있는 데이터나 객체를 자유롭게 쓸 수 있다.

 

1. request 주입받기

Servlet/ JSP에서 Session영역은 Request객체로부터 추출을 하게 된다.

컨트롤러12번줄에서 request를 먼저 주입받고, 15번줄 session객체를 추출한다. 16번줄 setAttribute로 데이터를 넣어준다.

22번줄에서도 request를 주입받고, 24번줄 request를 통해서 session에 저장된 데이터를 가져와서 session변수에 담고,

25번줄에서 session.getAttribute로 데이터를 가져온다.

실행을 하면 아래와 같이 브라우저에 나타나는데, test1을 클릭하면 새로운 요청을 발생시키고, 뒤로가기해서 result1을 클릭하면 역시 새로운 요청을 발생시키게 된다.

만약에 request영역에 저장이 되었다고 한다면 데이터가 날라가게 되는데, session에 저장했기 때문에 새로운 요청이 발생되어도 브라우저만 유지된다면 데이터를 그대로 사용할 수 있다!!

그러나, 크롬이 아닌 다른 브라우저(edge)에서 주소를 입력하면 출력되지 않는다.

브라우저마다 다른 세션영역에 저장되기 때문이다.

2. session객체 주입받기

여기까지는 일반 Servlet/ JSP와 동일하게 session객체를 사용할 때 request를 주입받아서 추출해도 되지만, 

Spring에서는 session객체를 바로 주입받을 수 있다. 

redirect와 forward중 어떤 것을 해도 session영역에 저장된 데이터는 잘 가져다 쓸 수 있다. 브라우저만 바뀌지 않으면!!

 

3. session객체 주입받기 - 빈객체 생성해서 주입

이번에는 빈을 저장해보자. 객체를 세션영역에 저장하는 것이다.

이렇게 객체를 세션영역에 저장해주면, 데이터를 저장하는 것과 동일하게 새로운 요청이 발생하더라도 사용이 가능하다.

 

4. session객체 주입받기 - @SessionAttribute사용

그런데, Session영역에 저장되어 있는 객체를 사용하고자 할 때 메서드의 매개변수로 @SessionAttribute를 설정하면 더 편하게 Session영역에 해당이름으로 저장되어있는 Bean객체를 찾아서 주입받을 수 있다. 해당 이름의 Bean객체가 없다면 null이 주입된다.

5. 객체 주입받기 - @SessionAttributes & @ModelAttribute 사용

@ModelAttribute를 통해 주입받는 Bean은 자동으로 Request영역에 저장되고 Request영역으로부터 주입받는다.

이 때, @ModelAttribute를 통해 주입받는 Bean을 @SessionAttributes로 지정해놓으면 request영역이 아닌 session영역에 저장되고 session영역으로부터 주입받을 수 있다.

(원래 @ModelAttibute로 저장하면 request영역에 저장되는데, @SessionAttributes로 지정하면 session영역에 저장된다!!)

주의할 점은 @ModelAttribute를 활용하여 객체를 생성해 반환하는 메소드를 반드시 작성해줘야 한다. 생략되면 오류발생.

23. SessionScope 빈 주입

Session scope

Bean을 정의할 때 session scope로 정의하면 브라우저가 서버에 최초의 요청을 보낼 때 Bean객체가 주입된다.

주입된 Bean은 주입만 이루어지므로 session영역에 저장되지는 않는다.

자바방식은 @SessionScope사용 , xml방식은 scope="session" 사용

 

1. 타입/ 이름을 통한 빈주입 - 자바방식

①  @Autowired, @Resource라고 했기 때문에 타입/ 이름을 통한 주입을 받게된다. 

②  RootAppContext에가서 정의된 빈 중에서 DataBean1, DataBean2타입을 찾아본다.

③  @SessionScope라고 정의되어있다. 이 빈이 주입되는 시점은 브라우저의 최초의 요청이 발생됐을때,

dataBean1(), dataBean2()메소드가 호출되고 new DataBean얘가 생성하는 빈 객체를 sessionBean에 주입하게 된다. 

최초의 요청이 발생됐을 때만 주입되고, 그 이후에는 주입되지 않는다. 한번 주입된 객체를 계속 사용하는 것이다.

④  그런데 result1.jsp에 아래와 같이 코드를 넣고 출력하니, 브라우저에는 데이터가 출력이 되지 않았다.  자동으로 세션영역에 저장되지 않았다는 의미다.

requestScope과 마찬가지로, 그냥 sessionScope때 주입되는 것으로 끝나고 그 이후에는 어떠한 작업도 해주지 않는다.

그래서 이 데이터를 JSP에서 사용하고 싶다면, requestScope에 했을 때 처럼 Model에 저장해줘야 한다.

model에 넣었으니까 request1.jsp에서도 sessionScope를 requestScope로 바꿔주기.

2. 타입/ 이름을 통한 빈주입 - xml방식

역시 빈을 정의하는 방식만 달라지고 나머지는 동일하다.

마찬가지로 그냥 실행해주면, 500오류가 나는데 requestScope와 동일한 원인이다.

원래 sessionScope는 웹브라우저가 최초의 요청을 발생시켰을 때 주입이 되는데,

xml은 서버가 가동이 될 때 얘를 무조건 주입하려고 시도한다.

그런데 scope가 session으로 되어있기때문에 주입에 실패하고 오류가 발생하는 것이다. 역시 @Lazy를 붙여주자.

3. 컴포넌트를 사용한 빈주입 (타입/ 이름) - 자바방식

컴포넌트를 사용하여 타입 및 이름을 통한 빈 주입방식으로 동시에 실행해보자. 

빈클래스에 @Component를 지정하여 타입을 통한 주입을 선언해주고, @Component(value="sessionBean4")로 이름을 통한 주입을 선언해준다.

컴포넌트를 사용하려면 ServletAppContext에 @ComponentScan이 꼭 있어야 한다.

컨트롤러에서는 @Autowired로 타입을 통한 주입, @Resource(name="sessionBean4")으로 이름을 통한 주입을 받는다.

4. 컴포넌트를 사용한 빈주입 (타입/ 이름) - xml방식

servlet-context.xml 파일에서 컴포넌트 스캔부분만 아래와 같이 하고, 나머지는 동일하다.

 

요약 ) Bean을 정의할 때 scope를 session으로 설정하면 최초의 요청이 발생할 때 새로운 bean이 주입된다.

24. ApplicationScope

Application Scope

서버가 가동될 때부터 서버가 종료되는 시점까지의 범위를 Application Scope이라고 한다.

Application Scope동안 사용할 수 있는 메모리영역이 만들어지며 ServletContext라는 클래스타입의 객체로 관리된다. ServletContext에 저장된 데이터나 객체는 서버가 종료되기 전까지 서버는 웹브라우저에 관계없이 동일한 메모리공간을 사용한다.

ServletContext

HttpServletRequest객체로부터 추출이 가능하다. 

jsp에서 추출할 때는 applicationScope.data1 로 호출하여 추출한다.

 

1. request 주입받기

2. ServletContext 주입받기

ServletContext는 Controller에서 주입받을 수도 있다.

그런데 HttpServletRequest객체는 매개변수로 주입받지는 못한다. 그럴 필요가 없기 때문이다.

대신 이렇게 @Autowired(타입에 의한 주입)를 이용하여  더 간편하게 HttpServletRequest를 주입받을 수 있다.

 

3. ServletContext 주입받기 - 빈객체 생성해서 주입

이번에는 빈을 넣어보자. 정상출력된다.

 

 

요약 ) ServletContext객체에 데이터나 객체를 담으면 서버가 종료될 때까지 사용할 수 있다.

25. ApplicationScope 빈 주입

Application scope

Bean을 정의할 때 application scope로 정의하면 서버가 가동될 때 자동으로 주입된다.

주입된 Bean은 주입만 이루어지므로 application영역에 저장되지는 않는다.

서버가 가동될 때 자동주입되는 것이므로 @Lazy를 설정하지 않아도 된다.

자바방식은 @ApplicationScope사용 , xml방식은 scope="application" 사용

 

1. 타입/ 이름을 통한 빈주입 - 자바방식

①  @Autowired, @Resource라고 했기 때문에 타입/ 이름을 통한 주입을 받게된다. 

②  RootAppContext에가서 정의된 빈 중에서 DataBean1, DataBean2타입을 찾아본다.

③  @ApplicationScope라고 정의되어있다. 이 빈이 주입되는 시점은 서버가 가동될 때,

dataBean1(), dataBean2()메소드가 호출되고 new DataBean얘가 생성하는 빈 객체를 applicationBean에 주입하게 된다. 

서버가 가동될 때만 주입되고, 그 이후에는 주입되지 않는다. 한번 주입된 객체를 계속 사용하는 것이다.

④  그런데 result1.jsp에 아래와 같이 코드를 넣고 출력하니, 브라우저에는 데이터가 출력이 되지 않았다. 

자동으로 어플리케이션 영역에 저장되지 않았다는 의미다.

역시 마찬가지로, 그냥 applicationScope때 주입되는 것으로 끝나고 그 이후에는 어떠한 작업도 해주지 않는다.

그래서 이 데이터를 JSP에서 사용하고 싶다면, Model에 저장해줘야 한다.

model에 넣었으니까 request1.jsp에서도 applicationScope를 requestScope로 바꿔주기.

2. 타입/ 이름을 통한 빈주입 - xml방식

역시 빈을 정의하는 방식만 달라지고 나머지는 동일하다.

@Lazy를 붙이지 않아도 잘 실행된다. application scope는 서버가 가동이 될 때 주입되기 때문에, 

서버가 가동이 될 때 무조건 주입하려는 xml의 시도에 오류가 나지 않고 주입이 된다.

Xml로 bean을 설정하고 byName으로 주입 받았을 경우에만 application영역에 자동저장된다.

3. 컴포넌트를 사용한 빈주입 (타입/ 이름) - 자바방식

컴포넌트를 사용하여 타입 및 이름을 통한 빈 주입방식으로 동시에 실행해보자.

빈클래스에 @Component를 지정하여 타입을 통한 주입을 선언해주고, @Component(value="applicationBean4")로 이름을 통한 주입을 선언해준다.

 

컴포넌트를 사용하려면 ServletAppContext에 @ComponentScan이 꼭 있어야 한다.

컨트롤러에서는 @Autowired로 타입을 통한 주입, @Resource(name="applicationBean4")으로 이름을 통한 주입을 받는다.

4. 컴포넌트를 사용한 빈주입 (타입/ 이름) - xml방식

servlet-context.xml 파일에서 컴포넌트 스캔부분만 아래와 같이 하고, 나머지는 동일하다.

 

요약 ) Bean을 정의할 때 scope를 application으로 설정하면 서버가 가동될 때 객체가 주입된다.

26. 쿠키

Cookie

사용자 웹브라우저(서버x)에 저장되는 데이터이다.

요청이 발생했을 때 웹브라우저는 쿠키에 저장된 정보를 서버에 전달하게 된다.

만약 서버가 응답결과로 쿠키정보를 웹브라우저에 전달하면, 웹브라우저가 쿠키에 저장하게 된다.

(서버가 웹브라우저에 쿠키정보 직접 저장x)

쿠키는 사용자 브라우저에 저장되는 것이므로 브라우저가 전달 해줄때만 쿠키정보를 사용할 수 있다.

 

Cookie 저장

서버측 코드로 쿠키에 데이터를 저장할 수 있는 방법은 없다.

브라우저로 보낼 응답 결과에 저장할 쿠키 정보를 담아 보내면 브라우저에 의해 쿠키가 저장된다.

Spring MVC에서 쿠키 저장은 Servlet / JSP에서 사용하는 방법으로 처리한다.

 

서버에서 쿠키를 저장하는게 아니다. 서버에서 브라우저로 응답결과를 보낼 때, 쿠키의 정보를 세팅해주면

그 정보를 브라우저가 받아서 쿠키를 저장한다. 

쿠키정보는 Servlet/jsp처럼 문자열데이터만 저장이 가능하다.

브라우저에 따라서 한글이 깨질 수 있기 때문에 한글이 있다면 인코딩/디코딩을 해줘야 한다. (try - catch사용)

응답결과에 쿠키정보를 담아 보내는 것이기 때문에 response객체를 주입받아야 한다.

new 사용해서 쿠키객체를 생성하고 데이터저장하고, 쿠키 수명 초단위로 설정 (365 * 24 * 60 * 60)

응답결과로 보낼 response에 쿠키정보를 담아준다. response.addCookie~~

이렇게 response에 담아주면 브라우저로 보낼 응답결과에 담기게 되며,

실행을 시키면 브라우저는 여기에 담긴 쿠키정보를 저장하게 된다.

실행하고, F11눌러 개발자도구 - Application - Cookies 에 들어가보면 아래와 같이 되어있다.

save cookie 를 누르는 순간, 컨트롤러의 save_cookie메소드가 실행되면서 쿠키생성, 데이터저장, response에저장이 일어나면서 브라우저로 전달이 되면서 브라우저가 쿠키정보를 저장하게 된다. 인코딩 때문에 value값이 아래처럼 나타난다.

Cookie 읽어오기

Cookie 정보는 브라우저가 요청을 발생시켰을 때 요청 정보에 모든 쿠키정보를 같이 담아서 서버로 전달해 준다.

서버가 쓰든 안쓰든 관계없이 무조건 브라우저는 쿠키정보를 다 보내게 된다.

 

1. Servlet / JSP 에서 쿠키 읽어오기

Servlet / JSP 에서는 쿠키사용이 번거롭다. 원하는 쿠키정보만 선별적으로 읽어올 수 없다.

모든 쿠키를 배열로 받아온 후, 반복문을 돌려서 이름으로 확인해야 한다. 

먼저 요청정보에 담겨 넘어오기 때문에 request객체를 주입받아야 한다. 인코딩을 했기 때문에 디코딩도 해줘야 한다.

if문이용해 쿠키이름별로 분기를 해야한다.

실행해주면 아래와 같이 콘솔창에 잘 받아와진다. 하지만 매우 번거롭다.

2. Spring MVC 에서 쿠키 읽어오기

Spring MVC에서는 브라우저가 보낸 쿠키정보를 매개변수로 주입받을 수 있다. 인코딩/디코딩도 자동으로 처리된다.

원하는 쿠키의 이름을 선별적으로 @CookieValue에 넣어서 가져올 수 있다.

 

요약
서버에 3종류의 사물함이 있다고 생각하자.
맨 윗줄 사물함은 RequestScope : 1회 체험용. 한번 요청한 후 사라진다. 
가운데 사물함은 SessionScope  : 정기 회원용(1달 회원권).  (세션이 브라우저에서는 쿠키라고 한다. 명칭만 다르다.)
맨 아랫줄 사물함은 ApplicationScope  : Owner용. 서버시작~끝 까지 자기 자신만을 위해 사용한다.

 

 

출처 : [인프런] 윤재성의 만들면서 배우는 Spring MVC 5