ToyProjects๐Ÿงธ/Dalmuriโญ

[Dalmuri] ๋งก๊น€ API ํ˜ธ์ถœํ•ด์„œ ๊ฐ์ • ๋ถ„์„ํ•˜๊ธฐ - WebClient๋ฅผ ์ด์šฉํ•ด์„œ

JanuDev 2026. 4. 3. 16:45

๋ถ€์ œ: ์š”์ฆ˜์€ ๋ˆ์—†์œผ๋ฉด ๊ฐœ๋ฐœ๋„ ๋ชปํ•œ๋‹ค.

 

[Dalmuri] Java๋กœ Google Cloud Nature Language API ํ˜ธ์ถœํ•ด์„œ ๊ฐ์ • ๋‹ค์ด์–ด๋ฆฌ ๋งŒ๋“ค๊ธฐ

๐ŸฅตAPI ์—ฐ๊ฒฐ ํ›„๊ธฐ : ์ฝ”๋“œ ์งœ๋Š”๊ฒƒ๋ณด๋‹ค ์ดˆ๊ธฐ ์„ธํŒ…์ด ํ›จ์”ฌ ๋” ์–ด๋ ต๋‹ค.. ์—ฌ๋Ÿฝ๋‹ค๊ธฐ๋ณด๋‹จ ๋ฐฉ๋ฒ•๋„ ๋งŽ๊ณ  ์ฝ์–ด์•ผ ํ•˜๋Š” ๊ณต์‹ ๋ฌธ์„œ๋„ ๋งŽ์•„์„œ, ์ •์ž‘ ๋‚ด๊ฐ€ ์›ํ•˜๊ฑฐ๋‚˜ ํ•„์š”ํ•œ ์ •๋ณด๋ฅผ ์ฐพ๋Š”๋ฐ ๋” ์‹œ๊ฐ„์ด ์˜ค๋ž˜ ๊ฑธ๋ฆฐ ๊ฒƒ

janudev.tistory.com

์ง„์งœ ๋“œ๋Ÿฝ๊ณ  ์น˜์‚ฌํ•œ ์„ธ์ƒ์ด๋‹ค... ๊ฑฐ๋ ๋ฑ…์ด ๊ฐœ๋ฐœ์ž๋“ค์€ ๊ฐœ๋ฐœ ์–ด๋–ป๊ฒŒ ํ•˜๋ผ๊ณ  ๋งจ๋‚  ๊ณผ๊ธˆํƒ€๋ น ํ•˜๋Š”์งˆ ๋ชจ๋ฅด๊ฒ ๋‹ค. ๋‚œ ํด๋กœ๋“œ ์ฝ”๋“œ๋„ ๋ˆ์•„๊นŒ์›Œ์„œ ๊ทธ๋ƒฅ ์žผ๋ฏผ์ด+ํด๋กœ๋“œ ๊ณ ๋ฌธํ•˜๊ณ  ์žˆ๋Š”๋ฐ...์ธํ…”๋ฆฌ์ œ์ด 1๋…„์น˜ ์š”๊ธˆ๋„ ๋Œ€ํ•™๊ต ๊ณ„์ •์œผ๋กœ 40ํผ ํ• ์ธ๋ฐ›๋Š”๊ฒƒ๋„ ๋œ๋œ ๋–จ๋ฉด์„œ ๊ฒฐ์ œํ•˜๊ณ  ์žˆ๋Š”๋ฐ... ๊ทธ๋ฆฌ๊ณ  ๊ฒŒ์‹œ๊ธ€ ์ž‘์„ฑ ๊ธฐ์ค€์ผ๋กœ ํ™˜์œจ๋„ ์žฅ๋‚œ์•„๋‹ˆ๊ฒŒ ๋†’์•„์„œ ๊ฐ€๊ฒฉ ๋”์˜ฌ๋ž์„๊ฑฐ๋‹ค...

์šฐ๋ฆฌ๋‚˜๋ผ ํ™˜์œจ๋„ ๋ฐ•์‚ด๋‚ฌ๋Š”๋ฐ ์ผ๋ณธ์€ ์„ญ์ข…ํ•˜๋‚˜์š”,,,,?


๊ธฐ์กด ๊ฒŒ์‹œ๊ธ€ ๋ณด๋ฉด ์•Œ๊ฒ ์ง€๋งŒ ์›๋ž˜ ๋งก๊น€ API๋ฅผ ์‚ฌ์šฉํ•ด์„œ ๊ฐ์ • ๋ถ„์„์„ ํ•˜๊ณ  ์‹ถ์—ˆ๋‹ค... ์™œ๋ƒ? ๊ณต์งœ๋‹ˆ๊นŒ.

