-
핸들러 메소드 - 1 (스프링 MVC - 5)Programming/Spring MVC 2020. 3. 24. 19:17728x90
1. 지원하는 메소드 아규먼트와 리턴 타입
주요한 아규먼트와 리턴 타입이며,
전부는 아님. 심지어 직접 커스텀하여 사용 가능
1) 핸들러 메소드 아규먼트 : 주로 요청 그 자체 또는 요청에 들어있는 정보를 받아오는데 사용한다.
요청 또는 응답 자체에 접근 가능한 API (Low Level 느낌)
- WebReqeust
- NativeWebRequest
- HttpServletRequest, HttpServletResponse (서블릿 API)
요청 본문을 읽어옥거나, 응답 본문을 쓸 때 사용할 수 있는 API (Low Level 느낌)
- InputStream, OutputStream
- Reader, Writer
HTTP/2 리소스 푸쉬에 사용
기존) 클라이언트가 서버에 요청 -> 서버 응답 -> 해당 리소스 재 요청 -> 서버 응답
이를 사용하면 ) 클라이언트 -> 서버에 요청 -> 해당 리소스까지 응답
- PushBuilder
GET, POST에 등에 대한 정보
- HttpMethod
LocaleResolver가 분석한 요청의 Locale 정보
- Locale
- TimeZone
- ZoneId
@PathVariable : URI 템플릿 변수 읽을 때 사용
@MatrixVariable : URI 경로 중에 키/값 쌍을 읽어 올 때 사용
@RequestParam : 서블릿 요청 매개변수 값을 선언한 메소드 아규먼트 타입으로 변환, 단순 타입인 경우에 이 애노테이션을 생략가능
@RequestHeader : 요청 헤더 값을 선언한 메소드 아규먼트 타입으로 변환해줌
2) 핸들러 메소드 리턴 : 주로 응답 또는 모델을 렌더링할 뷰에 대한 정보를 제공하는데 사용함
@ResponseBody : 리턴 값을 HttpMessageConverter를 사용해 응답 본문으로 사용함
HttpEntity, ResponseEntity : 응답 본문 뿐 아니라 헤더 정보까지, 전체 응답을 만들 때 사용함 (정교한 REST API 설계 가능)
String : ViewResolver를 사용해서 뷰를 찾을 때 사용할 뷰 이름
View : 암묵적인 모델 정보를 랜더링할 뷰 인스턴스
Map, Model : (RequestToViewNameTrranslator를 통해서)암묵적으로 판단한 뷰 랜더링할 때 사용할 모델 정보
@ModelAttribute : (RequestToViewNameTrranslator를 통해서)암묵적으로 판단한 뷰 랜더링할 때 사용할 모델 정보에 추가함
2. URI 패턴
@PathVariable
- 요청 URI 패턴의 일부를 핸들러 메소드 아규먼트로 받는 방법
- 타입 변환 지원
- 값이 반드시 있어야 함
- Optional 지원
@Controller public class SampleController { @GetMapping("/events/{id}") public @ResponseBody Event events(@PathVariable Integer id) { Event event = new Event(); event.setId(id); return event; } }
@MatrixVariable
- 요청 URI 패턴에서 키/값 쌍의 데이터를 메소드 아규먼트로 받는 방법
- 위와 나머지는 동일
- 그러나 이 기능을 기본적으로 비활성화 되어 있음. 활성화 하려면 다음꽈 같이 설정해야 함
1) 웹 설정
@Configuration public class WebConfig implements WebMvcConfigurer { @Override public void configurePathMatch(PathMatchConfigurer configurer) { UrlPathHelper urlPathHelper = new UrlPathHelper(); urlPathHelper.setRemoveSemicolonContent(false); configurer.setUrlPathHelper(urlPathHelper); } }
2) 컨트롤러 작성
@Controller public class SampleController { @GetMapping("/events/{id}") public @ResponseBody Event events(@PathVariable Integer id, @MatrixVariable String name) { Event event = new Event(); event.setId(id); event.setName(name); return event; } }
3. 요청 매개변수 (단순 타입)
요청 매개변수?
- 쿼리 매개변수
- 폼 데이터
@RequestParam
- 요청 매개변수에 들어있는 단순 타입 데이터를 메소드 아규먼트로 받아올 수 있다.
- 값이 반드시 있어야 한다. (required=false, Optional 사용해서 설정 가능)
- String 이 아닌 값들은 타입 컨버젼을 지원
- Map, MultiValueMap 을 사용하여 모든 요청 매개변수 받아올 수 있음
- 애노테이션 생략 가능 (비추)
@Controller public class SampleController { @GetMapping("/events/{id}") public @ResponseBody Event events(@PathVariable Integer id, @RequestParam String name) { Event event = new Event(); event.setId(id); event.setName(name); return event; } }
// localhost:8080/1?name=hongchan 으로 요청한 결과 {"id":1,"name":"hongchan"}
4. 폼 서브밋
1) 컨트롤러 작성
@Controller public class SampleController { @GetMapping("/events/form") public String eventsForm(Model model) { Event event = new Event(); event.setId(3); model.addAttribute("event", event); return "/events/form"; } @PostMapping("/events") public @ResponseBody Event events(@RequestParam String name, @RequestParam Integer id) { Event event = new Event(); event.setId(id); event.setName(name); return event; } }
2) html 작성
- @{ } : URL 표현식
- ${ } : Variable 표현식
- *{ } : Selection 표현식
다음과 같이 작성한 타임리프 html은
test코드를 작성하여 어떻게 렌더링되는지 확인이 용이함 (jsp는 불가능)
<!DOCTYPE html> <html lang="en" xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <form action="#" th:action="@{/events}" method="post" th:object="${event}"> <input type="text" title="id" th:field="*{id}"><br> <input type="text" title="name" th:field="*{name}"><br> <input type="submit" value="Create Event"> </form> </body> </html>
5. @ModelAttribute
- 여러 곳에 있는 단순 타입 데이터를 복합 타입 객체로 받아오거나 해당 객체를 새로 만들 때 사용할 수 있다.
(여러 곳? 요청 매개변수, URL 패스, 세션 등에 따로따로 있어도 객체로 받아올 수 있음)
- 생략 가능(비추)
BindingResult
- 값을 바인딩 할 수 없는 경우에는 BindException 에러, 직접 다루고 싶은 경우에는 BindingResult타입의 아규먼트를 바로 오른쪽에 사용한다.
@Valid, @Validated
- 바인딩 이후에 검증 작업을 추가로 하고 싶은 경우에 사용
- @Valid 애노테이션은 그룹을 지정할 방법이 없다
- @Validated는 스프링이 제공하는 애노테이션으로 그룹 클래스를 설정할 수 있다.
@Controller public class SampleController { @GetMapping("/events") public @ResponseBody Event events(@Valid @ModelAttribute Event event, BindingResult bindingResult) { if(bindingResult.hasErrors()) { System.out.println("===================="); bindingResult.getAllErrors().forEach(c -> { System.out.println(c.toString()); }); System.out.println("===================="); } return event; } }
package com.hongchan.demospringmvc; import javax.validation.constraints.Min; import javax.validation.constraints.NotBlank; public class Event { @Min(0) private Integer id; @NotBlank private String name; public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } }
6. 폼 서브밋 (에러 처리)
Post / Redirect / Get 패턴
- Post 이후에 브라우저를 리프레시 하더라도 폼 서브밋이 발생하지 않도록 하는 패턴
- 명령 로직을 (데이터 변환부, 데이터 조회부) 두 개로 나누어서 사용자가 화면 갱신을 했을 때, 조회부만 실행되도록 유도함
1) 컨트롤러 작성
@Controller public class SampleController { private List<Event> eventList = new ArrayList<>(); @GetMapping("/events/form") public String eventsForm(Model model) { Event event = new Event(); event.setId(3); model.addAttribute("event", event); return "/events/form"; } @PostMapping("/events") public String createEvents(@Valid @ModelAttribute Event event, BindingResult bindingResult) { if(bindingResult.hasErrors()) { System.out.println("===================="); bindingResult.getAllErrors().forEach(c -> { System.out.println(c.toString()); }); System.out.println("===================="); return "/events/form"; } // Save to database eventList.add(event); return "redirect:/events/list"; } @GetMapping("/events/list") public String showEvents(Model model) { // Select from database model.addAttribute(eventList); return "/events/list"; } }
2) form, list.html 작성
<!DOCTYPE html> <html lang="en" xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <form action="#" th:action="@{/events}" method="post" th:object="${event}"> <p th:if="${#fields.hasErrors('id')}" th:errors="*{id}">Incorrect data</p> <p th:if="${#fields.hasErrors('name')}" th:errors="*{name}">Incorrect data</p> <input type="text" title="id" th:field="*{id}"><br> <input type="text" title="name" th:field="*{name}"><br> <input type="submit" value="Create Event"> </form> </body> </html>
<!DOCTYPE html> <html lang="en" xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <a th:href="@{/events/form}">Create New Event</a> <div th:unless="${#lists.isEmpty(eventList)}"> <ul th:each="event: ${eventList}"> <p th:text="${event.name}">Event Name</p> </ul> </div> </body> </html>
인프런 백기선님 '스프링 MVC’ 강의를 듣고 정리한 내용입니다.
728x90'Programming > Spring MVC' 카테고리의 다른 글
모델, 바인더, 예외 처리, 전역 컨트롤러 (스프링 MVC - 7) (0) 2020.03.26 핸들러 메소드 - 2 (스프링 MVC - 6) (0) 2020.03.26 요청 맵핑하기 (스프링 MVC - 4) (0) 2020.03.24 WebMvcConfigurer (스프링 MVC - 3) (0) 2020.03.22 서블릿 애플리케이션 (스프링 MVC - 2) (0) 2020.03.22