카테고리 없음

Controller & RestController

hojin98 2026. 1. 30. 14:54
"Controller & RestController"

 

 

백엔드와 프론트엔드의 역할이 분리됨에 따라 프론트엔드는 화면에 그려낼 Data가 필요한데(프론트는 Data를 가지고 있지 않음),

백엔드는 주로 이 Data를 JSON형식으로 내려준다.

 

 

 

(Model 대신 JSON 데이터를 프론트에게 응답하는 경우)

 

 

1. 클라이언트가 Request를 보내면 DispatcherServlet이 받음.

2. DispatcherServlet은 이 요청을 Handler Mapping을 통해서 해당 Controller에게 보냄

3. 해당 Controller가 이 요청을 처리하고 데이터(JSON형태)를 정제해서 보내줌

4. JSON 데이터를 DispatcherServlet이 클라이언트에게 Response로 내려가게 됨

 

 

 


 

1. @Controller 어노테이션

 

전통적인 Spring MVC의 컨트롤러인 @Controller는 주로 View를 반환하기 위해 사용한다.

 

 

 

 

2. @RestController 어노테이션

 

@RestController는 @Controller에 @Response Body가 추가된 것이다.

 

즉, @Controller가 주로 View를 반환할 때 쓰이지만, 만약에 @Response Body와 같이 쓴다면

@RestController와 똑같은 역할을 수행할 수 있다는 것이다.

 

 

@Response Body란?

 

  • Spring MVC 컨트롤러의 메서드에 사용되는 어노테이션
  • 이 어노테이션이 붙은 메서드가 반환하는 값은 View를 찾는데 사용되지 않고, HTTP 응답 본문(Response Body)에 직접 작성된다.
  • 즉, JSON형식으로 응답을 내려줄때 사용하는 것이 @Response Body 어노테이션이다.

 

 

 

 

"요청 매핑 어노테이션"

 

 

 

1. 기본 매핑 어노테이션(@RequestMapping)

 

특정 URL로 Request를 보내면 들어온 요청을 Controller 내부의 특정 Method와 Mapping하기 위해 사용한다.

 

 

  • 사용법 1
    • 해당 컨트롤러의 전체 경로  prefix를 설정한다.
    • prefix >> "접두"(접할 접, 머리 두) 한마디로 "가장 앞에 붙는 경로"

 

@RestController
@RequestMapping("/hello")
public class HelloController {

		// ...

}

 

이런 식으로 가장 먼저 오는 경로로 설정해줄 때 사용하고,

@RequestMapping("/hello") >> /hello가 가장 먼저 오는 경로로 설정

 

 

 

  • 사용법 2
    • 특정  API의 전체 경로를 허용

 

@RestController
public class HelloController {

		@RequestMapping(value = "/hello", method = RequestMethod.GET)
    public void getHello() {
		    // ...
    }
    
		@RequestMapping(value = "/hello", method = RequestMethod.POST)
    public void postHello() {
		    // ...
    }
    
		@RequestMapping(value = "/hello", method = RequestMethod.PUT)
    public void putHello() {
		    // ...
    }
    
		@RequestMapping(value = "/hello", method = RequestMethod.PATCH)
    public void patchHello() {
		    // ...
    }
    
		@RequestMapping(value = "/hello", method = RequestMethod.DELETE)
    public void deleteHello() {
		    // ...
    }
}

 

GET, POST, PUT, PATCH, DELETE 메서드를 설정해주고, 어떤 경로로 맵핑 해줄 것인지를 설정해주는 것이

@RequestMapping의 2번째 사용법이다.

 

 

사용법 2와 같은 방법은 거의 쓰이지 않으며, 대부분 사용법 1의 용도로 @RequestMapping 어노테이션을 활용한다.

 

 

 

사용법2는 HTTP 메서드별 전용 어노테이션으로 대체한다. 

 

 

 

 

 

 

"HTTP 전용 메서드별 전용 어노테이션"

 

 

주로 사용하는 HTTP 메서드로는 GET, POST, PUT, PATCH, DELETE가 있다.

(위에 나온 사용법2를 대체하는 어노테이션)

 

 

  • GET
    • @GetMapping을 사용
@RestController
public class HelloController {

    @GetMapping("/hello")
    public void getHello() {
		    // ...
    }
}

 

 

  • POST
    • @PostMapping을 사용
@RestController
public class HelloController {

    @PostMapping("/hello")
    public void postHello() {
		    // ...
    }
}

 

 

 

  • PUT
    • @PutMapping을 사용
@RestController
public class HelloController {

    @PutMapping("/hello")
    public void putHello() {
		    // ...
    }
}

 

 

  • PATCH
    • @PatchMapping을 사용
