728x90
320x100
[사용기술]
Java, Spring Boot, Spring JPA, MySQL
[만들려는 것]
책을 위한 SNS.
[오늘 하려는 것]
회원(Member) 등록/수정/조회 API 개발
MemeberApiController.java
1.회원가입
package seulgi.bookbookclub.api;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.*;
import seulgi.bookbookclub.domain.Member;
import seulgi.bookbookclub.dto.*;
import seulgi.bookbookclub.service.MemberService;
import java.util.List;
import java.util.stream.Collectors;
@RestController
@RequiredArgsConstructor
@RequestMapping("/api/members")
public class MemberApiController {
private final MemberService memberService;
//회원가입
@PostMapping
public CreateMemberResponse saveMember(@RequestBody CreateMemberRequest request){
Member member = new Member(request.getMemberId(), request.getName()
, request.getNickName(), request.getInfo());
Integer seq = memberService.join(member);
return new CreateMemberResponse(seq);
}
///소스생략////
}
- 엔티티를 직접 받아오지 않고 CreateMemberRquest 객체를 생성하여 한번 감싸서 가져오고, CreateMemberResponse 객체도 생성하여 보여줄 때도 한 번 감싸서 보여줌.
- 왜 별도의 객체를 생성하여 감싸 가져오고 보여주나요? : 엔티티 객체를 그대로 사용하게 되면 엔티티가 변경될 때 난감해지고, 또 API의 스펙은 너무 다양한데 엔티티가 그걸 모두 수용할 수 없음.
CreateMemberRequest.java
package seulgi.bookbookclub.dto;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
public class CreateMemberRequest {
private String memberId;
private String name;
private String nickName;
private String info;
}
CreateMemberResponse.java
package seulgi.bookbookclub.dto;
import lombok.Data;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
public class CreateMemberResponse {
private Integer memberSeq;
public CreateMemberResponse(Integer memberSeq) {
this.memberSeq = memberSeq;
}
}
(+) MemberService.java 수정
package seulgi.bookbookclub.service;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import seulgi.bookbookclub.domain.Member;
import seulgi.bookbookclub.repository.MemberRepository;
import java.time.LocalDateTime;
import java.util.List;
@Service
@Transactional(readOnly = true)
@RequiredArgsConstructor
public class MemberService {
private final MemberRepository memberRepository;
//회원가입
@Transactional
public Integer join(Member member){
validateDuplicatieMember(member);
memberRepository.save(member);
return member.getMemberSeq();
}
//소스생략//
}
- 회원 가입 후에 String 타입의 멤버 아이디를 반환했었는데 고유한 값을 반환하는 것이 맞다고 판단되어 시퀀스를 반환하는 것으로 변경하였음.
회원등록(가입)API 테스트
포스트맨을 통해서 테스트하였음.
MemeberApiController.java
2. 회원수정
package seulgi.bookbookclub.api;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.*;
import seulgi.bookbookclub.domain.Member;
import seulgi.bookbookclub.dto.*;
import seulgi.bookbookclub.service.MemberService;
import java.util.List;
import java.util.stream.Collectors;
@RestController
@RequiredArgsConstructor
@RequestMapping("/api/members")
public class MemberApiController {
private final MemberService memberService;
//소스생략//
//회원가입
@PostMapping
public CreateMemberResponse saveMember(@RequestBody CreateMemberRequest request){
Member member = new Member(request.getMemberId(), request.getName()
, request.getNickName(), request.getInfo());
Integer seq = memberService.join(member);
return new CreateMemberResponse(seq);
}
//소스생략//
}
- 회원 수정도 업데이트용 요청객체와 응답객체를 별도로 생성하였음.
UpdateMemberRequest.java
package seulgi.bookbookclub.dto;
import lombok.AllArgsConstructor;
import lombok.Data;
@Data
@AllArgsConstructor
public class UpdateMemberRequest {
private String password;
private String nickName;
private String info;
}
UpdateMemberResponse.java
package seulgi.bookbookclub.dto;
import lombok.AllArgsConstructor;
import lombok.Data;
@Data
@AllArgsConstructor
public class UpdateMemberResponse {
private Integer memberSeq;
private String Nickname;
private String info;
}
(+) Member.java 수정
package seulgi.bookbookclub.domain;
import jakarta.persistence.*;
import lombok.Getter;
import lombok.NoArgsConstructor;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.annotation.LastModifiedDate;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;
import java.time.LocalDateTime;
@Entity
@Getter
@NoArgsConstructor
@EntityListeners(AuditingEntityListener.class)
public class Member {
//코드생략//
public Member(Member member, String password, String nickname, String info) {
this.memberSeq = member.getMemberSeq();
this.memberId = member.getMemberId();
this.password = password;
this.nickname = nickname;
this.info = info;
}
}
- 생성자를 추가하였음.
(+) MemberRepository.java 수정
package seulgi.bookbookclub.repository;
import jakarta.persistence.EntityManager;
import jakarta.persistence.PersistenceContext;
import org.springframework.stereotype.Repository;
import seulgi.bookbookclub.domain.Member;
import java.util.List;
@Repository
public class MemberRepository {
@PersistenceContext
private EntityManager em;
//코드생략//
public void update(Member member) {
em.merge(member);
}
//코드생략//
}
- 레파지토리에는 변경감지 기능을 이용하여 회원을 수정하는 메소드 생성.
(+) MemberService.java 수정
package seulgi.bookbookclub.service;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import seulgi.bookbookclub.domain.Member;
import seulgi.bookbookclub.repository.MemberRepository;
import java.time.LocalDateTime;
import java.util.List;
@Service
@Transactional(readOnly = true)
@RequiredArgsConstructor
public class MemberService {
private final MemberRepository memberRepository;
//코드 생략 //
@Transactional
public void updateMember(Integer memberSeq, String password, String nickName, String info) {
// 기존 회원 조회
Member existingMember = memberRepository.findByMemberSeq(memberSeq);
if (existingMember == null) {
throw new IllegalArgumentException("존재하지 않는 회원입니다.");
}
Member updatedMember = new Member(existingMember,
password != null && !password.isBlank() ? password : existingMember.getPassword(),
nickName != null && !nickName.isBlank() ? nickName : existingMember.getNickname(),
info != null && !info.isBlank() ? nickName : existingMember.getInfo()
);
memberRepository.update(updatedMember);
}
//코드 생략 //
}
- MemberService에도 회원 정보를 수정하는 메서드가 없어서 생성해 줬음.
- 값이 들어있는 객체만 수정하게끔 하느라 조금 더 복잡해짐.
회원수정 API 테스트
MemeberApiController.java
3. 회원조회
package seulgi.bookbookclub.api;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.*;
import seulgi.bookbookclub.domain.Member;
import seulgi.bookbookclub.dto.*;
import seulgi.bookbookclub.service.MemberService;
import java.util.List;
import java.util.stream.Collectors;
@RestController
@RequiredArgsConstructor
@RequestMapping("/api")
public class MemberApiController {
private final MemberService memberService;
//코드생략//
@GetMapping("/members")
public Result members(){
List<Member> findMembers = memberService.findMembers();
List<MemberDto> collect = findMembers.stream().map(m -> new MemberDto(m.getMemberId(), m.getNickname(), m.getNickname()))
.collect(Collectors.toList());
return new Result(collect);
}
}
- 엔티티를 DTO로 변환해서 반환하여 엔티티가 변해도 API스폑이 변경되지 않도록 함.
- 추가로 Result 클래스로 컬렉션을 감싸서 향후 필요한 필드를 추가할수 있도록 함.
회원조회 API 테스트
728x90
320x100
'💻 뚝딱뚝딱 > 북북클럽' 카테고리의 다른 글
[개발일지#008] 타임라인 등록/삭제/조회API 구현 (1) | 2025.01.22 |
---|---|
[개발일지#006] 조회용 샘플데이터 생성 (0) | 2025.01.21 |
[개발일지#005] 좋아요 도메인 개발 및 테스트 (0) | 2025.01.20 |
[개발일지#004] 팔로우 도메인 개발 및 테스트 (0) | 2025.01.20 |
[개발일지#003] 타임라인 도메인 개발 및 테스트 (0) | 2025.01.20 |