새소식

Java

[Java] 코드 예제 Part.1) JPA 학습 전 흉내내보기

  • -

 

 

 

 

JPA 맛

 

1)   취지

 

JPA 사용하기 전, JPA 없이 구현하는 것이 가능하다는 점을 확인해보자.

JPA를 사용하게 되면 어떻게 코드가 바뀌는 지도 알 수 있을 것이다.

 

예시는 멤버(Member) 클래스와 취미(Hobby) 클래스의 관계를 파악하여,

취미 클래스를 출력하였을 때, 해당 취미를 가진 멤버가 출력되게 해보고자 했습니다.

 

 

 

 

2)   ERD Diagram

 

 

멤버와 취미는 many to many 관계를 형성하고 있습니다.

하나의 멤버가 여러개의 취미를 가질 수 있고,

하나의 취미를 여러 멤버가 가지고 있을 수 있습니다.

 

 

 

 

 

3)   순서

 

 

1. Member.java로 멤버 클래스 만들어주기

<코드>

@Data

@AllArgsConstructor @NoArgsConstructor
public class Member {
private Integer id;
private String name;
private Integer age;
private List<MemberHobby> hobbies = new ArrayList<>();

public Member(String name, Integer age) {
this.id = Store.memberIndex++;
this.name = name;
this.age = age;
     }
}

<코드 분석>

@Data

@AllArgsConstructor @NoArgsConstructor
// @Data는 Lombok에서 자동으로 Getter, Setter, toString, equals, hashCode 메소드를 자동으로 생성
// @AllArgsConstructor는 모든 필드를 인자로 가지는 생성자를 자동으로 생성
// @NoArgsConstructor는 인자를 가지지 않는 기본 생성자를 자동으로 생성

public class Member {
// Member 클래스 선언

private Integer id;
private String name;
private Integer age;
private List<MemberHobby> hobbies = new ArrayList<>();
// id, name, age, hobbies를 변수로 선언
// List<MemberHobby> 필드 타입 hobbies를 선언해주면서 새로운 배열을 생성해줌
// → 이 List는 MemberHobby 객체를 저장합니다.


public Member(String name, Integer age) {
// name과 age를 매개변수로 하는 Member 클래스의 생성자를 선언(정의)
this.id = Store.memberIndex++;
// id필드에 Store.memberIndex 값을 할당하고 객체가 생성될 때마다 1을 더해줘 매번 새로운 id 생성
this.name = name;
this.age = age;
     }
}
// ★ 생성자 선언시 String name 과 Integer age를 매개변수로 하였지만, 아래에 id를 초기화시켰다.
// 일반적으로 매개변수에 기재하지 않은 필드도 초기화가 가능하다. (예시의 id처럼)

// 그럼 어차피 매개변수에 적어두지 않은 값을 초기화가능한데 굳이 매개변수를 왜 적을까?
// 그 이유는 매개변수의 경우 외부의 값을 가지고 올 수 있으므로!

 

 

 

 

2. Hobby.java로 취미 클래스 만들어주기

<코드>

@RequiredArgsConstructor
@NoArgsConstructor

@Getter
public class Hobby {
    private Integer id;
    private String name;
    private List<MemberHobby> members;

    public Hobby(Integer id, String name, Member member) {
        if(id == null) this.id = Store.hobbyIndex++;
        else this.id = id;
        this.name = name;
        this.members = new ArrayList<>();
    }
}
<코드 분석>

@RequiredArgsConstructor
@NoArgsConstructor
@Getter

public class Hobby {
// Hobby 클래스 선언

    private Integer id;
    private String name;
    private List<MemberHobby> members;
// List<MemberHobby> 타입 필드 members를 변수로 선언
// members라는 변수 이름이 Store쪽 배열객체이름과 같으니 충돌 및 혼동 주의


    public Hobby(Integer id, String name, Member member) {
// Member member를 매개변수로 가진 이유?
// MemberHbobby 클래스는 member 객체와 hobby 객체의 조합이고

// Hobby는 그런 MemberHobby 객체들이 저장되는 리스트인 members를 변수로 가지니까
// Member meber를 생성자 매개변수로 사용할 수 있습니다.

        if(id == null) this.id = Store.hobbyIndex++;
        else this.id = id;
// 생성자에서 조건문이 단일문장(중복문장이 아닌 경우)일 경우에 중괄호{}를 생략할 수 있다.
        this.name = name;
        this.members = new ArrayList<>();
    }
}

 