@RestController
public class HelloController {

    @PatchMapping("/hello")
    public void patchHello() {
		    // ...
    }
}

 

 

 

  • DELETE
    • @DeleteMapping을 사용
@RestController
public class HelloController {

    @DeleteMapping("/hello")
    public void deleteHello() {
		    // ...
    }
}

 

 

 


 

 

 

"데이터 전달 어노테이션"

 

 

 

 

1. 쿼리 파라미터 (Query Parameter, Query String)

2. 폼 데이터 (Form Data)

3. 경로 변수 (Path Variable)

4. 요청 본문 (Request Body)

 

 

 


 

1, 쿼리 파라미터 (@Request Param)

 

쿼리 파라미터는 URL의 ? 뒤에 오는 쿼리 파라미터들을 처리할 때 사용

예를 들어, GET/users?name = john & age 요청이 있다면, 이 중에서 ? 뒤에 오는

name = john,

age = 25

이것이 쿼리파라미터이다.(쿼리 스트링)

 

  • 기본 사용법
@RestController
public class UserController {
    
    // /users?name=john&age=30 요청이 들어온 상황이라면
    @GetMapping("/users")
    public String getUser(
				    @RequestParam String name, // name 값은 john
				    @RequestParam int age // age 값은 30
    ) {
				// ...
    }
}

 

/users?name=john&age=30 요청이 GET으로 들어온 상황이라고 가정해보면,

name = john이고, age = 30이라는 것을 꺼내서 쓸 수 있어야 한다.

 

실제 API의 주소는 /users까지기 때문에, @GetMapping("/users")라고 작성하고,

쿼리파라미터 john과 age를 꺼내와올 때는 @RequestParam을 사용한다.

 

@RequestParam String name, >> 이렇게 하면 john이 name이라는 변수 안에 Mapping됨.

@RequestParam int age; >> 30이라는 값이 age라는 변수 안에 Mapping됨

 

 

 

  • 선택적 파라미터와 기본값 설정
@RestController
public class UserController {
    
    // /users?page=1&size=10 요청이 들어온 상황이라면
    @GetMapping("/users")
    public List<String> getUsers(
            @RequestParam(defaultValue = "0") int page, // 1
            @RequestParam(defaultValue = "10") int size, // 10
            @RequestParam(required = false) String sort // null
    ) {
        // ...
    }
}

 

/users?page=1&size=10 요청이 GET으로 들어온 상황이라고 가정해보면,

 

Query Parameter는 들어오지 않아도 똑같은 API와 다름이 없다. 즉, ?page=1&size=10 이 쿼리파라미터가 없어도

@GetMapping("/users")에 들어오게 된다. Query Parameter는 있을 수도 있고, 없을 수도 있기 때문이다.

 

만약 쿼리파라미터가 없고 /users만 들어온 상태여도 defaultValue를 설정해줬기 때문에 괜찮다.

@RequestParam(defaultValue = "0") int page, >> defaultValue가 0이기 때문에, 만약 안들어온다면 1이 아니라 0으로 Mapping이 된다.

 

required = false로 설정하지 않으면 파라미터가 필수가 된다.

@RequestParam의 default required 값은 true이기 때문이다.

 

defaultValue를 설정하면 자동으로 required = false가 된다.

 

 

 

 


2. 폼데이터 or 쿼리파라미터 여러 개(@ModelAttribute)

 

HTML 폼 or 쿼리 파라미터 여러 개를 객체로 바인딩 할 때 사용한다,

@RequestParam을 여러 개 쓰는 대신 객체 하나로 받을 수 있다.

 

 

  • @RequestParam 여러 개를 @ModelAttribute 하나로 처리

 

@RequestParam을 여러개 사용

// @RequestParam이 너무 많은 경우
@GetMapping("/api/search")
public List<String> searchUsers(
        @RequestParam(required = false) String name,
        @RequestParam(required = false) String email,
        @RequestParam(required = false) Integer minAge,
        @RequestParam(required = false) Integer maxAge,
        @RequestParam(defaultValue = "0") int page,
        @RequestParam(defaultValue = "10") int size
) {
    // 파라미터가 많아서 복잡함!
}

// @ModelAttribute 사용 (추천)
@GetMapping("/api/search")
public List<String> searchUsers(@ModelAttribute UserSearchDto dto) {
    // 하나의 @ModelAttribute로 데이터를 받을 수 있다.
}

 

 

 

DTO (Data Tansfer Object) - 데이터를 옮기는 객체 (데이터를 Mapping해주기 위한, 담아주기 위한 클래스)

 

DTO클래스를 만들고, 위에 코드에서 맨 밑부분을 보면,

