Spring MVC

Spring MVC란 ?

Spring MVC란? 현재 가장 많이 사용하는 개발 패턴중 하나인 MVC 패턴에서 따온 것이다.

MVC 개념은 화면에서 보여주는 V(View), 데이터 처리 관리는 M(Model), V(View)와 M(Model)를 연결시켜주는 C(Controller) 각 첫글자를 따서 MVC 라고 한다.

Spring Framework를 MVC 패턴 개발시 편리하게 개발 가능하도록 제공한다. 일반적으로 Model View Controller의 형태로 제공하며, 최근에는 프론트와 백엔드의 서버 분리(스케일링이슈) 가 추세이다.

Spring MVC 구조와 처리 과정

Spring MVC

  • DispatcherServlet
    • 어플리케이션으로 들어오는 모든 request를 받는 관문이다.
    • request를 실제로 처리할 controller에게 전달하고 그 결과를 받아서 view에게 전달하는 적절한 응값을 생성할 수 있도록 흐름을 제어한다.
  • HandlerMapping
    • Request URL 각각을 어떤 Controller가 실제로 처리할 것인지 찾아주는 역할을 한다.
  • Controller
    • Request를 직접 처리한 후에 그 결과를 다시 DispatcherServlet에게 돌려준다.
  • ModelAndView
    • Controller가 처리한 결과와 그 결과를 보여줄 View에 관한 정보를 담고 있는 객체이다
  • ViewResolver
    • View 관련 정보를 갖고 실제 View를 찾아주는 역할을 한다.
  • View
    • Controller가 처리한 결과값을 보여줄 View를 생성한다.

Spring에서 filter, interceptor 차이

Filter

  • 요청과 응답을 거른 후에 정제하는 역할을 한다.
  • 서블릿 필터는 DispatcherServlet 이전에 실행이 되는데 필터가 동작하도록 지정된 자원의 앞단에서 요청내용을 변경하거나 여러가지 체크를 수행할 수 있다.
  • 스프링 컨텍스트 외부에 존재하여 스프링과 무관한 자원에 대해 동작한다.
  • 스프링 영역에 포함되어 있지 않다.

Interceptor

  • 요청에 대한 작업 전/후로 가로챈다고 보면 된다.
  • 스프링의 DispatcherSevlet이 컨트롤러를 호출하기 전, 후로 끼어들기 때문에 스프링 컨텍스트 내부에 Controller에 관한 요청과 응답에 대해 처리한다.

AOP

  • Aspect Oriented Programming(관점 지향 프로그래밍)
  • OOP를 보완하기 위해 나온 개념이고, OOP를 대체하는 개념은 아니다.
  • 객체 지향의 프로그램을 했을 중복을 줄일 수 없는 부분을 줄이기 위해 종단점(관점)에서 바라보고 처리한다.
  • 주로 ‘로깅’, ‘트랜잭션’, ‘에러 처리’ 등 비즈니스단의 메서드에서 조금 더 세밀하게 조정하고 싶을 때 사용한다.
  • 메소드 전후의 지점에 자유롭게 설정 가능하다.

3가지의 차이점

  • 처리 순서 “Filter > DispatcherServlet > Interceptor > AOP” 와 같다.
  • Interceptor와 Filter는 주로 주소를 대상을 구분해서 걸러내야 하는 반면, AOP는 주소, 파라미터, 애노테이션 등 다양한 방법으로 대상을 지정할 수 있다.

Spring 설정 파일(web.xml) 생성

Spring설정 파일(Bean정의 파일)의 지정

web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xmlns="http://xmlns.jcp.org/xml/ns/javaee"
  xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
  id="WebApp_ID" version="3.1">
 <display-name>springMVC</display-name>

  <listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
  </listener>
 <servlet>
   <servlet-name>dispatcherServlet</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
      <param-name>contextConfigLocation</param-name>
      <param-value></param-value>
   </init-param>
   <load-on-startup>1</load-on-startup>
  </servlet>
  <servlet-mapping>
   <servlet-name>dispatcherServlet</servlet-name>
    <url-pattern>/</url-pattern>
  </servlet-mapping>

</web-app>
  • 먼저 org.springframework.web.context.ContextLoaderListener 클래스를 리스너 등록한다.
  • 이것이 등록되어 있어서, Spring 설정 파일(/WEB-INF/applicationContext.xml)을 로드한다.
  • 이 경로 및 파일 이름은 contextConfigLocation에서 변경 될 수 있다.

Spring 설정 파일명 변경

 <context-param>
   <param-name>contextConfigLocation</param-name>
    <param-value>/WEB-INF/spring/app.xml</param-value>
  </context-param>
  <listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
  </listener>
  • Spring 설정 파일이 /WEB-INF/spring/app.xml으로 변경되었다.

서블릿에 Spring 설정 파일을 적용

 <servlet>
   <servlet-name>dispatcherServlet</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
      <param-name>contextConfigLocation</param-name>
      <param-value>/WEB-INF/spring/mvc-servlet.xml</param-value>
    </init-param>
   <load-on-startup>1</load-on-startup>
  </servlet>
  • Spring 설정 파일은 서블릿마다 설정할 수 있다. 설정하는 경우 init-param의 contextConfigLocation으로 설정한다.
  • Spring 설정 파일을 /WEB-INF/spring/mvc-servlet.xml으로 지정하였다.

