Chapter 6-3

ChangWoo·2023년 8월 9일
post-thumbnail

Part 6. 스프링 MVC의 Controller

6.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;
}
  • SampleDTO 클래스는 Lombok의 @Data 어노테이션을 이용해 처리한다.
  • @Data를 이용하게 되면 getter/setter, equals(), toString()등의 메서드를 자동 생성하기 때문에 편리하다.
  • SampleController의 메서드가 SampleDTO를 파라미터로 사용하게 되면 자동으로 setter 메서드가 동작하면서 파라미터를 수집하게 된다.
  • SampleController의 경로가 '/sample'* 이므로 ex01() 메서드를 호출하는 경로는 '/sample/ex01'이 된다.
  • 메서드에는 @GetMapping이 사용되었으므로, 필요한 파라미터를 URL 뒤에 '?name=AAA&age=10'과 같은 형태로 추가해서 호출할 수 있다.
< Tomcat 로그 >
INFO : org.zerock.controller.SampleController - SampleDTO(name=AAA, age=10)
  • 실행결과를 보면 SampleDTO 객체 안에 name과 age 속성이 제대로 수집된 것을 볼 수 있다.(자동으로 타입을 변환해서 처리한다.)
  • 프로젝트를 실행할 때 기본 경로는 '/controller'라는 경로로 동작하므로, 앞의 예제와 같이 '/'로 동작하도록 변경해서 실행해야 한다.

6.3.1 파라미터의 수집과 변환

  • Controller가 파라미터를 수집하는 방식은 파라미터 타입에 따라 자동으로 변환하는 방식을 이용한다.
  • SampleDTO에는 int 타입으로 선언된 age가 자동으로 숫자로 변환되는데, 만일 기본 자료형이나 문자열 등을 이용한다면 파라미터의 타입만을 맞게 선언해주는 방식을 사용할 수 있다.
< SampleController >
	@GetMapping("/ex02")
	public String ex02(@RequestParam("name") String name, @RequestParam("age") int age) {
		log.info("name: " + name);
		log.info("age: " + age);
		return "ex02";
	}
  • ex02() 메서드는 파라미터에 @RequestParam 어노테이션을 사용해서 작성되었는데, @RequestParam은 파라미터로 사용된 변수의 이름과 전달되는 파라미터의 이름이 다른 경우에 유용하게 사용된다.
  • 브라우저에서 'http://localhost:8080/sample/ex02?name=AAA&age=10' 과 같이 호출하면 이전과 동일하게 데이터가 수집된 것을 볼 수 있다.
INFO : org.zerock.controller.SampleController - name: AAA
INFO : org.zerock.controller.SampleController - age: 10

6.3.2 리스트, 배열 처리

  • 동일한 이름의 파라미터가 여러 개 전달되는 경우에는 ArrayList<> 등을 이용해 처리가 가능하다.
< SampleController >
	@GetMapping("/ex02List")
	  public String ex02List(@RequestParam("ids")ArrayList<String> ids) {
		log.info("ids: " + ids);
		return "ex02List";
	}
  • 스프링은 파라미터의 타입을 보고 객체를 생성하므로 파라미터의 타입은 List<>와 같이 인터페이스 타입이 아닌 실제적인 클래스 타입으로 지정한다.
  • 위 코드의 경우 'ids'라는 이름의 파라미터가 여러 개 전달되더라도 ArrayList< String > 이 생성되어 자동으로 수집된다.
  • 브라우저를 이용해 '프로젝트 경로/sample/ex02List?ids=111&ids=222&ids=333'을 호출한다면 아래와 같이 로그가 출력된다.
INFO : org.zerock.controller.SampleController - ids: [111, 222, 333]
  • 배열의 경우도 동일하게 처리할 수 있다.
< SampleController >
	@GetMapping("/ex02Array")
	  public String ex02Array(@RequestParam("ids") String[] ids) {
		log.info("array ids:" + Arrays.toString(ids));
		return "ex02Array";
	}
INFO : org.zerock.controller.SampleController - array ids:[111, 222, 333]

6.3.3 객체 리스트

  • 전달하는 데이터가 SampleDTO와 같이 객체 타입이고 여러 개를 처리해야 한다면 약간의 작업을 통해 한 번에 처리 가능하다.
  • SampleDTO를 여러 개 전달 받아 처리하고 싶다면 다음과 같이 SampleDTO의 리스트를 포함하는 SampleDTOList 클래스를 설계한다.