๊ทผ๋ฐ ๊ทธ ํƒ€์ด๋ฐ์— API๊ฐ€ ๊ณ ์žฅ๋‚˜์„œ ๋ฌธ์˜๋ฅผ ๋“œ๋ ธ๊ณ  ๋‹ค๋ฅธ ๋Œ€์ฒดํ’ˆ์ด ์žˆ์„๊นŒ ๊ฒ€์ƒ‰ํ•˜๋‹ค๊ฐ€ Google ์ž์—ฐ์–ด ๋ถ„์„ API๋ฅผ ์•Œ๊ฒŒ ๋˜์—ˆ๊ณ ... ๊ทธ๊ฑธ ํ™œ์šฉํ•˜๋ ค๊ณ  ๐Ÿถ๊ณ ์ƒ ํ•˜๋ฉด์„œ Google colud์— ๋‚ด ํ”„๋กœ์ ํŠธ ์ƒ์„ฑํ–ˆ๊ณ .. ๊ถŒํ•œ ์„ค์ •ํ–ˆ๊ณ .. pom.xml์— ์˜์กด์„ฑ ์ถ”๊ฐ€ํ•˜๊ณ  ์–ด์ฉŒ๊ตฌ ์ €์ฉŒ๊ตฌ ํ•œ๊ฑด๋ฐ...

์ด์ œ ๊ณผ๊ธˆ๋˜์„œ ๋ˆ ๋‚ด๊ณ  ์‚ฌ์šฉํ•˜๋ž€๋‹ค!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

๊ทธ๋ƒฅ ์—ฌ๋Ÿฌ๊ฐ€์ง€ ๊ณต๋ถ€ํ–ˆ๋‹ค๊ณ  ์ •์‹ ์Šน๋ฆฌํ•˜๋ จ๋‹ค...


1. ๋งก๊น€ API๋ž€?

https://matgim.ai/public-api/

๋ฐ์ดํƒ„์†Œํ”„ํŠธ๋ผ๋Š” ํšŒ์‚ฌ์—์„œ ์ถœ์‹œํ•œ API ์„œ๋น„์Šค์ธ๋ฐ, ๋‹ค์–‘ํ•œ ์ธ๊ณต์ง€๋Šฅ API๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ์„œ๋น„์Šค๋ผ๊ณ  ํ•œ๋‹ค. ์‹ค์ œ๋กœ ๊ฐ์ • ๋ถ„์„ API ๋ง๊ณ ๋„ ๋‹ค์–‘ํ•œ API๋“ค์ด ์žˆ๋‹ค.

์‹ฌ์ง€์–ด ๋น„์†์–ด ์ถ”์ถœ API ์ด๋Ÿฐ๊ฒƒ๋„ ์žˆ๋‹ค. ์ด๋Ÿฐ๊ฑธ ๋ฌด๋ฃŒ๋กœ ํ’€์–ด์ฃผ๋Š”๊ฒŒ ๋„ˆ๋ฌด ๊ฐ์‚ฌํ•  ๋”ฐ๋ฆ„...

์™„๋ฒฝํ•œ ๋ฌด๋ฃŒ๋Š” ์•„๋‹ˆ๊ณ , ํ•œ๋‹ฌ์— 100ํšŒ ์ด์ƒ์€ ๋งŒ์› + a๋กœ ๊ณผ๊ธˆ์ด ๋œ๋‹ค.

๊ทผ๋ฐ ํ”Œ์ ์„ ์‚ฌ์šฉํ•  ๋‚˜๋‚˜ ๋‚ด ์นœ๊ตฌ๋“ค์ด ๋งค์ผ๋งค์ผ ์ผ๊ธฐ๋ฅผ ์“ธ ์ •๋„๋กœ ๋ถ€์ง€๋Ÿฐํ•˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์—(ใ…‹ใ…‹ใ…‹ใ…‹ใ…‹ใ…‹ใ…‹ใ…‹ใ…‹ใ…‹ใ…‹ใ…‹) ์•ˆ์‹ฌํ•˜๊ณ  ๊ณผ๊ธˆ ๋ฒ„์ „ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์„๊ฑฐ๋‹ค. ์นœ๊ตฌ๋“ค์•„ ๊ณ ๋งˆ์›Œ!

 

2. ๊ฐœ๋ฐœ ์ˆœ์„œ

๊ธฐ์กด์˜ Google ์ž์—ฐ์–ด ๋ถ„์„ API๋ฅผ ์‹น ๋‹ค ์ฃผ์„์ฒ˜๋ฆฌํ•˜๊ณ  ๊ฑฐ๊ธฐ์— ์ƒˆ๋กœ์ด ๋งก๊น€ API๋ฅผ ์‚ฌ์šฉํ•  ๊ฒƒ์ด๊ธฐ ๋•Œ๋ฌธ์— controller, service๋Š” ์ƒˆ๋กœ์ด ์ƒ์„ฑ๋  ํ•„์š”๋Š” ์—†๋‹ค.

๋‹ค๋งŒ Google์—์„  ์ž์ฒด์ ์œผ๋กœ ์˜์กด์„ฑ์„ ์ถ”๊ฐ€์‹œ์ผœ์„œ ๊ฐ์ฒด๋ฅผ ๋ณธ์ธ๋“ค์ด ์ƒ์„ฑํ•ด์คฌ๋Š”๋ฐ(Sentiment, LanguageServiceClient์™€ ๊ฐ™์ด)

