티스토리 뷰
Global Setting관련해서는 GitHub를 확인해주세요. (JWT와 Security는 매우매우 중요해서 추후 블로그 올립니다.)
우린 컨트롤러부터 서비스 엔티티 순으로 내려가며 개발할 예정입니다. 그렇다면 여기서 의문이 생길겁니다.
왜 컨트롤러부터 개발하나요 ?
먼저 제 생각을 말씀드리면 개발 속도와 깔끔한 아키텍처를 위해서 입니다. 저희는 개발하면서 Entity를 먼저 개발해왔지만 그런식의 개발은 Entity에 의존적인 개발을 할 수 없게 만들고 Entity에 의존적인 개발을 한다는 것은 결국 데이터 중심의 애플리케이션 개발이기 때문에 객체 중심의 개발이 이루어지는 요즘과는 맞지 않습니다. 그렇기 때문에 이벤트 기반으로 먼저 개발을 진행한 후 이벤트에 필요한 속성들을 모아 Entity를 개발하는 것이 맞다고 생각하였습니다.
또한 인텔리제이를 사용중이면 option + enter 단축키로 자동완성을 사용하여 불필요한 타이핑도 줄일 수 있어 퍼포먼스에도 긍정적인 영향을 미칩니다. 이어서 FE랑 협업을 하더라도 금방 mock up이 나오기 때문에 장점이 굉장히 많습니다.
회원 domain Controller 개발
개발 시작전 패키지 구조는 다음과 같이 했습니다.
- global (config, globalException, security 등 공통 객체)
- domain
- Member
- entity
- persist (entity, Repository)
- vo (Enum, Embedded 타입)
- application (Service.java)
- controller (Controller.java)
- error (Exception.java)
- dto (Response/Request Dto)
- entity
- Member
전 현재 저렇게 작성했지만 다음을 더 추천드립니다.
- global
- domain
- Member
- dto
- error
- vo
- MemberController.java
- MemberService.java
- Member.java
- ...
- Member
사유는 불필요한 참조 (import)가 늘어나는 구조입니다. (위의 경우) 그렇기 때문에 불필요한 참조를 줄이기 위해 설계를 다르게 했습니다. 또한 Member에 속하는 하위 도메인도 Member에 포함될 예정입니다. (게시판에선 존재하지 않습니다.)
그러면 컨트롤러 코드를 보겠습니다.
@RestController
@RequiredArgsConstructor
@RequestMapping("/api/v1")
@Slf4j
public class MemberController {
private final MemberService memberService;
private final MemberReadService memberReadService;
// create
@PostMapping("/public/members")
public ResponseEntity<JoinResponse> create(@Valid @RequestBody JoinRequest request) {
return ResponseEntity.status(HttpStatus.CREATED).body(memberService.create(request.toEntity()));
}
// read
@GetMapping("/members/detail")
public ResponseEntity<MemberResponse> getDetailById() {
return ResponseEntity.ok().body(memberReadService.getDetailBy(this.getMemberId()));
}
// findAll
@GetMapping("/public/members")
public ResponseEntity<PageCustomResponse<MemberAllResponse>> getMembers(
@ModelAttribute MemberSearch memberSearch,
@PageableDefault(sort = "id", direction = Sort.Direction.DESC)Pageable pageable) {
return ResponseEntity.ok().body(memberReadService.getMembers(memberSearch, pageable));
}
// update
@PatchMapping("/members")
public ResponseEntity<Void> update(@Valid @RequestBody MemberUpdateRequest request) {
memberService.update(request.toEntity(), this.getMemberId());
return ResponseEntity.ok().build();
}
// delete
@DeleteMapping("/members")
public ResponseEntity<Void> delete() {
memberService.delete(this.getMemberId());
return ResponseEntity.noContent().build();
}
private Long getMemberId() {
log.debug("principal : {}", SecurityContextHolder.getContext().getAuthentication().getPrincipal().toString());
CustomUserDetails principal = (CustomUserDetails) SecurityContextHolder.getContext()
.getAuthentication().getPrincipal();
return principal.getId();
}
}
컨벤션을 준수하며 코딩하면 일관성 있고 더 좋은 코드를 작성할 수 있습니다.
https://google.github.io/styleguide/javaguide.html
코드 컨벤션 준수는 개발자의 기본입니다!!(매우 강조)
자 컨트롤러에서 주목할 것들을 짚어드리자면 다양한 DTO와 getMemberId() 메서드입니다. 기본적으로 수정 삭제 조회 로직에는 모두 memberId값은 필수입니다. 그치만 이 값들을 조회할 때 @PathVariable로 받아오면 쉽게 누구나 Id를 이용해 해당 api요청을 보내 수정이나 삭제할 수 있습니다. 그렇기 때문에 저희는 Security를 이용했습니다.
SecurityContextHolder.getContext().getAuthentication().getPrincipal();
는 Security 컨텍스트에 존재하는 UserDetails 객체를 Object 객체로 반환해줍니다. 또한 회원 토큰 정보로 들어온 정보기 때문에 절대 다른 회원이 접근할 수 없는 영역입니다. (해킹 제외) 이로써 회원들의 개인정보는 안전을 보장받을 수 있습니다.
이어서 DTO에 대해 설명드리겠습니다. DTO란 데이터 전달 객체로 외부에서 Json으로 데이터를 전달해주면 Json을 받아올 그릇이 필요합니다. 자바에선 보통 직렬화 하여 객체에 담아옵니다. 이 때 객체를 DTO라고 하는데요 자세한 건 다음 글을 참고해주시면 됩니다.
https://golf-dev.tistory.com/26
이어서 설명 드리면 DTO를 사용하면 다음과 같은 장점이 존재합니다.
1. Entity간 순환참조를 막을 수 있습니다.
2. 개발자가 직접 만든 객체기 때문에 명확한 이름을 지을 수 있다.
3. 어노테이션 기반으로 간편하게 validation이 가능하다.
4. 개발자가 직접 정의한 클래스이기 때문에 예외 상황에 대한 처리가 가능하다.
SecurityContextHolder.getContext().getAuthentication().getPrincipal(); 은 @AuthenticationPrincipal이라는 어노테이션으로 대체가 가능합니다.
궁금한점은 댓글 달아주시면 답글로 바로 답 해드리겠습니다!
'블로그 프로젝트' 카테고리의 다른 글
수 많은 요청에서 게시판 좋아요 기능의 데이터 정합성과 성능 개선하기 (0) | 2023.05.27 |
---|---|
[Spring boot + JPA] 게시판 프로젝트 - 회원 기능(레포지토리 개발) (0) | 2022.09.15 |
[Spring boot + JPA] 게시판 프로젝트 - 회원기능(엔티티 개발) (1) | 2022.09.12 |
[Spring boot + JPA] 게시판 프로젝트 - 회원기능(서비스 로직 개발 및엔티티 개발) (2) | 2022.08.29 |
[Spring boot + JPA] 블로그 프로젝트 시작 (설계 부터 세팅까지) (1) | 2022.08.15 |
- Total
- Today
- Yesterday
- Kotlin
- 개발자
- 인터뷰
- 취업준비
- 프로젝트
- 동시성
- Redis
- 면접
- MySQL
- IT
- swarm
- 코딩
- 개발
- 프로그래밍
- thread
- CS
- DB
- 면접준비
- 백엔드
- Spring
- 취준
- 취업
- 코드
- 자바
- java
- docker
- DevOps
- 게시판
- JPA
- 면접 준비
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |