이 글은 김영한의 [자바 ORM 표준 JPA 프로그래밍 - 기본편] 수강하며 정리한 글입니다.

 

👉 기본 환경

- Language: Java

- DB: H2 Database

- IDE: IntelliJ

 

 

⭐ N + 1 문제

: 연관관계가 설정된 엔티티 사이에서 하나의 엔티티를 조회했을 때, 조회된 엔티티의 개수(N 개)만큼 연관된 엔티티를 조회하기 위해 추가적인 쿼리가 발생하는 문제

    - 1: 하나의 엔티티를 조회하기 위한 쿼리의 개수

    - N: 연관된 데이터를 조회하기 위한 추가적인 쿼리의 개수

 

 

⌨️ 코드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
@Entity
public class Member extends BaseEntity {
    
    // 생략
 
    @Id @GeneratedValue
    @Column(name = "MEMBER_ID")
    private Long id;
 
    @Column(name = "USERNAME")
    private String name;
 
    @ManyToOne(fetch = FetchType.EAGER)
    @JoinColumn(name = "TEAM_ID")
    private Team team;
 
    // 생략
 
}
 
 
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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
public class Main {
    public static void main(String[] args) {
 
        // 생략
 
        try {
 
            Team teamA = new Team();
            teamA.setName("teamA");
            em.persist(teamA);
 
            Team teamB = new Team();
            teamB.setName("teamB");
            em.persist(teamB);
 
            Member member1 = new Member();
            member1.setName("user1");
            member1.setTeam(teamA);
            em.persist(member1);
 
            Member member2 = new Member();
            member2.setName("user2");
            member2.setTeam(teamB);
            em.persist(member2);
 
            em.flush();
            em.clear();
 
            List<Member> members = em.createQuery("select m from Member m", Member.class)
                    .getResultList();
 
            tx.commit();
        } catch (Exception e) {
            tx.rollback();
            e.printStackTrace();
        } finally {
            em.close();
        }
 
        emf.close();
 
    }
 
}
 
 

 

 

🖨️발생한 쿼리

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
32
33
34
35
36
37
38
39
40
41
Hibernate: 
    /* select
        m 
    from
        Member m */ select
            member0_.MEMBER_ID as member_i1_3_,
            member0_.INSERT_MEMBER as insert_m2_3_,
            member0_.createDate as createda3_3_,
            member0_.UPDATE_MEMBER as update_m4_3_,
            member0_.lastModifiedDate as lastmodi5_3_,
            member0_.USERNAME as username6_3_,
            member0_.TEAM_ID as team_id7_3_ 
        from
            Member member0_
 
Hibernate: 
    select
        team0_.TEAM_ID as team_id1_5_0_,
        team0_.INSERT_MEMBER as insert_m2_5_0_,
        team0_.createDate as createda3_5_0_,
        team0_.UPDATE_MEMBER as update_m4_5_0_,
        team0_.lastModifiedDate as lastmodi5_5_0_,
        team0_.name as name6_5_0_ 
    from
        Team team0_ 
    where
        team0_.TEAM_ID=?
 
Hibernate: 
    select
        team0_.TEAM_ID as team_id1_5_0_,
        team0_.INSERT_MEMBER as insert_m2_5_0_,
        team0_.createDate as createda3_5_0_,
        team0_.UPDATE_MEMBER as update_m4_5_0_,
        team0_.lastModifiedDate as lastmodi5_5_0_,
        team0_.name as name6_5_0_ 
    from
        Team team0_ 
    where
        team0_.TEAM_ID=?
 
 

 

 

📡 원인

1. Member 객체를 조회하기 위한 쿼리 발생

2. FetchType.EAGER의 경우, 필드값이 채워져 있어야하므로,

    - TeamA를 가져오기 위한 Query1

    - TeamB를 가져오기 위한 Query2

 

 

📰 해결 방법

1. FetchType.LAZY 선언

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
@Entity
public class Member extends BaseEntity {
    
    // 생략
 