org.springframework.web.servlet.DispatcherServlet 대해

보통 WEB 어플리케이션에서는 Servlet을 만들지만, Spring Web MVC에서는 Spring이 제공 해주기 때문에 따로 생성하지 않고 org.springframework.web.servlet.DispatcherServlet 을 사용한다.

DispatcherServlet이 클라이언트의 요청을 받아 컨트롤러 클래스(@Controller)에 할당하여 컨트롤러 클래스에서 반환으로 뷰(jsp)를 할당하고 클라이언트에 돌려준다. Spring MVC의 전체 제어를 수행하며 web.xml에 설정된다.

그래서 Spring MVC에서 WEB 응용 프로그램을 개발할 때, 대부분 의식하지 않지만 뒤에서 다양하게 동작한다.

CharacterEncodingFilter

  • 이전 예제에서는 생략했지만 CharacterEncodingFilter도 지정해야 한다.
  • 클라이언트로부터 전송된 데이터를 지정한 문자 코드에 강제로 인코딩한다.
  • 이것은 HttpServletRequest의 setCharacterEncoding을 뒤에서 실행해 줍니다.
  <filter>
    <filter-name>CharacterEncodingFilter</filter-name>
    <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
   <init-param>
      <param-name>encoding</param-name>
     <param-value>utf-8</param-value>
    </init-param>
   <init-param>
      <param-name>forceEncoding</param-name>
      <param-value>true</param-value>
   </init-param>
 </filter>
 <filter-mapping>
    <filter-name>CharacterEncodingFilter</filter-name>
    <url-pattern>/*</url-pattern>
 </filter-mapping>

Bean정의 파일

<beans xmlns="http://www.springframework.org/schema/beans"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
  xmlns:context="http://www.springframework.org/schema/context"
 xmlns:mvc="http://www.springframework.org/schema/mvc"
 xsi:schemaLocation="
   http://www.springframework.org/schema/beans
   http://www.springframework.org/schema/beans/spring-beans-4.2.xsd
    http://www.springframework.org/schema/context
   http://www.springframework.org/schema/context/spring-context-4.2.xsd
    http://www.springframework.org/schema/mvc
   http://www.springframework.org/schema/mvc/spring-mvc-4.2.xsd">

 <context:component-scan base-package="spring.test" />

 <mvc:annotation-driven />

 <bean
   class="org.springframework.web.servlet.view.InternalResourceViewResolver">
    <property name="prefix" value="/WEB-INF/" />
    <property name="suffix" value=".jsp" />
 </bean>
</beans>

처음에 component-scan 요소는 지정한 패키지 아래에 있는 어노테이션을 적용한 클래스를 자동으로 로딩한다. 로딩하는 어노테이션은 @Controller, @Service, @Component, @Repository 등이 있다.

다음 annotation-driven 요소는 Spring Web MVC를 하기 위해 설정해야 하는 값들이 자동으도 로딩해준다. 해당 설정 어노테이션은 @RequestMapping, @ModelAttribute, @SessionAttribute, @RequestParam 등이 있다.

마지막으로 org.springframework.web.servlet.view.InternalResourceViewResolver을 선언하고 있다. 이것이 jsp 파일의 위치를 지정해 준다. prefix와 suffix를 선언하고 있고, 컨트롤의 반환 값 문자열과 함께 다음 jsp 파일이 적용된다.

prefix문자열 + 컨트롤의 반환 문자열 + suffix문자열

예를 들자면, 컨트롤에서 반환한 값이 test라면

"/WEB-INF/" + test + ".jsp" > "/WEB-INF/test.jsp" 

이밖에 Csv 다운로드, Excel 다운로드 등보기 다운로드시킬 때는org.springframework.web.servlet.view.XmlViewResolver를 지정한다 이는 다음 기회에 설명한다.

<mvc:resources> 요소

이미지, CSS, JS 등 정적 리소스 파일에 액세스할 때, 다음과 같이 액세스할 디렉터리를 선언한다.

<mvc:resources mapping="/image/**" location="/WEB-INF/image/" />

위의 디렉터리에 이미지를 표시하는 jsp은 다음과 같이 작성한다.

<img src="./image/test.png"/>

JSP에서 Bean 사용

JSP에서 Spring Java Bean을 편하게 쓰기 위해 호출은 아래와 같이 한다.

먼저, 스프링 설정 파일에서 InternalResourceViewResolver 설정 시에 exposeContextBeansAsAttributes 속성을 true로 해준다.

<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
    <property name="exposeContextBeansAsAttributes" value="true" />
    <property name="prefix" value="/WEB-INF/jsp/" />
    <property name="suffix" value=".jsp" />
</bean>

아래와 같이 Java Bean 파일을 작성한다. 이름이 “foo” 인 싱글턴 객체가 생성된다.

@Component
public class Foo  {
    private String name;

    public String getName() {
        return name;
    }
}

JSP에서 Spring Java Bean인 foo을 JSP EL 에서 호출한다.

<%@page language="java" contentType="text/html; charset=UTF-8"%>
<div class="foo-name">
    <c:out value="${foo.name}"/>
</div>



최종 수정 : 2024-03-09