Keep going
스프링 MVC의 Controller 본문
스프링 MVC 를 이용하는 경우 작성되는 Controller의 특징
- HttpServletRequest, HttpServeltResponse를 거의 사용할 필요 없이 필요한 기능 구현
- 다양한 타입의 파라미터 처리, 다양한 타입의 리턴 타입 사용 가능
- GET 방식, POST 방식 등 전송 방식에 대한 처리를 어노테이션으로 처리 가능
- 상속/인터페이스 방식 대신에 어노테이션만으로도 필요한 설정 가능
1. @Controller, @RequestMapping
프로젝트 내 org.zerock.controller 패키지 폴더에 SampleController라는 이름의 클래스 작성
package org.zerock.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
@RequestMapping
public class SampleController {
}
|
cs |
- SampleController의 클래스 선언부에 @Controller라는 스프링 MVC에서 사용하는 어노테이션을 적용하고 있다.
- 작성된 SampleController 클래스는 위의 그림과 같이 자동으로 스프링의 객체(Bean)에 등록되는데 servlet-context.xml에 <context:component-scan base-package="org.zerock.controller" /> 태그를 이용하여 지정된 패키지를 조사하도록 설정되어 있기 때문이다.
- 해당 패키지에 선언된 클래스들을 조사하면서 스프링에서 객체 설정에 사용되는 어노테이션들을 가진 클래스들을 파악하고 필요하다면 이를 객체로 생성해서 관리하게 된다.
- 클래스 선언부에는 @Controller와 함께 @RequestMapping 을 많이 사용한다.
- @RequestMapping은 현재 클래스의 모든 메서드들의 기본적인 URL 경로가 된다.
예를 들어, SampleController 클래스를 /sample/* 이라는 경로로 지정했다면 /sample/aaa , /sample/bbb 와 같은 URL은 모두 SampleController에서 처리된다.
# SampleController클래스의 @log4j 어노테이션에 에러가 날때 (log4j cannot be resolved to a type)
→ 런타임부분을 주석처리해준다.
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
<exclusions>
<exclusion>
<groupId>javax.mail</groupId>
<artifactId>mail</artifactId>
</exclusion>
<exclusion>
<groupId>javax.jms</groupId>
<artifactId>jms</artifactId>
</exclusion>
<exclusion>
<groupId>com.sun.jdmk</groupId>
<artifactId>jmxtools</artifactId>
</exclusion>
<exclusion>
<groupId>com.sun.jmx</groupId>
<artifactId>jmxri</artifactId>
</exclusion>
</exclusions>
<!-- scope>runtime</scope--> 주석처리
</dependency>
|
cs |
@RequestMapping 어노테이션은 클래스의 선언과 메서드 선언에 사용할 수 있다.
package org.zerock.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import lombok.extern.log4j.Log4j;
@Controller
@RequestMapping("/sample/*")
@Log4j
public class SampleController {
@RequestMapping("")
public void basic() {
log.info("basic...............");
}
}
|
cs |
- SampleController는 Lombok의 @Log4j를 사용한다.
- @Log4j는 @Log가 java.util.Logging을 이용하는데 반해 Log4j 라이브러리를 활용한다. (Spring Legacy Project로 생성한 프로젝트는 기본적으로 Log4j 추가되있음)
2. @ReqeustMapping의 변화
- @Controller 어노테이션은 추가적인 속성을 지정할 수 없지만, RequestMapping의 경우 몇 가지의 속성을 추가할 수 있다.
- 가장 많이 사용하는 속성은 method 속성이다.
- Method 속성은 흔히 GET 방식, POST 방식을 구분해서 사용할 때 이용한다.
- 스프링 4.3버전부터는 이러한 @RequestMapping 을 줄여서 사용할 수 있는 @GetMapping, @PostMapping이 등장하는데 축약형의 표현이다.
package org.zerock.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import lombok.extern.log4j.Log4j;
@Controller
@RequestMapping("/sample/*")
@Log4j
public class SampleController {
@RequestMapping("")
public void basic() {
log.info("basic...............");
}
@RequestMapping(value="/basic", method = {RequestMethod.GET, RequestMethod.POST})
public void basicGet() {
log.info("basic get...........");
}
@GetMapping("/basicOnlyGet")
public void basicGet2() {
log.info("basic get only get....................");
}
}
|
cs |
- @RequestMapping은 GET, POST 방식 모두를 지원해야 하는 경우에 배열로 처리해서 지정할 수 있다.
- 일반적인 경우에는 GET, POST 방식만을 사용하지만 최근에는 PUT, DELETE 방식 등도 점점 많이 사용하고 있다.
- @GetMapping의 경우 오직 GET 방식에만 사용할 수 있으므로, 간편하기는 하나 기능에 대한 제한은 많다.
3. Controller의 파라미터 수집
- Controller를 작성할 때 가장 편리한 기능은 파라미터가 자동으로 수집되는 기능이다.
- 이 기능을 이용하면 매번 request.getParameter()를 이용하는 불편함을 없앨 수 있다.
- 실습을 위해 org.zerock.domain이라는 패키지를 작성하고, SampleDTO 클래스를 작성한다.
package org.zerock.domain;
import lombok.Data;
@Data
public class SampleDTO {
private String name;
private int age;
}
|
cs |
SampleController 메서드가 SampleDTO를 파라미터로 사용하게 되면 자동으로 setter 메서드가 동작하면서 파라미터를 수집하게 된다.
@GetMapping("/ex01")
public String ex01(SampleDTO dto) {
log.info(""+dto);
return "ex01";
}
|
cs |
- SampleController 경로가 /sample*/ 이므로 ex01()메서드를 호출하는 경로는 /sample/ex01 이 된다.
- 메서드에는 @GetMapping이 사용되었으므로 필요한 파라미터를 URL 뒤에 '?name=AAA&&age=10'과 같은 형태로 추가해서 호출할 수 있다.
- 실행된 결과를 보면 SampleDTO 객체 안에 name과 age 속성이 제대로 수집된 것을 볼 수 있다.
- 특히 주목할 점은 자동으로 타입을 반환해서 처리한다는 점이다.
3.1 파라미터의 수집과 변환
- Controller가 파라미터를 수집하는 방식은 파라미터 타입에 따라 자동으로 변환하는 방식을 이용한다.
- SampleDTO 에는 int 타입으로 선언된 age가 자동으로 숫자로 변환되는 것을 볼 수 있다.
- 만일 기본 자료형이나 문자열 등을 이용한다면 파라미터의 타입만을 맞게 선언해주는 방식을 사용할 수 있다.
@GetMapping("/ex02")
public String ex02(@RequestParam("name") String name, @RequestParam("age")int age) {
log.info("name: "+name);
log.info("age: "+age);
return "ex02";
}
|
cs |
- ex02() 메서드는 파라미터에 @RequestParam 어노테이션을 사용해서 작성되었는데, @RequestParam은 파라미터로 사용된 변수의 이름과 전달되는 파라미터의 이름이 다른 경우에 유용하게 사용된다.
- 이전 처럼 'http://localhost:8080/sample/ex02?name=AAA&age=10' 과 같이 호출하면 이전과 동일하게 데이터가 수집된 것을 볼 수 있다.
3.2 리스트, 배열 처리
- 동일한 이름의 파라미터가 여러 개 전달되는 경우에는 ArrayList<> 등을 이용해서 처리가 가능하다.
@GetMapping("/ex02List")
public String ex02List(@RequestParam("ids")ArrayList<String> ids) {
log.info("ids: "+ ids);
return "ex02List";
}
|
cs |
- 스프링은 파라미터의 타입을 보고 객체를 생성하므로 파라미터의 타입은 List<>와 같이 인터페이스 타입이 아닌 실제적인 클래스 타입으로 지정한다.
- 위 코드의 경우 'ids'라는 이름의 파라미터가 여러 개 전달되더라도 ArrayList<String>이 생성되어 자동으로 수집된다.
- 'http://localhost:8080/sample/ex02List?ids=111&ids=222&ids=333' 와 같이 호출한다면 아래와 같은 로그가 출력된다.
배열의 경우도 동일하게 처리할 수 있다.
@GetMapping("/ex02Array")
public String ex02Array(@RequestParam("ids") String[] ids) {
log.info("array ids: "+ Arrays.toString(ids));
return "ex02Array";
}
}
|
cs |
3.3 객체 리스트
- 만일 전달하는 데이터가 SampleDTO와 같이 객체 타입이고 여러 개를 처리해야 한다면 약간의 작업을 통해서 한 번 처리를 할 수 있다.
- 예를 들어 SampleDTO를 여러 개 전달받아서 처리하고 싶다면 SampleDTO의 리스트를 포함하는 SampleDTOList 클래스를 설계 한다.
package org.zerock.domain;
import java.util.ArrayList;
import java.util.List;
public class SampleDTOList {
private List<SampleDTO> list;
public SampleDTOList() {
list= new ArrayList<>();
}
}
|
cs |
@GetMapping("/ex02Bean")
public String ex02Bean(SampleDTOList list) {
log.info("list dtos: "+list);
return "ex02Bean";
}
|
cs |
- 파라미터는 '[인덱스]' 와 같은 형식으로 전달해서 처리할 수 있다.
- Tomcat은 버전에 따라서 문자열에서 '[]' 문자를 특수문자로 허용하지 않을 수 있기 때문에 ' [ '는 '%5B' 로 ' ] '는 '5D' 로 변경한다.
- 전송하려고 하는 URL :
'프로젝트 경로/sample/ex02Bean?list%5B0%5D.name=aaa&list%5B1%5D.name=BBB&list%5B2%5D.name=CCC'
위의 URL을 호출하면 여러 개의 SampleDTO 객체를 생성하는 것을 볼 수 있다.
3.4 @InitBinder
- 파라미터이 수집을 다른 용어로는 'binding(바인딩)' 이라고 한다.
- 변환이 가능한 데이터는 자동으로 변환되지만 경우에 따라서는 파라미터를 변환해서 처리해야 하는 경우도 존재한다.
- 예를 들어, 화면에서 '2018-01-01'과 같이 문자열로 전달된 데이터를 java.util.Date 타입으로 변환하는 작업이 그렇다.
- 스프링 Controller 에서는 파라미터를 바인딩할 때 자동으로 호출되는 @InitBinder를 이용해서 이러한 변환을 처리할 수 있다.
package org.zerock.domain;
import java.util.Date;
import lombok.Data;
@Data
public class TodoDTO {
private String title;
private Date dueDate;
}
|
cs |
- TodoDTO에는 특별하게 dueDate 변수의 타입이 java.util.Date 타입이다.
- 만일 사용자가 '2018-01-01'과 같이 들어오는 데이터를 변환하고자 할 때 문제가 발생하게 된다.
- 이러한 문제의 간단한 해결책은 @InitBinder를 이용하는 것이다.
@InitBinder
public void InitBinder(WebDataBinder binder) {
SimpleDateFormat dateForamt = new SimpleDateFormat("yyyy-MM-dd");
binder.registerCustomEditor(java.util.Date.class, new CustomDateEditor(dateForamt, false));
}
@GetMapping("/ex03")
public String ex03(TodoDTO todo) {
log.info("todo: " + todo);
return "ex03";
}
|
cs |
- 만일 브라우저에서 'http://localhost:8080/sample/ex03?title=test&dueDate=2018-01-01'과 같이 호출했다면 서버에서는 정상적으로 파라미터를 수집해서 처리한다.
- 반면에 @InitBinder 처리가 되지 않는다면 브라우저에서는 400 에러가 발생하는 것을 볼 수 있다. (400 에러는 요청 구문이 잘못되었다는 의미이다.
3.5 @DateTimeFormat
-@InitBinder를 이용해서 날짜를 변환할 수도 있지만, 파라미터로 사용되는 인스턴스 변수에 @DateTimeFormate을 적용해도 변환이 가능하다. (@DateTimeFormat을 이용하는 경우에는 @InitBinder는 필요하지 않다.)
package org.zerock.domain;
import java.util.Date;
import org.springframework.format.annotation.DateTimeFormat;
import lombok.Data;
@Data
public class TodoDTO {
private String title;
@DateTimeFormat(pattern = "yyyy/MM//dd")
private Date dueDate;
}
|
cs |
SampleController - @InitBinder 주석처리를 하고 실행시킨다.
- 문자열로 'yyyy/MM/dd'의 형식이 맞다면 자동으로 날짜 타입으로 변환이 된다.
출처 : 코드로 배우는 스프링 웹 프로젝트 [구멍가게 코딩단]
'Records > Spring Framework' 카테고리의 다른 글
스프링 MVC 프로젝트의 기본 구성 (0) | 2021.02.15 |
---|---|
스프링 MVC 의 Controller(2) (0) | 2021.02.09 |
스프링 MVC의 기본 구조 (0) | 2021.02.05 |
MyBatis와 스프링 연동 (0) | 2021.02.03 |
스프링과 Oracle Database 연동 (0) | 2021.02.03 |