변수 = 객체가 저장되는 메모리 주소를 가리키는 값

 

 

 

3. MemberHobby.java로 멤버 취미의 중간테이블 만들어주기

<코드>


@Getter
public class MemberHobby {
    private Member member;
    private Hobby hobby;

    public MemberHobby(Member member, Hobby hobby) {
        this.member = member;
        this.hobby = hobby;
        member.getHobbies().add(this);
        hobby.getMembers().add(this);
    }
}
<코드 분석>

@Getter
public class MemberHobby {
// MemberHobby 클래스 선언

    private Member member;
// Member 클래스의 객체를 참조하는 member라는 변수
    private Hobby hobby;
// Hobby 클래스의 객체를 참조하는 hobby라는 변수

    public MemberHobby(Member member, Hobby hobby) {
        this.member = member;
        this.hobby = hobby;

        member.getHobbies().add(this);
        hobby.getMembers().add(this);

// member 객체의 getHobbies 메소드를 실행하여 해당 멤버의 취미리스트 List<MemberHobby> hobbies를 가져와서, 거기에 this인 현재의 MemberHobyy 객체(this.member = member)를 추가해줌

//
hobby 객체의 getmembers 메소드를 실행하여 해당 취미의 멤버리스트 List<MemberHobby> members를 가져와서, 거기에 this인 현재의 MemberHobyy 객체(this.hobby = hobby)를 추가해줌

// ★ 그런데 hobbies와 members를 가져오는데 메소드 이름이 왜 getHobbies, getMembers로 대문자??
그 이유는 바로 메소드명은 소문자로 시작하는 것이 관례이므로
자바빈즈 표준규약에 따라 뒤에 따라오는 필드는 대문자로 시작하는 것을 권장하여

hobbies가 Hobbies로, members가 Members로 적힘.

    }
}

 

 

 

 

4. Store.java로 DB역할을 해줄 클래스 만들어주기

<코드>


public class Store {
    public static List<Member> members = new ArrayList<>();
    public static Integer memberIndex = 0;

    public static List<Hobby> hobbies = new ArrayList<>();
    public static Integer hobbyIndex = 0;

}
<코드 분석>

public class Store {
// Store 클래스 선언

    public static List<Member> members = new ArrayList<>();
    public static Integer memberIndex = 0;
// members라는 이름의 List<Member> 타입 변수를 선언하고, ArrayList 객체를 생성하여 할당합니다. 이 변수는 Member 객체의 목록을 저장하는 데 사용


    public static List<Hobby> hobbies = new ArrayList<>();
    public static Integer hobbyIndex = 0;
// hobbies라는 이름의 List<Hobby> 타입 변수를 선언하고, ArrayList 객체를 생성하여 할당합니다.
이 변수는
Hobby 객체의 목록을 저장하는 데 사용


}

 

 

 

 

 

5. MemberResponse.java를 만들어주며 내부클래스로 HobbyDto 넣기

<코드>


@Getter
public class MemberResponse {
    private Integer id;
    private String name;
    private Integer age;
    private List<HobbyDto> hobbies = new ArrayList<>();
    public MemberResponse(Member member){
        this.id = member.getId();
        this.age = member.getAge();
        this.name = member.getName();
        this.hobbies = member.getHobbies()
                .stream()
                .map(MemberHobby::getHobby)
                .map(HobbyDto::new)
                .toList();
    }

@Getter
@AllArgsConstructor
@NoArgsConstructor
public class HobbyDto {
    private Integer id;
    private String name;

    public HobbyDto(Integer id, String name) {
        this.id = id;
        this.name = name;
    }
    public HobbyDto toDto(Hobby hobby){
        return new HobbyDto(hobby.getId(), hobby.getName());
        }
    }
}
<코드 분석>

@Getter
public class MemberResponse {
// MemberResponse 클래스 선언