๋งก๊น€์€ ๊ทธ๋Ÿฐ๊ฑฐ ์—†์–ด์„œ ๋‚ด๊ฐ€ ์ง์ ‘ ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•ด์•ผ ํ•œ๋‹ค. 

 

(1) MatgimResponseDTO ๊ฐ์ฒด ์ƒ์„ฑ

๋งก๊น€ API์—์„œ ๋‹ค์Œ๊ณผ ๊ฐ™์€ json ํ˜•์‹์œผ๋กœ ๊ฐ€์ ธ์˜ค๊ธฐ ๋•Œ๋ฌธ์— ์ด๊ฒƒ๊ณผ ๋™์ผํ•œ ๊ตฌ์กฐ์˜ DTO๋ฅผ ๋งŒ๋“ ๋‹ค.

import com.fasterxml.jackson.databind.PropertyNamingStrategies;
import com.fasterxml.jackson.databind.annotation.JsonNaming;
import lombok.*;
import java.util.List;

@Getter
@Setter
@ToString
@NoArgsConstructor
@AllArgsConstructor
@JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class)
public class MatgimResponseDTO {
    private boolean success;
    private Result result;

    @Getter
    @Setter
    @ToString
    @NoArgsConstructor
    @AllArgsConstructor
    @JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class)
    public static class Result {
        private DocumentScore documentScore;
        private List<SentenceScore> sentenceScore;
    }

    @Getter
    @Setter
    @ToString
    @NoArgsConstructor
    @AllArgsConstructor
    @JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class)
    public static class DocumentScore {
        private double score;
        private double posScore;
        private double negScore;
    }

    @Getter
    @Setter
    @ToString
    @NoArgsConstructor
    @AllArgsConstructor
    @JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class)
    public static class SentenceScore {
        private String sentence;
        private double score;
    }

}

์ฐธ๊ณ ๋กœ

@JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class)

์ด๊ฑด Java๊ฐ์ฒด์˜ camelCase์™€ Json ๊ฐ์ฒด์˜ snake_case๋ฅผ ์„œ๋กœ ๋งคํ•‘์‹œ์ผœ์ฃผ๋Š” ์„ค์ •์ด๋‹ค.

์™ธ๋ถ€์—์„œ ๋“ค์–ด์˜ค๋Š” snake_caseํ˜•์‹์˜ Json ๋ฐ์ดํ„ฐ๋ฅผ Java์˜ caleCase๋กœ ํ•„๋“œ์— ์ž๋™์œผ๋กœ ๋งคํ•‘(์—ญ์ง๋ ฌํ™”)ํ•ด์ค„ ์ˆ˜ ์žˆ๋‹ค.

 

ํ˜„์žฌ ํด๋ž˜์Šค๋Š” 

public class MatgimResponseDTO {  // ์ตœ์ƒ์œ„ ๋ถ€๋ชจ ํด๋ž˜์Šค
    // ๋‚ด๋ถ€ ํด๋ž˜์Šค
    class Inner {}          // โŒ static ์—†์Œ
    static class Inner2 {}  // โœ… static ์žˆ์Œ
}

์ด๋Ÿฐ ๊ตฌ์กฐ์ด๋‹ค.  

  1. public class MatgimResponseDTO(์ตœ์ƒ์œ„ ํด๋ž˜์Šค) : ๋ถ€๋ชจ ํด๋ž˜์Šค๋ผ๋Š” ๊ฐœ๋…์ด ์—†์Œ. ๋…๋ฆฝ์ ์ธ ํŒŒ์ผ ๋‹จ์œ„, ์–ด๋””์„œ๋“  new MatgimResopnseDTO()๋กœ ๋ฐ”๋กœ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ์Œ.
  2. public class inner : MatgimResponseDTO๋ผ๋Š” '์ง‘' ์•ˆ์—์„œ๋งŒ ์‚ด ์ˆ˜ ์žˆ๋Š” ํด๋ž˜์Šค. ๋ฐ˜๋“œ์‹œ MatgimResponseDTO๊ฐ€ ๋จผ์ € ์ƒ์„ฑ๋˜์–ด์•ผ ํ•œ๋‹ค. static์ด ์—†๋Š” ๋‚ด๋ถ€ ํด๋ž˜์Šค์ผ ๋•Œ๋งŒ(=public class Inner์ผ๋•Œ๋งŒ) ์™ธ๋ถ€ ํด๋ž˜์Šค ๊ฐ์ฒด(MatgimResponseDTO)๊ฐ€ ์žˆ์–ด์•ผ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ๋‹ค.
  3. public static class Result(๋‚ด๋ถ€ ํด๋ž˜์Šค์— static์ด ์žˆ๋Š” ๊ฒฝ์šฐ) : ์ด๋ฆ„ํ‘œ๋Š” MatgimResponseDTO.Result๋ฅผ ๋‹ฌ๊ณ  ์žˆ์ง€๋งŒ ์‹ค์ œ๋ก  new MatgimResponseDTO.Result()๋กœ ํ˜ผ์ž ํƒœ์–ด๋‚  ์ˆ˜ ์žˆ์Œ