    @Id @GeneratedValue
    @Column(name = "MEMBER_ID")
    private Long id;
 
    @Column(name = "USERNAME")
    private String name;
 
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "TEAM_ID")
    private Team team;
 
    // 생략
 
}
 
 

🖨️발생한 쿼리

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Hibernate: 
    /* select
        m 
    from
        Member m */ select
            member0_.MEMBER_ID as member_i1_3_,
            member0_.INSERT_MEMBER as insert_m2_3_,
            member0_.createDate as createda3_3_,
            member0_.UPDATE_MEMBER as update_m4_3_,
            member0_.lastModifiedDate as lastmodi5_3_,
            member0_.USERNAME as username6_3_,
            member0_.TEAM_ID as team_id7_3_ 
        from
            Member member0_
 
 

 

2. fetch join 활용

* fetch join: 연관된 엔티티나 컬렉션을 함께 로딩하여 성능을 최적화하는 기능

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
@Entity
public class Member extends BaseEntity {
    
    // 생략
 
    @Id @GeneratedValue
    @Column(name = "MEMBER_ID")
    private Long id;
 
    @Column(name = "USERNAME")
    private String name;
 
    @ManyToOne(fetch = FetchType.EAGER)
    @JoinColumn(name = "TEAM_ID")
    private Team team;
 
    // 생략
 
}
 
 

🖨️발생한 쿼리

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
Hibernate: 
    /* select
        m 
    from
        Member m 
    join
        fetch m.team */ select
            member0_.MEMBER_ID as member_i1_3_0_,
            team1_.TEAM_ID as team_id1_5_1_,
            member0_.INSERT_MEMBER as insert_m2_3_0_,
            member0_.createDate as createda3_3_0_,
            member0_.UPDATE_MEMBER as update_m4_3_0_,
            member0_.lastModifiedDate as lastmodi5_3_0_,
            member0_.USERNAME as username6_3_0_,
            member0_.TEAM_ID as team_id7_3_0_,
            team1_.INSERT_MEMBER as insert_m2_5_1_,
            team1_.createDate as createda3_5_1_,
            team1_.UPDATE_MEMBER as update_m4_5_1_,
            team1_.lastModifiedDate as lastmodi5_5_1_,
            team1_.name as name6_5_1_ 
        from
            Member member0_ 
        inner join
            Team team1_ 
                on member0_.TEAM_ID=team1_.TEAM_ID
 
 

 

 

cf. @ManyToOne, @OneToOne: default - FetchType.EAGER

▶ FetchType.LAZY 필수 기재

 

'Java > JPA' 카테고리의 다른 글

[JPA_Basic] 값 타입과 불변 객체  (0) 2023.09.14
[JPA_Basic] Cascade  (0) 2023.09.11
[JPA_Basic] Proxy  (0) 2023.09.08
[JPA_Basic] @MappedSuperclass  (0) 2023.09.05
[JPA_Basic] 상속관계 매핑  (0) 2023.08.23

이 글은 김영한의 [자바 ORM 표준 JPA 프로그래밍 - 기본편] 수강하며 정리한 글입니다.

 

👉 기본 환경

- Language: Java

- DB: H2 Database

- IDE: IntelliJ

 

 

em.find();와 em.getReference();

em.find(): DB에서 실제 Enitty 객체 조회

em.getReference(): DB 조회를 미루는 Proxy Entity 객체 조회

 

 

Proxy 객체

- 실제 클래스를 상속받아 만들어짐

- 프록시 객체는 실제 객체의 참조를 보관

- 프록시 객체 호출 시, 프록시 객체는 실제 객체의 메서드 호출

* Proxy 객체의 초기화: Proxy 객체의 Target Entity를 생성하는 과정

1. getName() 요청

2. Proxy 객체의 target이 연결되어있는지 확인

→ 없을 경우, 영속성 컨텍스트에 target에 연결할 Entity 객체 요청

3. 영속성 컨텍스트에서 DB 조회 후,

4. 실제 Entity 객체 생성하여 반환

