수업내용/Spring

[2023.1.4.수] 스프링 MVC 웹 애플리케이션 1 (준비, 환경설정)

주니어주니 2023. 1. 4. 17:18

 

 

스프링 MVC 흐름 1 

 

 

 

* 스프링에서는 mvc 웹 애플리케이션을 개발하기 위해서 DispatcherServlet 클래스를 제공함

 

- DispatcherServlet : 클라이언트 요청 접수

                                    -> 컨트롤러 검색 (스프링 컨테이너에서 해당 요청을 처리할 컨트롤러 가져옴)

                                    -> 요청핸들러 메소드(execute 메소드) 실행 -> 반환 URL 전송

 

- Controller : 서비스에 의존 -> 서비스의 업무로직 실행시킴

                      -> 요청 처리(요청파라미터값 처리, 폼 입력값 유효성 검증, 업무로직 실행, 뷰에 표현할 데이터 담기)

                      -> 뷰이름/재요청 URL 반환

 

- Service : Mapper 인스턴스에 의존 -> 핵심 업무 로직 수행 (DB 액세스 작업) -> 뷰에 표현할 데이터 반환

 

- Mapper 인스턴스 : 데이터베이스 액세스 작업 구현

 

 

 

* 스프링 컨테이너는 2개

 

- DispatcherServlet이 만드는 스프링 컨테이너 = 자식 스프링 컨테이너

   : 자식스프링 컨테이너는 루트 스프링 컨테이너에 접근할 수 있음 (의존성 주입받을 수 있음)

- ContextLoadListener가 만드는 스프링 컨테이너 = 루트 스프링 컨테이너

   : 루트 스프링 컨테이너는 자식에 접근할 수 없음 

 

 


 

 

스프링 MVC 흐름 2

 

 

 

DispatcherServlet    : HTTP 요청을 접수 -> 요청 URI를 핸들러매핑으로 보냄 

 

핸들러매핑                 :  @를 스캔 -> 해당하는 컨트롤러를 검색 -> 컨트롤러 반환

                                      -> DispatcherServlet이 반환받은 컨트롤러를 핸들러어댑터로 보내서 실행 위임

 

핸들러어댑터              : 컨트롤러의 요청핸들러 메소드 수행

                                      + 핸들러어댑터의 ModelAndView객체에서 모델 객체 생성해서 컨트롤러로 줌

                                      -> 컨트롤러에서 Model 객체에 담은 값 -> ModelAndView의 Model 객체에 저장

                                      -> 컨트롤러에서 반환된 "home" -> ModelAndView의 viewName에 저장

                                      -> 컨트롤러의 최종 실행 결과 -> ModelAndView가 완성됨

                                      -> ModelAndView 객체를 DispatcherServlet으로 반환

 

DispatcherServlet      : view를 처리해야 함

                                      -> 전달받은 viewName을 ViewResolver로 보내서 VIew 객체를 찾아달라고 함

 

ViewResolver             :  기본적으로 가지고 있는 뷰 ( JstlView, RedirectView, ... )

                                        -> 뷰이름이 redirect로 시작하면 -> RedirectView 반환

                                            redirect로 시작하지 않으면 -> 앞에 "/WEB-INF/views/", 뒤에 ".jsp" 추가 -> JstlView 반환

                                        -> 뷰이름 "home" -> DispatcherServlet으로 JstlView 객체 반환  ("/WEB-INF/views/home.jsp")

 

DispatcherServlet       : JstlView 뷰 실행

 

JstlView 객체               : Model에 저장된 정보를 요청객체의 속성에 저장 -> /WEB-INF/views/home.jsp로 내부이동

 

 

 

 

 


 

 

 

spring mvc 프로젝트 생성하고, 홈페이지 연결하기

 

 


1. 전자정부 표준 프레임워크 지원 이클립스에서 eGovframee web proejct 메뉴로 프로젝트를 생성한다.

 

 

 

-> Maven update 하기

 

 

 


