IT/development

[Spring]springframework Controller

알 수 없는 사용자 2022. 11. 27. 07:06
반응형

목차

    Spring Controller

    spring controller의 paramter 수집

    Controller를 작성할 때 가장 편리한 기능은 parameter가 자동으로 수집되는 기능임, 이 기능을 이용하면 매번 request.getParameter()를 이용하는 불편함을 없앨 수 있음

    위와 같이 SampleDTO class가 있고(Lombok 사용으로 @Data 어노테이션으로 자동으로 setter, getter, toString method 생성)

    위와 같이 SampleController의 method가 SampleDTO를 parameter로 사용하게 되면 자동으로 setter 메서드가 동작하면서 parameter를 수집하게 됨
    method에는 @GetMapping이 사용되었으므로, 아래와 같이 브라우저에서 필요한 parameter를 추가후 호출하게 되면

    아래와 같이 Tomcat의 log에 호출한 parameter값이 찍히는걸 확인할 수 있음(주목할 점은 자동으로 타입을 변환해서 처리한다는 점)

     

    parameter의 수집과 변환

    Controller가 parameter를 수집하는 방식은 parameter type에 따라 자동으로 변환하는 방식을 이용함
    예를 들어 위읫 SampleDTO에는 int type으로 선언된 age가 자동으로 숫자로 변환되는 것을 볼수 있음

    만일 기본 자료형이나 문자열 등을 이용한다면 아래 이미지와 같이 parameter의 type만을 맞게 선언해주는 방식을 사용할 수 있음

     

    위에서는 @RequestParam 어노테이션을 사용했는데 @RequestParam은 parameter로 하나 이상의 parameter를 받을 때(사용된 변수의 이름과 전달되는 parameter의 이름이 다른 경우에 유용하게 사용됨)사용됨, 단점이 있는데 넘어오는 requestParam중 @RequestParam에서 지정한 키값이 존재하지 않다면 BabRequest http 400 에러가 발생함 이를 방지하기 위한 방법 url: https://heavenly-appear.tistory.com/302

    브라우저에서 http://localhost:9393/sample/ex02?name=dev&age=98 이런식으로 parameter를 추가해서 호출 시 아래 이미지처럼 이전과 동일하게 데이터가 들어온 것을 확인 할 수 있음

    사진 출처 :https://n1tjrgns.tistory.com/198

     

    Controller에서 Parameter를 받는 방법

    httpServletRequest.getParameter() - 가장 흔히 사용하는 일반적인 방법 @RequestMapping("/test") public String test(HttpServletRequest req){ String userId = req.getParamenter("userId"); return "test"; } httpServletRequest.getAttribute() getParam

    n1tjrgns.tistory.com

     

    리스트, 배열 처리

    동일한 이름의 parameter가 여러 개 전달되는 경우에는 아래 이미지와 같이 ArrayList<> 등을 이용해서 처리가 가능함
    스프링은 parameter의 type을 보고 객체를 생성하므로 parameter의 type은 List<>와 같이 interface type이 아닌 실제적인 class type으로 지정해야 함 아래 코드의 경우 'ids'라는 이름의 parameter가 여러개 전달되더라도 ArrayList이 생성되어 자동으로 수집됨

    브라우저에서 http://localhost:9393/sample/ex02List?ids=dev&ids=111&ids=222 이런식으로 호출 시 아래 이미지 처럼 데이터가 들어옴

    아래 이미지처럼 배열의 경우도 동일하게 처리할 수 있음

    브라우저에서 http://localhost:9393/sample/ex02Array?ids=dev&ids=good&ids=tel 이렇게 호출 시 아래 이미지 처럼 데이터가 들어옴

     

    객체 리스트

    만일 전달하는 데이터가 SampleDTO와 같이 객체 타입이고 여러 개를 처리해야 한다면 약간의 작업으로 한번에 처리 가능
    예를 들어 SampleDTO를 여러 개 전달 받아서 처리하고 싶다면 아래 이미지처럼 SampleDTO의 리스트를 포함하는 SampleDTOList class를 설계함

    SampleController에서는 아래 이미지처럼 SampleDTOList tyle을 parameter로 사용하는 method를 작성함

    parameter는 "[인덱스]"와 같은 형식으로 전달해서 처리할 수 있음
    전송하려고 하는 URL: http://localhost:9393/sample/ex02Bean?list[0].name=aaa&list[2].name=bbb
    Tomcat은 version에 따라서 위와 같은 문자열에서 "[]" 문자를 특수문자로 허용하지 않을 수 있는데 이 경우에는 아래와 같은 에러를 발생시킴

    Javascript를 이용하는 경우에는 encodeURLComponent()와 같은 방법으로 해결할 수 있으나 URL 인코딩 방식으로 처리하도록 함
    참조 url: https://stackoverflow.com/questions/9966053/what-does-5b-and-5d-in-post-requests-stand-for
    위의 url을 http://localhost:9393/sample/ex02Bean?list%5B0%5D.name=aaa&list%5B2%5D.name=bbb 변경후 다시 요청하면 아래와 같이 3개의 SampleDTO객체가 생성된 것을 볼 수 있고 '[]' 안에 인덱스 번호에 맞게 객체의 속성값이 들어간 게 확인 됨

    parameter의 수집을 다른 용어로는 바인딩이라고 하는데 변환이 가능한 데이터는 자동으로 변환되지만 경우에 따라서 parameter를 변환해서 처리해야 하는 경우도 존재하는데 예를 들면 화면에서 '2018-02-21'과 같이 문자열로 전달 된 데이터를 java.util.Date타입으로 변환하는 과정이 그렇다
    스프링 Controller에서는 @InitBinder를 이용해서 이러한 변환처리를 할 수 있음
    아래와 같이 TodoDTO 클래스를 하나 만들고 dueDate의 변수타입을 java.util.Date로 설정했음

    아래와 같이 SampleController에서 /ex03으로 요청받게 매핑 한 뒤

    브라우저에서 http://localhost:9393/sample/ex03?title=test&dueDate=2018-02-21 이런식으로 호출을 하면 아래처럼 400 에러가 발생한다.

    이를 해결하기 위해 SampleController에서 아래처럼 @InitBinder를 이용해서 작업을 해준다.

    @InitBinder 설명 참조 url: https://nkcnow.tistory.com/174

     

    요청 파라미터 바인딩

    @InitBinder 스프링프레임워크에서의 바인딩이란 모델 클래스(오브젝트)의 프로퍼티(메서드 set)에 값을 넣는 것을 말한다. 두가지 바인딩을 제공하는데.. 첫 번째는 xml설정 파일을 통해 의 에 값을

    nkcnow.tistory.com

    그 후 다시 브라우저에서 http://localhost:9393/sample/ex03?title=test&dueDate=2018-02-21로 호출 하면 아래와 같이 타입이 변환되어 값이 들어옴

     

    @InitBinder 외에 또 다른 방법

    아래와 같이 parameter로 사용되는 인스턴스 변수에 @DateTimeFormat을 적용해도 변환이 가능함(이 경우에는 @InitBinder가 필요 없음)

    브라우저에서 dueDate의 형식이 2018/02/21으로 호출(http://localhost:9393/sample/ex03?title=test&dueDate=2018/02/21)할 경우 @InitBinder를 사용했을 때와 동일하게 타입이 변환되어 값이 들어옴

     

    Controller의 return type

    스프링 MVC의 구조가 기존의 상속과 인터페이스에서 어노테이션을 사용하는 방식으로 변한 이후 가장 큰 변화 중 하나는 return type이 자유로워 졌다는 점임
    Controller의 method가 사용할 수 있는 return type은 주로 다음과 같음

    String: jsp를 이용하는 경우에는 jsp파일의 경로와 파일이름을 나타내기 위해서 사용함
    void: 호출하는 URL과 동일한 이름의 jsp를 의미함
    VO, DTO 타입: 주로 JSON type의 데이터를 만들어서 반환하는 용도로 사용됨
    ResponseEntity 타입: response 할 때 Http 헤더 정보와 내용을 가공하는 용도로 사용함
    Model, ModelAndView: Model로 데이터를 반환하거나 화면까지 같이 지정하는 경우에 사용함(최근에는 많이 사용하지 않음)
    HttpHeaders: 응답에 내용 없이 Http 헤더 메시지만 전달하는 용도로 사용함

    @ResponseBody

    비동기 통신인 경우 서버로 보낼 때도 http 본문(body)에 담고 서버에서 클라이언트로 돌려줄 때도 본문에 담아서 보내야 하는데 이 때 사용하는 애노테이션임
    HTTP로 본문에 담아 서버로 전송한걸 JAVA로 변환해줄 때 사용하는게 @RequestBody이고 반대의 경우 사용하는게 @ResponseBody임

    사진 출처 : https://lee-mandu.tistory.com/242

    예제

    위와 같이 객체를 주고 받을 때는 아래처럼 동작

    출처 : https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81-%EC%9E%85%EB%AC%B8-%EC%8A%A4%ED%94%84%EB%A7%81%EB%B6%80%ED%8A%B8/lecture/49578?tab=curriculum

    ※ return 되는 데이터가 view를 통해서 출력되지 않고 HTTP Response Body에 직접 쓰여지게 됨

    아래와 같은 메서드의 경우는 JSON type으로 객체를 변환해서 브라우저에 전달됨
    선행작업이 필요함(pom.xml에 Jackson Databind 라이브러리를 추가해야 함, 안 할 경우 에러 발생)

    아래와 같이 JSON type으로 변환되어 브라우저에 전달됨

     

    ResponseEntity

    HTTP protocol의 header를 다룰 경우에 스프링 MVC에서는 HttpServletRequest나 HttpServletResponse를 직접 핸들링하지 않아도 이런 작업이 가능하게 되어 있음
    이러한 처리를 위해 ResponseEntity를 통해서 원하는 헤더 정보나 데이터를 전달할 수 있음
    ResponseEntity는 HttpHeaders 객체를 같이 전달할 수 있고, 이를 통해서 원하는 HTTP 헤더 메시지를 가공하는 것이 가능함
    아래 이미지는 Controller에서 JSON type의 Header Message와 200 OK라는 상태 코드를 브라우저로 전송하는 method임

    Header Message가 잘 들어왔고 개발자도구에서 보면 200 OK라는 상태코드가 전달됨이 확인 됨

     

    Controller의 Exception 처리

    Controller를 작성할 때 예외 상황을 고려하면 처리해야 하는 작업이 엄청나게 늘어날 수 밖에 없는데 스프링 MVC에서는 이러한 작업을 다음과 같은 방식으로 처리할 수 있음

    @ExceptionHandler와 @ControllerAdvice를 이용한 처리
    @ResponseEntity를 이용하는 예외 메시지 구성

     

    ControllerAdvice

    @ControllerAdvice는 스프링의 AOP(Aspect-Oriented-Programming)을 이용하는 방식(간단히 언급하면 핵심적인 로직은 아니지만 프로그램에서 필요한 '공통적인 관심사(cross-concern)는 분리'하자는 개념임)
    이를 활용해서 공통적인 예외사항에 대해서는 별도로 @ControllerAdvice를 이용해서 분리하는 방식임

    아래 이미지는 공통적인 예외처리를 담당할 CommonExceptionAdvice 클래스를 생성 후 Exception Message를 콘솔에 출력
    model에 Exception을 담아서 예외 발생 시 에러 페이지로 넘겨서 error_page에서 에러 메시지를 출력하는 예제임
    @ControllerAdvice 어노테이션은 해당 객체가 스프링의 컨트롤러에서 발생하는 예외를 처리하는 존재임을 명시하는 용도임
    @ExceptionHandler는 해당 method가 () 들어가는 예외타입을 처리한다는 것을 의미하며 @ExceptionHandler 어노테이션의 속성으로는 Exception 클래스 타입을 지정할 수 있음(아래의 경우는 Exception.class를 지정하였으므로 모든 예외에 대한 처리가 except()만을 이용해서 처리할 수 있음
    만일 특정한 타입의 예외를 다루고 싶다면 Exception.class 대신에 구체적인 예외의 클래스를 지정해야 함

    예외처리가 있는 클래스는 servlet-context.xml에 component-scan에 해당 클래스가 있는 패키지를 설정해줘야 함

    에러 페이지가 정상적으로 출력되는 지 확인하기 위해서 브라우저에서 고의로 parameter를 넣지 않고 호출한 결과는 아래 이미지와 같음

    출처 : 코드로 배우는 스프링 웹 프로젝트(개정판)예제

     

    반응형