【问题标题】:Call another rest api from my server in Spring-Boot在 Spring-Boot 中从我的服务器调用另一个 rest api
【发布时间】:2017-07-10 22:54:24
【问题描述】:

我想根据用户的特定请求从我的后端调用另一个 web-api。例如,我想调用 Google FCM 发送消息 api 来向特定用户发送事件消息。

改造有什么方法可以做到这一点吗?如果没有,我该怎么做?

【问题讨论】:

标签: api spring-boot spring-data retrofit


【解决方案1】:

由于问题明确标记了 spring-boot,值得注意的是最近的版本已经为 WebClient 提供了一个预配置的构建器实例,因此您可以直接将其注入到服务构造函数中,而无需定义自定义 bean。

@Service
public class ClientService {

    private final WebClient webClient;

    public ClientService(WebClient.Builder webClientBuilder) {
        webClient = webClientBuilder
                        .baseUrl("https://your.api.com")
    }

    //Add all the API call methods you need leveraging webClient instance

}

https://docs.spring.io/spring-boot/docs/2.0.x/reference/html/boot-features-webclient.html

【讨论】:

    【解决方案2】:

    在这种情况下,需要通过我的 API 下载文件托管在其他服务器中。

    在我的情况下,不需要使用 HTTP 客户端来下载外部 URL 中的文件,我结合了以前代码中适用于本地服务器中文件的几个答案和方法。

    我的代码是:

    @GetMapping(value = "/download/file/pdf/", produces = MediaType.APPLICATION_PDF_VALUE)
        public ResponseEntity<Resource> downloadFilePdf() throws IOException {
            String url = "http://www.orimi.com/pdf-test.pdf";
        
            RestTemplate restTemplate = new RestTemplate();
            byte[] byteContent = restTemplate.getForObject(url, String.class).getBytes(StandardCharsets.ISO_8859_1);
            InputStream resourceInputStream = new ByteArrayInputStream(byteContent);
        
            return ResponseEntity.ok()
                    .header("Content-disposition", "attachment; filename=" + "pdf-with-my-API_pdf-test.pdf")
                    .contentType(MediaType.parseMediaType("application/pdf;"))
                    .contentLength(byteContent.length)
                    .body(new InputStreamResource(resourceInputStream));
        }
    

    它适用于 HTTP 和 HTTPS 网址!

    【讨论】:

    • 接受的答案已经展示了如何使用 Spring 的RestTemplate 来实现所需的结果。您的代码有何不同?
    【解决方案3】:

    正如这里的各种答案中提到的,WebClient 现在是推荐的路线。 您可以从配置 WebClient 构建器开始:

    @Bean
    public WebClient.Builder getWebClientBuilder(){
        return WebClient.builder();
    }
    

    然后注入 bean,您可以使用如下 API:

    @Autowired
    private WebClient.Builder webClientBuilder;
    
    
    Product product = webClientBuilder.build()
                .get()
                .uri("http://localhost:8080/api/products")
                .retrieve()
                .bodyToMono(Product.class)
                .block();
    

    【讨论】:

      【解决方案4】:

      使用 WebClient 而不是 RestTemplate 的现代 Spring 5+ 答案。

      为特定的 Web 服务或资源配置 WebClient 为 bean(可以配置其他属性)。

      @Bean
      public WebClient localApiClient() {
          return WebClient.create("http://localhost:8080/api/v3");
      }
      

      从您的服务中注入并使用 bean。

      @Service
      public class UserService {
      
          private static final Duration REQUEST_TIMEOUT = Duration.ofSeconds(3);
      
          private final WebClient localApiClient;
      
          @Autowired
          public UserService(WebClient localApiClient) {
              this.localApiClient = localApiClient;
          }
      
          public User getUser(long id) {
              return localApiClient
                      .get()
                      .uri("/users/" + id)
                      .retrieve()
                      .bodyToMono(User.class)
                      .block(REQUEST_TIMEOUT);
          }
      
      }
      

      【讨论】:

      • 对于那些正在搜索包含 WebClient 的软件包的人来说,spring-boot-starter-webflux in org.springframework.boot。您必须将其包含在您的 pom.xml 文件中。
      • 发现@ersu 的评论有用的人也发现这很有用;)stackoverflow.com/a/60747437/413032
      【解决方案5】:

      Retrofit 有什么方法可以做到这一点吗?如果没有,我该怎么做?

      Retrofit 是适用于 Android 和 Java 的类型安全 REST 客户端。 Retrofit 将您的 HTTP API 转换为 Java 接口。

      更多信息请参考以下链接

      https://howtodoinjava.com/retrofit2/retrofit2-beginner-tutorial

      【讨论】:

        【解决方案6】:

        为 Rest Template 创建 Bean 以自动连接 Rest Template 对象。

        @SpringBootApplication
        public class ChatAppApplication {
        
            @Bean
            public RestTemplate getRestTemplate(){
                return new RestTemplate();
            }
        
            public static void main(String[] args) {
                SpringApplication.run(ChatAppApplication.class, args);
            }
        
        }
        

        通过使用 RestTemplate - exchange() 方法来使用 GET/POST API。下面是在控制器中定义的 post api。

        @RequestMapping(value = "/postdata",method = RequestMethod.POST)
            public String PostData(){
        
               return "{\n" +
                       "   \"value\":\"4\",\n" +
                       "   \"name\":\"David\"\n" +
                       "}";
            }
        
            @RequestMapping(value = "/post")
            public String getPostResponse(){
                HttpHeaders headers=new HttpHeaders();
                headers.setAccept(Arrays.asList(MediaType.APPLICATION_JSON));
                HttpEntity<String> entity=new HttpEntity<String>(headers);
                return restTemplate.exchange("http://localhost:8080/postdata",HttpMethod.POST,entity,String.class).getBody();
            }
        

        参考本教程[1]

        [1]https://www.tutorialspoint.com/spring_boot/spring_boot_rest_template.htm

        【讨论】:

          【解决方案7】:

          您尝试通过调用另一个 API/URI 来获取自定义 POJO 对象详细信息作为输出,而不是 String,试试这个解决方案。我希望它对如何使用 RestTemplate 也有帮助,

          Spring Boot中,首先我们需要为@Configuration注解类下的RestTemplate创建Bean。您甚至可以编写一个单独的类并使用 @Configuration 进行注释,如下所示。

          @Configuration
          public class RestTemplateConfig {
          
              @Bean
              public RestTemplate restTemplate(RestTemplateBuilder builder) {
                 return builder.build();
              }
          }
          

          然后,您必须在您的服务/控制器下使用 @Autowired@Injected 定义 RestTemplate,无论您尝试使用 RestTemplate .使用下面的代码,

          @Autowired
          private RestTemplate restTemplate;
          

          现在,将看到如何使用上面创建的 RestTemplate 从我的应用程序调用另一个 api 的部分。为此,我们可以使用多种方法,例如 execute()getForEntity()getForObject() 等。这里我将代码与执行()的例子。我什至尝试过其他两个,我遇到了将返回的 LinkedHashMap 转换为预期的 POJO 对象的问题。下面的 execute() 方法解决了我的问题。

          ResponseEntity<List<POJO>> responseEntity = restTemplate.exchange(
              URL, 
              HttpMethod.GET, 
              null, 
              new ParameterizedTypeReference<List<POJO>>() {
              });
          List<POJO> pojoObjList = responseEntity.getBody();
          

          快乐编码:)

          【讨论】:

          • 所以当我尝试使用几乎与您完全相同的代码时,我收到错误“无法反序列化 [my pojo class] 的实例超出起始对象令牌。您知道为什么会这样吗?
          • 请验证您的 pojo 是否实现了 Serializable 接口?如果没有实现它并尝试。
          • 很遗憾,这并没有解决,还是谢谢你。
          【解决方案8】:

          This website has some nice examples for using spring's RestTemplate. 下面是一个如何获取简单对象的代码示例:

          private static void getEmployees()
          {
              final String uri = "http://localhost:8080/springrestexample/employees.xml";
          
              RestTemplate restTemplate = new RestTemplate();
              String result = restTemplate.getForObject(uri, String.class);
          
              System.out.println(result);
          }
          

          【讨论】:

          • Object result = restTemplate.getForObject(uri, Object .class); - 更通用
          • @Muhammad Faizan Uddin 我考虑过,但是如果由于任何原因无法正确序列化对象,iirc 现在可能会起作用;而字符串方法总是有效的,因为 JSON 总是可以序列化为字符串。
          • RestTemplate 将在未来的版本中被弃用,使用更现代的替代品WebClient
          • Added an answer 下面是 WebClient。
          • 教程真的很不错
          猜你喜欢
          • 2022-12-16
          • 2020-07-17
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2017-03-19
          • 1970-01-01
          相关资源
          最近更新 更多