2. pom.xml에 의존성 정보를 추가한다.

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<groupId>com.sample</groupId>
	<artifactId>spring-web</artifactId>
	<packaging>war</packaging>
	<version>1.0.0</version>
	<name>spring-web</name>
	<url>http://www.egovframe.go.kr</url>

	<!-- 
		<properties /> 태그는
		pom.xml 파일에서 사용하는 상수값을 정의한다.
	 -->
	<properties>
		<!-- 자바 버전을 정의한다. -->
		<maven.compiler.source>11</maven.compiler.source>
		<maven.compiler.target>11</maven.compiler.target>
		<!-- 스프링 프레임워크 버전을 정의한다. -->
		<spring.maven.artifact.version>5.3.6</spring.maven.artifact.version>
		<!-- 로그출력을 지원하는 slf4j 버전을 정의한다. -->
		<slf4j.version>1.7.25</slf4j.version>
	</properties>
	
	<!-- 
		<depedencies /> 태그는
		프로젝트의 라이브러리 의존성 정보를 정의한다.
		라이브러리 의존성 정보는 <dependency />태그로 정의한다.
		라이브러리 의존성 정보는 groupId, artifactId, version으로 구성된다.
	 -->
	<dependencies>
		<!-- 
			spring-webmvc 라이브러리 의존성을 추가
			* spring-web.jar, spring-webmvc.jar 라이브러리를 추가한다.
			* spring-web.jar는 웹환경에 최적화된 Spring Container(객체 생성/조립/관리 담당하는 객체(공장))를 제공한다.
			* spring-webmvc.jar는 MVC 패턴의 웹 애플리케이션을 개발을 지원하는 인터페이스, 클래스, 어노테이션, 서블릿 등을 지원한다.
                	(@Controller, @RestController, @GetMapping, @PostMapping, @RequestParam)
		 -->
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-webmvc</artifactId>
			<version>5.3.24</version>
		</dependency>
		<!-- 
			spring-context 라이브러리 의존성 추가 
			* spring-context.jar, spring-aop.jar, spring-beans.jar, spring-core,jar, spring-expression.jar 
			  라이브러리를 추가한다.
			* spring-context.jar, spring-beans, spring-core는 Spring Container를 제공한다.
			* spring-aop.jar는 관점지향프로그래밍을 지원한다.
			* spring-expression.jar는 spring EL을 지원한다.
		-->
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-context</artifactId>
			<version>5.3.24</version>
		</dependency>
		<!-- 
			spring-jdbc 라이브러리 의존성 추가
			* spring-jdbc.jar, spring-tx.jar 라이브러리를 추가한다.
			* spring-jdbc.jar는 spring-jdbc기반의 데이터베이스 엑세스를 지원한다.
			* spring-tx.jar는 트랜잭션 처리를 지원한다.
		 -->
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-jdbc</artifactId>
			<version>5.3.24</version>
		</dependency>
		<!-- 
			mybatis 라이브러리 의존성 추가 
			* mybatis.jar 라이브러리 추가
			* mybatis는 SQL Mapping Framework이다. 
			* mybatis는 ibatis보다 더 쉽게 데이터베이스 엑세스를 구현할 수 있다. 
		-->
		<dependency>
			<groupId>org.mybatis</groupId>
			<artifactId>mybatis</artifactId>
			<version>3.5.11</version>
		</dependency>
		<!-- 
			mybatis-spring 라이브러리 의존성 추가 
			* mybatis와 spring의 연동을 지원한다. 
			* mybatis를 이용하는 데이터베이스 엑세스 작업의 핵심 객체를 스프링의 빈으로 등록시킨다. 
			* Mapper 인터페이스를 스캔해서 Mapper 인스턴스(객체)를 생성하고 스프링 컨테이너의 빈으로 등록시킨다.
		-->
		<dependency>
			<groupId>org.mybatis</groupId>
			<artifactId>mybatis-spring</artifactId>
			<version>3.0.1</version>
		</dependency>
		<!-- 
			오라클 jdbc 드라이버 라이브러리 의존성 추가 
		-->
		<dependency>
			<groupId>com.oracle.database.jdbc</groupId>
			<artifactId>ojdbc11</artifactId>
			<version>21.8.0.0</version>
		</dependency>
		<!-- 
			로그 출력을 지원하는 라이브러리 의존성
		 -->
		<dependency>
			<groupId>org.slf4j</groupId>
			<artifactId>slf4j-api</artifactId>
			<version>1.7.36</version>
		</dependency>
		<dependency>
			<groupId>ch.qos.logback</groupId>
			<artifactId>logback-classic</artifactId>
			<version>1.2.3</version>
			<scope>compile</scope>
		</dependency>
		<dependency>
			<groupId>org.slf4j</groupId>
			<artifactId>jul-to-slf4j</artifactId>
			<version>${slf4j.version}</version>
		</dependency>
		<dependency>
			<groupId>org.slf4j</groupId>
			<artifactId>log4j-over-slf4j</artifactId>
			<version>${slf4j.version}</version>
		</dependency>
		
		<!-- 
			자바 웹 관련 라이브러리 의존성 추가
			* 서블릿, JSP, JSTL 라이브러리 의존성을 추가한다.
		 -->
		<dependency>
			<groupId>javax.servlet</groupId>
			<artifactId>servlet-api</artifactId>
			<version>2.5</version>
			<scope>provided</scope>
		</dependency>
		<dependency>
			<groupId>javax.servlet</groupId>
			<artifactId>jstl</artifactId>
			<version>1.2</version>
		</dependency>
		<dependency>
			<groupId>taglibs</groupId>
			<artifactId>standard</artifactId>
			<version>1.1.2</version>
		</dependency>
		<dependency>
			<groupId>javax.servlet.jsp</groupId>
			<artifactId>javax.servlet.jsp-api</artifactId>
			<version>2.3.3</version>
			<scope>provided</scope>
		</dependency>
		
		<!-- 파일 업로드를 지원하는 라이브러리 의존성 추가 -->
		<dependency>
		    <groupId>commons-fileupload</groupId>
		    <artifactId>commons-fileupload</artifactId>
		    <version>1.4</version>
		</dependency>
		
	</dependencies>

	<build>
		<plugins>
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-war-plugin</artifactId>
				<version>3.3.2</version>
			</plugin>
		</plugins>
	</build>

