본문 바로가기

Development/Spring

[Spring] Controller와 API 구현하기

Controller

  • 컨트롤러는 비즈니스 로직과 클라이언트의 요청을 연결하는 역할을 한다.
  • 즉 컨트롤러는 클라이언트로부터 받은 요청에 대해 서비스 레이어에 구현된 적절한 메서드를 호출해서 결괏값을 받는다.

@Controller와 @RestController

  • @Controller와 @RestController는 Spring Framework에서 웹 컨트롤러를 만들 때 사용되는 어노테이션이다.
  • 두 어노테이션 모두 컨트롤러 역할을 수행하지만 작동 방식과 처리하는 요청 유형에 있어 차이가 있다.

* 아래는 Google Gemini 답변입니다.

기능 @Controller @RestController
기능 웹 요청 처리 웹 요청 처리 및 JSON 응답 자동 생성
반환 값 View 객체, ModelAndView, String 등 객체 (JSON 형식으로 변환)
@ResponseBody 필요 (JSON 응답 시) 생략 가능 (기본적으로 JSON 응답)
기본 경로 /WEB-INF/views 하위 템플릿 파일 없음

 

@Controller:

  • 기본적인 웹 컨트롤러 역할을 수행합니다.
  • View 객체, ModelAndView, String 등을 반환하여 뷰를 렌더링합니다.
  • @ResponseBody 어노테이션을 사용하여 JSON 응답을 직접 생성할 수 있습니다.
  • 기본 경로/WEB-INF/views 하위 템플릿 파일입니다.

@RestController:

  • @Controller + @ResponseBody 어노테이션의 조합과 동일합니다.
  • 객체를 반환하면 자동으로 JSON 형식으로 변환하여 응답합니다.
  • @ResponseBody 어노테이션을 생략할 수 있습니다.
  • 기본 경로는 설정되지 않습니다.
  • @RestController는 @Component를 상속받기 때문에, 생성자 주입 시 @Autowired를 생략해도 스프링 컨테이너가 자동으로 의존성을 주입합니다.

@Controller와 @RestController의 동작 방식

@Controller

  • DispatcherServlet이 요청을 받아 컨트롤러에 매핑합니다.
  • 컨트롤러는 요청을 처리하고 View 객체, ModelAndView, String 등을 반환합니다.
  • ViewResolver는 반환된 값을 사용하여 뷰를 렌더링합니다.

@RestController

  • DispatcherServlet이 요청을 받아 컨트롤러에 매핑합니다.
  • 컨트롤러는 요청을 처리하고 객체를 반환합니다.
  • Jackson 라이브러리는 반환된 객체를 JSON 형식으로 변환합니다.
  • 변환된 JSON 응답은 클라이언트에게 전송됩니다.

HTTP Method별 어노테이션 선언

@GetMapping은 HTTP GET 요청을 처리하는 메서드에 사용되는 어노테이션입니다. 다음과 같은 정보를 제공합니다.

  • 요청 메서드: GET
  • 요청 URI: 메서드에 지정된 경로

@PostMapping은 HTTP POST 요청을 처리하는 메서드에 사용되는 어노테이션입니다. 다음과 같은 정보를 제공합니다.

  • 요청 메서드: POST
  • 요청 URI: 메서드에 지정된 경로
  • 요청 본문: 클라이언트에서 전송하는 데이터

@PutMapping은 HTTP PUT 요청을 처리하는 메서드에 사용되는 어노테이션입니다. 다음과 같은 정보를 제공합니다.

  • 요청 메서드: PUT
  • 요청 URI: 메서드에 지정된 경로
  • 요청 본문: 리소스를 업데이트하는 데 사용되는 데이터

@DeleteMapping은 HTTP DELETE 요청을 처리하는 메서드에 사용되는 어노테이션입니다. 다음과 같은 정보를 제공합니다.

  • 요청 메서드: DELETE
  • 요청 URI: 메서드에 지정된 경로

예시:

@RestController
public class MyController {

    @GetMapping("/")
    public String hello() {
        return "Hello, World!";
    }

    @PostMapping("/user")
    public User createUser(@RequestBody User user) {
        // 사용자 생성 로직
        return user;
    }

    @PutMapping("/user/{id}")
    public User updateUser(@PathVariable Long id, @RequestBody User user) {
        // 사용자 업데이트 로직
        return user;
    }

    @DeleteMapping("/user/{id}")
    public void deleteUser(@PathVariable Long id) {
        // 사용자 삭제 로직
    }
}

@PathVariable

  • @PathVariable 어노테이션은 Spring Boot에서 URL 경로의 일부를 메서드 매개 변수에 바인딩하는 데 사용된다.
  • 이를 통해 URL 경로에 포함된 동적 값을 메서드에서 사용할 수 있다.
@RestController
public class MyController {

    @GetMapping("/user/{id}")
    public User getUser(@PathVariable Long id) {
        // 사용자 ID로 사용자 정보를 조회하는 로직
        return user;
    }
}
  • 위 예시에서 @GetMapping 어노테이션이 지정된 getUser() 메서드는 /{id} 경로로 요청을 처리한다.
  • @PathVariable 어노테이션이 지정된 id 매개 변수는 URL 경로에서 {id} 부분의 값을 받아온다.