5. 반환된 Entity 객체를 Proxy 객체의 target에 연결

 

 

Proxy 객체 특징

- Proxy 객체는 처음 사용할 때 한 번만 초기화

- Proxy 객체를 초기화하더라도 Entity 객체로 바뀌는 것이 아니라, Proxy 객체를 통해서 실제 Entity 객체에 접근하는 것

    * 타입 체크 시, == 비교가 아닌 instance of 사용

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
32
33
34
35
36
37
38
public class Main {
    public static void main(String[] args) {
        
        // 생략
 
        try {
 
            Member member1 = new Member();
            member1.setName("user1");
            em.persist(member1);
 
            Member member2 = new Member();
            member2.setName("user2");
            em.persist(member2);
 
            em.flush();
            em.clear();
 
            Member m1 = em.find(Member.class, member1.getId());
            Member m2 = em.getReference(Member.class, member2.getId());
 
            logic(m1, m2);
 
            tx.commit();
        } catch (Exception e) {
            tx.rollback();
        } finally {
            em.close();
        }
    }
 
 
    private static void logic(Member m1, Member m2) {
        System.out.println("m1 == m2: " + (m1.getClass() == m2.getClass()));
    }
 
}
 
 

🚨 logic()을 구현하여, getClass == 비교 시 false가 반환 됨

    - m1.getClass(): Entity

    - m2.getClass(): Proxy

m1, m2가 어떤 객체로 넘어올 지 알 수 없으므로 instance of 사용

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
32
33
34
35
36
37
38
39
public class Main {
    public static void main(String[] args) {
        
        // 생략
 
        try {
 
            Member member1 = new Member();
            member1.setName("user1");
            em.persist(member1);
 
            Member member2 = new Member();
            member2.setName("user2");
            em.persist(member2);
 
            em.flush();
            em.clear();
 
            Member m1 = em.find(Member.class, member1.getId());
            Member m2 = em.getReference(Member.class, member2.getId());
 
            logic(m1, m2);
 
            tx.commit();
        } catch (Exception e) {
            tx.rollback();
        } finally {
            em.close();
        }
    }
 
 
    private static void logic(Member m1, Member m2) {
        System.out.println("m1 Class: " + (m1 instanceof Member));
        System.out.println("m2 Class: " + (m2 instanceof Member));
    }
 
}
 
 

 

- 영속성 컨텍스트에 찾는 엔티티가 이미 있으면, em.getReference()를 호출해도 실제 Entity 반환

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
public class Main {
    public static void main(String[] args) {
        
        // 생략
 
        try {
 
            Member member1 = new Member();
            member1.setName("user1");
            em.persist(member1);
 
            em.flush();
            em.clear();
 
            Member findMember = em.find(Member.class, member1.getId());
            System.out.println("findMember.id = " + findMember.getClass());
 
            Member refMember = em.getReference(Member.class, member1.getId());
            System.out.println("refMember.id = " + refMember.getClass());
 
            tx.commit();
        } catch (Exception e) {
            tx.rollback();
        } finally {
            em.close();
        }
    }
 
}
 
 

refMember.getClass()가 Entity 객체로 반환되는 이유

    - 같은 영속성 컨텍스트 안에 같은 PK를 통해 가져온 객체는 == 비교 시, JPA는 항상 true를 반환해야 함

    - 영속성 컨텍스트에 존재하는 Entity 대신 Proxy를 가져올 이점이 없음

+ 만일 getReference()로 Proxy 객체를 먼저 조회할 경우는 findMember가 Proxy 객체가 반환됨

    - 같은 영속성 컨텍스트 안에 같은 PK를 통해 가져온 객체는 == 비교 시, JPA는 항상 true를 반환해야 함

 

