ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 핸들러 메소드 - 1 (스프링 MVC - 5)
    Programming/Spring MVC 2020. 3. 24. 19:17
    728x90

     

    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

    댓글

Designed by Tistory.