Controller
Spring Controller란
Spring에서 Controller란 DispatcherServlet이 이용할 수 있도록 만들어진 요청
처리 도구이다.
TestController 생성
다음 위치에 클래스를 생성한다.
com.haakdemy.spring08.controller.TestController
package com.hakademy.spring08.controller;
public class TestController {
}
이 컨트롤러를 등록하는 방법은 2가지가 존재한다. 1. servlet-context.xml에 등록하는 방법 2. @Controller를 사용하는 방법
servlet-context.xml에 직접 등록할 경우의 코드
<beans:beans ...>
...
<beans:bean name="주소" class="com.hakademy.spring08.controller.TestController"/>
...
</beans:beans>
Controller 애노테이션을 사용하는 경우의 코드
@Controller를 class 윗줄에 추가하고 import를 수행한다.
package com.hakademy.spring08.controller;
import org.springframework.stereotype.Controller;
@Controller
public class TestController {
}
이 문서에서는 2번 방법을 사용한다.
정상적으로 등록이 되었는지 확인하고 싶다면 spring explorer를 사용한다.
[Window] → [Show View] → [Other...] 선택한다.

검색창에 "spring explorer" 입력 후 [Spring Explorer] 선택한다.

해당 프로젝트에 컨트롤러가 잘 등록되어 있는지 확인한다.

기본 요청 처리 및 결과 보여주기
다음 주소를 처리할 수 있는 메소드를 구현한다.
http://localhost:8080/spring08/test1
context path(artifactID)를 제외한 경로인 /test1
을 처리할 수 있도록 다음과 같이 메소드를 TestController에 구성한다
@RequestMapping("/test1")
@ResponseBody
public String test1(){
return "test1 호출";
}
import까지 마치고 나면 요청을 처리할 수 있는 매핑이 한 개 생성된다. 서버에 프로젝트를 Add 한 뒤 위에 적힌 접속 주소를 브라우저를 켜서 접속하면 화면에 test1 호출이라는 글자가 나타나는 것을 확인할 수 있다.

