성장일기

내가 보려고 정리하는 공부기록

백엔드/스프링 MVC

[Spring MVC] 3. 요청 매핑하기 - (1) (@Controller와 @RestController, RequestMapping 사용, RequestParam)

와나나나 2024. 4. 7. 21:23
728x90

인프런 김영한 강사님의 스프링MVC 강의를 듣고학습한 내용을 정리한 게시물입니다.

https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81-mvc-1/dashboard

 

김영한 스프링 MVC 1편 - 백엔드 웹 개발 핵심 기술 강의 - 인프런

웹 애플리케이션을 개발할 때 필요한 모든 웹 기술을 기초부터 이해하고, 완성할 수 있습니다. 스프링 MVC의 핵심 원리와 구조를 이해하고, 더 깊이있는 백엔드 개발자로 성장할 수 있습니다., 원

www.inflearn.com

 

컨트롤러를 이용하여 요청을 전달받고, 웹페이지에 응답을 작성하거나 뷰를 반환하기도 한다. 요청을 전달받을 때, 우리는 특정 주소로 매핑을 해야하며, 웹페이지에 응답을 띄울지 뷰를 보여줄지 정해야한다.

 

1. @Controller와 @RestController

앞서 말했듯이 반환형식을 정해야하는데, 이때 @Controller와 @RestController를 알아야한다.

 

@Controller

@Controller는 반환 값이 String이면 뷰 이름으로 인식한다. 그래서 반환한 문자열과 같은 이름을 가진 뷰가 렌더링된다. 즉, 주로 뷰를 반환하기 위해 사용한다는 것이다.

 

예를 들어 아래 코드에서는 basic 패키지에 있는 items라는 뷰를 반환한다.

@Controller
@RequestMapping("/basic/items")
@RequiredArgsConstructor
public class BasicItemController {

    private final ItemRepository itemRepository;

    @GetMapping
    public String items(Model model) {
        List<Item> items = itemRepository.findAll();
        model.addAttribute("items", items);
        return "basic/items";
    }
    
    ...
}

 

참고로 응답으로 보여줄 뷰, 즉 동적html은 resource/templates 패키지에 넣어주면 된다. (내 IntelliJ 기준 ...)

 

찾아보니 @Controller로 뷰 뿐만 아니라 데이터를 반환할 수도 있다고 한다. return에 String타입을 쓰게 되면 뷰 이름으로 인식하지만, 객체를 반환하면 Json으로 바꾸어 반환할 수 있다고 한다!!

 

객체를 반환하기 위해서는 viewResolver가 아닌 HTTP 메시지 컨버터 (HttpMessageConverter)를 사용한다. 

 

HttpMessageConverter 인터페이스

public interface HttpMessageConverter<T> {


	boolean canRead(Class<?> clazz, @Nullable MediaType mediaType);

	boolean canWrite(Class<?> clazz, @Nullable MediaType mediaType);


	T read(Class<? extends T> clazz, HttpInputMessage inputMessage)
			throws IOException, HttpMessageNotReadableException;

	void write(T t, @Nullable MediaType contentType, HttpOutputMessage outputMessage)
			throws IOException, HttpMessageNotWritableException;
}

 

이 인터페이스는 요청, 응답에 모두 사용된다.

  • canRead(), canWrite() : 메시지 컨버터가 해당 클래스, 타입을 지원하는지 확인  ->> 사용전 체크할 때 좋을 것같다.
  • read(), write() : 메시지 컨버터를 통해 메시지 읽고 쓰는 기능

 

우리가 처리해아하는 데이터의 타입에 따라 사용되는 컨버터가 달라진다. 스프링 부투는 대상 클래스타입과 미디어타입을 체크해 사용 여부를 결정하게 된다.

 

몇가지 주요 메시지 컨버터를 알아보자

  • 기본 문자처리 (단순 문자열) : StringHttpMessageConverter
    • 클래스타입 : String, 미디어타입 : */* (암거나 가능하다는 뜻이다)
  • 객체처리 : MappingJackson2HttpMessageConverter
    • 클래스타입 : 객체 또는 HashMap,  미디어타입 : application/json 관련
  • 바이트배열 : ByteArrayHttpMessageConverter
    • 클래스타입 : byte[] , 미디어타입 : */*

 