๊ทธ๋ ‡๋‹ค๋ฉด public class์™€ public static class์˜ ์ฐจ์ด๋Š”?

  • public class : ์™ธ๋ถ€ ํด๋ž˜์Šค์˜ ์ธ์Šคํ„ด์Šค๊ฐ€ ๋จผ์ € ์ƒ์„ฑ๋˜์•ผ๋งŒ ์กด์žฌํ•  ์ˆ˜ ์žˆ๋Š” ํด๋ž˜์Šค. ๋‹จ ์ตœ์ƒ์œ„ ํด๋ž˜์Šค์˜ ๊ฒฝ์šฐ ์™ธ๋ถ€ ํด๋ž˜์Šค๋ผ๋Š” ๊ฐœ๋…๋„ ์—†๋‹ค(ex. MatgimResponseDTO)
  • public static class : public class ๋‚ด๋ถ€์—์„œ๋งŒ ์“ธ ์ˆ˜ ์žˆ๋Š” ์ •์  ํด๋ž˜์Šค. ์—ฌ๊ธฐ์„  public Static class Result, public static class DocumentScore, public static class SentenceScore๊ฐ€ ์žˆ๋‹ค. ์ผ๋ฐ˜ ํด๋ž˜์Šค์ฒ˜๋Ÿผ ํ˜ผ์ž ์ƒ์„ฑ ๊ฐ€๋Šฅํ•˜๋ฉฐ ์ฃผ๋กœ DTO ๊ณ„์ธต ๊ตฌ์กฐ๋ฅผ ๋งŒ๋“ค ๋•Œ ๊ถŒ์žฅ๋œ๋‹ค.

๐Ÿ‘‰ "๋‚ด๋ถ€ ํด๋ž˜์Šค์ผ ๋•Œ" static ์—†์œผ๋ฉด “๋ถ€๋ชจ ์—†์ด๋Š” ๋ชป ํƒœ์–ด๋‚จ” → MatgimResponseDTO์—์„  ํ•ด๋‹น ์—†์Œ(์• ์ดˆ์— ๋‚ด๋ถ€ ํด๋ž˜์Šค๊ฐ€ ์•„๋‹ˆ๊ธฐ ๋•Œ๋ฌธ)
๐Ÿ‘‰ static ์žˆ์œผ๋ฉด “ํ˜ผ์ž ํƒœ์–ด๋‚  ์ˆ˜ ์žˆ์Œ”

MatgimResponseDTO
 โ””โ”€โ”€ Result
      โ””โ”€โ”€ DocumentScore
      โ””โ”€โ”€ SentenceScore

์—ฌ๊ธฐ์„œ MatgimResponseDTO๋Š” ์ตœ์ƒ์œ„ ํด๋ž˜์Šค๋กœ ๋ถ€๋ชจ๊ฐ€ ์—†๋‹ค. 

Result, DocumentScore, SentenceScore์€ MatgimResponseDTO ์•ˆ์— ํฌํ•จ๋œ ๋‚ด๋ถ€ ํด๋ž˜์Šค.

Result ๋‚˜ DocumentScore์„ static์œผ๋กœ ์„ ์–ธํ•ด์•ผ ํ•˜๋Š” ์ด์œ ๋Š”

  1. ๋…๋ฆฝ์  ์ธ์Šคํ„ด์Šคํ™” : Jackson์ด JSON์„ Java๊ฐ์ฒด๋กœ ๋ฐ”๊ฟ€ ๋•Œ, ์™ธ๋ถ€ ํด๋ž˜์Šค์ธ MatgimResponseDTO๋ฅผ ๋จผ์ € ๋งŒ๋“ค์ง€ ์•Š๊ณ ๋„ ๋‚ด๋ถ€์˜ Result๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ์–ด์•ผ ํ•œ๋‹ค.
  2. ๋ฉ”๋ชจ๋ฆฌ ํšจ์œจ : static์ด ์•„๋‹ˆ๋ฉด ๋‚ด๋ถ€ ํด๋ž˜์Šค ๊ฐ์ฒด๋Š” ์ž์‹ ์„ ๊ฐ์‹ธ๊ณ  ์žˆ๋Š” ์™ธ๋ถ€ ํด๋ž˜์Šค์˜ ์ •๋ณด๋ฅผ ํ•ญ์ƒ ๋“ค๊ณ  ์žˆ์–ด์•ผ ํ•œ๋‹ค. DTO์ฒ˜๋Ÿผ ๋‹จ์ˆœ ๋ฐ์ดํ„ฐ๋ฅผ ๋‹ด๋Š” ์šฉ๋„๋ผ๋ฉด ์ด๋Ÿฐ ์—ฐ๊ฒฐ ๊ณ ๋ฆฌ๋Š” ๋ฉ”๋ชจ๋ฆฌ ๋‚ญ๋น„๋งŒ ์ดˆ๋ž˜ํ•œ๋‹ค.
  3. ๊ตฌ์กฐ์  ๊ทธ๋ฃนํ™” : ๊ด€๋ จ ์žˆ๋Š” ๋ฐ์ดํ„ฐ ๊ตฌ์กฐ(Result, Score)๋ฅผ ๋”ฐ๋กœ ๋งŒ๋“ค์ง€ ์•Š๊ณ  ํ•˜๋‚˜์˜ ํŒŒ์ผ ์•ˆ์—์„œ ๋…ผ๋ฆฌ์ ์œผ๋กœ ๋ฌถ์–ด ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ์–ด ๊ฐ€๋…์„ฑ์ด ์ข‹์•„์ง„๋‹ค.

