Spring 8일차

Shin·2023년 3월 2일
0

spring

목록 보기
8/8

@RequestMapping 의 속성

consumes

: client의 reqeuest 를 제한하는 용도

client 의 request 안의 header 정보 내부에 있는 content-type 의 일치 여부를 통해 reqeust 를 제한한다.

reqeust 라는 것의 내부에는

  • start line
  • header
  • reqeustbody

로 분류된다. 그 중에서 get 방식의 경우, 데이터가 start line 의 url 에 쿼리스트링 형태로 담기게 된다.

그런데 header 의 content-type 이라는 것은 requestbody 의 데이터 형식을 지정해주는 것이다.

서버 측에서 request 에 대한 mapping 으로 consumes 에 제한을 걸게되면, get 방식의 경우 그 제한에 걸려버리게 된다.

consumes 는 하나만 받는 것이 아니기 때문에, 배열 형태로 작성해준다.

브라우저의 request header 부분을 보게 되면, get 방식의 경우 conttent-type 항목이 존재하지 않는 것을 볼 수 있다. 그렇기 때문에 RequestMapping 의 consumes 속성을 통해 제한을 걸게 되면 get 방식의 요청이 정상적으로 이루어질 수 없게 되고, 415 에러가 발생하게 된다.

post 방식의 경우, 기본적으로 content-type 이라는 속성이 request header 에 존재하고 있다. 그리고, 그 default 값으로 Content-Type: application/x-www-form-urlencoded 으로 존재하고 있다.

다만 content-type 이라는 속성이 존재하더라도, handler 의 consumes 속성에 매핑한 값과 매칭이 되지 않기 때문에 get 방식과 마찬가지로 415 error 가 발생하게 된다.

이를 해결하기 위해서는 consumes 배열 내부에 application/x-www-form-urlencoded 를 추가해주던가, ajax 혹은 axios 와 같은 처리를 통해 content-type 을 consumes 에 지정해준 값으로 바꾸어 준다.

consumes 에 form 태그의 기본 content-type 을 입력해주고 나니 아까와는 다르게 415 error 가 아닌, 404 error 가 발생하는 것을 볼 수 있다.

보통의 request 는 특별한 경우가 아닌 이상, 요청을 제한하는 경우는 많지 않다.

대신 요청을 처리하고 난 뒤 client 에게 데이터를 전달할 때 해당 데이터가 일반적인 text/html 인지, application/json 인지 정해주는 경우가 많다.
즉 request의 content-type 을 통해 들어오는 데이터를 특정하는 케이스보다 response의 content-type 을 지정하는 케이스가 훨씬 많다.

produces

: client 에게 반환하는 return 하는 data 의 content-type 을 지정하는 역할을 하는 속성이다.

browser 는 response의 content-tpye 을 확인하고, type 에 맞춰서 적절한 처리를 시행한다.

즉, browser 는 결과 데이터가 어떤 타입으로 올 지 모르기 때문에, 타입을 지정해주어야 return 데이터에 걸맞는 처리가 이루어진다.

주의해야 할 점은, produces 속성은 return 하는 데이터의 타입을 지정하는 역할을 하는 것이지, 내가 리턴하는 데이터가 produces 의 타입으로 변환되는 것이 아니다.

messageConverter 라는 것이 타입으로 변환을 시켜준다.

또한, produces 라는 속성은 특정 이유 때문에 @ResponseBody 라는 어노테이션과 함께 사용이 이루어지는 경우가 대부분이다.

return 이 jsp라면, jsp에 설정된 content-type 으로 덮어씌워져서 보내진 것.

다만, produces 로 잡은 타입이 최종적으로 browser 에게 반환된다, 라는 보장은 없다. 왜냐하면, @RequestMapping 의 구조 상 String 으로 반환된 값은 view resolver 에 의해 View 객체로 생성된 후, 그렇게 생성된 view 객체가 최종적으로 반환되기 때문이다.

responsebody 를 통해 데이터를 보낸 것이 아니라, stream 을 통해 새로운 html 파일을 생성해서 별개의 결과를 보내고자 보낸 것.

즉 printWriter 가 가지고 있는 기본적인 content-type 을 통해 전송이 이루어지게 된 것이다.

때문에 한글 인코딩도 모두 깨져서 반환이 이루어지고, response의 header 부분에도 produces 로 설정한 content-type 이 존재하지 않는다.

즉 단독으로 produces 만 사용해봐야 큰 영향을 끼치지 못하게 된다.

Gson 이라는 외부 라이브러리를 new 를 통해 객체 생성해서 사용하는 케이스.

Gson 객체를 생성하는 메소드를 Bean 으로 수동으로 등록한 뒤, autowired 를 통해 자동 생성을 활용하는 케이스

Bean 을 수동으로 등록할 때의 장점

  • 외부 라이브러리를 Bean 으로 등록해서 효율적으로 사용할 수 있게 된다.
  • 프로그램의 크기가 커지고, 자주 기능이 변경되는 경우에는 수동으로 등록했을 때, 유지보수의 효율성이 올라간다.

interface 를 기반으로 구현 클래스를 수동으로 등록하면 전략 패턴을 이용할 수 있게 된다.

@Autowired 를 굳이 사용하지 않고도, getBean 을 사용해서 수동으로 applicationContext 내부에 있는 bean 객체를 가져와 사용할 수도 있다.

ApplicationContextAware

application context(=root-context)를 직접 사용하는 방법
(@Autowired를 사용한 자동 주입이 아니라 수동으로 사용하는 방법)

사용은 가능하지만, 구현체를 만들어야 가능하다.
spring이 ApplicationContextAware의 interface 를 제공해준다.

