{"id":5877,"date":"2022-07-28T15:31:30","date_gmt":"2022-07-28T06:31:30","guid":{"rendered":"https:\/\/www.skyer9.pe.kr\/wordpress\/?p=5877"},"modified":"2023-02-14T14:40:52","modified_gmt":"2023-02-14T05:40:52","slug":"feign-client","status":"publish","type":"post","link":"https:\/\/www.skyer9.pe.kr\/wordpress\/?p=5877","title":{"rendered":"Feign Client"},"content":{"rendered":"<h1>Feign Client<\/h1>\n<p><a href=\"https:\/\/vmpo.tistory.com\/109\">\ucc38\uc870<\/a><\/p>\n<p>Rest API \ud638\ucd9c\uacfc Json \uc744 \ud074\ub798\uc2a4\ub85c \uc790\ub3d9\ubcc0\ud658\uae4c\uc9c0 \ud574\uc8fc\ub294 \ub77c\uc774\ube0c\ub7ec\ub9ac\uc774\ub2e4.<\/p>\n<h2>\uc758\uc874\uc131<\/h2>\n<pre><code class=\"language-gradle\">dependencies {\n    implementation &#039;org.springframework.cloud:spring-cloud-openfeign-core:3.1.5&#039;\n    implementation &#039;org.springframework.cloud:spring-cloud-starter-openfeign:3.1.5&#039;\n    # compile(&quot;org.springframework.cloud:spring-cloud-starter-openfeign&quot;)\n}<\/code><\/pre>\n<h2>\ud65c\uc131\ud654<\/h2>\n<pre><code class=\"language-java\">@EnableFeignClients\n@SpringBootApplication\npublic class HelloApplication {\n    public static void main(String[] args) {\n        SpringApplication.run(HelloApplication.class, args);\n    }\n}<\/code><\/pre>\n<h2>\uc124\uc815<\/h2>\n<pre><code class=\"language-java\">public class FeignClientConfig implements Jackson2ObjectMapperBuilderCustomizer {\n    private static final Logger log = LoggerFactory.getLogger(FeignClientConfig.class);\n\n    public FeignClientConfig() {\n    }\n\n    @Bean\n    public FeignFormatterRegistrar localDateFeignFormatterRegister() {\n        return (registry) -&gt; {\n            DateTimeFormatterRegistrar registrar = new DateTimeFormatterRegistrar();\n            registrar.setUseIsoFormat(true);\n            registrar.registerFormatters(registry);\n        };\n    }\n\n    @Bean\n    public FeignErrorDecoder decoder() {\n        return new FeignErrorDecoder();\n    }\n\n    public void customize(Jackson2ObjectMapperBuilder jacksonObjectMapperBuilder) {\n        jacksonObjectMapperBuilder\n                .featuresToEnable(DeserializationFeature.READ_UNKNOWN_ENUM_VALUES_AS_NULL)\n                .featuresToDisable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)\n                .timeZone(TimeZone.getDefault())\n                .modulesToInstall(new Module[]{new JavaTimeModule()})\n                .locale(Locale.getDefault()).simpleDateFormat(&quot;yyyy-MM-dd HH:mm:ss&quot;);\n    }\n}<\/code><\/pre>\n<pre><code class=\"language-java\">public class FeignRetryConfig {\n    @Value(&quot;${feign.retry.period}&quot;)\n    private long period;\n    @Value(&quot;${feign.retry.max-period}&quot;)\n    private long maxPeriod;\n    @Value(&quot;${feign.retry.max-attempt}&quot;)\n    private int maxAttempt;\n\n    public FeignRetryConfig() {\n    }\n\n    @Bean\n    public Retryer retryer() {\n        return new Retryer.Default(this.period, this.maxPeriod, this.maxAttempt);\n    }\n}<\/code><\/pre>\n<pre><code class=\"language-java\">public class FeignErrorDecoder implements ErrorDecoder {\n    @Override\n    public Exception decode(String methodKey, Response response) {\n        switch (response.status()){\n            case 400:\n                break;\n            case 404:\n                if(methodKey.contains(&quot;getOrders&quot;)){\n                    return new ResponseStatusException(HttpStatus.valueOf(response.status()),\n                            &quot;User&#039;s orders is empty.&quot;);\n                }\n                break;\n            default:\n                return new Exception(response.reason());\n        }\n        return null;\n    }\n}<\/code><\/pre>\n<h2>\uc11c\ube44\uc2a4<\/h2>\n<pre><code class=\"language-java\">@FeignClient(name = &quot;HELLO-SERVICE&quot;,configuration = {FeignClientConfig.class, FeignRetryConfig.class})\npublic interface HelloService {\n    @GetMapping(&quot;\/hello\/{itemId}&quot;)\n    HelloModel getHelloByItemId(@PathVariable(&quot;itemId&quot;) String itemId);\n\n    @PostMapping(&quot;\/hello\/basic&quot;)\n    ProductDetailBasicResponseModel fetchHello(\n            @RequestBody List&lt;ItemidOnlyDto&gt; req\n    );\n}<\/code><\/pre>\n<h2>Header \ubd99\uc774\uae30<\/h2>\n<h3>\ud2b9\uc815 \uba54\uc18c\ub4dc\uc5d0\ub9cc \ubd99\uc774\uae30<\/h3>\n<pre><code class=\"language-java\">@FeignClient(name = &quot;HELLO-SERVICE&quot;,configuration = {FeignClientConfig.class, FeignRetryConfig.class})\npublic interface HelloService {\n    @GetMapping(&quot;\/hello\/{itemId}&quot;)\n    HelloModel getHelloByItemId(@PathVariable(&quot;itemId&quot;) String itemId);\n\n    @PostMapping(&quot;\/hello\/basic&quot;)\n    ProductDetailBasicResponseModel fetchHello(\n            @RequestHeader(&quot;X-Auth-Token&quot;) String accessToken,\n            @RequestBody List&lt;ItemidOnlyDto&gt; req\n    );\n}<\/code><\/pre>\n<h3>\ubaa8\ub4e0 \uba54\uc18c\ub4dc\uc5d0 \ubd99\uc774\uae30<\/h3>\n<p><code>RequestInterceptor<\/code> \ub97c \uad6c\ud604\ud574 \uc90c\uc73c\ub85c \ud574\uc11c,<br \/>\n\ubaa8\ub4e0 Feign Client method \uc5d0 header \uac00 \uc790\ub3d9\uc73c\ub85c \ubd99\ub294\ub2e4.<\/p>\n<pre><code class=\"language-java\">@Component\npublic class FeignRequestInterceptor implements RequestInterceptor {\n    private static final String X_AUTH_TOKEN = &quot;X-Auth-Token&quot;;\n    @Override\n    public void apply(RequestTemplate requestTemplate) {\n        ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();\n        if (requestAttributes == null) {\n            return;\n        }\n        HttpServletRequest request = requestAttributes.getRequest();\n        LoginInfo loginInfo = (LoginInfo) request.getAttribute(&quot;loginInfo&quot;);\n        if (loginInfo == null) {\n            return;\n        }\n\n        requestTemplate.header(X_AUTH_TOKEN, loginInfo.getBrowser());\n    }\n}<\/code><\/pre>\n<h2>\ud6c4\uae30<\/h2>\n<p>\ucca8 JPA \uc811\ud588\uc744 \ub54c,<br \/>\n\uba85\ub839 \ud558\ub098 \ud638\ucd9c\ud558\uba74,<br \/>\n\uc9c0 \ud63c\uc790 \ucffc\ub9ac \uc791\uc131\ud574\uc11c \ud638\ucd9c\ud558\uace0 \ub9ac\ud134\uac12 \ubc1b\uc544\uc11c \uc5d4\ud130\ud2f0\uc5d0 \ucc44\uc6cc\uc8fc\uace0&#8230;<br \/>\n\uc2e0\uae30\ud588\ub294\ub370&#8230;<\/p>\n<p>\ub531 \uadf8\ub290\ub08c\uc774\ub2e4.<br \/>\n\uba85\ub839 \ud558\ub098 \ud638\ucd9c\ud558\uba74,<br \/>\n\uc9c0 \ud63c\uc790 RequestBody \uc0dd\uc131\ud574\uc11c url \ud638\ucd9c\ud558\uace0,<br \/>\n\ub9ac\ud134 json \ubc1b\uc544\uc11c response class \uc5d0 \ub9e4\ud551\uae4c\uc9c0 \ud574\uc900\ub2e4.<br \/>\n\uc2ec\uc9c0\uc5b4 \uc11c\ubc84\uac00 \uc8fd\uc5b4 \uc788\uc73c\uba74 retry \uae4c\uc9c0\ub3c4 \ud574\uc900\ub2e4.<\/p>\n<p>\ub354\uad70\ub2e4\ub098,<br \/>\nlearning curve \ub77c\ub294 \ub2e8\uc5b4 \uc4f0\ub294\uac8c \ubbfc\ub9dd\ud560 \uc815\ub3c4\ub85c \uc27d\ub2e4.<\/p>\n<p>\ud5d0&#8230;<br \/>\n(\uba38\ub9ac\uac00 \ub098\uc058\uba74 \uc190\uac00\ub77d\uc774 \uace0\uc0dd\ud55c\ub2e4.)<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Feign Client \ucc38\uc870 Rest API \ud638\ucd9c\uacfc Json \uc744 \ud074\ub798\uc2a4\ub85c \uc790\ub3d9\ubcc0\ud658\uae4c\uc9c0 \ud574\uc8fc\ub294 \ub77c\uc774\ube0c\ub7ec\ub9ac\uc774\ub2e4. \uc758\uc874\uc131 dependencies { implementation &#039;org.springframework.cloud:spring-cloud-openfeign-core:3.1.5&#039; implementation &#039;org.springframework.cloud:spring-cloud-starter-openfeign:3.1.5&#039; # compile(&quot;org.springframework.cloud:spring-cloud-starter-openfeign&quot;) } \ud65c\uc131\ud654 @EnableFeignClients @SpringBootApplication public class HelloApplication { public static void main(String[] args) { SpringApplication.run(HelloApplication.class, args); } } \uc124\uc815 public class FeignClientConfig implements Jackson2ObjectMapperBuilderCustomizer { private static final Logger log = LoggerFactory.getLogger(FeignClientConfig.class); public FeignClientConfig()\u2026 <span class=\"read-more\"><a href=\"https:\/\/www.skyer9.pe.kr\/wordpress\/?p=5877\">Read More &raquo;<\/a><\/span><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[29],"tags":[],"class_list":["post-5877","post","type-post","status-publish","format-standard","hentry","category-spring-boot-2-5"],"_links":{"self":[{"href":"https:\/\/www.skyer9.pe.kr\/wordpress\/index.php?rest_route=\/wp\/v2\/posts\/5877","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.skyer9.pe.kr\/wordpress\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.skyer9.pe.kr\/wordpress\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.skyer9.pe.kr\/wordpress\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.skyer9.pe.kr\/wordpress\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=5877"}],"version-history":[{"count":13,"href":"https:\/\/www.skyer9.pe.kr\/wordpress\/index.php?rest_route=\/wp\/v2\/posts\/5877\/revisions"}],"predecessor-version":[{"id":7591,"href":"https:\/\/www.skyer9.pe.kr\/wordpress\/index.php?rest_route=\/wp\/v2\/posts\/5877\/revisions\/7591"}],"wp:attachment":[{"href":"https:\/\/www.skyer9.pe.kr\/wordpress\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=5877"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.skyer9.pe.kr\/wordpress\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=5877"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.skyer9.pe.kr\/wordpress\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=5877"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}