    private Integer id;
    private String name;
    private Integer age;
    private List<HobbyDto> hobbies = new ArrayList<>();
// 아래에 선언될 HobbyDto 타입의 hobbies라는 배열을 변수로 가짐
// ★★ hobbies라는 변수 이름이 Store쪽 배열객체이름, Member의 배열 객체 이름과 같은데? -> 변수명 충돌가능성 있음



    public MemberResponse(Member member){
// Member 클래스의 member를 매개변수로 MemberResponse의 생성자 선언

        this.id = member.getId();
        this.age = member.getAge();
        this.name = member.getName();

        this.hobbies = member.getHobbies()
// Member 클래스 member 객체로부터 getHobbies 메소드를 통해 hobbies들을 가져와
// MemberResponse의 hobbies 리스트를 채웁니다.

                .stream()
// hobbies 리스트를 스트림으로 변환

                .map(MemberHobby::getHobby)
// MemberHobby 객체에서 getHobby() 메서드를 호출하여 Hobby 객체로 변환

                .map(HobbyDto::new)
// Hobby 객체를 HobbyDto 객체로 변환
// HobbyDto::newHobby 객체를 입력으로 받아 HobbyDto의 생성자를 호출하는 함수

                .toList();
// 스트림의 요소들을 리스트로 변환합니다. 변환된 HobbyDto 객체들의 리스트를 생성

// this.hobbies = ...: 최종 변환된 HobbyDto 객체들의 리스트를
MemberResponse 클래스의 hobbies 필드에 할당

    }


@Getter
@AllArgsConstructor
@NoArgsConstructor

public class HobbyDto {
// MemberResponse 중괄호 안에서 HobbyDto 클래스 선언 (내부클래스로!)
// 그 클래스 내에서 참조하는 값을 내부클래스로 넣음으로 가독성이 좋아짐
    private Integer id;
    private String name;

    public HobbyDto(Integer id, String name) {
        this.id = id;
        this.name = name;
    }
    public HobbyDto toDto(Hobby hobby){
        return new HobbyDto(hobby.getId(), hobby.getName());
// toDto 메소드를 선언
        }
    }
}
★ 람다식으로 변환
this.hobbies = member.getHobbies()

                .stream()
                .map(MemberHobby::getHobby)
                .map(HobbyDto::new)
                .toList();


이 부분을 이해하기 쉽게 람다식으로 변환해보자

this.hobbies = member.getHobbies()
        .stream()
        .map(hobby -> new HobbyDto(hobby.getId(), hobby.getName()))
        .collect(Collectors.toList());
// Hobby 객체를 HobbyDto 객체로 변환
// Hobby 객체의 idname을 사용하여 HobbyDto 객체를 생성

 

 

 

 

6. MemberRequest.java 만들어주기

<코드>

public record MemberRequest(String name, Integer age) {
    public Member toEntity(){
        return new Member(name, age);
    }
}
<코드 분석>

public record MemberRequest(String name, Integer age) {
// Java 14부터 도입된 레코드(record) 클래스를 선언,
// name과 age를 변수로!

    public Member toEntity(){
// toEntity() 메서드는 MemberRequest 객체를 Member 엔티티로 변환하는 메서드 (반환타입은 Member)
        return new Member(name, age);
    }
}

// MemberRequest 객체의 nameage 필드 값을 이용하여 새로운 Member 객체를 생성하고, 이를 Member 엔티티로 변환하여 사용할 수 있습니다.



// 레코드 클래스는 불변(immutable)하며, 자동으로 equals(), hashCode(), toString() 메서드를 생성하고,
// 필드에 접근할 수 있는 getter 메서드를 제공합니다.
// 이를 통해 데이터 객체를 간편하게 생성하고 필드 값을 읽을 수 있습니다.

 

 

 

 

7. MemberController.java를 만들어주며 멤버를 등록하는 기능 만들어주기

<코드>

@RestController
@RequestMapping("/api/v1/members")
@RequiredArgsConstructor
public class MemberController {
    private final MemberService memberService;