@RequestParam

  • @RequestParam 어노테이션은 HTTP 요청의 쿼리 파라미터 값을 메서드 매개 변수에 바인딩하는 데 사용된다.
  • URI에서 '?'를 기준으로 우측에'{Key}={value}' 형태로 구성된 요청을 처리한다.(쿼리 스트링)
@RestController
public class MyController {

    @GetMapping("/user")
    public User getUser(@RequestParam String name, @RequestParam int age) {
        // 사용자 이름과 나이로 사용자 정보를 조회하는 로직
        return user;
    }
}
  • 위 예시에서 @GetMapping 어노테이션이 지정된 getUser() 메서드는 /user 경로로 요청을 처리한다.
  • @RequestParam 어노테이션이 지정된 name과 age 매개 변수는 URL 쿼리 파라미터 name과 age의 값을 받아온다.
  • 따라서 URI는 /user?name=Kim&age=1 이 될 수 있다.
  • Map 객체를 사용하면 쿼리스트링에 어떤 값이 들어올지 모를때 유용히 사용할 수 있다.
// http://localhost:8080/api/v1/get-api/request2?key1=value1&key2=value2
@GetMapping(value = "/request2")
public String getRequestParam2(@RequestParam Map<String, String> param) {
    StringBuilder sb = new StringBuilder();

    param.entrySet().forEach(map -> {
        sb.append(map.getKey() + " : " + map.getValue() + "\n");
    });

    return sb.toString();
    }

POST API

  • POST API는 웹 애플리케이션을 통해 데이터베이스 등의 저장소에 리소스를 저장할 때 사용되는 API 이다.
  • GET API에서는 URL의 경로나 파라미터에 변수를 넣어 요청을 보냈지만, POST API에서는 저장하고자 하는 리소스나 값을 HTTP body에 담아 서버에 전달한다.

@RequestBody

  • @RequestBody 어노테이션은 HTTP 요청 본문을 Java 객체로 바인딩하는 데 사용된다.
  • Spring Boot는 요청 본문을 JSON, XML 등 다양한 형식으로 파싱하고 DTO 객체에 매핑할 수 있다.

 

Spring Boot는 기본적으로 다음과 같은 HttpMessageConverter를 자동으로 설정한다.

  • MappingJackson2HttpMessageConverter: JSON 형식 변환
  • XmlMappingJackson2HttpMessageConverter: XML 형식 변환
  • StringHttpMessageConverter: String 형식 변환
  • ByteArrayHttpMessageConverter: byte[] 형식 변환

 

Spring Boot는 다음과 같은 방식으로 HttpMessageConverter를 자동 설정한다.

  1. Content-Type 헤더: 요청의 Content-Type 헤더를 기반으로 적절한 HttpMessageConverter를 선택한다.
  2. Accept 헤더: 응답의 Accept 헤더를 기반으로 적절한 HttpMessageConverter를 선택한다.
// http://localhost:8080/api/v1/post-api/member2
@PostMapping(value = "/member2")
public String postMemberDto(@RequestBody MemberDto memberDTO) {
    return memberDTO.toString();
    }
  • 위 코드에서 @RequestBody는 HTTP body의 내용을 해당 어노테이션이 지정된 객체에 매핑하는 역할을 한다.
  • MemberDTO라는 객체와 body에 데이터를 매핑시키는데, 이 때 객체의 각 멤버 변수와 요청 메시지의 키가 같은 값 끼리 매핑한다.

PUT API

PUT API는 서버를 통해 데이터베이스 같은 저장소에 존재하는 리소스 값을 업데이트 하는 데 사용한다.

@PutMapping("/user/{id}")
public User updateUser(@PathVariable Long id, @RequestBody User user) {
    // 사용자 업데이트 로직
    return user;
}

HttpEntity와 ResponseEntity

  • HttpEntity는 Header와 Body로 구성된 Http 요청과 응답을 구성하는 역할을 수행한다.
  • RequestEntityResponseEntity는 HttpEntity를 상속받아 구현한 클래스입니다.
  • 그중 ResponseEntity는 서버에 들어온 요청에 대해 응답 데이터를 구성해서 전달할 수 있게 한다.
  • ResponseEntity는 HttpEntity로부터 HttpHeaders와 Body를 가지고 자체적으로 HttpStatus를 구현한다.
  • 이 클래스를 활용하면 응답 코드 변경과 Header, Body를 쉽게 구성할 수 있다.
// http://localhost:8080/api/v1/put-api/member3
@PutMapping(value = "/member3")
public ResponseEntity<MemberDto> postMemberDto3(@RequestBody MemberDto memberDto) {
    return ResponseEntity
        .status(HttpStatus.ACCEPTED)
        .body(memberDto);
}

위 메서드에서 ResponseEntity.status를 통해 202 응답 코드를 Header에 추가하고, Body에는 DTO객체를 담아서 요청에 응답을 보낸다.

DELETE API

  • DELETE API는 데이터베이스 등의 저장소에 있는 리소스를 삭제할 때 사용한다.
  • 서버에서는 클라이언트로부터 리소스를 식별할 수 있는 값을 받아 데이터베이스나 캐시에 있는 리소스를 조회하고 삭제하는 역할을 수행한다.
@DeleteMapping("/user/{id}")
public void deleteUser(@PathVariable Long id) {
    // 사용자 삭제 로직
}
// http://localhost:8080/api/v1/delete-api/request1?email=value
@DeleteMapping(value = "/request1")
public String getRequestParam1(@RequestParam String email) {
    return "e-mail : " + email;
}

참고자료