[Spring] 8.Controller
스프링 MVC 컨트롤러
스프링 MVC를 공부하는 데 있어서 필수적인 내용은 컨트롤러를 어떻게 만들고, 처리하는가입니다!
우선 MVC 컨트롤러가 무엇을 처리하는지부터 알아보겠습니다~!
- 파라미터 수집 : 웹에서 가장 많이하는 작업은 사용자의 요청에 필요한 데이터를 추출하고, 이를 VO(Value Object) 혹은 DTO(Data Transfer Object)로 변환하는 파라미터의 수집작업입니다.
- 애노테이션을 통한 간편 설정 : 개발자는 클래스나 메소드의 선언에 필요한 애노테이션을 추가함으로써 요청이나 응답에 필요한 모든 처리를 완료할 수 있습니다.
- 로직의 집중 : 기존의 모델 2는 특정한 URI마다 컨트롤러를 개발하는 경우가 많았지만 스프링 MVC 컨트롤러의 경우 각 메소드마다 필요한 애노테이션을 설정할 수 있기 떄문에 여러 메소드를 하나의 컨트롤러에 집중해서 작업할 수 있습니다.
- 테스트의 편리함 : 스프링은 테스트 모듈을 사용해서 스프링 MVC로 작성된 코드를 WAS의 실행없이도 테스트할 수 있습니다.
스프링 MVC 에서 주로 사용하는 애노테이션의 종류
스프링 MVC에서는 컨트롤러가 상속 등의 전통적인 기법을 사용하지 않는 대신에 애노테이션으로 많은 일을 처리합니다!
Spring Project의 servlet-context.xml 파일
컨트롤러의 개발과 관련해서 가장 먼저 알아야하는 내용은 스프링 MVC 컨트롤러가 어떤 설정을 통해서 동작하는지에 대한 이해입니다!
servlet-context는 웹과 관련된 자원을 관리하는 파일이죠~! 스프링 MVC 관련 설정만을 분리하기 위해서 만들어진 파일입니다!
servlet-context를 보면 controller가 어떻게 동작하는지 알 수 있습니다.
<!-- servlet-context.xml 주요부분 -->
<!-- 클래스 선언에 애노테이션을 이용해서 컨트롤러를 작성할 수 있다는 선언 -->
<annotation-driven />
<!-- 웹에서 이미지나 CSS,JavaScript 파일과 같이 고정된 자원들의 위치를 의미 -->
<resources mapping="/resources/**" location="/resources/" />
<!-- 뷰를 어떻게 처리하는가에 대한 설정 -->
<beans:bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<!-- WEB-INF 는 절대로 브라우저에서 직접 접근할 수 없는 경로이기에 컨트롤러에 의해 접근-->
<beans:property name="prefix" value="/WEB-INF/views/" />
<beans:property name="suffix" value=".jsp" />
</beans:bean>
<!-- base-package 속성 값에 해당하는 패키지 내부의 클래스들을 조사한다는 뜻-->
<context:component-scan base-package="io.github.kookyungmin" />
컨트롤러 실습 - void 리턴 타입의 경우
이제부터 컨트롤러를 간단하게 작성하고 URI에 따른 결과를 보겠습니다!
그 전에 src/main/java 에 controller 폴더를 추가해줍니다!
먼저 컨트롤러의 메소드 리턴 타입이 void인 경우를 봐보겠습니다!
//SampleContoller.java
package io.github.kookyungmin.controller;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
//컨트롤러
@Controller
public class SampleController {
//로그를 남겨줌
private static final Logger logger =
LoggerFactory.getLogger(SampleController.class);
//void return 타입
@RequestMapping("doA") //URI에 doA 가 입력되면 doA()가 호출됨
public void doA() {
logger.info("doA 호출됨");
}
}
Run on Server를 해보겠습니다!
Spring 로그를 보면, URI 에 “/”만 입력되면 HomeController가 “/doA”가 입력되면 SampleController가 호출되는 것을 볼 수 있습니다!
한 번 접속해보겠습니다!
현재 /kookyungmin/WEB-INF/views/ 경로에 doA.jsp 파일이 없기에 페이지 오류가 떴지만,
접속로그를 보면 SampleController의 doA가 제대로 호출함을 알 수 있습니다!
String 리턴 타입인 경우
만일 컨트롤러에서 메소드의 리턴 타입이 문자열인 경우라면 결과는 ‘문자열+.jsp’ 파일을 찾아서 실행하게 됩니다~! (servlet-context에서 prefix, subfix 와 연관)
//SampleContoller.java
//컨트롤러
@Controller
public class SampleController {
//로그를 남겨줌
private static final Logger logger =
LoggerFactory.getLogger(SampleController.class);
//String return 타입
@RequestMapping("doB") //URI에 /doB 가 입력되면 doB()가 호출됨
public String doB(@ModelAttribute("msg") String msg) {
logger.info("doB 호출됨");
return "result";
}
}
doB() 메소드 내의 파라미터에 사용된 @ModelAttibute(“msg”)는 요청 시 msg 이름의 파라미터를 문자열로 처리해주고, 뷰에 전달되도록 합니다.
쉽게 말해서 자동으로 모델 객체를 생성해서 String 타입의 msg 속성을 추가해서 뷰에 전달하는 것입니다!
// /WEB-INF/views/result.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset="UTF-8">
<title>result.jsp</title>
</head>
<body>
<!-- 전달받은 model의 속성 msg에 접근 -->
<span>Hello ${msg}</span>
</body>
</html>
만들어진 결과 데이터를 전달해야 하는 경우
컨트롤러를 제작하면서 가장 많이 하는 작업은 다른 객체의 도움을 받아 만들어진 데이터를 뷰로 전달하는 일을 하는 것입니다!
이 때는 스프링 MVC의 Model 객체를 사용해서 간편하게 처리할 수 있습니다!
간단하게 실습해보겠습니다!
먼저, 데이터를 담을 객체인 ProductVO를 만들겠습니다.
package io.github.kookyungmin.domain;
public class ProductVO {
private String name;
private double price;
public ProductVO(String name, double price) {
super();
this.name = name;
this.price = price;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
@Override
public String toString() {
return "ProductVO [name=" + name + ", price=" + price + "]";
}
}
//SampleContoller.java
//컨트롤러
@Controller
public class SampleController {
//로그를 남겨줌
private static final Logger logger =
LoggerFactory.getLogger(SampleController.class);
//만들어진 결과 데이터를 전달
@RequestMapping("doC")
public String doC(Model model) {
//sample date 만듬
ProductVO product = new ProductVO("Sample Product", 10000);
logger.info("doC 호출됨");
model.addAttribute(product);
return "productDetail";
}
}
위의 코드를 보시면 doC() 메소드의 선언에 특이하게도 Model이라는 클래스를 파라미터로 사용한 것을 볼 수 있습니다. Model 클래스는 스프링 MVC에서 기본적으로 제공되는 클래스로,
이 클래스의 용도는 뷰에 원하는 데이터를 전달하는 일종의 컨테이너나 상자의 역할을 한다고 생각하면 됩니다!
위의 메소드에서는 ProductVO 클래스의 객체를 생성한 후 Model에 담아서 뷰로 전달했습니다~!
Model의 method인 addAttribute()를 이용했는데, addAttribute()는 크게 두가지의 형태입니다.
- addAttribute(“이름”,객체) : 객체에 특별한 이름을 부여해 뷰에서 이름값을 이용해서 객체 처리
- addAttribute(객체) : 자동으로 저장되는 객체의 클래스명 앞글자를 소문자로 처리한 클래스명을 이름으로 간주
예를 들어 위의경우 ProductVO를 이름 없이 저장했기에, 뷰에서의 이름은 productVO가 됩니다!
뷰의 코드는 다음과 같습니다!
<!-- productDetail.jsp -->
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset="UTF-8">
<title>productDetail.jsp</title>
</head>
<body>
<!-- 전달받은 model의 속성 productVO에 접근 -->
<span>${productVO.name}</span>
<span>${productVO.price}</span>
</body>
</html>
리다이렉트를 해야 하는 경우
가끔은 특정한 컨트롤러의 로직을 처리할 때 다른 경로를 호출해야 하는 경우가 있습니다~!
이 경우에는 스프링 MVC의 특별한 문자열인 redirect: 를 이용합니다!
리다이렉트를 하는 경우 RedirectAttributes 클래스를 파라미터로 같이 사용하게 되면 리타이렉트 시점에 원하는 데이터를 임시로 추가해서 넘기는 작업이 가능합니다!
//SampleContoller.java
//컨트롤러
@Controller
public class SampleController {
//로그를 남겨줌
private static final Logger logger =
LoggerFactory.getLogger(SampleController.class);
@RequestMapping("/doE")
public String doE(RedirectAttributes rttr) {
//rttr 객체에 임시데이터 msg를 추가하여 넘김
rttr.addFlashAttribute("msg","This is the Message!! with redirected");
return "redirect:/doF";
}
@RequestMapping("/doF")
public void doF(@ModelAttribute("msg") String msg) {
logger.info("doF called..........."+msg);
}
}
Run on Server하고 브라우저에 http:// localhost:8081/kookyungmin/doE라고 입력하면, 리다이렉트에 의해 http:// localhost:8081/kookyungmin/doF로 이동합니다.
JSON 데이터를 생성하는 경우
스프링 MVC의 장점 중 하나는 최근 프로그래밍에서 많이 사용되는 JSON 데이터에 대한 처리를 너무나 간단하게 처리할 수 있다는 것입니다!
이를 위해서 pom.xml에 jackson-databind 라이브러리를 추가해줍니다!
<!-- jackson -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.8.4</version>
</dependency>
//SampleContoller.java
//컨트롤러
@Controller
public class SampleController {
//로그를 남겨줌
private static final Logger logger =
LoggerFactory.getLogger(SampleController.class);
//ProductVO를 json 데이터 형태로 반환
@RequestMapping("/doJSON")
public @ResponseBody ProductVO doJSON() {
ProductVO product = new ProductVO("샘플상품",30000);
return product;
}
}
product가 json 데이터 형태로 출력이 되었네요!!
다음과 같이 Chrome 확장 프로그램에 JSON Formatter 를 추가하면 좀더 보기 쉬운 형태로 변환해줍니다.
WAS 없이 컨트롤러 테스트하기
스프링 MVC에서는 WAS 구동 없이도 컨트롤러를 테스트 할 수 있습니다!
다음과 같이 pom.xml에서 Servlet을 변경해주면됩니다!
<!-- Servlet -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
</dependency>