    @PostMapping
    @ResponseStatus(HttpStatus.CREATED)
    public void save(@RequestBody MemberRequest member){
        memberService.save(member.toEntity());
    }
}
<코드 분석>

@RestController
// Spring Framework에서 RESTful API를 제공하는 컨트롤러 클래스임을 나타냄

@RequestMapping("/api/v1/members")
// /api/v1/members 경로로 들어오는 요청을 이 컨트롤러에서 처리하도록 매핑

@RequiredArgsConstructor
// final이나 @NonNull으로 선언된 필드를 가지고 있는 클래스에 대해
//해당 필드를 매개변수로 갖는 생성자를 자동으로 생성해줍니다.
// 생성자는 
final 필드만을 인자로 받습니다.


public class MemberController {
    private final MemberService memberService;
// MemberService 타입의 memberService 변수를 선언합니다.
// final 키워드로 선언되어 있으므로, 한 번 초기화된 이후에는 다른 객체로 변경할 수 없습니다.


    @PostMapping
// HTTP POST 요청을 처리하는 메서드

    @ResponseStatus(HttpStatus.CREATED)
// 해당 메서드가 성공적으로 실행되었을 때 HTTP 상태 코드를 '201 Created'로 설정

    public void save(@RequestBody MemberRequest member){
// MemberRequest 객체를 요청의 본문(RequestBody)에서 받아와서 save() 메서드에 전달하는 역할
// POST 요청의 본문에는 JSON 형식으로 작성된 MemberRequest 객체가 포함되어야 합니다.


        memberService.save(member.toEntity());
// MemberRequest 객체 member를 Member 엔티티로 변환하는 메서드를 호출
// memberService를 통해 Member 엔티티를 저장하는 메서드를 호출

}

 

 

 

 

8. MemberService.java를 만들어주며 멤버리스트에 멤버를 추가하는 기능

<코드>

@Service
public class MemberService {
    public void save(Member member){
            Store.members.add(member);
    }
}
<코드 분석>

@Service
// Spring Framework에서 비즈니스 로직을 수행하는 서비스(Service) 클래스임을 나타냄

public class MemberService {
// MemberService 클래스 선언

    public void save(Member member){
// Member 객체 member를 변수로 받는 save 메소드를 선언하고 void라 반환값이 없음
            Store.members.add(member);
// Store 클래스의 members 필드로 선언된 List<Member> 배열에 member를 추가함
    }
}

 

 

 

 

9. 멤버 추가해보기

 

Talend API Tester를 이용해서 POST를 통해 멤버를 추가해보자.

Method를 POST로,
Request Mapping 경로에 해당하는 api/v1/members를 입력해주고,
Content Type은 json,
Body에 member의 변수인 name과 age를 입력한 후,
Send 버튼을 눌러줍니다.

 

 

 

 

 


성공적으로 멤버 추가되었고 ResponseStatus(HttpStatus.CREATED)에 의해 201 코드가 나오게 됩니다.

 

 

 

 

 

 

10. MemberController에 멤버를 조회하는 기능 만들어주기

<코드>

@RestController
@RequestMapping("/api/v1/members")
@RequiredArgsConstructor
public class MemberController {
    private final MemberService memberService;

    @PostMapping
    @ResponseStatus(HttpStatus.CREATED)
    public void save(@RequestBody MemberRequest member){
        memberService.save(member.toEntity());
    }

    @GetMapping
    public List<MemberResponse> findAll(){
        return memberService.findAll();
    }
}
<코드 분석>

@RestController
@RequestMapping("/api/v1/members")
@RequiredArgsConstructor
public class MemberController {
    private final MemberService memberService;

    @PostMapping
    @ResponseStatus(HttpStatus.CREATED)
    public void save(@RequestBody MemberRequest member){
        memberService.save(member.toEntity());
    }

    @GetMapping
// HTTP GET 요청을 처리하는 메서드임을 나타냅니다.

    public List<MemberResponse> findAll(){
        return memberService.findAll();
// localhost:3360/api/v1/members로 GET 요청을 보내면 MemberController 클래스의 findAll() 메서드가 // 실행되고, memberService의 findAll 메소드가 실행되어 그 결과 값이  List<MemberResponse> 타입
// 으로
반환됩니다.

    }
}

 

 

 

 

11. MemberService에 멤버를 조회하는 로직 만들어주기

<코드>

@Service
public class MemberService {
    public void save(Member member){
        Store.members.add(member);
    }