- 영속성 컨텍스트의 도움을 받을 수 없는 준영속 상태일 때, 프록시를 초기화하면 org.hibernate.LazyInitializationException 발생

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
32
33
34
public class Main {
    public static void main(String[] args) {
        
        // 생략
 
        try {
 
            Member member1 = new Member();
            member1.setName("user1");
            em.persist(member1);
 
            em.flush();
            em.clear();
 
            Member refMember = em.getReference(Member.class, member1.getId());
            System.out.println("refMember.id = " + refMember.getClass());
 
//            em.detach(refMember);
//            em.close();
            em.clear();
 
            System.out.println("refMember.id = " + refMember.getName());
            // org.hibernate.LazyInitializationException
 
            tx.commit();
        } catch (Exception e) {
            tx.rollback();
        } finally {
            em.close();
        }
    }
 
}
 
 

 

 

 Proxy 객체 확인

- Proxy 인스턴스 초기화 여부 확인

    - emf.getPersistenceUnitUtil().isLoaded(refMember);

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
public class Main {
    public static void main(String[] args) {
        
        // 생략
 
        try {
 
            Member member1 = new Member();
            member1.setName("user1");
            em.persist(member1);
 
            em.flush();
            em.clear();
 
            Member refMember = em.getReference(Member.class, member1.getId());
            System.out.println("refMember.id = " + refMember.getClass());
            System.out.println("isLoaded: " + emf.getPersistenceUnitUtil().isLoaded(refMember)); // false
 
            refMember.getName();
            System.out.println("isLoaded: " + emf.getPersistenceUnitUtil().isLoaded(refMember)); // true
 
            tx.commit();
        } catch (Exception e) {
            tx.rollback();
        } finally {
            em.close();
        }
    }
 
}
 
 

 

- Proxy 강제 초기화

    - Hibernate.initialize(refMember);

 

'Java > JPA' 카테고리의 다른 글

[JPA_Basic] Cascade  (0) 2023.09.11
[JPA_Basic] N+1 문제  (0) 2023.09.10
[JPA_Basic] @MappedSuperclass  (0) 2023.09.05
[JPA_Basic] 상속관계 매핑  (0) 2023.08.23
[JPA_Basic] ERD를 기반으로 한 Entity 작성  (0) 2023.08.17

이 글은 김영한의 [자바 ORM 표준 JPA 프로그래밍 - 기본편] 수강하며 정리한 글입니다.

 

👉 기본 환경

- Language: Java

- DB: H2 Database

- IDE: IntelliJ

 

 

@MappedSuperclass

- 주로 등록일, 수정일, 등록자, 수정자 같이 전체 엔티티에서 공통적으로 사용하는 정보를 모을 때 사용

 

📑 특징

- 상속관계 매핑 X

- Entity가 아니므로, 테이블과 매핑되지 않음 ▶ 상속받는 자식 클래스에 매핑 정보만 제공

- 생성해서 사용할 일이 없으므로 abstract class로 사용

 

1. BaseEntity 생성

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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
import javax.persistence.Column;
import javax.persistence.MappedSuperclass;
import java.time.LocalDateTime;
 
@MappedSuperclass
public abstract class BaseEntity {
 
    @Column(name = "INSERT_MEMBER")
    private String createBy;
    private LocalDateTime createDate;
    @Column(name = "UPDATE_MEMBER")
    private String lastModifiedBy;
    private LocalDateTime lastModifiedDate;
 
    public String getCreateBy() {
        return createBy;
    }
 
    public void setCreateBy(String createBy) {
        this.createBy = createBy;
    }
 
    public LocalDateTime getCreateDate() {
        return createDate;
    }
 
    public void setCreateDate(LocalDateTime createDate) {
        this.createDate = createDate;
    }
 
    public String getLastModifiedBy() {
        return lastModifiedBy;
    }
 
    public void setLastModifiedBy(String lastModifiedBy) {
        this.lastModifiedBy = lastModifiedBy;
    }
 
    public LocalDateTime getLastModifiedDate() {
        return lastModifiedDate;
    }
 
    public void setLastModifiedDate(LocalDateTime lastModifiedDate) {
        this.lastModifiedDate = lastModifiedDate;
    }
}
 
 

 

2. BaseEntity 상속

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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
import javax.persistence.*;
import java.util.ArrayList;
import java.util.List;
 
