web.xml : Tomcat구동과 관련된 설정
root-context.xml, servlet-context.xml : 이 2가지 파일은 스프링과 관련된 설정이다.
web.xml
context-param에는 root-context.xml의 경로가 설정되어 있다.
root-context.xml파일이 처리되면 root-context.xml 파일에 있는 Bean(객체) 설정들이 동작한다.
root-conext.xml에 정의된 객체들은 스프링의 영역 안에 생성되고, 객체들 간의 의존성을 처리한다.
ContextLoaderListener는 Spring컨테이너를 생성하고,
Spring은 모든 Servlet과 Filters 공유하는 역할을 한다고 한다.
root-context.xml의 beans graph에 있는 그림이다.
hotel, restaurant, chef의 의존성이 처리된다.
root-context.xml이 처리된 후 DispatcherServlet이라는 Servlet관련된 설정이 동작한다.
우선 이 그림을 한 번 살펴보고 가자.
DispatcherServlet * Front-Controller 패턴
모든 Request를 DispatcherServlet을 통하도록 설계되어 있고, 이런 방식이 Front-Controller패턴이다.
Front-Controller 패턴을 이용하는 경우에는 모든 Request의 처리에 대한 분배가 정해진 방식대로 동작한다.
이러한 특징으로 엄격한 구조를 만들어 낼 수 있다.
ExController에 @Controller라는 스프링MVC에서 사용하는 @어노테이션을 적용한다.
작성된 ExController클래스는 자동으로 스프링의 객체(Bean)으로 등록된다.
이 부분은 servlet-context.xml파일을 보면 확인할 수 있다.
이거는 servlet-context.xml의 일부인데,
com.xml.practice는 mvc프로젝트를 생성할 때 기본으로 생성되는 패키지이고, 이 패키지 안에 HomeController가 있다.
SpringMVC를 생성할 때 com.velog.io라는 패키지가 생성되고, 저 패키지 밑에는 HomeController가 생긴다.
root-context.xml, servlet-context.xml
이 두 개의 xml파일에서 모두 component-scan을 한다.
해당 패키지에 선언된 클래스들을 스캔하면서 스프링에서 객체(Bean) 설정에 사용되는,
@어노테이션들을 가진 클래스들을 파악하고 필요한 경우 이를 객체로 생성해서 관리한다.
클래스가 스프링에서 관리되면 클래스 옆에 그림과 같이 's'모양의 아이콘이 추가된다.
현재 클래스의 모든 메서드들의 기본적인 URL의 경로가 된다.
ex) TestController 클래스에,
@RequestMapping('/sample/*') 이렇게 경로를 지정했다고 하면
/sample/aaa
/sample/bbb
이 두 가지 경로 모두 AController에서 처리된다.
@Controller같은 경우 추가적인 속성을 지정할 수 없다.
@RequestMapping의 경우에는 몇 가지의 속성을 추가할 수 있다.
RequestMapping(value="/basic", method=RequestMethod.GET)
그런데 이제는 이 방법보다는
@GetMapping("/basic")
@PostMapping("/basic")으로 쓴다.Get,Post방식 모두를 지원해야 하는 경우에는
@RequestMapping(value="/abc", method={RequestMethod.GET, RequestMethod.Post})
예제를 위해서 SamDTO클래스를 생성해준다.
@Data public class SamDTO{ private String name; private int age; }
Lombok의 @Data 어노테이션을 이용해서 getter/setter, equals(), toString()이 생성된다.
@Controller @RequestMapping("/sample/*") @Log4j public class TestController{ @GetMapping("/ex01") public String ex01(SamDTO dto){ log.info(""+dto); return "ex01"; } }
AController의 메소드가 SamDTO를 파라미터로 사용하게 되면,
자동으로 SamDTO의 setter메소드가 동작하면서 파라미터를 수집하게 된다.
AController의 경로가 '/sample*' 이므로
그런데 ex01()메소드에 GetMapping이 설정되어 있다.
호출하는 경로는 sample/ex01이 된다.
필요한 파라미터를 URL뒤에 '?name=AAA&age=10' 같은 형태로 추가해서 호출을 해보면,
다음과 같은 로그가 찍힐 것이다.
INFO : packageName.AController-SamDTO(name=AAA, age=10)
@Controller가 파라미터를 수집하는 방식은 파라미터 타입에 따라 자동으로 변환하는 방식이다.
ex>위의 예제에서 보면 int타입으로 선언된 age(SamDTO)가 자동으로 숫자로 변화되는 것을 볼 수 있다.
@RequestParam
기본 자료형이나 문자열 등을 이용한다면 파라미터의 타입만을 맞게 선언해주는 방식을 사용할 수 있다.
ex02() 메서드는 파라미터에 @RequestParam 어노테이션을 사용해서 작성되었다.
@RequestParam은 파라미터로 사용된 변수의 이름과 전달되는 파라미터의 이름이 다른 경우 유용하다
@RequestParam을 사용한 경우이다.
@GetMapping("/ex02")
public String ex02(@RequestParam("name") String name,
@RequsetParam("age") int age){
log.info("name:"+name);
log.info("age:"+age);
return "ex02";
}
@RequestParam을 이용해서 List, Array배열 처리도 가능하다
@GetMapping("/ex02List")
public String ex02List( @RequestParam("ids")ArrayList<String> ids){
log.info("ids: "+ids);
return "ex02List";
스프링은 파라미터의 타입을 보고 객체를 생성하므로,
파라미터의 타입은 List와 같은 인터페이스 타입이 아닌 실제적인 ArrayList와 같은 클래스 타입으로 지정한다.
이 코드의 경우네느 'ids'라는 이름의 파라미터가 여러 개 전달되더라도 ArrayList이 생성되어 자동으로 수집한다.
/sample/ex02List?ids=111&ids=222&ids=333 을 호출하면
INFO : 패키지.컨트롤러 - ids:{111,222,333}
이렇게 로그가 찍힌다.
다음으로 객체 자체를 List로 만들어서 처리해보자.
SamListDTO.java로 객체를 만들어주자.
@Data
public class SamListDTO{
private List<SamDTO> list;
public SamListDTO(){
list = new ArrayList<>();
}
}
Controller.java
@GetMapping("/ex02Bean")
public String ex02Bean(SamListDTO list){
log.info("list dtos: "+list);
return "ex02Bean";
}
테스트 URL 프로젝트경로/sample/ex02Bean?list[0].name=aaa&list[2].name=bbb
[] Tomcat버전에 따라서 이 부분에서 에러가 발생할 수 있다.
==> /sample/ex02Bean?list%5B0%5D.name=aaa 이렇게 호출해주면INFO : 패키지.컨트롤러 - list dtos : SamListDTO(list=[SamDTO(name=aaa, age=0)
이렇게 로그가 찍히는 것을 확인할 수 있다.
파라미터로 사용되는 인스턴스 변수에 @DateTimeFormat을 적용해 타입 변환이 가능하다.
@Data
public class TodoDTO{
private String title;
@DateTimeFormat(pattern="yyyy/MM/dd")
private Date dueDate;
}
Test URL : localhost:~/sample/ex03?title=testFile&dueDate=2018/01/01
INFO : package.Controller - todo: TodoDTO(title=testFile, dueDate=Mon Jan 01 00:00:00 KST 2018
이렇게 로그가 찍히는 것을 확인할 수 있다.
참고 : 코드로 배우는 스프링 웹 프로젝트