@ModelAttribute UserSearchDTO dto >> @ModelAttribute 어노테이션을 활용해 6개의 @RequestParam 필드들을

DTO 클래스로 한번에 묶어서 객체로 처리할 수 있게 된다.

// 바인딩용 DTO 클래스
public class UserSearchDto {
    private String name;
    private String email;
    private Integer minAge;
    private Integer maxAge;
    private Integer page = 0;      // 기본값 설정 가능
    private Integer size = 10;     // 기본값 설정 가능
    
    // ...
}

 

 

 


3. 경로 변수(@PathVariable)

 

 

 

URL의 경로의 일부를 변수로 받을 때 사용

GET/users/123 형태의 요청에서 123값을 받을 수 있다.

 

쿼리파라미터와 혼동하지 않도록 주의!

 

 

  • 기본 사용법
@RestController
public class UserController {
    
    // GET /users/123
    @GetMapping("/users/{userId}")
    public String getUser(@PathVariable Long userId) { // userId는 123
        // ...
    }
}

 

쿼리파라미터와 다른 점이, @GetMapping("/users/{userId}") >> { } 중괄호를 사용하여 받고 싶은 변수 명을 적어준다.

그 다음 @PathVariable Long userId >> 이렇게 해주면 userId 변수 안에 123이라는 값이 Mapping된다.

 

 

 

 

 


4. 요청 본문 (Request Body)

 

HTTP 요청의 본문(Body)에 있는 데이터를 객체로 전환할 때 사용한다.

주로 JSON형태의 데이터를 받을 때 사용하며, REST API에서 가장 많이 사용된다.

 

 

 

@RestController
public class UserController {
    
    // POST /users
    // Body: {"name": "John", "email": "john@example.com", "age": 30}
    @PostMapping("/api/users")
    public String createUser(@RequestBody CreateUserRequest request) {
        // ...
    }
}

 

위에 코드에서 Body : {"name" : "John", "email" : "john@example.com", "age" : 30} 이러한 JSON형태를 바디로 보낸다면,

@RequestBody로 받을 수 있다. 대신 Body의 값들은 객체이므로, 객체의 형태를 DTO클래스로 정의해줘야한다.

 

 

 

 

DTO 클래스 (CreateUserRequest)

@Getter
public class CreateUserRequest {
		// 위의 요청의 경우 아래와 같이 값이 매핑됩니다.
		private String name; // John
		private String email; // john@example.com
		private int age; // 30
}

 

 

이렇게 @RequestBody 어노테이션을 활용하여 데이터를 받아 올 수 있다.

 


 

 

 

 

"PathVariable과 RequestParam은 언제 어떤 것을 써야할까?"

 

 

 

  • PathVariable을 사용하는 경우
    • @PathVariable은 URL 경로 자체에 값이 포함되어 있기 때문에 반드시 값이 있어야 한다.
    • -> PathVariable은 생략되면 안되는 필수값이다.

 

 

GET /posts/123

GET /posts

 

 

만약, posts/123에서 /123을 삭제하면, /posts가 되어버리므로, 서로 다른 API가 된다.

 

 

 

  • @RequestParam을 사용하는 경우
    • @RequestParam은 쿼리 파라미터를 받아오게 되는데 각 Key / Value값은 조건부이다. 즉, 있어도 되고 없어도 되는 값일 때 사용한다. 주로 검색용에 많이 쓰인다.
    • -> 쿼리 파라미터가 있든 없든 동일한 API이다.

 

GET /users?nickname=스파르타

GET /users

GET /users?address=서울시

 

이 3개의 API는 다 같은 API이다, 그 이유는 @RequestParam(쿼리 스트링)을 사용하고 있는데, 쿼리 스트링은 조건부, 즉 있어도 되고 없어도 되는 값이므로, ?nickname = 스파르타, ?address = 서울시 이 두개의 쿼리 파라미터를 지워도

GET/users는 다 똑같다. 단지 조건(쿼리 파라미터)만 다를 뿐이다.

 

PathVariable은 생략될 수 없는 필수값 이기 때문에 삭제시 완전 다른 API가 되버리고, RequestParam의 쿼리 파라미터는 조건부이기 때문에 조건만 다를뿐, 다 같은 API이다.

 

 

 

 

 

 


 

***

RequestParam은 조건부이다, 즉 있어도 되고 없어도 되는데, 하지만 스프링에서 @RequestParam은 default로 required = ture로 되어 있기 때문에, 내가 @RequestParam에 대한 Key / Value를 조건부로 있어도 되고, 없어도 되게 설정을 하고 싶으면, 반드시 required = false라는 옵션을 작성 해야지만 진정한 조건부로 사용할 수 있다!