@Entity
public class Team extends BaseEntity {
 
    @Id @GeneratedValue
    @Column(name = "TEAM_ID")
    private Long id;
    private String name;
 
    @OneToMany(mappedBy = "team"// mappedBy: 상대 Entity의 FK field 값
    private List<Member> members = new ArrayList<>();
 
 
    public Long getId() {
        return id;
    }
 
    public void setId(Long id) {
        this.id = id;
    }
 
    public String getName() {
        return name;
    }
 
    public void setName(String name) {
        this.name = name;
    }
 
    public List<Member> getMembers() {
        return members;
    }
 
    public void setMembers(List<Member> members) {
        this.members = members;
    }
 
    public void addMember(Member member) {
        member.setTeam(this);
        this.getMembers().add(member);
    }
}
 
 

* @Entity 클래스는 엔티티나 @MappedSuperclass로 지정한 클래스만 상속 가능

 

🖨️ 실행 결과

1
2
3
4
5
6
7
8
9
10
11
12
Hibernate: 
    
    create table Team (
       TEAM_ID bigint not null,
        INSERT_MEMBER varchar(255),
        createDate timestamp,
        UPDATE_MEMBER varchar(255),
        lastModifiedDate timestamp,
        name varchar(255),
        primary key (TEAM_ID)
    )
 
 

 

'Java > JPA' 카테고리의 다른 글

[JPA_Basic] N+1 문제  (0) 2023.09.10
[JPA_Basic] Proxy  (0) 2023.09.08
[JPA_Basic] 상속관계 매핑  (0) 2023.08.23
[JPA_Basic] ERD를 기반으로 한 Entity 작성  (0) 2023.08.17
[JPA_Basic] 다대다 매핑  (0) 2023.08.16

👉 기본 환경

- Language: Java

- DB: MySQL

- IDE: IntelliJ

 

 

⌨️ 코드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
plugins {
    id 'java'
}
 
group = 'kr.co.project1'
version = '1.0'
 
repositories {
    mavenCentral()
}
 
dependencies {
    testImplementation platform('org.junit:junit-bom:5.9.1')
    testImplementation 'org.junit.jupiter:junit-jupiter'
 
    compile 'javax.servlet:servlet-api:2.5'
    compile 'org.springframework:spring-webmvc:4.3.18.RELEASE'
}
 
test {
    useJUnitPlatform()
}
 
 

 

 

🖨️오류

 

 

 

📡 원인

gradle.build 파일 내 오류

Could not find method compile() for arguments [javax.servlet:servlet-pi:2.5] on root project 'one_step' of type org.gradle.api.Project.

: org.gradle.api.Project 유형의 루트 프로젝트 'one_step'에서 [javax.servlet:servlet-pi:2.5] 인자에 대한 compile() 메서드를 찾을 수 없음

 

+ Gradle 7.0 버전부터는 compile 메서드 대신 implementation과 compileOnly 등의 의존성 구성 메서드 사용

 

 

📰 해결 방법

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
plugins {
    id 'java'
}
 
group = 'kr.co.project1'
version = '1.0'
 
repositories {
    mavenCentral()
}
 
dependencies {
    testImplementation platform('org.junit:junit-bom:5.9.1')
    testImplementation 'org.junit.jupiter:junit-jupiter'
 
    implementation 'javax.servlet:servlet-api:2.5'
    implementation 'org.springframework:spring-webmvc:4.3.18.RELEASE'
 
}
 
test {
    useJUnitPlatform()
}
 
 

implementation으로 의존성 추가

 

👉 기본 환경

- Language: Java

- DB: MySQL

- IDE: IntelliJ

 

 

WebClient

    - HTTP 클라이언트(서버에 API 요청을 보내는 주체) 라이브러리

    - 비동기적으로 요청하는 non-blocking 처리 방식