๋”ฐ๋ผ์„œ static์ด ๋ถ™์ง€ ์•Š๋Š” ๋‚ด๋ถ€ ํด๋ž˜์Šค๋Š” ๋ถ€๋ชจ(์™ธ๋ถ€)๊ฐ€ ์žˆ์–ด์•ผ ํƒœ์–ด๋‚  ์ˆ˜ ์žˆ๋Š” ์ž์‹์ด๊ณ , static class๋Š” ๋ถ€๋ชจ ์ง‘ ์•ˆ์— ์‚ด์ง€๋งŒ ์ž๊ธฐ ์ฐจ์™€ ์—ด์‡ ๋ฅผ ๋”ฐ๋กœ ๊ฐ€์ง€๊ณ  ์žˆ๋Š” ๋…๋ฆฝ๋œ ์„ฑ์ธ์ด๋ผ ๋ณผ ์ˆ˜ ์žˆ๋‹ค.

 

(2) WebClient ์„ค์ •

์‹ค๋ฌด์—์„œ RestTemplate๋ฅผ ์ด์šฉํ•ด์„œ ์™ธ๋ถ€ API์™€ ์—ฐ๊ฒฐํ•˜๋Š”๊ฒŒ ํ‘œ์ค€์ด์—ˆ๋Š”๋ฐ, ์š”์ฆ˜ RestTemplate ์“ฐ๋Š”๊ฒƒ๋„ ๊ตฌ์‹œ๋Œ€์ ์ด๋ผ ๊ถŒ์žฅ๋˜์ง€ ์•Š๋Š”๋‹ค๊ณ  ํ•œ๋‹ค. (๊ทธ๋ž˜์„œ ์„ ๋ฐฐ๊ฐ€ ๋ฆฌํŒฉํ† ๋ง ํ•˜๋‹ค๊ฐ€ ๊ธฐ์กด ์ฝ”๋“œ ๋‹ค ์ด์ƒํ•ด์ ธ์„œ ๋กค๋ฐฑํ•œ๊ฑด ์•ˆ๋น„๋ฐ€)

๊ทธ๋ž˜์„œ ์ดˆ์žฅ๋ถ€ํ„ฐ ๊ทธ๋ƒฅ RestTemplate๋ง๊ณ  ์ข€ ๋” ์ข‹์€๊ฒŒ ๋ญ๊ฐ€ ์žˆ์„์ง€ ์ƒ๊ฐํ•˜๋‹ค๊ฐ€ WebClient๋ผ๋Š”๊ฑธ ๋ฐœ๊ฒฌํ–ˆ๋‹ค. WebClient๋Š” ๋น„๋™๊ธฐ ๋ฐ ๋น„์ฐจ๋‹จ ํ†ต์‹ ์„ ํšจ์œจ์ ์œผ๋กœ ์ฒ˜๋ฆฌํ•˜๋Š” ๋ฐ˜์‘ํ˜• Http client๋ผ๊ณ  ํ•œ๋‹ค.

  1. ๋น„๋™๊ธฐ, ๋…ผ๋ธ”๋กœํ‚น(Non-Blocking) ๋ฐฉ์‹ : WebClient๋Š” Reactive Stack์„ ๊ธฐ๋ฐ˜์œผ๋กœ ํ•œ๋‹ค. API์š”์ฒญ์„ ๋ณด๋‚ธ ๋’ค ์‘๋‹ต์ด ์˜ฌ ๋•Œ ๊นŒ์ง€ ์Šค๋ ˆ๋“œ๊ฐ€ ๋Œ€๊ธฐ(Block)ํ•˜์ง€ ์•Š๊ณ  ๋‹ค๋ฅธ ์ผ์„ ํ•  ์ˆ˜ ์žˆ๋‹ค. ์ ์€ ์ˆ˜์˜ ์Šค๋ ˆ๋“œ๋กœ ํ›จ์”ฌ ๋งŽ์€ ๋™์‹œ ์š”์ฒญ์„ ํ•  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ์„œ๋ฒ„์˜ ์ฒ˜๋ฆฌ๋Ÿ‰์ด ํš๊ธฐ์ ์œผ๋กœ ๋Š˜์–ด๋‚œ๋‹ค. 
  2. ์‹ฑ๊ธ€ํ†ค(Singleton)์œผ๋กœ ๊ด€๋ฆฌ๋˜๋Š” ์žฌ์‚ฌ์šฉ์„ฑ : @Bean์œผ๋กœ ๋“ฑ๋กํ•˜๋ฉด ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ๊ฐ€ WebClient ๊ฐ์ฒด๋ฅผ ๋”ฑ ํ•˜๋‚˜๋งŒ ๋งŒ๋“ค์–ด์„œ ๊ด€๋ฆฌํ•œ๋‹ค. ๋ฆฌ์†Œ์Šค๋ฅผ ์ ˆ์•ฝํ•˜๊ณ  ์„ค์ •์„ ๊ณต์œ ํ•  ์ˆ˜ ์žˆ๋‹ค. 
  3. ์œ ์—ฐํ•œ ํ™•์žฅ์„ฑ: ๋‚˜์ค‘์— ํƒ€์ž„์•„์›ƒ ์„ค์ •, ๋กœ๊น…์šฉ ํ•„ํ„ฐ, ํŠน์ • API ์ „์šฉ ์ธ์ฆ ํ—ค๋” ์ถ”๊ฐ€ ๋“ฑ๋“ฑ์„ builder์— ํ•œ์ค„๋งŒ ์ถ”๊ฐ€ํ•˜๋ฉด ๋œ๋‹ค. ๋˜ํ•œ ํ•œ๋ฒˆ ๋นŒ๋“œ๋œ WebClient๋Š” ์ƒํƒœ๊ฐ€ ๋ณ€ํ•˜์ง€ ์•Š์œผ๋ฏ€๋กœ ์—ฌ๋Ÿฌ ์Šค๋ ˆ๋“œ์—์„œ ๋™์‹œ์— ์‚ฌ์šฉํ•ด๋„ ์•ˆ์ „ํ•˜๋‹ค.
  4. ๊ฐ€๋…์„ฑ๊ณผ ์œ ์ง€๋ณด์ˆ˜ : .retrieve().bodyToMono(MatgimResponseDTO.class) ์ด๊ฑฐ ํ•œ์ค„์ด๋ฉด API์‘๋‹ต์ธ snake_case๋ฅผ ์šฐ๋ฆฌ๊ฐ€ ๋งŒ๋“  camelCase๋กœ ์ž๋™ ๋ณ€ํ™˜ํ•ด์ค€๋‹ค.