</project>

 



3. spring-webmvc용 Bean Configuration 파일 정의하기


src/main/webapp/WEB-INF 폴더에 spring 폴더를 추가한다.
* spring 폴더에 spring bean configuration 파일을 추가한다. 파일명은 web-context.xml이다.

* web-context.xml의 namespace 탭에서 context와 mvc를 체크한다.

 

 

* spring-mvc 빈 설정하기

       * spring mvc 어노테이션을 활성화시키는 빈을 등록시키는 태그를 추가한다.

 

 


       * InternalResourceViewResolver의 prefix와 suffix값을 설정한다.
         

 


      * Controller를 스캔해서 스프링 컨테이너의 빈으로 등록시키는 태그를 추가한다.
      

 

 

- web-context.xml 

 

<?xml version="1.0" encoding="UTF-8"?>
<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/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.3.xsd
		http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd">

	<!-- 
		<mvc:annotation-driven> 태그는
			spring mvc 관련 어노테이션을 감지/분석해서 적절한 작업을 수행하는 객체를 스프링의 빈으로 등록시킨다. 
			
		<mvc:argument-resolvers> 태그는
			사용자정의 HandlerMethodArgumentResolver를 추가시킨다.
			* LoginUserHandlerMethodArgumentResolver는 요청핸들러 메소드의 매개변수에 @LoginUser 어노테이션이 지정되어 있으면
			  세션에서 로그인된 사용자정보를 조회해서 매개변수에 전달한다. 
	 -->
	<mvc:annotation-driven>
		<mvc:argument-resolvers>
			<bean class="com.sample.web.resolver.LoginUserHandlerMethodArgumentResolver" />
		</mvc:argument-resolvers>
	</mvc:annotation-driven>
	
	<!-- 
		사용자정의 인터셉터를 스프링 컨테이너의 빈으로 등록한다.
	 -->
	<mvc:interceptors>
		<mvc:interceptor>
			<mvc:mapping path="/**/*"/>
			<mvc:exclude-mapping path="/home"/>
			<mvc:exclude-mapping path="/register"/>
			<mvc:exclude-mapping path="/success"/>
			<mvc:exclude-mapping path="/login"/>
			<bean class="com.sample.web.interceptor.LoginCheckHandlerInterceptor" />
		</mvc:interceptor>
	</mvc:interceptors>
	
	<!-- 
		<mvc:view-resolvers/> 태그는
			spring mvc가 지원하는 다양한 뷰-템플릿기술(모델의 데이터를 표현하는 기술)에 대한 설정을 지원하는 태그다.
	 -->
	<mvc:view-resolvers>
		<!-- 
			<mvc:jsp /> 태그는
				Controller의 요청핸들러 메소드가 반환하는 뷰 이름("home")을 실제 JSP 경로에 맞게 맞추도록
				prefix="/WEB-INF/view/"와 suffix=".jsp"를 지정한다.
		 -->
		<mvc:jsp prefix="/WEB-INF/views/" suffix=".jsp"/>
	</mvc:view-resolvers>
	
	<!-- 
		<context:component-scan /> 태그는
			com.sample.web 패키지에서 클래스를 스캔해서 스프링 컨테이너의 빈으로 등록시킨다.
			이 애플리케이션에서 com.sample.web.controller 패키지에 모든 Controller 클래스를 스캔해서 스프링 컨테이너의 빈으로 등록시킨다.
	 -->
	<context:component-scan base-package="com.sample.web" />

	<!-- 
		multipart 요청(첨부파일 업로드 요청)을 지원하는 MultipartResolver 객체를 스프링 컨테이너의 빈으로 등록시킨다.
		얘는 반드시 id를 "multipartResolver"로 지정해야 한다. 
	 -->
	 <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
	 	<property name="defaultEncoding" value="UTF-8" />
	 	<property name="maxUploadSize" value="10485760" />
	 	<property name="maxUploadSizePerFile" value="10485760" />
	 </bean>
