본문 바로가기
IT 공부/자바와 웹 애플리케이션

[스프링] - 스프링 웹 MVC 프로젝트 세팅 방법

by exdus3156 2024. 1. 6.

# 스프링 프레임워크 프로젝트 생성 #

스프링(Spring) 프레임워크는 웹에 주로 사용되지만 그렇다고 웹에 종속된 프레임워크가 아니다. 스프링은 의존성 주입(Dependency Injection) 기법을 적용한 객체지향 프레임워크다. 따라서 스프링의 코어는 의존성 주입과 관련된 기술이고, 바로 여기에 웹MVC와 같은 라이브러리를 추가로 설정해 웹 프로젝트로 만들어 사용하는 것이다.

여기서는 웹을 기반으로한 스프링 프레임워크 프로젝트 세팅에 대해 정리하려고 한다. 왜냐하면 자바 스프링 프로젝트는 언제나 프로젝트 세팅이 까다로웠기 때문이다. 이 참에 정리해보았다.

※ 원래 프로젝트 빌드 시, 롬복(lombok)이나 로그(log4j2)를 함께 쓰지만, 여기서는 순수하게 스프링만 파악하기 위해 일부러 생략해보았다. 각 링크를 타고 가면 독립적으로 이 라이브러리의 빌드 방법이 정리되어 있다.

 

 

1) 일단 기본 웹 프로젝트부터 생성하기!! (그레이들)

새로운 웹 프로젝트를 생성해보자. JavaEE(JakartaEE) 템플릿을 활용해 간단한 웹 프로젝트를 생성한다. 여기까지는 아직 스프링 기술과 전혀 상관이 없는 단계다.

빌드 시스템은 메이븐이나 그레이들이나 아무거나 선택해도 상관은 없다. 하지만 개인적으로 그레이들이 제일 무난하다고 생각한다.

여기가 중요한데, JavaEE 템플릿을 사용했으므로 정확히 어떤 버전의 JavaEE 스펙에 의존할지 설정해야 한다. 자바 웹 프로젝트는 기본적으로 톰캣과 같은 WAS, 서블릿 컨테이너의 사양을 따라야 한다.(링크) 사용하는 톰캣 버전이 9이기 때문에 JavaEE 8 버전을 선택한다. 이외에 다른 의존 기술은 없으니 넘어가자.

그레이들 빌드 툴이 프로젝트를 생성하는데 시간이 꽤 걸린다. 기다리면 기본적인 톰캣 기반의 서블릿 웹 프로젝트가 생성된다.

그리고 필수는 아니지만 개발 편의를 위해 톰캣 설정을 몇 가지 조정해보자.

먼저 배포 방식을 exploded 변경하자. 이것의 의미는 다음 링크에 정리해놓았다. (링크)

그리고 프로젝트의 URI 컨텍스트를 조정한다. / 하나만 적어도 상관은 없다. 여기까지가 자바 웹 프로젝트 생성 방식이다. 아직 스프링과는 전혀 별개다.

 

 

2) 스프링 코어 라이브러리 연계 및 테스트

스프링은 위 세 가지 라이브러리가 기본이다. Spring Core와 Spring Context 이 두 가지가 핵심을 이룬다. Spring Test 라이브러리 또한 사실상 필수라 할 수 있는데, 이는 스프링 프레임워크를 하나씩 실험해가며 정상 작동하는지 확인해야 하기 때문이다.

실제로 테스트를 해보자. 테스트 목적은 스프링이 실행되어 빈(bean)을 찾아서 생성하고, 의존성 주입(DI)을 하는지 확인하는 것이다.

간단하게 테스트용 가짜 객체를 두 개 만들어본다.

그리고 WEB-INF 폴더에 <root-context.xml>을 두자. 사실 이 파일의 위치 자체는 어디에 두든 상관 없지만, WEB-INF 폴더에 두는 것이 관례다. (여기서 개발팀이 각자 따르고 있는 추가적인 폴더 구조가 있을 수 있으니 필요하다면 추가하라.)

이 파일은 스프링이 빈을 찾고 생성하고 관리할 수 있도록 빈 정보를 알려주는 것이다. 복잡하게 xml 태그를 사용해도 되지만, 일반적으로 스프링 프로젝트 개발에서 개발자가 직접 만드는 클래스는 어노테이션을 활용한다. 웹과 별개로 사용해야 하는 빈은 이렇게 만드는 것이 좋다. 고로 <context:component-scan> 태그를 활용하자.

<root-context.xml>