๋”๋ณด๊ธฐ
์ฐธ๊ณ ๋กœ ์Šค๋ ˆ๋“œ(thread)๋ž€?

ํ•˜๋‚˜์˜ ํ”„๋กœ์„ธ์Šค ์•ˆ์—์„œ ๋…๋ฆฝ์ ์œผ๋กœ ์‹คํ–‰๋˜๋Š” '์ž‘์€ ์‹คํ–‰ ๋‹จ์œ„'

์‰ฝ๊ฒŒ ๋น„์œ ํ•˜์ž๋ฉด "์ผ๊พผ"์ด๋‹ค.  ์ž๋ฐ” ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜(์„œ๋ฒ„)์ด๋ผ๋Š” ์‹๋‹น์—์„œ ์†๋‹˜์˜ ์ฃผ๋ฌธ์„ ๋ฐ›๊ณ  ์š”๋ฆฌํ•ด์„œ ์„œ๋น™๊นŒ์ง€ ํ•˜๋Š” ์ง์› ํ•œ ๋ช…์ด ๊ณง ์Šค๋ ˆ๋“œ ํ•˜๋‚˜๋ผ๊ณ  ์ƒ๊ฐํ•˜๋ฉด ๋œ๋‹ค.

  • ์Šค๋ ˆ๋“œ๊ฐ€ ๋งŽ์œผ๋ฉด? ์ผ๊พผ์ด ๋งŽ์œผ๋‹ˆ ๋™์‹œ์— ์—ฌ๋Ÿฌ ์†๋‹˜์„ ์‘๋Œ€ํ•  ์ˆ˜ ์žˆ์ง€๋งŒ, ์ผ๊พผ๋งˆ๋‹ค ์›”๊ธ‰(๋ฉ”๋ชจ๋ฆฌ ์ ์œ )์„ ์ค˜์•ผ ํ•˜๊ณ  ๊ด€๋ฆฌํ•˜๊ธฐ๊ฐ€ ํž˜๋“ค์–ด์ง
  • ์Šค๋ ˆ๋“œ๊ฐ€ ์ ์œผ๋ฉด? ์„œ๋ฒ„๊ฐ€ ์‚ฌ์šฉํ•˜๋Š” ๋ฉ”๋ชจ๋ฆฌ๊ฐ€ ์ ๊ณ  ๊ฐ€๋ณ์ง€๋งŒ, ์ผ๊พผ์ด ๋ชจ์ž๋ผ๋ฉด ์†๋‹˜๋“ค์ด ์ค„์„ ์„œ์„œ ๊ธฐ๋‹ค๋ ค์•ผํ•จ

โŒ Thread 1๊ฐœ

์š”์ฒญ1 → ๋๋‚˜์•ผ → ์š”์ฒญ2 → ๋๋‚˜์•ผ → ์š”์ฒญ3 ๐Ÿ‘‰ ๋А๋ฆผ
 

โœ” Thread ์—ฌ๋Ÿฌ ๊ฐœ

์š”์ฒญ1
์š”์ฒญ2
์š”์ฒญ3
๋™์‹œ์— ์ฒ˜๋ฆฌ๐Ÿ‘‰ ๋น ๋ฆ„

 

 

