[2023.1.4.수] 스프링 MVC 웹 애플리케이션 1 (준비, 환경설정)
스프링 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