인텔리제이에는 자동으로 스프링 xml 파일 템플릿을 제공해준다. 물론 편의를 위한 것이므로 위 파일의 내용을 일일이 타자로 쳐도 상관은 없다.

아래는 테스트 코드다. 통과해야 한다. 통과하면 스프링이 정상 작동한다는 뜻이다.

여기까지가 스프링 코어가 작동하는지 확인하는 단계다. 그러나 아직 웹 기술과는 별개의 상태다.

 

 

3) 스프링 웹 MVC 라이브러리 추가 및 웹으로 스프링 코어 활성화

그레이들로 spring web mvc 라이브러리를 추가해준다. 이 라이브러리에는 웹과 관련된 여러 클래스들이 들어 있으며, 이를 이용하면 웹 기반에서 스프링을 활성화할 수 있다.

톰캣의 <web.xml> 파일을 위와 같이 수정해야 한다. 이 설정이 바로 웹과 스프링이 연계되는 시작 지점이다. 

리스너로 ContextLoaderListner를 등록한다. 리스너란 특정 이벤트 발생 시 실행되는 객체를 말하며, <web.xml>에 위와 같이 등록할 수 있다. 그리고 등록하는 객체는 spring web mvc 라이브러리에 있는 객체다. 이것은 톰캣이 실행되고, 서블릿 컨텍스트가 로드되는 이벤트 발생 시 자동 실행된다.

이 객체는 애플리케이션 전체에서 접근할 수 있는 context-param 변수를 내부적으로 이용한다. 즉, context config location 정보를 가져와 그곳에 있는 xml 파일을 읽어 스프링의 애플리케이션 컨텍스트를 생성한다. 이것이 바로 빈이 생성되고 관리되는 공간이다.

여기까지 하면 웹 프로젝트에서 스프링이 제공하는 코어 기능(의존성 주입 및 관리)을 활용할 수 있는 단계다. 이 코어 기능만을 활용하겠다면, 여기서 프로젝트 설정을 끝내고 바로 서블릿 코딩으로 넘어가도 큰 문제는 없다.

 

 

4) 스프링 MVC로 웹 프로젝트 설정하기

단, 3단계에서 끝내고 프로젝트를 개발하는 것은 스프링의 코어 기술인 의존성 주입 부분만을 활용하는 것이 된다.

그러나 스프링 웹 프레임워크는 생각보다 훨씬 더 많은 기능을 내장하고 있으며, Spring Web MVC 기술은 단순히 빈(bean)과 의존성 관리만이 아니라, 웹 프로젝트의 구조에 통째로 관여하는 기술이다. 깊이로 따지자면 Spring Core 보다 조금 더 특수화된 기술이라 할 수 있다.

관건은 익히 잘 알고 있는 MVC 디자인 패턴을 스프링이 어떻게 구현하고 있는지 파악하는 것이다. 기술 이름에서 알 수 있듯이, 스프링 웹 MVC는 바로 MVC 디자인 패턴 자체를 스프링으로 구현한 것이다. 따라서 일일이 MVC 패턴을 개발자가 만드는 것이 아니라, 이미 스프링이 마련해놓은 프레임을 바탕으로 개발자가 맞춰주면 되는 것이다. (링크)

따라서 스프링 웹 MVC 패턴을 톰캣의 서블릿 컨테이너에 적용하고 보는 것이 핵심이다.

설명을 이어가기 전에 중요한 핵심은, 이 포스팅의 맨 처음에 언급했듯이, 스프링이 웹에 많이 사용되긴 하지만 그 본질적인 기능(core)은 웹이 아니라는 점이다. 스프링 웹 MVC는 스프링의 객체지향 프레임워크를 활용해서 한 번 더 특수화된 용도로 만든 웹 전용 프레임워크다!

이 계층 구조를 염두에 두고 지금부터 프로젝트를 설정해보자.

 

위 그림은 스프링 웹 MVC의 전체 구조다. 스프링은 톰캣과 같은 서블릿 엔진, 서블릿 컨테이너 위에서 동작한다. (그래서 실제로 스프링 MVC 설정은 톰캣의 설정 파일을 이리저리 건드리며 만들어나간다.)

MVC 패턴이란 요청 메시지를 컨트롤러(controller)가 받아서 해야 하는 로직이 무엇인지 해석한 후, 모델(model, 서비스)에 그 일을 요청한다. 그리고 모델에서 전달된 결과 데이터를 컨트롤러가 적합한 뷰(view)에 전달한다. 뷰는 결과 데이터를 가지고 웹 콘텐츠(html)를 동적으로 생성하고, 제어흐름을 컨트롤러에게 넘긴다. 최종적으로 response 메시지에 담긴 콘텐츠가 톰캣에 의해 네트워크로 전송된다.