    public List<MemberResponse> findAll(){
        return Store.members
                .stream()
                .map(MemberResponse::new)
                .toList();
    }
}
<코드 분석>

@Service
public class MemberService {
    public void save(Member member){
        Store.members.add(member);
    }

    public List<MemberResponse> findAll(){
// findAll 메소드 선언을 해주고 결과 값을 List<MemberResponse>로 반환합니다.
        return Store.members
// Store 클래스의 members 변수로 선언된 List<Member> 배열
                .stream()
// stream 메소드를 이용하여 배열을 스트림으로 변환해줌
                .map(MemberResponse::new)
// map 함수를 통해 각 멤버 객체를 MemberResponse 객체로 매핑합니다.
// MemberResponse::newMemberResponse의 생성자를 참조하여 매핑을 수행합니다.
// MemberResponse의 생성자는 id, age, name와 hobbies 리스트배열

                .toList();
// 매핑된 결과를 리스트로 변환
    }
}
★ 람다식으로 변환
return Store.members
        .stream()
        .map(MemberResponse::new)
        .toList();

람다식으로 변환해보자

return Store.members
        .stream()
        .map(member -> new MemberResponse(member))
        .collect(Collectors.toList());
//각  Member 객체를 MemberResponse 객체로 변환합니다.
// member를 입력으로 받아 MemberResponse 객체를 생성

 

 

 

 

 

12. 멤버 조회해보기

 

 

Talend API Tester의 GET을 이용하여 멤버를 조회해보자
(GET은 따로 값을 입력해주지 않아도 된다)


 

 

 

 

 

13. HobbyRequest.java 만들기

<코드>

public class HobbyRequest {
    private final String name;
    private final Integer memberId;

    public HobbyRequest(String name, Integer memberId) {
        this.name = name;
        this.memberId = memberId;
    }

    public String getName() {
        return name;
    }

    public Integer getMemberId() {
        return memberId;
    }
}
<코드 분석>

public class HobbyRequest {
// HobbyRequest 클래스 선언
    private final String name;
    private final Integer memberId;

    public HobbyRequest(String name, Integer memberId) {
        this.name = name;
        this.memberId = memberId;
    }

    public String getName() {
        return name;
    }

    public Integer getMemberId() {
        return memberId;
    }
}
// 생성자와 getter 메서드를 통해 필드들의 값을 설정하고 읽을 수 있도록 만들어줌

 

 

 

 

14. HobbyController.java 만들어서 취미 추가해주기

<코드>

@RestController
@RequestMapping("/api/v1/hobbies")
@RequiredArgsConstructor
public class HobbyController {
    private final HobbyService service;

    @PostMapping
    public void save(@RequestBody HobbyRequest request){
        service.save(request);
    }
}

<코드 분석>

@RestController
@RequestMapping("/api/v1/hobbies")
// /api/v1/hobbies 경로로 들어오는 요청을 이 컨트롤러에서 처리하도록 매핑
@RequiredArgsConstructor

public class HobbyController {
// HobbyController 클래스 선언

    private final HobbyService service;
// HobbyService의 객체 service를 변수로 선언


    @PostMapping
    public void save(@RequestBody HobbyRequest request){
        service.save(request);
// /api/v1/hobbies 경로로 POST 요청이 들어왔을 때, HobbyRequest 객체를 받아와서
// service를 통해 저장하는 역할을 수행
    }
}

 

 

 

 

 

15. HobbyService.java 만들어서 취미 추가하는 로직 만들어주기

<코드>

@Service
@RequiredArgsConstructor
public class HobbyService {

    public void save(HobbyRequest request){
        Hobby hobby = new Hobby(null, request.getName(), null);
        Store.hobbies.add(hobby);
    }
}
<코드 분석>

@Service
@RequiredArgsConstructor
public class HobbyService {
// HobbyService 클래스 선언