๊ทธ๋Ÿผ ํ”„๋กœ์„ธ์Šค(process)๋ž€?

์‹œ์Šคํ…œ์—์„œ ์‹คํ–‰ ์ค‘์ธ ํ”„๋กœ๊ทธ๋žจ

์ด์ œ ์™œ ์ตœ๊ทผ์— RestTemplate๊ฐ€ ์•„๋‹Œ WebClient๊ฐ€ ์‚ฌ์šฉ๋˜๋Š”์ง€ ์ด์ œ ์•Œ๊ฒ ๋‹ค~

 

1๏ธโƒฃ pom.xml์— ์˜์กด์„ฑ ์ถ”๊ฐ€

<!-- webClient -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-webflux</artifactId>
</dependency>

 

2๏ธโƒฃ WebCientConfig ์ž‘์„ฑํ•˜๊ธฐ

@Configuration
public class WebClientConfig {

    @Bean
    public WebClient MatgimWebClient(){
       return WebClient.builder()
               .defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
               .build();
    }
}
  • @Configuration : ์Šคํ”„๋ง์ด ์‹œ์ž‘๋  ๋•Œ Configuration ์–ด๋…ธํ…Œ์ด์…˜์„ ์ฝ์–ด์„œ ์„ค์ •์„ ์‹คํ–‰ํ•จ. ์ž๋ฐ”์˜ ์ผ๋ฐ˜ ํด๋ž˜์Šค๊ฐ€ ์•„๋‹Œ ์Šคํ”„๋ง ์‹œ์Šคํ…œ์˜ ์„ค๊ณ„๋„ ์—ญํ• 
  • @Bean : ๋‹ค๋ฅธ ์„œ๋น„์Šค ํด๋ž˜์Šค์—์„œ new WebClient()๋ฅผ ๋งค๋ฒˆ ํ•  ํ•„์š” ์—†์ด ์Šคํ”„๋ง์ด ๋ฏธ๋ฆฌ ๋งŒ๋“ค์–ด์ค€ ์ด ๊ฐ์ฒด๋ฅผ "์ฃผ์ž…(@Autowired)"๋ฐ”๋‹น ์“ธ ์ˆ˜ ์žˆ์Œ(์‹ฑ๊ธ€ํ†ค ํŒจํ„ด)
  • public WebClient MatgimWebClient() : ์ƒ์„ฑ๋  ๊ฐ์ฒด์˜ ํƒ€์ž…์€ WebClient, ์ด Bean์˜ ์ด๋ฆ„์€ MatgimWebClient
  • WebClient.builder() : WebClient ๊ฐ์ฒด๋ฅผ ๋งŒ๋“ค๊ธฐ ์œ„ํ•œ ์กฐ๋ฆฝ ๋„๊ตฌ(Builder)๋ฅผ ๊บผ๋‚ด๋Š” ๋‹จ๊ณ„
  • defaultHeader(HttpHeader.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE) : ํด๋ผ์ด์–ธํŠธ๋กœ ๋ณด๋‚ด๋Š” ๋ชจ๋“  ์š”์ฒญ์€ ๊ธฐ๋ณธ์ ์œผ๋กœ JSON์ž„์„ ๋ช…์‹œํ•จ)
  • build() : ์„ค์ •์„ ๋งˆ์นœ ์ตœ์ข… ๊ฐ์ฒด๊ฐ€ ์ƒ์„ฑ๋˜์–ด ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ์— ๋ณด๊ด€๋จ

3๏ธโƒฃ API ํ˜ธ์ถœํ•˜๊ธฐ

String body = request.getText();
Map<String,String> bodyMap = new HashMap<>();
bodyMap.put("document", body);

MatgimResponseDTO result = webClient.post()
        .uri(matgimUrl)
        .header("Content-Type", "application/json")
        .header("x-auth-token", matgimApiKey)
        .bodyValue(bodyMap)
        .retrieve()
        .bodyToMono(MatgimResponseDTO.class)
        .block();

์ด์ œ service๋‹จ์—์„œ API ํ˜ธ์ถœ๋ถ€๋ฅผ ์ž‘์„ฑํ•˜๋ฉด ๋œ๋‹ค. 

  • ์š”์ฒญ ๋ฐ์ดํ„ฐ ์ค€๋น„
String body = request.getText(); // ์‚ฌ์šฉ์ž๊ฐ€ ๋ณด๋‚ธ ์ผ๊ธฐ ๋‚ด์šฉ ๋“ฑ์„ ๊ฐ€์ ธ์˜ด
Map<String, String> bodyMap = new HashMap<>();
bodyMap.put("document", body); // API๊ฐ€ ์›ํ•˜๋Š” {"document": "๋‚ด์šฉ"} ํ˜•์‹์œผ๋กœ ๋งŒ๋“ฆ
  • ํ˜ธ์ถœ๋ถ€ ์ž‘์„ฑ
