Spring Boot 2.0 – actuator – custom endpoint
Spring Boot 2.0 – actuator – custom endpoint
Zanim zaczniesz czytać ten wpis proponuję zapoznać się z artykułem https://javaleader.pl/2019/07/17/spring-boot-aplikacja-production-ready/. Do dzieła!
Utwórzmy projekt Spring Boota – plik pom.xml – niezbędne zależności:
<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-webflux</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies>
Klasa własnego endpointa – (w starszych wersjach Spring Boota należało zaimplementować interfejs tak jak poniżej):
@Component public class CustomEndpoint implements Endpoint<List<String>> { ... }
W nowszych wersjach Spring Boota tj. Spring Boot > 2 czyli wersji na której oparty jest ten wpis powyższy mechanizm zastąpiono adnotacjami:
// any methods annotated with @ReadOperation, @WriteOperation, or @DeleteOperation are automatically exposed over JMX and, in a web application, over HTTP as well. @Endpoint(id="custom-endpoint") @Component public class CustomEndPoint { @ReadOperation public String myPoint(){ return "Hello World" ; } }
Plik application.properties:
management.endpoints.web.exposure.include=*
Testy:
http://localhost:8080/actuator/custom-endpoint
Wynik w przeglądarce WWW:
Hello World
[UWAGA] jeśli w nagłówkach żądania ustawiony jest parametr: content-type:application/json to w tym przypadku wystąpi błąd ponieważ w metodzie myPoint zwracany jest zwykły String:
There was an error parsing JSON data
Unexpected token H in JSON at position 0
Dodajmy operację typu CRUD:
// @WebEndpoint is exposed only over HTTP and not over JMX. @Component @WebEndpoint(id = "custom-list-operations-endpoint") public class CustomEndPointOperation { List<String> stringList = new ArrayList(); // GET // http://localhost:8080/actuator/custom-list-operations-endpoint @ReadOperation public String getAllItems() { return stringList.toString(); } // POST // http://localhost:8080/actuator/custom-list-operations-endpoint/text?text=2 // A Selector can be used on a parameter of an Endpoint method to indicate that // the parameter is used to select a subset of the endpoint's data. @WriteOperation public WebEndpointResponse addItem(@Selector String text) { stringList.add(text); return new WebEndpointResponse<>(httptatus.CREATED.value()); } // DELETE // http://localhost:8080/actuator/custom-list-operations-endpoint/text?text=2 @DeleteOperation public void deleteItem(@Selector String text) { stringList.remove(text); } public List<String> getStringList() { return stringList; } public void setStringList(List<String> stringList) { this.stringList = stringList; } }
Testujemy:
Odczyt – READ:
http://localhost:8080/actuator/custom-list-operations-endpoint
Zapis – POST:
http://localhost:8080/actuator/custom-list-operations-endpoint/text?text=sample
Usunięcie – DELETE:
http://localhost:8080/actuator/custom-list-operations-endpoint/text?text=sample
Jeśli zależy nam na tym aby wynik żądania opakować w dodatkowe nagłówki lub mieć wpływ na zwracany wynik jeśli parametry żądania są niepoprawne to należy napisać klasę rozszerzającą np. niżej weryfikowany jest parametr przekazany przez użytkownika pod kątem tego czy jest on liczbą, jeśli nie jest to zwracany jest odpowiedni kod błędu:
@Component @EndpointWebExtension(endpoint = CustomEndPointOperation.class) public class EndpointExtension { private final CustomEndPointOperation customEndPointOperation; public EndpointExtension(final CustomEndPointOperation customEndPointOperation) { this.customEndPointOperation = customEndPointOperation; } @WriteOperation WebEndpointResponse addItem(@Selector String text) { if (isNumeric(text)) { return new WebEndpointResponse<>( httptatus.CONFLICT.value()); } return new WebEndpointResponse<>( httptatus.CREATED.value()); } public static boolean isNumeric(String str) { return str.matches("-?\\d+(\\.\\d+)?"); } }
Leave a comment