    public void save(HobbyRequest request){
// save() 메서드는 HobbyRequest 객체를 받아와서 저장하는 역할

        Hobby hobby = new Hobby(null, request.getName(), null);
// Hobby 객체를 생성하고, 생성자에 null을 전달하여 ID와 관련된 필드를 설정하지 않습니다.
// Hobby 객체의 name 필드에는 request에서 가져온 이름을 설정

        Store.hobbies.add(hobby);
// Store 클래스의 hobbies 배열에 hobby 객체를 추가
    }
}

 

 

 

 

 

16. 취미 추가해보기

 

Talend API Tester를 이용해서 POST를 통해 취미를 추가해보자.

 

 

HobbyRequest의 객체를 받아와서 저장하니, HobbyRequest 객체의 변수 name, memberId를 입력해줍니다.





17. 멤버와 취미를 연결해주기위해 ConnectRequest.java 만들어주기

<코드>

public record ConnectRequest(Integer memberId, Integer hobbyId) {
}
<코드 분석>

public record ConnectRequest(Integer memberId, Integer hobbyId) {
// ConnectRequest라는 레코드 클래스 생성
// 레코드 클래스는 데이터를 저장하고 조회하기 위한 간단한 데이터 객체를 생성하는 데 사용
// 회원의 고유식별자 memberId, 취미의 고유식별자 hobbyId

}

 

 

 

 

18. HobbyController에 연결하는 기능 추가

<코드>

@RestController
@RequestMapping("/api/v1/hobbies")
@RequiredArgsConstructor
public class HobbyController {
    private final HobbyService service;

    @PostMapping
    public void save(@RequestBody HobbyRequest request){
        service.save(request);
    }
    @PostMapping("/connect")
    public void save(@RequestBody ConnectRequest request) {
        service.connect(request);
    }
}
<코드 분석>

@RestController
@RequestMapping("/api/v1/hobbies")
@RequiredArgsConstructor
public class HobbyController {
    private final HobbyService service;

    @PostMapping
    public void save(@RequestBody HobbyRequest request){
        service.save(request);
    }

    @PostMapping("/connect")
// /api/v1/hobbies/connect 경로에 대한 POST 요청을 처리하는 메서드임을 나타냄
    public void save(@RequestBody ConnectRequest request) {
        service.connect(request);
// service 객체를 통해 ConnectRequest 객체를 connect 메서드를 호출
    }
}

 

 

 

 

19. MemberController에 아이디를 이용하여 멤버 찾는 기능 추가

<코드>

@RestController
@RequestMapping("/api/v1/members")
@RequiredArgsConstructor
public class MemberController {
    private final MemberService memberService;

    @PostMapping
    @ResponseStatus(HttpStatus.CREATED)
    public void save(@RequestBody MemberRequest member){
        memberService.save(member.toEntity());
    }

    @GetMapping
    public List<MemberResponse> findAll(){
        return memberService.findAll();
    }

    @GetMapping("{id}")
    public MemberResponse findById(@PathVariable("id") Integer id){
        return new MemberResponse(memberService.findById(id));
    }

}
<코드 분석>

@RestController
@RequestMapping("/api/v1/members")
@RequiredArgsConstructor
public class MemberController {
    private final MemberService memberService;

    @PostMapping
    @ResponseStatus(HttpStatus.CREATED)
    public void save(@RequestBody MemberRequest member){
        memberService.save(member.toEntity());
    }

    @GetMapping
    public List<MemberResponse> findAll(){
        return memberService.findAll();
    }

    @GetMapping("{id}")
// {id} 경로 변수를 사용하여 GET 요청을 처리하는 메서드,동적으로변하는멤버의 ID

    public MemberResponse findById(@PathVariable("id") Integer id){
// findById 메서드를 선언
// @PathVariable("id")
해당 메서드의 매개변수인 id에 경로 변수의 값이 자동으로 바인딩됩니다.
// 즉, 경로에서 추출한 ID 값을 메서드에서 사용할 수 있게 됩니다.

        return new MemberResponse(memberService.findById(id));
// 찾은 회원을 MemberResponse 객체로 변환하여 반환
    }

}

 

 

 

 

20. MemberService에 아이디를 이용하여 멤버 찾는 기능 추가

<코드>

@Service
public class MemberService {