MatgimResponseDTO result = webClient.post() // 1. POST ๋ฐฉ์‹
        .uri(matgimUrl) // 2. ๋ชฉ์ ์ง€ ์ฃผ์†Œ(URL) ์„ค์ •
        .header("Content-Type", "application/json") // 3. JSON ๋ฐ์ดํ„ฐ๋ผ๊ณ  ์•Œ๋ฆผ
        .header("x-auth-token", matgimApiKey) // 4. ์ธ์ฆ ํ‚ค๋ฅผ ํ—ค๋”์— ๋‹ด์Œ
        .bodyValue(bodyMap) // 5. ์ค€๋น„ํ•œ ๋ฐ์ดํ„ฐ๋ฅผ ๋ชธ์ฒด(Body)์— ์‹ค์Œ
        .retrieve() // 6. ์ด์ œ ์š”์ฒญ์„ ์จ
        .bodyToMono(MatgimResponseDTO.class) // 7. ๋ฐ›์€ JSON์„ ์•„๊นŒ ๋งŒ๋“  DTO ๊ฐ์ฒด๋กœ ์ž๋™ ๋ณ€ํ™˜
        .block(); // 8. ๊ฒฐ๊ณผ๊ฐ€ ์˜ฌ ๋•Œ๊นŒ์ง€ ๊ธฐ๋‹ค๋ฆผ (๋™๊ธฐ์  ์ฒ˜๋ฆฌ)

.block()์˜ ์˜๋ฏธ: ์›๋ž˜ WebClient๋Š” ๋น„๋™๊ธฐ(Non-blocking)๋กœ ๋™์ž‘ํ•˜์ง€๋งŒ, ์—ฌ๊ธฐ์„œ .block()์„ ์“ฐ๋ฉด ์‘๋‹ต์ด ์˜ฌ ๋•Œ๊นŒ์ง€ ๋‹ค์Œ ์ฝ”๋“œ๋กœ ๋„˜์–ด๊ฐ€์ง€ ์•Š๊ณ  ๊ธฐ๋‹ค๋ฆฐ๋‹ค. ์™œ๋ƒ๋ฉด

double score = result != null ? result.getResult().getDocumentScore().getScore() * 2.5 : 0;
        score = Math.max(-1, Math.min(1, score));

        double positive = result != null ? result.getResult().getDocumentScore().getPosScore() : 0;
        double negative = result != null ? result.getResult().getDocumentScore().getNegScore() : 0;
        double magnitude = (Math.abs(positive) + Math.abs(negative)) * 5;

        response.setScore(score);
        response.setMagnitude(magnitude);
        return ResponseEntity.ok(response);

์ด ๋กœ์ง ๋•Œ๋ฌธ์—.. ๊ธฐ์กด์— google api์—์„  ๊ฐ์ •์„ score๊ณผ magnitude๋กœ ๋ถ„๋ฆฌํ•ด์„œ ๋ณด๋‚ด์คฌ๋Š”๋ฐ, ๋งก๊น€์€ ๊ธ์ •์ ์ธ ๊ฐ์ •, ๋ถ€์ •์ ์ธ ๊ฐ์ •์˜ ์ ์ˆ˜๋งŒ ์•Œ๋ ค์ค€๋‹ค. ๊ทธ๋ž˜์„œ ๊ทธ๊ฑธ score๊ณผ magnitude๋กœ ๋ณ€ํ™˜ํ•œ ๊ฐœ์ธ์ ์ธ ๋กœ์ง์ด๋‹ค... ์ด ๋ถ€๋ถ„์€ ํ•„์ˆ˜๋Š” ์•„๋‹ˆ๋‹ค!

 

[์ฐธ๊ณ  ๋ฌธํ—Œ]

https://m.blog.naver.com/seek316/223337685249 

 

[Java] Spring Boot - WebClient ์‚ฌ์šฉํ•˜๊ธฐ

WebClient๋ž€? WebClient๋Š” Spring Boot ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์—์„œ HTTP ์š”์ฒญ์„ ๋งŒ๋“œ๋Š” ๋ฐ ์‚ฌ์šฉ๋˜๋Š” ๊ฐ•๋ ฅ...

blog.naver.com

https://coding-factory.tistory.com/279

 

[Java] ์ž๋ฐ” Thread(์Šค๋ ˆ๋“œ) ์‚ฌ์šฉ๋ฒ• & ์˜ˆ์ œ

Thread๋ž€? ํ•˜๋‚˜์˜ ํ”„๋กœ์„ธ์Šค ๋‚ด๋ถ€์—์„œ ๋…๋ฆฝ์ ์œผ๋กœ ์‹คํ–‰๋˜๋Š” ํ•˜๋‚˜์˜ ์ž‘์—… ๋‹จ์œ„๋ฅผ ๋งํ•˜๋ฉฐ, ์„ธ๋ถ€์ ์œผ๋กœ๋Š” ์šด์˜์ฒด์ œ์— ์˜ํ•ด ๊ด€๋ฆฌ๋˜๋Š” ํ•˜๋‚˜์˜ ์ž‘์—… ํ˜น์€ ํƒœ์Šคํฌ๋ฅผ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค. ์Šค๋ ˆ๋“œ์™€ ํƒœ์Šคํฌ(ํ˜น์€ ์ž‘

coding-factory.tistory.com