작성한 매핑에 대해 살펴보면 다음과 같다.
RequestMapping
@RequestMapping("/test1")
/test1 경로로 들어온 요청을 처리하겠다고 명시하는 Annotation이다. 다음과 같이 작성하는 것이 원칙이지만 생략이 가능하여 일반적으로 생략하고 작성한다.
@RequestMapping(value="/test1")
위와 같이 선언한 경우 GET/POST 등 전송방식을 고려하지 않고 해당 주소에 대한 모든 요청을 처리하게 된다.
ResponseBody
@ResponseBody
@ResponseBody는 매핑에서 반환된 값이 화면에 그대로 출력된다는 의미이다. Spring에서 자체적으로 설정되어 있는 View Resolver를 무시하기 때문에 원하는 내용을 간단하게 테스트하거나 다운로드 등 기본 설정을 따르지 말아야 할 경우 사용한다.
Mapping Method
public String test1(){
return "test1 호출";
}
메소드만으로는 의미가 없고 위에서 언급한 @RequestMapping, @ResponseBody와 조합하여 생각해야 의미가 있다.
/test1
이라는 요청이 발생하면 메소드가 실행된다.실행이 완료되면 화면에 "test1 호출"이라는 글자를 출력하여 사용자에게 전송한다.
GET 방식 요청 처리
전송 방식 중 GET방식만 처리하고 싶은 경우에는 다음과 같이 매핑을 선언한다.
@RequestMapping(value="/test2", method = RequestMethod.GET)
@ResponseBody
public String test2() {
return "test2 호출";
}
위의 매핑을 분석해보면
/test2
의 주소로GET
방식 요청이 발생할 경우 test2 메소드가 실행된다.실행이 완료되면 화면에 "test2 호출"이라는 글자를 출력하여 사용자에게 전송한다.
GetMapping
@RequestMapping 대신 Spring 4.3부터는 간단하게 사용할 수 있는 @GetMapping 이 있다.
@GetMapping("/test2")
POST 방식 요청 처리
전송 방식 중 POST 방식만 처리하고 싶은 경우에는 다음과 같이 매핑을 선언한다.
@RequestMapping(value="/test3", method = RequestMethod.POST)
@ResponseBody
public String test3() {
return "test3 호출";
}
위의 매핑을 분석해보면
/test3
의 주소로POST
방식 요청이 발생할 경우 test3 메소드가 실행된다.실행이 완료되면 화면에 "test3 호출"이라는 글자를 출력하여 사용자에게 전송한다.
POST 방식은 직접 테스트가 어렵기 때문에 POSTMAN 등을 이용하여 테스트한다.
PostMapping
@RequestMapping 대신 @PostMapping을 사용할 수 있다(Spring 4.3 이상)
@PostMapping("/test3")
요청 파라미터 처리
Spring에서는 다양한 방법으로 요청 파라미터를 처리할 수 있다.
예를 들어 다음과 같은 주소가 있다고 가정해보자.
http://localhost:8080/spring08/test4?name=david&age=20
이 요청주소에는 2개의 Parameter가 존재한다.
name = david
age = 20
이 파라미터를 받을 수 있도록 Mapping을 구현해본다.
@RequestMapping("/test4")
@ResponseBody
public String test4(HttpServletRequest request) {
String name = request.getParameter("name");
int age = Integer.parseInt(request.getParameter("age"));
String str = "test4 호출(name = "+name+", age = "+age + ")";
return str;
}
기존 JSP 처럼 요청 객체를 매개변수에 선언하게 되면 Spring이 자동으로 주입해준다. Spring에서 Mapping을 만들 때에는 이처럼 다양한 객체들을 선언만으로 이용할 수 있다.
하지만 위의 코드는 가독성이 떨어지므로 Spring의 기능을 사용하면 다음과 같이 개선된다.
@RequestMapping("/test5")
@ResponseBody
public String test5(
@RequestParam String name,
@RequestParam int age) {
String str = "test5 호출(name = "+name+", age = "+age + ")";
return str;
}
RequestParam
@RequestParam을 사용하면 파라미터를 변수에 바로 담도록 Spring에게 요청할 수 있다. 이름을 지정하거나 기본값을 지정할 수 있는 옵션을 가지고 있다. 위의 예시에서는 다음과 같이 요청했다고 생각해볼 수 있다.
/test5
로 접속하는 요청에 대해서 name이라는 이름의 파라미터를 String 변수에 담아라/test5
로 접속하는 요청에 대해서 age라는 이름의 파라미터를 int 변수에 담아라
위의 조건이 만족되지 않을 경우 400 상태 오류가 발생한다. 만약 데이터가 없을 수도 있다면 다음과 같이 작성한다.
@RequestMapping("/test6")
@ResponseBody
public String test6(
@RequestParam(required = false) String name,
@RequestParam(required = false, defaultValue = "0") int age) {
String str = "test6 호출(name = "+name+", age = "+age + ")";
return str;
}
위의 매핑을 분석하면 다음과 같다.
/test6
으로 접속하는 요청에 대해서 name이라는 이름의 파라미터를 String 변수에 담아라(없으면 null로 설정하라)/test6
으로 접속하는 요청에 대해서 age라는 이름의 파라미터를 int 변수에 담아라(없으면 0으로 설정하라)
ModelAttribute
@RequestParam만으로 받을 경우 데이터의 개수가 증가하면 변수를 많이 선언해야 하는 번거로움이 있다. 특히, 웹 페이지에서 기본적인 CRUD를 처리하다 보면 Database와 동일한 형태의 데이터(ex : DTO, VO)들을 전송하고 받아서 처리하는 경우가 많다. 이 때 @ModelAttribute를 이용하면 편하게 모든 데이터를 받을 수 있다.
클래스 파일 생성 : com.hakademy.spring08.entity.TestDto
public class TestDto {
private String name;
private int age;
public TestDto() {
super();
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "TestDto [name=" + name + ", age=" + age + "]";
}
}
클래스 안에 다음과 같은 구성 요소들을 배치하였다.
이름, 나이를 저장할 변수
기본 생성자
setter/getter 메소드
toString() 메소드 재정의
lombok을 이용하면 좀 더 간소화된 클래스를 만들 수 있지만 나중에 살펴보는 것으로 한다. 완성된 매핑 코드는 다음과 같다.
@RequestMapping("/test7")
@ResponseBody
public String test7(@ModelAttribute TestDto testDto) {
return "test7 호출 "+testDto;
}
아래의 주소로 접속해보면 처리 여부를 확인할 수 있다.
http://localhost:8080/spring08/test7?name=david&age=20
View Resolver 이용하기
@ResponseBody를 이용하면 화면에 글자를 출력할 수 있지만 홈페이지 화면과 같은 복잡한 내용들은 보여줄 수 없다. 따라서 다음과 같이 처리해야한다.
컨트롤러의 매핑에서 사용자의 요청을 처리한다.
요청을 처리한 뒤 보여줄 페이지의 이름을 반환한다.
페이지를 렌더링한다.
사용자에게 전송한다.
1번까지는 이전 코드들과 동일하지만 매핑에서 바로 사용자에게 출력하는 것이 아니라 뷰(View)를 불러서 2차 작업을 수행한 뒤 전송한다는 것이 차이점이라고 볼 수 있다.
프로젝트의 구조를 살펴보면 뷰 페이지의 위치를 알 수 있다.
spring08controller
+-- src
| +-- main
| | +-- java
| | +-- resources
| | +-- webapp
| | +-- WEB-INF
| | +-- web.xml
| | +-- lib
| | +-- spring
| | | +-- root-context.xml
| | | +-- appServlet
| | | +-- servlet-context.xml
| | +-- views
| +-- test
| +-- java
| +-- resources
+-- target
경로는 webapp 부터 산정하므로 다음과 같이 작성할 수 있다.
/WEB-INF/views/???.jsp
servlet-context.xml에 보면 기본적으로 View Resolver가 등록된것을 확인할 수 있는데, 이 View Resolver가 자동으로 다음을 추가해준다.
접두사(Prefix) : /WEB-INF/views/
접미사(Suffix) : .jsp
<beans:bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<beans:property name="prefix" value="/WEB-INF/views/" />
<beans:property name="suffix" value=".jsp" />
</beans:bean>
따라서 컨트롤러에서는 접두사, 접미사를 제외한 순수한 이름만 반환하면 되므로 다음과 같이 처리할 수 있다.
/WEB-INF/views/test.jsp를 만든다(#jsp-생성)
http://localhost:8080/spring08/test8
을 처리할 수 있는 매핑을 생성한다.(#mapping-생성)처리 후 반환 주소로 접두사, 접미사를 제외한
test
를 반환한다.
JSP 생성
/WEB-INF/views/test.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<h1>테스트 페이지</h1>
Mapping 생성
com.hakademy.spring08.TestController
@RequestMapping("/test8")
public String test8() {
return "test";
}
View Resolver를 사용하기 위해서 @ResponseBody 는 제거한다. 따라서 반환값에 자동으로 접두사, 접미사가 추가되어 View페이지의 경로가 완성된다.
다음 주소로 접속하여 정상적으로 출력되는지 확인한다
http://localhost:8080/spring08/test8
View 페이지에 데이터 전달하기
컨트롤러에서 처리를 마치고 View page에 데이터를 전달하고 싶다면 Model 또는 ModelAndView를 사용할 수 있다. ModelAndView는 데이터와 뷰 정보가 합쳐진 객체이므로 여기서는 Model을 사용하여 처리하는 법을 살펴본다.
/WEB-INF/view/test9.jsp
를 생성하여message
를 출력하도록 구현한다.http://localhost:8080/spring08/test9
를 처리할 수 있는 매핑을 생성한다.처리 코드 내에서 Model을 이용하여 데이터를 전달한다.
Model 에 있는 addAttribute() 를 이용한다.
test9 페이지 생성
message
라는 항목을 출력할 수 있도록 작성한다.
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<h1>test9.jsp 페이지</h1>
<h2>message = ${message}</h2>
test9 매핑 생성
message
라는 항목을 전달하도록 작성한다.
@RequestMapping("/test9")
public String test9(Model model) {
model.addAttribute("message", "모델로 데이터를 전달합니다");
return "test9";
}
다음 주소로 접속하여 확인하면 데이터가 잘 전달된 것을 알 수 있다.
http://localhost:8080/spring08/test9
Last updated