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+)?");
    }
}

Zobacz kod na GitHubie i zapisz się na bezpłatny newsletter!

.

Leave a comment

Your email address will not be published.


*