Overview
I will introduce how to call third-party API in Spring Boot project. We’ll send GET request to this resource https://sampleapis.com/api-list/coffee, then display response data in view (browser).
Prerequisites
You need these knowledge at basic level:
- Java
- Spring Boot
- Thymeleaf
Development process
Create Project
Go to https://start.spring.io/ and generate a project with these dependencies:
Unzip the file and open the project in your code editor. I use Intellij community edition.
Create Controller
import com.myproject.apidemo.Coffee;import org.springframework.core.ParameterizedTypeReference;import org.springframework.stereotype.Controller;import org.springframework.ui.Model;import org.springframework.web.bind.annotation.*;import org.springframework.web.reactive.function.client.WebClient;@Controllerpublic class CoffeeController {@GetMapping("/coffee")public String coffee(Model model) {String url = "https://api.sampleapis.com/coffee/hot";WebClient.Builder builder = WebClient.builder();String coffeeList = builder.build().get().uri(url).retrieve().bodyToMono(String.class).block();System.out.println("---------------------");System.out.println(coffeeList);model.addAttribute("coffeeList", coffeeList);return "coffee";}}import com.myproject.apidemo.Coffee; import org.springframework.core.ParameterizedTypeReference; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.*; import org.springframework.web.reactive.function.client.WebClient; @Controller public class CoffeeController { @GetMapping("/coffee") public String coffee(Model model) { String url = "https://api.sampleapis.com/coffee/hot"; WebClient.Builder builder = WebClient.builder(); String coffeeList = builder.build() .get() .uri(url) .retrieve() .bodyToMono(String.class) .block(); System.out.println("---------------------"); System.out.println(coffeeList); model.addAttribute("coffeeList", coffeeList); return "coffee"; } }import com.myproject.apidemo.Coffee; import org.springframework.core.ParameterizedTypeReference; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.*; import org.springframework.web.reactive.function.client.WebClient; @Controller public class CoffeeController { @GetMapping("/coffee") public String coffee(Model model) { String url = "https://api.sampleapis.com/coffee/hot"; WebClient.Builder builder = WebClient.builder(); String coffeeList = builder.build() .get() .uri(url) .retrieve() .bodyToMono(String.class) .block(); System.out.println("---------------------"); System.out.println(coffeeList); model.addAttribute("coffeeList", coffeeList); return "coffee"; } }
Enter fullscreen mode Exit fullscreen mode
If you can’t import some of them, then one possible problem is Maven doesn’t load your pom.xml file correctly. Reloading the project resolves this issue in my case.
You can directly type url in your browser and check the response data, it is a list of coffee in JSON format.
You can map response data to Java object if you want. For this, you need to create Coffee class and define fields that you want to hold as Coffee object. For me, Coffee class has two fields, title and description. This way, when response data maps to Coffee object, the object only holds title and description from response JSON data.
package com.myproject.todoapp;public class Coffee {String title;String description;public Coffee() {}public Coffee(String title, String description) {this.title = title;this.description = description;}// getters and setters// toString method}package com.myproject.todoapp; public class Coffee { String title; String description; public Coffee() { } public Coffee(String title, String description) { this.title = title; this.description = description; } // getters and setters // toString method }package com.myproject.todoapp; public class Coffee { String title; String description; public Coffee() { } public Coffee(String title, String description) { this.title = title; this.description = description; } // getters and setters // toString method }
Enter fullscreen mode Exit fullscreen mode
import com.myproject.apidemo.Coffee;import org.springframework.core.ParameterizedTypeReference;import org.springframework.stereotype.Controller;import org.springframework.ui.Model;import org.springframework.web.bind.annotation.*;import org.springframework.web.reactive.function.client.WebClient;@Controllerpublic class CoffeeController {@GetMapping("/coffee")public String coffee(Model model) {String url = "https://api.sampleapis.com/coffee/hot";WebClient.Builder builder = WebClient.builder();List<Coffee> coffeeList = builder.build().get().uri(url).retrieve().bodyToMono(new ParameterizedTypeReference<List<Coffee>>() {}).block();System.out.println("---------------------");System.out.println(coffeeList);model.addAttribute("coffeeList", coffeeList);return "coffee";}}import com.myproject.apidemo.Coffee; import org.springframework.core.ParameterizedTypeReference; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.*; import org.springframework.web.reactive.function.client.WebClient; @Controller public class CoffeeController { @GetMapping("/coffee") public String coffee(Model model) { String url = "https://api.sampleapis.com/coffee/hot"; WebClient.Builder builder = WebClient.builder(); List<Coffee> coffeeList = builder.build() .get() .uri(url) .retrieve() .bodyToMono(new ParameterizedTypeReference<List<Coffee>>() { }) .block(); System.out.println("---------------------"); System.out.println(coffeeList); model.addAttribute("coffeeList", coffeeList); return "coffee"; } }import com.myproject.apidemo.Coffee; import org.springframework.core.ParameterizedTypeReference; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.*; import org.springframework.web.reactive.function.client.WebClient; @Controller public class CoffeeController { @GetMapping("/coffee") public String coffee(Model model) { String url = "https://api.sampleapis.com/coffee/hot"; WebClient.Builder builder = WebClient.builder(); List<Coffee> coffeeList = builder.build() .get() .uri(url) .retrieve() .bodyToMono(new ParameterizedTypeReference<List<Coffee>>() { }) .block(); System.out.println("---------------------"); System.out.println(coffeeList); model.addAttribute("coffeeList", coffeeList); return "coffee"; } }
Enter fullscreen mode Exit fullscreen mode
In this tutorial, I prefer converting the response data to Coffee object, so I stick to second version implementation.
Create View page
Finally we need view page just to display list of coffee:
<!doctype html><html lang="en" xmlns:th="http://www.thymeleaf.org"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1"><title>Coffee</title></head><body><h3>Coffee List</h3><table><tbody><tr th:each="coffee: ${coffeeList}"><td th:text="${coffee.title}"></td><td th:text="${coffee.description}"></td></tr></tbody></table></body></html><!doctype html> <html lang="en" xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>Coffee</title> </head> <body> <h3>Coffee List</h3> <table> <tbody> <tr th:each="coffee: ${coffeeList}"> <td th:text="${coffee.title}"></td> <td th:text="${coffee.description}"></td> </tr> </tbody> </table> </body> </html><!doctype html> <html lang="en" xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>Coffee</title> </head> <body> <h3>Coffee List</h3> <table> <tbody> <tr th:each="coffee: ${coffeeList}"> <td th:text="${coffee.title}"></td> <td th:text="${coffee.description}"></td> </tr> </tbody> </table> </body> </html>
Enter fullscreen mode Exit fullscreen mode
Done! Now you should be able to get data from http://localhost:8080/coffee.
Refactoring code
Although we could successfully call the API, there’s a room for improvement. Currently coffee method instantiates WebClient.Builder object each time when it gets called. This is unnecessary overhead. Better implementation is creating separate file that configures WebClient.Builder.
Create configuration file for WebClient:
@Configurationpublic class WebClientConfig {@Beanpublic WebClient webClient(WebClient.Builder builder) {return builder.build();}}@Configuration public class WebClientConfig { @Bean public WebClient webClient(WebClient.Builder builder) { return builder.build(); } }@Configuration public class WebClientConfig { @Bean public WebClient webClient(WebClient.Builder builder) { return builder.build(); } }
Enter fullscreen mode Exit fullscreen mode
Inject the Bean to our Controller class:
private WebClient webClient;@Autowiredpublic ToDoListController(WebClient webClient) {this.webClient = webClient;}@GetMapping("/coffee")public String coffee(Model model) {String url = "https://api.sampleapis.com/coffee/hot";List<Coffee> coffeeList = webClient.get().uri(url).retrieve().bodyToMono(new ParameterizedTypeReference<List<Coffee>>() {}).block();// other code}private WebClient webClient; @Autowired public ToDoListController(WebClient webClient) { this.webClient = webClient; } @GetMapping("/coffee") public String coffee(Model model) { String url = "https://api.sampleapis.com/coffee/hot"; List<Coffee> coffeeList = webClient .get() .uri(url) .retrieve() .bodyToMono(new ParameterizedTypeReference<List<Coffee>>() { }) .block(); // other code }private WebClient webClient; @Autowired public ToDoListController(WebClient webClient) { this.webClient = webClient; } @GetMapping("/coffee") public String coffee(Model model) { String url = "https://api.sampleapis.com/coffee/hot"; List<Coffee> coffeeList = webClient .get() .uri(url) .retrieve() .bodyToMono(new ParameterizedTypeReference<List<Coffee>>() { }) .block(); // other code }
Enter fullscreen mode Exit fullscreen mode
Now Spring Boot automatically instantiates and manages WebClient object behind the scene.
暂无评论内容