2023-09-29 작성

스프링 @어노테이션 기본적인 사용법 알기

이번 포스팅에서는 기본적인 스프링 어노테이션 사용법을 연습해 볼 것이다. 헷갈리는 어노테이션들이 많으니 예제를 보며 감을 익히는 것을 추천한다.

@Controller

@Controller 어노테이션은 HTTP 요청을 처리하는 컨트롤러를 의미하며, Spring MVC 뷰를 반환하는 데 사용된다. 즉 View(화면)을 리턴할 때 쓰인다. 

아래의 예시처럼 리턴 타입이 String인 경우 src/main/resources/templates 경로에서 리턴값이 "home".html 파일을 찾아서 해당 뷰를 보여준다.

HomeController.java

@Controller
public class HomeController {

	@GetMapping(value = "/")
	public String home() {
		return "home"; // src/main/resources/templates/home.html 반환
	}
}

@RestController

@RestController는 @Controller + @Responsebody를 합친 것이라고 생각하면 된다.

@RestController 어노테이션은 RESTful 웹 서비스를 위한 컨트롤러를 의미하며, RESTful 웹 서비스의 JSON, XML 등의 응답을 반환하는 데 사용된다. @Controller와 달리 view 화면을 리턴하지 않고, 컨트롤러에서 Data를 리턴할 수 있다.

아래의 예시처럼 객체 데이터를 반환하기만 하면, JSON, XML 형식으로 HTTP 응답하게 된다.

HomeController.java

@RestController
public class HomeController {

	@GetMapping(value = "/")
	public BoardVO home() {
		return new BoardVO("제목", "내용");
	}
}

BoardVO.java

@AllArgsConstructor
@Getter
public class BoardVO {
	String title; // 제목
	String content; // 내용
}

아래와 같이 json 형식으로 데이터가 출력된다.

@Controller과 @RestController의 차이

@Controller는 일반적으로 HTTP 요청을 처리하고 뷰를 반환하는 데 사용된다.
@RestController는 HTTP 요청에 대한 RESTful 웹 서비스의 JSON, XML 등의 응답을 반환하는 데 사용된다.

경로 매핑(mapping)

아래 어노테이션들은 특정 경로(URL)를 매칭하는데 쓰인다.

어노테이션 HTTP 역할 예시
@RequestMapping ALL 요청 메서드와 URL 매핑을 함께 지정 @RequestMapping(value="/users", method=RequestMethod.GET)
@GetMapping GET 리소스 조회 @GetMapping(value="/users")
@PostMapping POST 리소스 생성 @PostMapping(value="/users")
@PutMapping PUT 리소스 갱신 @PutMapping(value="/users")
@PatchMapping PATCH 리소스 일부 갱신 @PatchMapping(value="/users")
@DeleteMapping DELETE 리소스 삭제 @DeleteMapping(value="/users")

@RequestMapping과 @XXMapping 중 무엇을 사용해야 할까?

간단한 HTTP 요청에 대해서는 @XXMapping을 사용하는 것이 코드 가독성과 유지보수성을 높일 수 있다. 하지만 여러 개의 HTTP 요청 메서드에 대해 하나의 메서드로 처리해야 하는 경우는 @RequestMapping을 사용해야 한다.

@RequestMapping(value="/users", method=RequestMethod.GET)
public String home() {
	return "home";
}

@GetMapping(value = "/")
public String home() {
	return "home";
}

요청 데이터 관련

@PathVariable

'URL 경로의 일부'를 매개변수로 전달받는 어노테이션이다. 예를 들어 http://localhost:8080/users/test123 로 호출하면 입력값인 'test123'을 매개변수로 받게 된다.

@RestController
@Slf4j
public class HomeController {

	@GetMapping("/users/{id}")
	public void getUserById(@PathVariable String id) {
		log.info(id); // 출력 결과 : test123
	}
}

@RequestParam

'HTTP 요청 파라미터'를 매개변수로 전달받는 어노테이션이다. 예를 들어 http://localhost:8080/users?name=개발새발 로 호출하면 key, value 형식에 따라 키값인 name에 맞는 '개발새발'을 매개변수로 받게 된다.

@RestController
@Slf4j
public class HomeController {

	@GetMapping("/users")
	public void getAllUsers(@RequestParam("name") String name) {
		log.info(name); // 출력 결과 : 개발새발
	}
}

