클라이언트 측의 요청을 직접 전달 받아 비즈니스 로직을 거친 후 만들어진 Model 데이터를 View로 전달
클라이언트로부터 받은 POST, PATCH, GET, DELETE 등의 요청을 각 핸들러 메서드와 매핑해서 로직을 수행
@RestController
@RequestMapping("/v1/members")
public class MemberController {
// logic
}
✔️ @RestController : 해당 메소드가 REST API의 리소스를 처리하기 위한 API엔드포인트로 동작함을 정의
➡️ 자동으로 Spring bean 등록
✔️ @RequestMapping(URL) : 클라이언트의 요청과 클라이언트 요청을 처리하는 핸들러 메서드를 매핑해주는 역할. 클래스 전체에 사용되는 공통 URL을 설정
@PostMapping
public ResponseEntity postMember(@RequestParam("name") String name) {
// post member logic
// 회원 등록
return ResponseEntity<>(response, HttpStatus.CREATED);
}
✔️ @PostMapping : POST 요청을 처리하는 핸들러 메서드와 매핑되는 어노테이션
✔️ @RequestParam : 핸들러 메서드의 파라미터의 종류, 클라이언트로부터 받은 파라미터를 변수로 사용
✔️ @ResponseEntity : 메소드에서 JSON 문자열을 리턴하는 대신 ResponseEntity 객체를 리턴
❗️HTTP 응답 상태를 함께 리턴함으로써 좀 더 명확한 결과를 알려줌
@PatchMapping("/{member-id}")
public ResponseEntity updateMember(@PathVariable("member-id") long memberId) {
// patch(update) member logic
// 회원 정보 수정 -> id가 memberId인 회원 정보 수정
return ResponseEntity<>(response, HttpStatus.OK);
}
✔️ @PatchMapping : PATCH 요청을 처리하는 핸들러 메서드와 매핑되는 어노테이션
✔️ @PathVariable : 핸들러 메서드의 파라미터의 종류, 전달받은 URL을 변수로서 사용
❗️핸들러 메서드의 URL 문자열과 동일해야함
@GetMapping
public ResponseEntity getAllMembers() {
// get member logic
// 전체 회원 조회
return ResponseEntity<>(HttpStatus.OK);
}
@GetMapping("/{member-id}")
public ResponseEntity getMember(@PathVariable("member-id") long memberId) {
// get member logic
// 특정 회원 정보 조회 -> id가 memberId인 회원 정보 조회
return ResponseEntity<>(HttpStatus.OK);
}
✔️ @GetMapping : GET 요청을 처리하는 핸들러 메서드와 매핑되는 어노테이션
@DeleteMapping("/{member-id}")
public ResponseEntity deleteMember(@PathVariable("member-id") long memberId) {
// member delete logic
// 특정 회원 삭제 -> id가 memberId인 회원 삭제
return ResponseEntity<>(HttpStatus.NO_CONTENT);
}
✔️ @DeleteMapping : DELETE 요청을 처리하는 핸들러 메서드와 매핑되는 어노테이션
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/v1/members")
public class MemberController {
@PostMapping
public ResponseEntity postMember(@RequestParam("name") String name) {
// post member logic
// 회원 등록
return ResponseEntity<>(response, HttpStatus.CREATED);
}
@PatchMapping("/{member-id}")
public ResponseEntity updateMember(@PathVariable("member-id") long memberId) {
// patch(update) member logic
// 회원 정보 수정 -> id가 memberId인 회원 정보 수정
return ResponseEntity<>(response, HttpStatus.OK);
}
@GetMapping
public ResponseEntity getAllMembers() {
// get member logic
// 전체 회원 조회
return ResponseEntity<>(HttpStatus.OK);
}
@GetMapping("/{member-id}")
public ResponseEntity getMember(@PathVariable("member-id") long memberId) {
// get member logic
// 특정 회원 정보 조회 -> id가 memberId인 회원 정보 조회
return ResponseEntity<>(HttpStatus.OK);
}
@DeleteMapping("/{member-id}")
public ResponseEntity deleteMember(@PathVariable("member-id") long memberId) {
// member delete logic
// 특정 회원 삭제 -> id가 memberId인 회원 삭제
return ResponseEntity<>(HttpStatus.NO_CONTENT);
}
}
Data Transfer Object, 데이터를 전송하기 위한 객체
DTO 클래스를 이용한 코드의 간결성
클라이언트로부터 전달받는 파라미터의 개수가 늘어나는 경우 코드가 길어짐
➡️ 하나의 객체로 받아서 간결하게 해결하자❗️
데이터 유효성 검증의 단순화
전달받은 데이터의 validation 검증 로직이 핸들러 메소드 내에 있는 경우, 검증 항목이 늘어날수록 코드 복잡해짐
➡️ 유효성 검사 로직을 외부로 빼서 핸들러 메소드를 간결하게 하자❗️
❗️DTO는 Post, Patch, Response(리턴값) 등 데이터가 사용되는 클래스별로 필요 ➡️ DTO 클래스의 단점!
❗️주의할 점 : DTO 클래스에서는 필드 각각 getter가 반드시 필요함 (없으면 Response Body에 해당 멤버 변수의 값이 포함되지 않는 문제 발생, setter 는 필수 x)
Post 핸들러 메서드의 인자로 들어오는 데이터를 위한 클래스
// PostDTO class
public class MemberPostDto {
@NotBlank
@Email
private String email;
@NotBlank
private String name;
@Pattern(regexp = "^010-\\d{3,4}-\\d{4}$")
private String phone;
}
// Controller
@PostMapping
public ResponseEntity postMember(@Valid @RequestBody MemberPostDto memberPostDto) {
Member member = mapper.memberPostDtoToMember(memberPostDto);
Member response = memberService.createMember(member);
return new ResponseEntity<>(mapper.memberToMemberResponseDto(response), HttpStatus.CREATED);
}
✔️ @NotBlank : null
, ""
, " "
을 허용하지 않는 어노테이션
✔️ @Email : 이메일 형식 지정 어노테이션
✔️ @Pattern : 정규표현식 지정 어노테이션
✔️ @RequestBody : JSON 형식의 Request Body를 Dto 클래스의 객체로 변환
✔️ @ResponseBody : Dto 클래스의 객체를 Response Body로 변환
❗️핸들러 메서드의 리턴 값이 ResponseEntity인 경우 내부적으로 DTO 클래스의 객체를 JSON 형식으로 바꿔주기 때문에 따로 작성하지 않음
✔️ @Valid : Dto 클래스에서 유효성 검증 로직이 실행되도록 하는 어노테이션
Patch 핸들러 메서드의 인자로 들어오는 데이터를 위한 클래스
// PatchDTO class
@Getter
@Setter
public class MemberPatchDto {
private long memberId;
@NotSpace
private String name;
@Pattern(regexp = "^010-\\d{3,4}-\\d{4}$")
private String phone;
}
// Controller
@Validated
public class MemberController {
...
@PatchMapping("/{member-id}")
public ResponseEntity updateMember(@PathVariable("member-id") @Positive long memberId,
@Valid @RequestBody MemberPatchDto memberPatchDto) {
Member member = mapper.memberPatchDtoToMember(memberPatchDto);
Member response = memberService.updateMember(member);
return new ResponseEntity<>(mapper.memberToMemberResponseDto(response), HttpStatus.OK);
}
}
✔️ @Validated : @PathVariable이 추가된 변수의 유효성 검증 수행을 위한 어노테이션
✔️ @NotSpace : Custom Validator 어노테이션
지금까지 사용한 validator ➡️ Jakarta Bean Validation에 내장된 어노테이션
(Jakarta Bean Validation : 유효성 검증을 위한 표준 스펙에서 지원하는 내장 어노테이션들. API가 아닌 스펙(사양)자체 ➡️ 구현체 따로 있음! ex.Hibernate Validator)
Jakarta Bean Validation에 목적에 맞는 어노테이션이 없으면?? 만들어서 사용하자!