Control 레이어 – 입력과 출력 담당

클라이언트가 http를 요청시 요청을 처리하고 응답을 해주는 레이어이다. 로직이 복잡해지면 비즈니스 레이어를 추가할 수 도있고, DB 를 처리한다면 persistence 레이어가 더 추가될 수 있다. 디자인 패턴이란게 정답이 있는게 아니므로, 무조건 컨트롤 레이어, 비즈니스 레이어, persistence 레이어가 있어야 한다고 생각하지말고 어떻게 하는게 좀 더 확장성 있고 유지보수성이 있는지 생각해보고 받아들이자.

컨트롤 레이어에서는 http request 시 입력데이터가 어떤 형태로 오는지 response 시 데이터가 어떤 형태로 나가는지를 유의깊게 봐야한다.

컨트롤 레이어를 담당할 controller 패키지를 추가한다. com.eastflag.fullstack 패키지를 선택후 우클릭후 new -> package 를 누른 다음 controller를 입력한다.

HelloController 자바 클래스를 만든다. controller 패키지를 선택 후 우클릭 new -> Java Class 후 HelloController를 입력한다

모든 http 메서드 허용

HelloController에 아래와 같이 작성한다.

빨간색이 뜨면 import 가 되지 않은것이다. Alt-Enter를 눌러서 자동 import 해준다.

@RestController annotation은 안드로이드 등 모바일의 사용성이 높아지면서 4.x에 처음으로 도입된 기능으로 웹페이지를 리턴해주는게 아니라 json, xml 등의 Resource를 리턴해줄수 있도록 해주는 기능이다.

RequestMapping의 의미는 받아들이는 url 경로를 의미한다. 호스트가 localhost이므로 http://localhost:8080/hello가 url 주소값이 된다. 그리고 리턴타입은 스트링이므로 이 유알엘을 호출하면 hello test라는 스트링값이 리턴된다. 리스타트 후 브라우저에서 테스트해본다.

http://localhost:8080/hello

브라우저에 Hello test라고 출력되면 정상동작이다. 브라우저에서 하는 모든 호출은 GET 방식인데, 위 API는 모든 메서드를 받아들이기 때문에 가능하다.

postman으로 GET 방식을 테스트해서 아래와 같이 body 부분이 나오면 정상이다.

이번에는 POST로 테스트해보자.

잘된다. 그 이유는 @RequestMapping이 모든 HTTP 메서드를 혀용해주기 때문이다.

GET 만 허용

hello2() 메서드를 추가하고 RequestMapping을 GetMapping으로 바꾸고 url 주소도 hello2로 변경한다.

이 API를 postman 으로 GET으로 테스트하면 상태코드 200이 리턴될 것이다.

하지만, post를 테스트하면 결과는 http 상태코드가 405번 method not allowed가 나온다. 405 상태코드는 Get 메서드만 허용되었는데 Post 메서드로 호출하였다는 얘기다. 이 에러코드는 웹서버에서 해당 에러를 감지해서 보냈기 때문에 http 에러 코드만 보면 어떤 에러인지를 알 수 있다. 왜냐하면 이것이 http 표준 프로토콜 이기 때문이다.

rfc2616 문서중 10절 에러 코드 내용을 살펴보면 다음과 같다.

GET 메서드 + query parameter

hello3() 메서드를 추가하고 url 주소도 hello3로 변경한다.

GET과 POST의 가장 큰 차이점은 GET은 request 시에 Header만 존재하고 Body가 없다는 것이다. 그러므로 URL 뒤 ? 다음에 key=value&key=value… 이런식으로 key=value를 &로 연결해서 데이터를 보낸다. 이것을 query 파라메터라고 한다.


서버에서는 @RequestParam 어노테이션을 사용해서 query parameter에서 넘어온 key에 해당하는 값을 꺼내서 할당한다.

postman으로 테스트해보자.

GET 메서드 + uri parameter

query parameter 와 uri parameter는 사실상 동일하다. 단지 표현 방식에만 차이가 있을 뿐이다. 예를 들어서 name 이라는 키에 gildong 이라는 value를 보낼려면 query paramter 방식에서는 name=gildong 으로 보내게 되는데 uri parameter 방식에서는 /gildong 으로 보내게 된다. key는 서버에서 /{name} 으로 받게된다.

uri parameter 는 @Pathvariable 어노테이션을 사용하여 받는다.

http://localhost:8080/hello32/gildong 이렇게 테스트해보자. gildong 이 uri parameter 의 value에 해당된다. 서버에서는 {name}으로 지정했으므로 name이라는 key에 gildong이 할당되게 된다.

POST + query parameter

이 부분이 아마 웹개발하면서 많이 개발자들이 오해하는 부분이다. Get은 Query Parameter를 사용하고 Post는 body에 데이터를 보내야 한다고 알고 있다면 그것은 잘못된 생각이다.

Get은 Request시에 body에 데이터를 보낼수가 없다. 그래서 Get은 Query Parameter 밖에 사용할 수가 없다. 하지만 Post는 body에 데이터를 담아서 보낼수 있으므로 body로 데이터를 보내지만 그렇다고 Query Parameter로 데이터를 보낼수 없는것이 아니다.

이 예제는 Post 메서드로 보내면서 Query Parameter로 데이터를 보내는 예제이다.  Query Parameter 는 Url을 정의하는 규격일 뿐이다.

postman으로 테스트한 결과는 다음과 같다.

POST

웹에서 회원가입이나 혹은 로그인 화면 같은데서 input 박스에 값을 넣고 submit 버튼을 누르면 POST방식으로 전송이 되고 input에 담긴 데이터들은 x-www-form-urlencoded 방식으로 body에 담겨서 전송 된다. 이것을 구현해본다.

request body에 들어오더라도 스프링에서는 여전히 @RequestParam으로 데이터를 매핑한다.

이것을 postman으로 테스트를 할려면 다음과 같이 해야 한다.

URL뒤에 파라메터를 붙이는게 아니라 body에 name=gildong을 postman에서 넣는 방법은 Body를 선택하고 x-www-form-urlencoded를 선택하고 key와 value에 각각 name, gildong을 넣는다. x-www-form-urlencoded라는 것은 내가 body에 보내는 데이터 타입이 form 방식이라는것을 명시하는것이다.

SEND 버튼을 누르기 전에 fiddler를 켜두고 패킷을 캡쳐해서 확인해보면 다음과 같다.

request 헤더의 Content-Type이 application/x-www-form-urlencoded 라고 되어있는 부분을 유의깊게 보자. Content-Type이 의미하는것은 Body에 담긴 데이터의 Media type이 x-www-form-urlencoded 타입이라는 것을 명시하게 되고 서버에서는 Content-Type을 먼저 일고 해당 Body를 처리하게 된다. 만약 이 type이 맞지 않게 되면 415 Unsupported Media Type 에러가 나게 된다.