@RequestBody

HTTP 요청의 '본문(body)'을 매개변수로 전달받는 어노테이션이다. 주의할 점은 GET 통신에서는 @RequestParam을 사용하지만, POST 통신에서는 @RequestBody를 사용한다. 따라서 POST 통신으로 전송하기 위해 home.html에 소스를 추가할 것이다.

home.html

<!DOCTYPE html>
<html lang="ko">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
</head>
<script type="text/javascript">
function createUser() {
	const requestData = new Object();
	requestData.userId = document.getElementById("userId").value;
	requestData.userNm = document.getElementById("userNm").value;
	
	const httpRequest = new XMLHttpRequest();
	httpRequest.open('POST', '/users', true);
	httpRequest.responseType = "json";
	httpRequest.setRequestHeader('Content-Type', 'application/json');
	httpRequest.send(JSON.stringify(requestData));
}
</script>
<body>
	<form>
		<table>
			<thead>
				<tr>
					<th>아이디</th>
					<th>이름</th>
				</tr>
			</thead>
			<tbody>
				<tr>
					<td><input type="text" id="userId" /></td>
					<td><input type="text" id="userNm" /></td>
				</tr>
			</tbody>
		</table>
		 <button onclick="createUser()">등록</button>
	</form>
</body>
</html>

위 소스를 실행하면 아래처럼 보여진다. 아이디와 이름을 입력하고 등록 버튼 클릭 시, POST 방식으로 json 문자열 데이터를 HTTP 요청으로 보내면 @RequestBody 어노테이션을 통해 객체 데이터를 매개변수로 전달받게끔 구현하고자 한다. 

UserVO.java

@Getter
public class UserVO {
	String userId; // 아이디
	String userNm; // 이름
}

HomeController.java

@RestController
@Slf4j
public class HomeController {

	@PostMapping("/users")
	public void createUser(@RequestBody UserVO userVO) {
		log.info(userVO.getUserId() + "/" + userVO.getUserNm()); // 출력 결과 : test123 / 개발새발
	}
}

응답 데이터 관련

@ResponseBody

HTTP 응답의 본문(body)을 생성하는 메서드에 적용하는 어노테이션이다. 위에서 언급했듯이 @Controller + @Responsebody를 합친 것이 @RestController 이다. 추가 관련 내용은 @RequestBody / @ResponseBody 어노테이션 포스팅을 읽어보자.

@Controller
public class HomeController {
	
	@GetMapping("/data")
	public @ResponseBody List<String> getData() {
		List<String> list = new ArrayList<>();
		list.add("차은우");
		list.add("카리나");
		list.add("혜인");
		
		return list; 
	}
}

출력 결과

@ResponseStatus

HTTP 응답의 상태 코드를 지정하는 어노테이션이다.

@RestController
public class HomeController {
	
	@GetMapping("/users/{id}")
	@ResponseStatus(HttpStatus.NOT_FOUND)
	public void getUserById(@PathVariable String id) {
	}
}

http 상태 코드는 HttpStatus 클래스에 따라 구체적으로 정의되고 있다.

@ResponseEntity

보통 RESTful API를 개발할 때 클라이언트와 서버 간의 통신에 필요한 정보를 제공해야 한다. 그럴 때 ResponseEntity를 사용하여, 적절한 정보를 생성해서 클라이언트에 전달할 수 있다. HTTP Response 메시지를 감싸는 어노테이션이므로 HTTP 상태코드, 응답 헤더, 응답 본문 데이터 등을 포함하여 전달하면 된다. 추가적인 내용은 ResponseEntity를 잘 쓰는 방법 포스팅을 참고하자.

@RestController
public class HomeController {
	
	@GetMapping("/user")
	public ResponseEntity<User> getUser() {
		User user = userService.getUser();
		return ResponseEntity.ok(user); // 성공을 의미하는 OK(200 code)와 함께 user 객체 리턴
	}
}

MVC 패턴으로 REST API 개발 예시

  • @Controller : 웹 화면(view)을 보여준다.
  • @RestController <---> @Service <---> @Mapper : 클라이언트에서 요청한 데이터를 가져와서 응답한다.
  • @Autowired : 보통 bean에 의존성 주입을 하고 싶을 때 사용한다. Spring Container가 관리하며, 이 어노테이션을 붙여주어야 두 클래스의 의존관계가 형성된다.