본문 바로가기

카테고리 없음

(2021.08.30)스프링 공부 5일차. 뷰 영역 구현

앞서 공부한 내용

  • 📌 컨트롤러는 최종적으로 결과를 출력할 뷰와 뷰에 전달할 객체를 담고 있는 ModelAndView 객체를 리턴한다.
  • 📌 DispatcherServlet은 ViewResolver를 사용하여 결과를 출력할 View 객체를 구하고, 구한 View 객체를 이용하여 내용을 생성한다.

 

👀 MVC 처리 흐름도

 

Client가 Server(스프링)에게 요청하면 View 뿐만 아니라, xml, json, excel, pdf로 클라이언트의 요청을 처리하여 보여줄 수 있다.


1.2. ViewResolver

 컨트롤러는 아래 코드와 같이 결과를 생성할 뷰의 이름만 지정할 뿐, 뷰에 의존적이지 않다. 

@Controller
public class HelloController {
	@RequestMapping("/hello.do")
    public String hello() {
    	//처리 결과를 보여줄 뷰 이름 지정
        return "hello";

컨트롤러가 지정한 뷰 이름으로부터 응답 결과 화면을 생성하는 뷰 객체는 ViewResolver가 구한다.

 

📋 주요 ViewResolver 구현 클래스는 다음과 같다.

 

ViewResolver 구현 Class 설명
InternalResourceViewResolver 뷰 이름으로부터 JSP나 Tiles 연동을 위한 뷰 객체를 리턴한다.
VelocityViewResolver 뷰 이름으로부터 Velocity 연동을 위한 뷰 객체를 리턴한다.
VelocityLayoutViewResolver VelocityViewResolver와 동일한 기능을 제공하며,추가로 Velocity의 레이아웃 기능을 제공한다.
BeanNameViewResolver 뷰 이름과 동일한 이름을 갖는 Bean 객체를 뷰 객체로 사용한다.
ResourceBundleViewResolver 뷰 이름과 뷰 객체 간의 Mapping 정보를 저장하기 위해 Resource 파일을 사용한다.
XmlViewResolver 뷰 이름과 뷰 객체 간의 Mapping 정보를 저장하기 위해 XML 파일을 사용한다.

(💬 취소선을 그은 ViewResolver 구현 클래스는 거의 사용하지 않는다.)

 

📌 자주 사용되는 ViewResolver 구현 클래스로는

 

InternalResourceViewResolver 클래스와, BeanNameViewResolver 클래스가 있다.

 

 

📌ViewResolver Interface는 다음과 같이 정의되어 있다.

package org.springframework.web.servlet;
import java.util.Locale

public interface ViewResolver {
	View resolveViewName(String viewName, Locale locale) throws Exception;
}

ViewResolver는 뷰 이름과 지역화를 위한 Locale을 파라미터로 전달 받으며, Mapping 되는 뷰 객체를 리턴한다.

 

만약, Mapping 되는 뷰 객체가 존재하지 않으면 null을 리턴한다.

 

1.2. View 객체 

ViewResolver는 응답 결과를 생성할 뷰 객체를 리턴한다. 모든 뷰 클래스는 View Interface를 구현하고 있으며,

 

View Interface는 다음과 같이 정의되어 있다.

package org.springframework.web.servlet
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public interface View {
	String RESPONSE_STATUS_ATTRIBUTE = View.class.getName() + ".responseStatus";
    String getContentType();
    void render(Map<String, ?> model, HttpServletRequest request) throws Exception;
}

📌 getContentType() 메서드

 

getContentType() 메서드는 "text/html"과 같은 응답 결과의 컨텐츠 타입을 리턴한다.

 

📌 render() 메서드

 

render() 메서드는 실제로 응답 결과를 생성한다.

 

render() 메서드의 첫번째 파라미터인 model에는 컨트롤러가 리턴한 ModelAndView 객체의 모델 데이터가 전달된다.

각각의 View 객체는 이 모델 데이터로부터 응답 결과를 생성하는 데 필요한 정보를 구한다.

 


1.3. InternalResourceViewResolver 설정

InternalResourceViewResolver 클래스는 JSP나 HTML 파일과 같이 WEB Application의 내부 Resource를 이용하여

뷰를 생성하는 AbstaractUrlBasedView 타입의 뷰 객체를 리턴한다.

 

기본적으로 사용하는 View 클래스는 InternalResourceViewResolver 클래스 이다.

 

InternalResourceViewResolver 클래스는 다음과 같이 설정한다.

 

<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver"
	p:prefix="/WEB-INF/viewjsp" p:suffix=".jsp">
</bean>

InternalResourceViewResolver는 컨트롤러가 지정한 뷰 이름으로부터 실제로 사용될 뷰를 선택하는데, 이 때 컨트롤러가 지정한 뷰 이름 앞뒤로 prefix 프로퍼티와 suffix 프로퍼티를 추가한 값이 실제로 사용될 Resource 경로가 된다.

 

 

기본적으로 사용되는 InternalResourceViewResolver 클래스는 단순히 지정한 Resource 경로(일반적으로 JSP)로 요청을 전달한다.   (💬 JSP로 모든 결과를 보여주려면 이 클래스만을 사용해도 된다.)

 


1.4. BeanNameResolver 설정

BeanNameResolver 클래스는 뷰 이름과 동일한 이름을 갖는 bean을 뷰 객체로 사용한다.

 

BeanNameResolver는 주로 커스텀 뷰 클래스를 뷰로 사용해야 하는 경우에 사용된다.

 

예를 들어, 파일 다운로드를 위한 정보를 읽어와 뷰에 전달하는 컨트롤러는 다운로드 관련 정보를 뷰에 전달할 것이다.

(💬 JSP, HTML 이외의 뷰를 보여주려면 BeanNameViewResolver을 사용한다.)

@Controller
public class DownloadController {
	@RequestMapping("/download.do")
    public ModelAndView download(HttpServletRequest request, HttpServletResponse response) {
    	File downloadFile = getFile(request);
        return new ModelAndView("download", "downloadFile", downloadFile);
    }
}

위 결과를 보여줄 뷰 클래스가 DownloadView 클래스라고 하자. 이 경우 DownloadView 클래스를 "download" 이름으로 빈에 등록하고 ViewResolver로 BeanNameResolver 클래스를 사용하면 된다.

<bean id="viewResolver" class="org.springframework.web.servlet.view.BeanNameViewResolver" />
	<bean id="download" class="madvirus.spring.chap07.view.DownloadView" />

위 코드와 같이 설정하면 DownloadController 클래스의 처리 결과를 DownloadView가 생성하게 된다.

 


1.5. 다수의 ViewResolver 설정하기

하나의 DispatcherServlet은 1개 이상의 ViewResolver를 설정할 수 있다. 다수의 ViewResolver를 설정한 경우 "order" 프로퍼티를 이용하여 뷰 이름을 검사할 ViewResolver의 순서를 결정할 수 있다.

 

"order" 프로퍼티의 값이 작은 ViewResolver가 높은 우선 순위를 갖는다. 만약 우선 순위를 명시하지 않으면 Integer.MAX_VALUE를 "order" 프로퍼티의 값으로 갖는다.(즉, 가장 낮은 우선순위를 갖게 된다.)

 

DispatcherServlet은 "order" 프로퍼티의 값이 작은, 즉, 우선순위가 높은 ViewResolver에게 뷰 객체를 요청한다. 만약 우선순위가 높은 ViewResolver가 "null"을 리턴하면, 그 다음 우선순위가 높은 ViewResolver에게 뷰 객체를 요청한다. 뷰 객체를 구하면, 해당 뷰 객체를 이용하여 응답 결과를 생성한다.

 

아래의 코드는 "order" 프로퍼티를 설정하는 예이다.

<bean class="org.springframework.web.servlet.view.XmlViewResolver"
	<p:location="/WEB-INF/nonHtml-view.xml" p:order="0" />
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"
	<p:prefix="/WEB-INF/viewjsp/" p:suffix=".jsp" order="1" />

❗ 우선순위를 결정할 때 주의할 점 ❗ 

InternalResourceViewResolver는 마지막 우선 순위를 갖도록 지정해야 한다. 그 이유는 InternalResourceViewResolver는 항상 뷰 이름에 Mapping 되는 뷰 객체를 리턴하기 때문에 null을 리턴하지 않아서 우선 순위가 낮은 ViewResolver는 사용하지 못하게 된다.