    public void save(Member member){
        Store.members.add(member);
    }

    public List<MemberResponse> findAll(){
        return Store.members
                .stream()
                .map(MemberResponse::new)
                .toList();
    }

    public Member findById(Integer id) {
        return Store.members
                .stream()
                .filter(member -> member.getId().equals(id))
                .findFirst()
                .orElse(null);
    }
}
<코드 분석>

@Service
public class MemberService {

    public void save(Member member){
        Store.members.add(member);
    }

    public List<MemberResponse> findAll(){
        return Store.members
                .stream()
                .map(MemberResponse::new)
                .toList();
    }

    public Member findById(Integer id) {
// findById 메소드는 Integer 타입의 id 매개변수를 받습니다. (조회하고자 하는 회원의 id)

        return Store.members
                .stream()
// Store 클래스에 있는 members 리스트를 스트림으로 변환

                .filter(member -> member.getId().equals(id))
// 스트림에서 ID가 id와 일치하는 회원을 필터링합니다.

                .findFirst()
// 필터링된 스트림에서 첫 번째로 일치하는 회원을 찾습니다.
                .orElse(null);
//  호출하여 찾은 회원이 없는 경우 null을 반환
    }
}
// 마지막으로, findById 메소드는 찾은 회원을 반환합니다.

 

 

 

 

21. HobbyService에 연결하는 메소드 추가

<코드>

@Service
@RequiredArgsConstructor
public class HobbyService {
    private final MemberService memberService;

    public void save(HobbyRequest request){
        Hobby hobby = new Hobby(null, request.getName(), null);
        Store.hobbies.add(hobby);
    }

    public void connect(ConnectRequest request){
        Member member = memberService.findById(request.memberId());
        Hobby hobby = Store.hobbies
                .stream()
                .filter(h-> h.getId().equals(request.hobbyId()))
                .findFirst()
                .get();
        new MemberHobby(member, hobby);
    }

}
<코드 분석>

@Service
@RequiredArgsConstructor
public class HobbyService {

    private final MemberService memberService;
//  MemberService의 findById 기능을 써야하니까 변수로 memberService 선언

    public void save(HobbyRequest request){
        Hobby hobby = new Hobby(null, request.getName(), null);
        Store.hobbies.add(hobby);
    }


    public void connect(ConnectRequest request){
//  ConnectRequest 객체를 받아와서 멤버와 취미를 연결하는 역할

        Member member = memberService.findById(request.memberId());
//  request에서 가져온 멤버 ID에 해당하는 멤버를 member 객체 member로 가져옵니다.

        Hobby hobby = Store.hobbies
                .stream()
//  stream() 메서드를 호출하여 스트림을 생성

                .filter(h-> h.getId().equals(request.hobbyId()))
//  h 객체의 ID가 request에서 가져온 취미 ID와 일치하는지 필터링합니다.

                .findFirst()
                .get();
// 필터링된 첫 번째 취미 객체를 가져옵니다.

        new MemberHobby(member, hobby);
//  MemberHobby 객체를 생성합니다. 이를 통해 회원과 취미를 연결합니다.
    }
}

 

 

 

 

22. 연결해보자

 

Talend API Tester를 이용해서 POST를 통해 멤버와 취미를 연결해보자

 

 

 

 

ConnectRequest에서 Integer hobbyId, Integer memberId를 변수로 받으니
두 값을 Body에 넣고 POST를 해줍니다.




 

 

 

GET으로 api/v1/members를 확인해봅시다.

 

 

 

 

이렇게 되면 MemberController GetMapping에 따라 MemberResponse List가 출력되게 되는데,

public class MemberResponse {
    private Integer id;
    private String name;
    private Integer age;
    private List<HobbyDto> hobbies = new ArrayList<>();

    public class HobbyDto {
        private Integer id;
        private String name;

이므로 위 사진과 같이 출력됩니다.

 

 

 

 

 

 

 

Contents

포스팅 주소를 복사했습니다

이 글이 도움이 되었다면 공감 부탁드립니다.