    ▶ 요청을 보내고 응답을 받을 때까지 대기하지 않기 때문에 처리 속도가 빠름

 

 

1. Dependency 추가

1
2
3
4
5
6
dependencies {
    ...
 
    implementation 'org.springframework.boot:spring-boot-starter-webflux' // HTTP 클라이언트 라이브러리
}
 
 
 

 

2. WebClient 사용

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
32
33
34
35
36
import com.example.demo.dto.srt.RqstParams;
import org.springframework.stereotype.Service;
import org.springframework.web.reactive.function.client.WebClient;
import reactor.core.publisher.Mono;
 
@Service
public class SrtFcstInfoServiceImpl implements SrtFcstInfoService {
 
    // UltraSrtNcst
    @Override
    public void getUltraSrtNcst(RqstParams rqstParams) {
        WebClient webClient = WebClient.builder()
                .baseUrl("https://apis.data.go.kr/1360000/VilageFcstInfoService_2.0/getUltraSrtNcst")
                .build();
 
        String url = "?serviceKey=" + rqstParams.getServiceKey() +
                "&numOfRows=" + rqstParams.getNumOfRows() +
                "&pageNo=" + rqstParams.getPageNo() +
                "&dataType=" + rqstParams.getDataType() +
                "&base_date=" + rqstParams.getBase_date() +
                "&base_time=" + rqstParams.getBase_time() +
                "&nx=" + rqstParams.getNx() +
                "&ny=" + rqstParams.getNy();
 
        Mono<String> result = webClient.get().uri(url)
                .retrieve()
                .bodyToMono(String.class);
 
        String response = result.block();
 
        System.out.println(response);
 
    }
 
}
 
 
 

- WebClient webClient

    - Spring에서 제공하는 비동기적인 웹 요청을 처리하는 클래스

    - 웹 리소스에 대한 요청을 보내고 응답을 받아올 수 있음

    - WebClient.builder()

        - WebClient 인스턴스 생성을 위한 빌더 패턴 사용

        - 요청 보낼 대상의 URL 설정

    - build()

        - 이전 단계에서 설정한 정보를 기반으로 실제 WebClient 인스턴스를 생성하고 반환

 

- Mono<String>

    - 웹 요청의 결과인 Response Body 저장

    - 비동기적으로 값을 처리하고 반환하는데 사용

    - webClient.get().uri(url)

        - webClient.get(): 생성한 WebClient 인스턴스를 이용하여 HTTP GET 요청 생성

        - uri(url): baseUrl 메서드로 이미 설정한 기본 URL에 상대 경로를 추가

    - retrieve()

        - 실제로 HTTP 요청을 보내고, 응답을 받아오는 역할

    - bodyToMono(String.class)

        - HTTP Response Body를 Mono로 변환

        - String.class: Response Body를 문자열 형태로 받아옴

 

+ retrieve return

    - toEntity: response 자체를 얻기 위해 사용

    - bodyToMono: response body 데이터를 얻기 위해 사용

    - bodyToFlux: response body 데이터를 stream*으로 처리하기 위해 사용

* Steam: 데이터를 한 번에 모두 받아오는 것이 아니라, 조금씩 조각 조각 나누어 비동기적으로 처리하는 방식

 

- result.block()

    - 비동기적인 작업을 동기적으로 블로킹

    - Mono 작업이 끝날 때까지(=웹 요청의 응답을 받을 때까지) 현재 스레드를 블로킹하고, 응답을 받으면 해당 응답을 문자열 형태로 반환

 

 

 

📚 참고 자료

 

[SpringBoot] WebClient를 이용하여 외부 API 호출하기

안녕하세요. J4J입니다. 이번 포스팅은 webClient를 이용하여 외부 api 호출하는 방법에 대해 적어보는 시간을 가져보려고 합니다. WebClient란? webClient는 spring 5에서 부터 등장한 HTTP 클라이언트 라이

jforj.tistory.com

 

'Java > Spring' 카테고리의 다른 글

[SpringBoot] 스프링 부트 프로젝트 생성  (0) 2023.08.23
[SpringBoot_JPA_1] resources/static and templates  (0) 2023.05.20