< SampleDTOList 클래스 > 
package org.zerock.domain;
import java.util.ArrayList;
import java.util.List;
import lombok.Data;
@Data
public class SampleDTOList {	
	private List<SampleDTO> list;	
	public SampleDTOList() {
		list = new ArrayList<>();
	}
}
  • SampleController에서는 SampleDTOList 타입을 파라미터로 사용하는 메서드를 작성한다.
< SampleController >
	@GetMapping("/ex02Bean")
	  public String ex02Bean(SampleDTOList list) {
		log.info("list dtos: " + list);
		return "ex02Bean";
	}
  • 파라미터는 '[인덱스]'와 같은 형식으로 전달해서 처리할 수 있다.
  • 전송하고자 하는 URL = '프로젝트 경로/sample/ex02Bean?list[0].name=aaa&list[2].name=bbb'
  • Tomcat은 버전에 따라 위와 같은 문자열에서 '[]'문자를 특수문자로 허용하지 않을 수 있다.
  • JavaScript를 이용하는 경우에는 encodeURIComponent()와 같은 방법으로 해결할 수 있으나 예제의 경우 '['는'%5B'로']'는 '%5D'로 변경되도록 한다.
  • '프로젝트 경로/sample/ex02Bean?list%5B0%5D.name=aaa&list%5B1%5D.name=BBB&list%5B2%5D.name=CCC'
  • 위의 URL을 호출하면 다음과 같이 여러 개의 SampleDTO 객체를 생성한다.
INFO : org.zerock.controller.SampleController - list dtos: SampleDTOList(list=[SampleDTO(name=aaa, age=0), SampleDTO(name=BBB, age=0), SampleDTO(name=CCC, age=0)])
  • 출력된 결과를 보면 3개의 SampleDTO 객체가 생성된 것을 볼 수 있고, '[]'안에 인덱스 번호에 맞게 객체의 속성값이 세팅된 것을 확인할 수 있다.

6.3.4 @InitBinder

  • 파라미터의 수집을 다른 용어로는 'binding'이라고 한다.
  • 변환이 가능ㅎ안 데이터는 자동으로 변환되지만 경우에 따라 파라미터를 변환해서 처리해야 하는 경우도 존재한다.
  • 예를 들어, 화면에서 '2018-01-01'과 같이 문자열로 전달된 데이터를 java.util.Date 타입으로 변환하는 작업이 그러하다.
  • 스프링 Controller에서는 파라미터를 바인딩할 때 자동으로 호출되는 @InitBinder를 이용해 이러한 변환을 처리할 수 있다.
  • org.zerock.domain 패키지에 TodoDTO라는 클래스를 작성한다.
< Todo DTO 클래스 >
package org.zerock.domain;
import java.util.Date;
import lombok.Data;
@Data
public class TodoDTO {
	private String title;
	private Date dueDate;
}
  • TodoDTO에는 특별하게 dueDate 변수의 타입이 java.util.Date 타입이다.
  • 만일 사용자가 '2018-01-01'과 같이 들어오는 데이터를 변환하고자 할 때 문제가 발생하게 된다.
  • 이러한 문제의 간단한 해결책은 @InitBinary를 이용하는 것이다.
< SampleController >
@Controller
@RequestMapping("/sample/*")
@Log4j
public class SampleController {
	@InitBinder
	public void initBinder(WebDataBinder binder) {
		SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
		binder.registerCustomEditor(java.util.Date.class, new CustomDateEditor(dateFormat, false));
	}
... 생략 ...
	@GetMapping("/ex03")
	public String ex03(TodoDTO todo) {
		log.info("todo: " + todo);
		return "ex03";
	}
INFO : org.zerock.controller.SampleController - todo: TodoDTO(title=test, dueDate=Mon Jan 01 00:00:00 KST 2018)
  • 반면에 @InitBinder 처리가 되지 않는다면 브라우저에서는 400에러가 발생하는 것을 볼 수 있다. (400에러는 요청 구문(syntax)이 잘못되었다는 의미다.)
  • 날짜가 정상적으로 처리되어도 아직 jsp 페이지는 없으므로 다음과 같은 결과를 확인할 수 있다.

6.3.5 @DateTimeFormat

  • @InitBinder를 이용해 날짜를 변환할 수 있지만, 파라미터로 사용되는 인스턴스 변수에 @DateTimeFormat을 적용해도 변환이 가능하다.
< TodoDTO >
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;
}
  • 문자열로 'yyyy/MM/dd'의 형식이 맞다면 자동으로 날짜 타입으로 변환된다.
INFO : org.zerock.controller.SampleController - todo: TodoDTO(title=test, dueDate=Mon Jan 01 00:00:00 KST 2018)
profile
한 걸음 한 걸음 나아가는 개발자

0개의 댓글