[section 3] Spring MVC - API 계층(2) - Controller, DTO

수경·2022년 12월 25일
0

코드스테이츠

목록 보기
42/57

Controller

클라이언트 측의 요청을 직접 전달 받아 비즈니스 로직을 거친 후 만들어진 Model 데이터를 View로 전달

클라이언트로부터 받은 POST, PATCH, GET, DELETE 등의 요청을 각 핸들러 메서드와 매핑해서 로직을 수행

Controller 클래스

@RestController
@RequestMapping("/v1/members")
public class MemberController {
	// logic
}

✔️ @RestController : 해당 메소드가 REST API의 리소스를 처리하기 위한 API엔드포인트로 동작함을 정의
➡️ 자동으로 Spring bean 등록

✔️ @RequestMapping(URL) : 클라이언트의 요청과 클라이언트 요청을 처리하는 핸들러 메서드를 매핑해주는 역할. 클래스 전체에 사용되는 공통 URL을 설정

POST

@PostMapping
public ResponseEntity postMember(@RequestParam("name") String name) {
	// post member logic
    // 회원 등록
    return ResponseEntity<>(response, HttpStatus.CREATED);
}

✔️ @PostMapping : POST 요청을 처리하는 핸들러 메서드와 매핑되는 어노테이션

✔️ @RequestParam : 핸들러 메서드의 파라미터의 종류, 클라이언트로부터 받은 파라미터를 변수로 사용

✔️ @ResponseEntity : 메소드에서 JSON 문자열을 리턴하는 대신 ResponseEntity 객체를 리턴
❗️HTTP 응답 상태를 함께 리턴함으로써 좀 더 명확한 결과를 알려줌

PATCH

@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 문자열과 동일해야함

GET

@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 요청을 처리하는 핸들러 메서드와 매핑되는 어노테이션

DELETE

@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);
    }
}

DTO

Data Transfer Object, 데이터를 전송하기 위한 객체

DTO의 필요성

  1. DTO 클래스를 이용한 코드의 간결성
    클라이언트로부터 전달받는 파라미터의 개수가 늘어나는 경우 코드가 길어짐
    ➡️ 하나의 객체로 받아서 간결하게 해결하자❗️

  2. 데이터 유효성 검증의 단순화
    전달받은 데이터의 validation 검증 로직이 핸들러 메소드 내에 있는 경우, 검증 항목이 늘어날수록 코드 복잡해짐
    ➡️ 유효성 검사 로직을 외부로 빼서 핸들러 메소드를 간결하게 하자❗️

❗️DTO는 Post, Patch, Response(리턴값) 등 데이터가 사용되는 클래스별로 필요 ➡️ DTO 클래스의 단점!

❗️주의할 점 : DTO 클래스에서는 필드 각각 getter가 반드시 필요함 (없으면 Response Body에 해당 멤버 변수의 값이 포함되지 않는 문제 발생, setter 는 필수 x)

PostDto

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 클래스에서 유효성 검증 로직이 실행되도록 하는 어노테이션

PatchDto

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 어노테이션

Custom Validator

지금까지 사용한 validator ➡️ Jakarta Bean Validation에 내장된 어노테이션
(Jakarta Bean Validation : 유효성 검증을 위한 표준 스펙에서 지원하는 내장 어노테이션들. API가 아닌 스펙(사양)자체 ➡️ 구현체 따로 있음! ex.Hibernate Validator)

Jakarta Bean Validation에 목적에 맞는 어노테이션이 없으면?? 만들어서 사용하자!

profile
어쩌다보니 tmi뿐인 블로그😎

0개의 댓글