스프링 웹 MVC는 바로 위 MVC 패턴을 스프링으로 만든 것이다.

특이하게도 스프링 웹 MVC는 톰캣이 URL 패턴에 매핑되는 서블릿을 찾아 실행하게 두지 않고, 무조건 모든 요청을 FrontController가 일단 받고, 그 FrontController가 적합한 컨트롤러를 찾아 실행하는 방식이다. 당연히 이 FrontController는 스프링 웹 MVC 라이브러리에 구현되어 있다.

따라서 첫 번째로 해야할 것은 톰캣에 FrontController를 / URL에 매핑시키는 것이다.

FrontCotroller는 DispatcherServlet이라고 불린다. 이것을 / url에 매핑시키면 모든 url 요청을 전부 DispatcherServlet이 받아서 처리할 것이다. 여기까진 톰캣의 설정 원리를 그대로 사용하는 것이다.

 

두 번째로 해야할 것은 아래의 <servlet-context.xml>을 만드는 것이다. 이름은 아무렇게나 상관없지만 관례적으로 이렇게 작성한다.

파일의 위치 또한 그냥 WEB-INF에 그대로 두면 된다.

우리가 <web.xml>로 Dispatcher 서블릿을 등록할 때, 인자로 contextConfigLocation으로 바로 이 설정 파일의 위치를 알려준 것이다. 이 설정 파일은 root-context.xml과 원리가 똑같다. 즉, Dispatcher 서블릿은 이 설정 파일을 통해 웹 MVC와 관련된 빈을 찾아서 등록하고 생성하고 의존성을 주입해준다.

<mvc:annotaion-driven> 태그를 통해 Dispatcher 서블릿은 자동으로 스프링 웹 MVC와 관련된 어노테이션을 식별하여 관련 기능을 실행한다. @RequestParam, @GetMapping, @RequestMapping, 등의 어노테이션 말이다.

이것은 <root-context.xml>로 빈을 관리하는 것과 똑같은 원리다. 그럼에도 <root-context.xml>과 <servlet-context.xml>을 분리한 이유는 스프링 계층 구조에 있다. <servlet-context.xml>은 스프링 웹 MVC와 관련된 빈을 관리한다. 스프링 코어와 웹이 계층적으로 분리되어 있기 때문에 빈 설정 파일도 분리하는 것이다. 무엇이 스프링이고, 무엇이 스프링웹MVC인지 구분하는 것은 대략적으로 사용하는 빈의 의존성 경로를 보면 된다. 만약 springwebmvc 패키지를 사용한다면 servlet-context.xml에 두는 식이다.

따라서 웹 MVC 기술과 관련된 모든 빈(bean)은 바로 이 <servlet-context.xml> 파일로 조정해준다. 예를 들어, <mvc:resources> 태그는 "/resources/..." 경로로 오는 url 요청은 정적 파일 요청으로 인식하겠다는 뜻이다. 따라서 스프링 MVC 컴포넌트가 처리하지 않는다. 톰캣이 정적 파일을 반환해준다.

뷰 리졸버(resolver)란, 뷰 담당 객체를 찾아주는 시스템이다. 이 객체 자체가 빈(bean)으로 등록되어 있는데, 컨트롤러가 간단한 이름으로 뷰 객체를 지정해주면, Dispatcher 서블릿이 이 객체를 사용해 뷰 담당 객체를 찾는다. prefix나 suffix는 그 위치에 대한 식별자로, 이름 앞뒤에 붙인다.

만약 데이터베이스와 같이 웹 MVC 패턴에 종속된 개념이 아니라면 <root-context.xml>로 설정해주면 될 것이다.

 

5) 컨트롤러 등록

마지막으로 컨트롤러 등록이다. DispatcherServlet을 통해 톰캣에 스프링 웹 MVC 구조를 성공적으로 안착시켰다. 그러나 아직 <servlet-context.xml>에 웹 관련 컴포넌트(빈)의 탐색 대상과 범위를 지정하지 않았다. 그래서 컨트롤러가 스프링 빈으로 등록되지 않았다. 아래처럼 작성하자.

 

그리고 간단한 테스트용 컨트롤러를 만들어 톰캣을 실행해 체크해보자.

 


여기까지가 스프링 웹 MVC 프로젝트 설정 단계의 완료다. 남은 것은 스프링 웹 MVC 프레임워크의 기술을 공부하고 사용해 개발을 하면 된다.