<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.itwill</groupId>
<artifactId>spring1</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>war</packaging>
<description>Spring Web MVC Example</description>
<!-- 프로젝트에서 사용하는 라이브러리(의존성) 이름/버전 설정 -->
<dependencies>
<!-- Java EE(Servlet/JSP, EL, action tag) -->
<dependency>
<groupId>jakarta.servlet</groupId>
<artifactId>jakarta.servlet-api</artifactId>
<version>6.0.0</version>
<scope>provided</scope>
</dependency>
<!-- JSTL -->
<dependency>
<groupId>jakarta.servlet.jsp.jstl</groupId>
<artifactId>jakarta.servlet.jsp.jstl-api</artifactId>
<version>3.0.0</version>
</dependency>
<dependency>
<groupId>org.glassfish.web</groupId>
<artifactId>jakarta.servlet.jsp.jstl</artifactId>
<version>3.0.1</version>
</dependency>
<!-- JUnit Test -->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>5.9.3</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>5.9.3</version>
<scope>test</scope>
</dependency>
<!-- Log4j, Slf4j logging -->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.20.0</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>2.20.0</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-slf4j-impl</artifactId>
<version>2.20.0</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.36</version>
</dependency>
<!-- Lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.26</version>
<scope>compile</scope>
</dependency>
<!-- Spring Web MVC -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>6.0.9</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>6.0.9</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>6.0.9</version>
</dependency>
<!-- Spring Test -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>6.0.9</version>
</dependency>
</dependencies>
<!-- 프로젝트 빌드 플러그인 설정 -->
<build>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<release>17</release> <!-- 자바 버전 -->
</configuration>
</plugin>
<plugin>
<artifactId>maven-war-plugin</artifactId>
<version>3.2.3</version>
</plugin>
</plugins>
</build>
</project>
<?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:mybatis="http://mybatis.org/schema/mybatis-spring"
xsi:schemaLocation="
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.xsd
http://mybatis.org/schema/mybatis-spring http://mybatis.org/schema/mybatis-spring.xsd">
<!-- bean definitions here -->
</beans>
<?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/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd">
<!-- Spring MVC 설정들을 애너테이션(annotation) 기반으로 처리 -->
<mvc:annotation-driven />
<!-- Spring MVC에서 dispatcherServlet이 처리하지 않는
정적 요청에 필요한 파일들(image, css, javascript, ...)의 폴더 위치 -->
<mvc:resources location="/static" mapping="/**" />
<!-- View Resolver: Spring MVC에서 사용하는 뷰(JSP, ...)를 찾기 위한 설정 -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/views/" />
<property name="suffix" value=".jsp" />
</bean>
<!-- 특정 패키지 아래에 선언된 컴포넌트 애너테이션(@Controller, @RestController)이
선언된 클래스들을 bean으로 관리:
컨트롤러 클래스들을 작성하는 패키지 이름.
-->
<context:component-scan base-package="com.itwill.spring1.web" />
</beans>
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="https://jakarta.ee/xml/ns/jakartaee"
xmlns:web="http://xmlns.jcp.org/xml/ns/javaee"
xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee https://jakarta.ee/xml/ns/jakartaee/web-app_5_0.xsd"
id="WebApp_ID" version="5.0">
<display-name>spring1</display-name>
<!-- 스프링 컨텍스트 설정 정보들을 저장한 파일의 위치 -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/application-context.xml</param-value>
</context-param>
<!-- Filter 설정 -->
<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>
<!-- Listener 설정 -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!-- Servlet 설정 -->
<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/servlet-context.xml</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>
<?xml version="1.0" encoding="UTF-8"?>
<Configuration>
<Appenders>
<Console name="out" target="SYSTEM_OUT">
<PatternLayout charset="UTF-8"
pattern="%d{HH:mm:ss.SSS} %-5level %logger - %m%n" />
</Console>
</Appenders>
<Loggers>
<!-- org.springframe 패키지와 그 아래의 모든 패키지에서 info 이상의 로그를 출력 -->
<Logger name="org.springframework" level="info" additivity="false">
<AppenderRef ref="out" />
</Logger>
<Root level="info" additivity="false">
<AppenderRef ref="out" />
</Root>
</Loggers>
</Configuration>
package com.itwill.spring1.web;
import java.time.LocalDateTime;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;
import com.itwill.spring1.dto.UserDto;
import lombok.extern.slf4j.Slf4j;
@Slf4j // Logger 객체(log)를 생성.
@Controller
public class ExampleController {
@GetMapping("/") // GET 방식의 요청 주소가 "/"(context root)인 요청을 처리하는 메서드.
public String home(Model model) {
log.info("home()");
LocalDateTime now = LocalDateTime.now();
model.addAttribute("now", now); // 뷰에 전달할 데이터를 세팅.
return "index"; // 뷰의 이름(/WEB-INF/views/index.jsp)
}
@GetMapping("/ex1")
public void example1() {
log.info("example1() 호출");
컨트롤러 메서드가 void인 경우(뷰의 이름을 리턴하지 않는 경우)
요청 주소의 이름이 뷰의 이름이 됨.
}
@GetMapping("/ex2")
public void getParamEx(String username, int age) {
log.info("getParamEx(username={}, age={})", username, age);
컨트롤러 메서드를 선언할 때 파라미터의 이름을 요청 파라미터 이름과 같게 선언하면 DispatcherServlet이 컨트롤러 메서드를 호출하면서 요청 파라미터의 값들을 argument로 전달해줌!
}
@PostMapping("/ex3")
public String getParamEx2(
@RequestParam(name = "username") String name, // (1)
@RequestParam(defaultValue = "0") int age // (2)
) {
컨트롤러 메서드를 선언할 때, 파라미터 선언 앞에 @RequestParam 애너테이션을 사용하는 경우:
(1) 메서드 파라미터와 요청 파라미터 이름이 다를 때, name 속성으로 요청 파라미터 이름을 설정.
(2) 요청 파라미터 값이 없거나 비어있을 때, defaultValue 속성 설정.
log.info("getParamEx2(name={}, age={})", name, age);
return "ex2";
}
@GetMapping("/ex4")
public String getParamEx3(UserDto user) {
log.info("getParamEx3(user={})", user);
DispatcherServlet은 컨트롤러의 메서드를 호출하기 위해서
1. 요청 파라미터들을 분석(request.getParameter()).
2. UserDto의 기본 생성자를 호출해서 객체를 생성.
3. 요청 파라미터들의 이름으로 UserDto의 setter 메서드를 찾아서 호출.
4. UserDto 객체를 컨트롤러 메서드를 호출할 때 argument로 전달.
return "ex2";
}
@GetMapping("/sample")
public void sample() {
log.info("sample()");
}
@GetMapping("/forward")
public String forwardTest() {
log.info("forwardTest()");
컨트롤러 메서드에서 다른 페이지(요청 주소)로 forward하는 방법:
"forward:"으로 시작하는 문자열을 리턴하면 DispatcherServlet은 리턴값이 뷰의 이름이 아니라 포워드 이동할 페이지 주소로 인식.
return "forward:/sample";
}
@GetMapping("/redirect")
public String redirectTest(RedirectAttributes attrs) {
log.info("redirectTest()");
// 컨트롤러 메서드에서 리다이렉트되는 페이지까지 유지되는 정보를 저장할 때:
attrs.addFlashAttribute("redAttr", "테스트");
컨트롤러 메서드에서 다른 페이지(요청 주소)로 redirect하는 방법:
"redirect:"으로 시작하는 문자열을 리턴하면 DispatcherServlet은 리턴값이 뷰의 이름이 아니라 리다이렉트 이동할 페이지 주소로 인식.
return "redirect:/sample";
}
}
DispatcherServlet <=== (Data) ===> Controller
Controller <=== (Data) ===> Service
데이터베이스의 테이블 구조를 자바 클래스로 표현한 객체.
package com.itwill.spring1.dto;
import lombok.Data;
@Data
public class UserDto {
// 폼에서 전달한 요청 파라미터 값들을 저장하기 위한 클래스.
private String username;
private int age;
}
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8" trimDirectiveWhitespaces="true" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>Spring 1</title>
</head>
<body>
<header>
<h1>메인 페이지</h1>
<h2>${ now }</h2>
</header>
<nav>
<ul>
<li>
<c:url var="ex1" value="/ex1" />
<a href="${ ex1 }">Example 1</a>
</li>
<li>
<c:url var="sample" value="/sample" />
<a href="${ sample }">Sample</a>
</li>
<li>
<c:url var="forwardTest" value="/forward" />
<a href="${ forwardTest }">포워드 테스트</a>
</li>
<li>
<c:url var="redirectTest" value="/redirect" />
<a href="${ redirectTest }">리다이렉트 테스트</a>
</li>
</ul>
</nav>
</body>
</html>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8" trimDirectiveWhitespaces="true" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>Spring 1</title>
</head>
<body>
<header>
<h1>Example 1</h1>
</header>
<main>
<h2>GET submit</h2>
<c:url var="ex2" value="/ex2" />
<form action="${ ex2 }"> <%-- form method 기본값은 "get" --%>
<input type="text" name="username" placeholder="이름 입력" />
<input type="number" name="age" placeholder="나이 입력" />
<input type="submit" value="제출" />
</form>
<hr />
<h2>POST submit</h2>
<c:url var="ex3" value="/ex3" />
<form action="${ ex3 }" method="post">
<input type="text" name="username" placeholder="이름 입력" />
<input type="number" name="age" placeholder="나이 입력" />
<input type="submit" value="제출" />
</form>
<hr />
<h2>DTO submit</h2>
<c:url var="ex4" value="/ex4" />
<form action="${ ex4 }" method="get">
<input type="text" name="username" placeholder="이름 입력" />
<input type="number" name="age" placeholder="나이 입력" />
<input type="submit" value="제출" />
</form>
</main>
</body>
</html>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8" trimDirectiveWhitespaces="true" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>Spring 1</title>
</head>
<body>
<header>
<h1>포워드/리다이렉트 테스트</h1>
<h2>Redirect Flash Attr: ${ redAttr }</h2>
</header>
</body>
</html>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8" trimDirectiveWhitespaces="true" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>Spring 1</title>
</head>
<body>
<header>
<h1>요청 처리 결과</h1>
</header>
</body>
</html>