</beans>

 

 


4. web.xml 정의하기

 

* src/main/webapp/WEB-INF 폴더에 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">

	<!-- 
		Root WebApplicationContext 생성하기 (루트에서 만드는 스프링 컨테이너) 
		* <context-param /> 태그에 spring bean configuration 파일의 경로 및 이름을 지정한다.
		* <listener /> 태그에 ContextLoaderListener 클래스를 등록한다.
		* ContextLoaderListener
			- 리스너 클래스다.
			- <context-param /> 태그에 contextConfigLocation으로 설정된 빈 설정정보를 읽어서 루트 스프링 컨테이너를 생성한다.
			
		* Listener
			- Java Servlet API다.
			- Java Servlet의 이벤트처리를 지원하는 인터페이스다.
	 -->
   <context-param>
      <param-name>contextConfigLocation</param-name>
      <param-value>
         /WEB-INF/spring/database-context.xml
         /WEB-INF/spring/service-context.xml
      </param-value>
   </context-param>
   
   <listener>
      <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
   </listener>
   
   <!-- 
   		클라이언트 <-> 서버 간 한글 텍스트 인코딩 처리를 지원하는 필터
    -->
   <filter>
   		<filter-name>encodingFilter</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>
   </filter>
   <filter-mapping>
   		<filter-name>encodingFilter</filter-name>
   		<url-pattern>/*</url-pattern>
   </filter-mapping>
   
	<!-- 
		DispatcherServlet은 spring mvc가 제공하는 FrontController이다.
		* 모든 URL 요청에 대해서(<url-pattern>/</url-pattern>) DispatcherServlet이 실행되도록 설정함
		* 아래의 설정정보에 지정된 web-context.xml 파일을 읽어서 DispatcherServlet이 스프링 컨테이너를 생성하게 한다.
		  스프링 컨테이너에는 web-context.xml에 설정된 클래스들이 스프링 컨테이너에 빈으로 등록된다.
		  스프링 컨테이너의 빈으로 등록된 객체들 중에는 HomeController, UserController, PostController 등 다양한 컨트롤러 객체가 포함되어 있다.
		  DispatcherServlet은 요청이 접수되면 요청 URI에 해당하는 매핑정보가 포함된 컨트롤러 객체를 스프링 컨테이너에서 가져와서 실행시킨다. 
		  (/home 이면 HomeController를 실행) 
		  <init-param>
			<param-name>contextConfigLocation</param-name>
			<param-value>/WEB-INF/spring/web-context.xml</param-value>
		  </init-param>
		  
		  * 웹서버가 실행될 때 DispatcherServlet 객체를 생성하고, 초기화시키기
		  	<load-on-startup>1</load-on-startup>
		  	* 숫자1은 우선순위를 나타낸다. 서블릿객체를 여러개 등록하는 경우 숫자가 낮을 수록 먼저 생성되고 초기화된다.
		  	* 사용목적 : 웹서버가 켜질 때 DispatcherServlet 객체를 생성하고, 초기화 작업을 완료시키기 위해서 설정한다.
		  	* DispatcherServlet 초기화 과정에서 <init-param />태그의 정보를 읽어서 Spring Container를 생성하고,
		  	  설정정보를 분석해서 필요한 객체를 생성하고, 조립한다.
	 -->
	<servlet>
		<servlet-name>app</servlet-name>
		<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
		<init-param>
			<param-name>contextConfigLocation</param-name>
			<param-value>/WEB-INF/spring/web-context.xml</param-value>
		</init-param>
		<load-on-startup>1</load-on-startup>
	</servlet>
	<servlet-mapping>
		<servlet-name>app</servlet-name>
		<url-pattern>/</url-pattern>
	</servlet-mapping>
	
	<!-- 
		모든 jsp의 앞부분에 아래 경로가 include됨
	 -->
	<jsp-config>
		<jsp-property-group>
			<url-pattern>*.jsp</url-pattern>
			<include-prelude>/WEB-INF/views/common/tags.jsp</include-prelude>
		</jsp-property-group>
	</jsp-config>
</web-app>

 

 


5. 컨트롤러 정의하기


* src/main/java 소스 폴더에 com.sample.web.controller 패키지를 추가한다.
* 생성한 패키지에 HomeController 자바클래스를 생성한다.

 

 

* 어노테이션

 

spring mvc의 주요 어노테이션

@Controller
클래스가 HTTP 요청을 처리하는 Controller 클래스임을 나타낸다.<context:component-scan />으로 자동 스캔되어서 스프링 컨테이너의 빈으로 등록된다.

@GetMapping
요청 URI와 요청 핸들러 메소드를 매핑시킨다. 

 

 

* Model 객체에 담기  

 

요청객체에 담으면

-> Jsp에서는 요청객체에서 바로 꺼내면 되지만, json, xml, 등에서는 꺼내기 어려움(요청객체 -> JSON 변환)

-> 앞으로는 Model 객체에서 꺼냄 

 

모델에서 특정 타입으로 변환하는 객체 -> 뷰 

 

HTML은 보여지는 화면이 있으니까 뷰에서 뷰 템플릿을 거쳐야 함 

 

 


6. jsp에 코드 추가하기

* src/main/webapp/WEB-INF 폴더에 view 폴더를 추가한다.
* views 폴더에 home.jsp를 추가한다.

 

 

 


7. 브라우저에서 홈화면 요청하기

 

* http://localhost:8080/spring-web/home