이 interface 를 구현한 구현체를 Bean 으로 등록해서 사용이 가능하다.

구현체인 ApplicationContextProvider 를 Bean 으로 등록하기 위해 @Component 어노테이션을 붙여준다.

그러면 produces 라는 속성이 필요한가...?

@ResponseBody

HTTP 의 기본 통신 방식

  • Request와 Response 라는 단순한 구조로 이루어져 있다.

굳이 RequestBody 를 사용하지 않는 이유는, get 방식을 사용했을 경우에 body 부분에 데이터가 담기지 않는 문제가 발생하고, 또한 Command 객체를 생성해서 사용할 수 있었기 때문이다.

다만 ResponseBody 의 경우, 내가 만든 문자열이나 상태코드, headers 들을 직접 설정해서 전송할 수 있다.

즉, Stream 을 직접 열어서 데이터를 전송하는 것이 아니라, ResponseBody 안에 데이터를 담아서 HttpResponse 를 반환한다.

그리고 반환된 HttpResponse 객체 내부에 담긴 ResoponseBody 의 데이터를 뽑아서 사용하게 된다.

상태코드

따라서 Controller 를 사용할 때
view 객체를 리턴하는 Controller 와 Ajax 를 통해 클라이언트가 결과 데이터만 받아갈 수 있는 rest 기반의 controller 두 가지를 나누어서 사용하게 된다.

그리고, ResponseBody 안에 담길 데이터의 타입을 설정하는 것이 produces 속성이다. 그렇기 때문에 @ResponseBody 어노테이션과 produces 속성이 같이 사용되게 되는 것이다.

일반적인 controller 사용

controller가 Data를 직접 client 에게 보내는 경우

= rest api 를 기반으로 client 의 ajax/axios 호출에 대한 결과를 return 할 때
=> JSP 를 사용하지 않는다. 대신에 등장하는 속성이 produces, @ResponseBody

정석은 ResponseEntity 라는 객체가 리턴되는 것이지만, Data 만을 리턴하는 케이스도 존재한다.
@ResponseBody 라는 어노테이션이 붙어있다면, 문자열만 리턴이 발생하더라도, view resolver 에 의해 jsp 파일을 찾는 것이 아니라 자체적으로 ResponseEntity 객체를 생성해 리턴한다.
이렇게 문자열만 리턴할 경우, 오직 데이터만을 리턴하게 되고, header 나 상태코드를 지정할 수 없게 된다.

String, 문자열만 반환했기 때문에 상태코드는 실제 처리 결과에 따른 코드인 200이 status line 내부에 찍히게 된다.

ResponseEntity<>() 의 생성자에는 data, headers, 상태를 순서대로 담는다.
그 중 상태는 상수값으로 미리 설정이 되어 있다.

httpStatus.CREATED = 201, 서버에서 무언가가 생성이 되었다는 것을 나타내는 상태코드

rest api 의 규약 중 하나로, 상태코드에는 서버에서의 처리 결과를 알아볼 수 있도록 적절한 코드로 리턴해주어야 한다.

browser 의 입장에서는 produces 에 씌여진 값에 의해 messageConverter 에 의해 변환되지만, 궁극적으로 ResponseEntity 의 header 의 content-type 으로 적혀져 있는 값으로 리턴되게 된다.

ResponseEntity 를 생성하여 return 하는 케이스

User 라는 VO객체를 return 하는 케이스

이 케이스에서는 리턴 타입과, produces 속성 값을 messageConverter 가 확인한 뒤, 내부적으로 데이터를 json-text-xml-img... 등으로 변환해서 반환하게 된다.


두 케이스의 responseBody 에 전달되는 data 는 동일하다. 다만 VO 객체를 리턴할 경우, 상태코드나 headers 의 설정이 default 값으로 설정되게 된다.

@RestController 라는 어노테이션을 이용하면, 기본적으로 jsp를 안쓰고 rest 방식으로 데이터를 리턴하겠다라는 의미이며, 의미적으로 @Controller@ResponseBody 라는 두 개의 어노테이션이 합쳐진 어노테이션이다.

ResponseEntity 가 handler adapter 에게 리턴될 때, messageConverter 라는 것이 존재하는데 사용자가 produces 에 지정한 content-type 에 맞춰서 데이터를 변환한 뒤 dispatcher servlet 에게 반환하게 된다.

REST API

일반적으로 유저는 Internet 이라는 물리적 platform 위에 www(world wide web) 이라는 service를 활용하고 있다.

SOAP

simple Object Access Protocol 기반의 web service.
이 방법은 http 이 아닌, SOAP 라는 프로토콜을 이용하겠다는 방식

이 방식의 장점은, 보안성과 데이터 무결성.
하지만, 단점으로 protocol 자체가 복잡하고, web 의 c/s 구조와 잘 맞지 않는다.

따라서 일반적인 web 이 아닌 일반적인 enterprise application에서 사용되는 케이스가 많다.

HTTP

HyperText Transfer Protocol 기반의 web service.

HTTP 라는 프로토콜은 web 의 구조와 상당히 잘 어울린다.

HTTP protocol 의 개발자 중 한 명(로이 필딩)이 현재의 프로토콜의 사용 방법에 의문을 품고, 훨씬 양질의 서비스를 구현할 수 있는 하나의 기준이자 가이드를 제시하게 된다. 이것을 아키텍처 라고 부르고, 그것의 이름이 REST 이다.

이러한 규칙을 잘 지켜서 만든 서비스를 RESTFUL 한 서비스이다, 라고 지칭하게 된다.

상세한 포스팅은 해당 링크로...

0개의 댓글