@RestController

@RestController는 @Controller에 @ResponseBody가 추가된 것이다. 이는 반환 값으로 뷰를 찾는 것이 아니라, HTTP 메시지 바디에 바로 입력한다. 

 

 

이렇게 코드를 작성한다면 user() 가 실행되었을 때 Http 바디에 "get users"라는 문자가 띄워진다.

 

그럼 저 메소드가 언제 되는건데 ? 

 

 

2. @RequestMapping

@RequestMapping을 통해 요청과 메소드를 매핑할 수 있다. 주로 value와 method을 사용한다.

 

value ?

value에는 요청받을 url을 넣어준다.

 

method ?

method에는 어떤 요청을 받을지 넣어준다! POST, GET, DELETE같은..

메소드 속성을 지정하지 않으면 모두 허용하게 된다.

 

    @RequestMapping(value = "/hello-basic", method = RequestMethod.GET)
    public String helloBasic() {
        log.info("helloBasic");
        return "ok";
    }
    
    @GetMapping(value = "/hello-basic")
    public String helloBasic() {
        log.info("helloBasic");
        return "ok";
    }

 

첫 코드블럭처럼 value와 method 속성을 지정해도 되지만, 메소드에 따른 매핑 애노테이션이 따로 있다. GetMapping뿐만 아니라 PutMapping, PatchMapping, DeleteMapping 등 축약 애노테이션을 모두 제공한다!

 

 

속성은 value와 method를 가장 많이 사용하지만, 몇가지 더 소개하자면 아래와 같은 것들이 있다.

 

params

이 속성은 특정 파라미터 조건 매핑이다. 특정 파라미터가 있어야 매핑이 된다.

@GetMapping(value = "/mapping-param", params = "mode=debug")
public String mappingParam() {
	log.info("mappingParam");
    return "ok";
}

 

이런식으로 사용할 수 있다. 그러나 잘 사용하지는 않는다고 한다.

 

headers

이 속성은 특정 헤더 조건 매핑이다. 헤더에 특정 조건이 들어가있어야 하고 이는 postman으로 테스트 해야한다.

 

consumes, produces

이 속성들은 미디어 타입 조건 매핑이다. consumes는 받는 데이터타입을 지정하고, produces는 보내는 데이터 타입을 지정한다.

 

 

이번에는 사용자에게 입력받은 것을 파라미터로 쉽게 사용하는 방법을 작성하려 한다.

3. @RequestParam

이 애노테이션을 사용하면 요청 파라미터를 아주 편리하게 쓸 수 있다.

 

    @ResponseBody
    @RequestMapping("/request-param-v2")
    public String requestParamV2(@RequestParam("username") String username,
                                 @RequestParam("age") int age) {

        log.info("username = {}, age = {}", username, age);
        return "ok";

    }

    /*
    param이랑 이름 똑같이 지으면 생략 가능
     */
    @ResponseBody
    @RequestMapping("/request-param-v3")
    public String requestParamV3(@RequestParam String username,
                                 @RequestParam int age) {

        log.info("username = {}, age = {}", username, age);
        return "ok";

    }

 

@RequestParam() 안에 http 파라미터 이름을 써주고, 변수 이름도 별도로 사용할 수 있다. 만약 변수이름과 파라미터 이름이 같다면, ()내부를 생략하여 두번째 코드블럭처럼 써줄 수 있다.

 

이 애노테이션의 속성 중 required라는 속성을 이용해 해당 파라미터값의 필수 여부도 지정할 수 있다.

 

  • required=true : 파라미터 필수
  • required = false : 파라미터 필수 X

기본값은 true로 설정되어있다. 

 

만약 int인 age를 false로 지정하게 되면 null이 되었을 때 예외가 발생한다. int는 기본형이라 null이 들어올 수 없기 때문에!! 

이럴 경우에는 age의 타입을 Integer로 바꾸거나, defaultValue를 설정해주면 된다. 이것도 @RequestParam의 속성 중 하나이다.