JavaRush /Kurslar /All lectures for TK purposes /Funksional Endpoint'ler

Funksional Endpoint'ler

All lectures for TK purposes
Dereje , Sapak
Elýeterli

Spring Web MVC, WebMvc.fn'i öz içine alýar, bu ýeňil funksional programmalaşdyryş modelidir, onda funksiýalar soraglary ugurlamak we işlemek üçin ulanylýar we şertnamalar durnuklylygy üpjün etmek üçin işlenip düzülýär. Bu, adatyň esaslandyrýan programmalaşdyryş modeline alternatiw bolup, başgaça, şol bir DispatcherServlet'de işlemek üçin ulanylýar.

Gysgaça beýany

WebMvc.fn'de HTTP soragy HandlerFunction bilen işlenýär: bir funksiýa, ol ServerRequest alýar we ServerResponse berýär. Sorag hem, jogap obýekti hem, JDK 8 üçin HTTP soragyna we jogaba elýeterliligi üpjün edýän Durnukly şertnamalary bar. HandlerFunction, adatyň esaslandyrýan programmalaşdyryş modelinde @RequestMapping bilen belliklenen metod korpusynyň ekwiwalentidir.

Gelýän soraglar RouterFunction bilen funksiýa-handler'e ugurlanýar: bir funksiýa, ol ServerRequest kabul edýär we islege bagly HandlerFunction berýär (meselem, Optional<HandlerFunction>). Eger routlama funksiýasy gabat gelýän bolsa, handler funksiýasy yzyna gaýdýar, bolmasa - boş Optional. RouterFunction, @RequestMapping adatyň ekwiwalentidir, ýöne esasy tapawudy, routlama funksiýalarynyň diňe bir maglumatlary däl, eýsem, işlemäge bolan logikany geçirýänligidir.

RouterFunctions.route() routlama gurmak üçin bir guradyjy berýär, bu bolsa routlama döretmegi ýeňilleşdirýär, aşakdaky mysalda görkezilişi ýaly:

Java
import static org.springframework.http.MediaType.APPLICATION_JSON;
import static org.springframework.web.servlet.function.RequestPredicates.*;
import static org.springframework.web.servlet.function.RouterFunctions.route;
PersonRepository repository = ...
PersonHandler handler = new PersonHandler(repository);
RouterFunction<ServerResponse> route = route()
    .GET("/person/{id}", accept(APPLICATION_JSON), handler::getPerson)
    .GET("/person", accept(APPLICATION_JSON), handler::listPeople)
    .POST("/person", handler::createPerson)
    .build();
public class PersonHandler {
    // ...
    public ServerResponse listPeople(ServerRequest request) {
        // ...
    }
    public ServerResponse createPerson(ServerRequest request) {
        // ...
    }
    public ServerResponse getPerson(ServerRequest request) {
        // ...
    }
}
Kotlin
import org.springframework.web.servlet.function.router
val repository: PersonRepository = ...
val handler = PersonHandler(repository)
val route = router { 
    accept(APPLICATION_JSON).nest {
        GET("/person/{id}", handler::getPerson)
        GET("/person", handler::listPeople)
    }
    POST("/person", handler::createPerson)
}
class PersonHandler(private val repository: PersonRepository) {
    // ...
    fun listPeople(request: ServerRequest): ServerResponse {
        // ...
    }
    fun createPerson(request: ServerRequest): ServerResponse {
        // ...
    }
    fun getPerson(request: ServerRequest): ServerResponse {
        // ...
    }
}
  1. Create router using the router DSL.

Eger RouterFunction'y bir bean hökmünde belläli, meselem, ony @Configuration bilen belliklenen klasda açsak, ol awtomatiki usulda servlet tarapyndan ýüze çykarylar.

HandlerFunction

ServerRequest we ServerResponse, JDK 8 üçin HTTP soragyna we jogabyna elýeterliligi üpjün edýän durnukly interfeýslerdir, şol sanda başlyklar, korpus, metod we status kodlary.

ServerRequest

ServerRequest, HTTP metody, URI identifikatory, başlyklar we sorag parametrlerine elýeterliligi üpjün edýär, we korpusa elýeterlilik body metodlary arkaly üpjün edilýär.

Aşakdaky mysalda soragyň korpusy String görnüşinde çykarylýar:

Java
String string = request.body(String.class);
Kotlin
val string = request.body<String>()

Aşakdaky mysalda korpus List<Person> görnüşinde çykarylýar, burada Person obýektleri serialize edilen formadan dekodlanýar, meselem JSON ýa-da XML formaty:

Java
List<Person> people = request.body(new ParameterizedTypeReference<List<Person>>() {});
Kotlin
val people = request.body<Person>()

Aşakdaky mysal parametrler elýeterliligini görkezýär:

Java
MultiValueMap<String, String> params = request.params();
Kotlin
val map = request.params()

ServerResponse

ServerResponse, HTTP jogaba elýeterliligi üpjün edýär, we ol durnukly bolany üçin, ony döretmek üçin build metodyny ulanyp bolýar. Jogap statusy sazlamaga, jogap başlygyna goşmaga ýa-da jogap korpusyny geçirmäge sazlaýjy ulanyp bolýar. Aşakdaky mysalda 200 (OK) statusly JSON formatly jogap döredilýär:

Java
Person person = ...
ServerResponse.ok().contentType(MediaType.APPLICATION_JSON).body(person);
Kotlin
val person: Person = ...
ServerResponse.ok().contentType(MediaType.APPLICATION_JSON).body(person)

Aşakdaky mysal, Location başlygy bilen 201 (CREATED) statusly jogap döretmegi görkezýär we ýok jogap göwresi:

Java
URI location = ...
ServerResponse.created(location).build();
Kotlin
val location: URI = ...
ServerResponse.created(location).build()

Göwresi asynhron netije görnüşinde CompletableFuture, Publisher ýa-da ReactiveAdapterRegistry tarapyndan goldanýan islendik ýerleşýän görnüşi ulanyp bolýar. Mysal:

Java
Mono<Person> person = webClient.get().retrieve().bodyToMono(Person.class);
ServerResponse.ok().contentType(MediaType.APPLICATION_JSON).body(person);
Kotlin
val person = webClient.get().retrieve().awaitBody<Person>()
ServerResponse.ok().contentType(MediaType.APPLICATION_JSON).body(person)

Eger diňe bir göwresi däl-de, eýsem statusy ýa-da başlyklar bir asynhron görnüşe esaslansa, ReactiveAdapterRegistry tarapyndan goldanýan CompletableFuture<ServerResponse>, Publisher<ServerResponse> ýa-da islendik beýleki asynhron görnüşi kabul edýän ServerResponse statik async metodyny ulanyp bolýar. Mysal:

Java
Mono<ServerResponse> asyncResponse = webClient.get().retrieve().bodyToMono(Person.class)
  .map(p -> ServerResponse.ok().header("Name", p.name()).body(p));
ServerResponse.async(asyncResponse);

Server Sent Events, ServerResponse statik sse methody arkaly berlenip biler. Bu metodyň görkezýän sazlaýjysy, ýazgylary ýa-da beýleki obýektleri JSON formatda ugratmaga mümkinçilik berýär. Mysal:

Java
public RouterFunction<ServerResponse> sse() {
    return route(GET("/sse"), request -> ServerResponse.sse(sseBuilder -> {
                // SseBuilder obýektini bir ýerde sakla...
            }));
}
// Başga bir thread'de, hat yazyp
sseBuilder.send("Hello world");
// ýa-da JSON'a öwrüler obýektde
Person person = ...
sseBuilder.send(person);
// Täsiri dürli metodlar bilen sazla
sseBuilder.id("42")
        .event("sse event")
        .data(person);
// we bir wagt tamamlanar
sseBuilder.complete();
Kotlin
fun sse(): RouterFunction<ServerResponse> = router {
    GET("/sse") { request -> ServerResponse.sse { sseBuilder ->
        // SseBuilder obýektini bir ýerde sakla...
    }
}
// Başga bir thread'de, hat yazyp
sseBuilder.send("Hello world")
// ýa-da JSON'a öwrüler obýektde
val person = ...
sseBuilder.send(person)
// Täsiri dürli metodlar bilen sazla
sseBuilder.id("42")
        .event("sse event")
        .data(person)
// we bir wagt tamamlanar
sseBuilder.complete()

Handler sınıplary

Handler funksiýasyny lamda wyraženiýasy ýaly ýazyp bolýar, aşakdaky mysalda görkezilşi ýaly:

Java
HandlerFunction<ServerResponse> helloWorld =
  request -> ServerResponse.ok().body("Hello World");
Kotlin
val helloWorld: (ServerRequest) -> ServerResponse =
  { ServerResponse.ok().body("Hello World") }

Bu amatly, ýöne programmada birnäçe funksiýa gerek, we birnäçe gömülen lamda wyraženiýasy hemme zady bulaşdyryp biler. Şol sebäpli baglanşykly handler funksiýalary bir handler clasda toparlamak peýdaly bolar, bu adatyň esaslandyrýan programmalaşdyryş modelinde @Controller ýaly rol oýnaýar. Mysal, aşakdaky klas reaktiw Person deposyny görkezýär:

Java
import static org.springframework.http.MediaType.APPLICATION_JSON;
import static org.springframework.web.reactive.function.server.ServerResponse.ok;
public class PersonHandler {
    private final PersonRepository repository;
    public PersonHandler(PersonRepository repository) {
        this.repository = repository;
    }
    public ServerResponse listPeople(ServerRequest request) { 
        List<Person> people = repository.allPeople();
        return ok().contentType(APPLICATION_JSON).body(people);
    }
    public ServerResponse createPerson(ServerRequest request) throws Exception { 
        Person person = request.body(Person.class);
        repository.savePerson(person);
        return ok().build();
    }
    public ServerResponse getPerson(ServerRequest request) { 
        int personId = Integer.parseInt(request.pathVariable("id"));
        Person person = repository.getPerson(personId);
        if (person != null) {
            return ok().contentType(APPLICATION_JSON).body(person);
        }
        else {
            return ServerResponse.notFound().build();
        }
    }
}
  1. listPeople – bu handler funksiýasy, ol depodan tapylan ähli Person obýektlerini JSON formatda yzyna berýär.
  2. createPerson – bu handler funksiýasy, ol sorag korpusynda bar bolan täze Person obýektini saklaýar.
  3. getPerson – bu handler funksiýasy, ol id ýol üýtgetmesi bilen belliklenen bir kişini yzyna berýär. Biz bu Person obýektini depodan alýarys we eger tapylsa JSON formatda jogap döredýäris. Eger tapylmasa, 404 Not Found jogabyny yzyna berýäris.
Kotlin
class PersonHandler(private val repository: PersonRepository) {
    fun listPeople(request: ServerRequest): ServerResponse { 
        val people: List<Person> = repository.allPeople()
        return ok().contentType(APPLICATION_JSON).body(people);
    }
    fun createPerson(request: ServerRequest): ServerResponse { 
        val person = request.body<Person>()
        repository.savePerson(person)
        return ok().build()
    }
    fun getPerson(request: ServerRequest): ServerResponse { 
        val personId = request.pathVariable("id").toInt()
        return repository.getPerson(personId)?.let { ok().contentType(APPLICATION_JSON).body(it) }
                ?: ServerResponse.notFound().build()
    }
}
  1. listPeople – bu handler funksiýasy, ol depodan tapylan ähli Person obýektlerini JSON formatda yzyna berýär.
  2. createPerson – bu handler funksiýasy, ol sorag korpusynda bar bolan täze Person obýektini saklaýar.
  3. getPerson – bu handler funksiýasy, ol id ýol üýtgetmesi bilen belliklenen bir kişini yzyna berýär. Biz bu Person obýektini depodan alýarys we eger tapylsa JSON formatda jogap döredýäris. Eger tapylmasa, 404 Not Found jogabyny yzyna berýäris.

Wali dasiýa

Funksional endpoint, sorag korpusyna walidasiýany ulanyp bolýar Spring walidasiýa serişdeleri bilen. Mysal üçin, Person üçin Spring infrastrukturasyndan ulanyjy-defined Validator:

Java
public class PersonHandler {
    private final Validator validator = new PersonValidator(); 
    // ...
    public ServerResponse createPerson(ServerRequest request) {
        Person person = request.body(Person.class);
        validate(person); 
        repository.savePerson(person);
        return ok().build();
    }
    private void validate(Person person) {
        Errors errors = new BeanPropertyBindingResult(person, "person");
        validator.validate(person, errors);
        if (errors.hasErrors()) {
            throw new ServerWebInputException(errors.toString()); 
        }
    }
}
  1. Validator obýektini döredýäris.
  2. Walidasiýa amala aşyrylýar.
  3. 400 jogaby üçin exception döredilýär.
Kotlin
class PersonHandler(private val repository: PersonRepository) {
    private val validator = PersonValidator() 
    // ...
    fun createPerson(request: ServerRequest): ServerResponse {
        val person = request.body<Person>()
        validate(person) 
        repository.savePerson(person)
        return ok().build()
    }
    private fun validate(person: Person) {
        val errors: Errors = BeanPropertyBindingResult(person, "person")
        validator.validate(person, errors)
        if (errors.hasErrors()) {
            throw ServerWebInputException(errors.toString()) 
        }
    }
}
  1. Validator obýektini döredýäris.
  2. Walidasiýa amala aşyrylýar.
  3. 400 jogaby üçin exception döredilýär.

Handler'ler hem JSR-303 adaty şablony walidasiýa API'ni ulanyp bilerler, LocalValidatorFactoryBean esasly global bir validator obýektini döredip we injekte edip.

RouterFunction

Funksiýa-router'ler soraglary degişli HandlerFunction'a ugurlamak üçin ulanylýar. Umuman, funksiýa-router'ler özbaşdak ýazylyp gutarmadyk, şonuň üçin RouterFunctions kömekçi kelasynyň metodyny ulanyp döredilýär. RouterFunctions.route() (parametrler ýok) funksiýa-router döretmek üçin amatly bir guradyjy berýär, şeýle-de RouterFunctions.route(RequestPredicate, HandlerFunction) diňe bir router döretmegiň göni ýoluny hödürleýär.

Umuman, route() guradyjysyny ulanyp maslahat berilýär, sebäbi ol çylşyrymly tipik senariýalar üçin amatly gysga ýollary üpjün edýär, statistik elementleri import etmeýärler, olar kyn tapylýar. Mysal üçin, funksiýa-router guradyjysy GET soraglary üçin GET(String, HandlerFunction) metodyny hödürleýär; we POST soraglary üçin POST(String, HandlerFunction).

HTTP metodlaryna esaslanýan bäşlikde, route guradyjysy soraglara gatnaşygy berýän goşmaça predikatlar girizmek üçin ýol berýär. Her HTTP metody üçin, goşmaça çäklendirmeler bolup biler, alýan parametr hökmünde RequestPredicate alýar.

Predikatlar

Öz RequestPredicate'iňizi ýazyp bilersiňiz, ýöne kömekçi klasse RequestPredicates, sorag bäşligi, HTTP metodo, mazmuny tipi arkaly ulanylýan umumy ulanylýan realizasiýalary üpjün edýär. Aşakdaky mysal, Accept başlygyny esaslandyrýan çäklendirmäni döretmek üçin sorag predikatyny ulanýar:

Java
RouterFunction<ServerResponse> route = RouterFunctions.route()
    .GET("/hello-world", accept(MediaType.TEXT_PLAIN),
        request -> ServerResponse.ok().body("Hello World")).build();
Kotlin
import org.springframework.web.servlet.function.router
val route = router {
    GET("/hello-world", accept(TEXT_PLAIN)) {
        ServerResponse.ok().body("Hello World")
    }
}

Käbir sorag predikatlaryny biri-birine birleşdirip bolýar:

  • RequestPredicate.and(RequestPredicate) – ikisi hem gabat gelmelidir.

  • RequestPredicate.or(RequestPredicate) – islendik biri gabat geler.

RequestPredicates içinden köp predikat birleşdi. Mysal üçin, RequestPredicates.GET(String) RequestPredicates.method(HttpMethod) we RequestPredicates.path(String) predikatlaryny birleşdirýär. Mysalda hem RequestPredicates.GET guradyşyny ulanyp we içindäki accept predikatyny birleşdirýän iki sorag predikat ulanylýar.

Routlar

Funksiýa-router'ler täsiri bilen hasaplanylýar: eger birinji rout gabat gelmeýän bolsa, ikinji netijä çenlenip hasaplanýar, we şm. Şonuň üçin, has belli routlary umumylaşdyrylanlardan öň beýan etmäge gowy düşünilýär. Bu Spring bean'lerinde funksiýa-router'leri belläli, ol hem soňra düşündirilýär. Aňsat, adatyň esaslandyrýan programmalaşdyryş modelinden tapawutlanýar, ol ýerde iň belli kontroler metody awtomatiki saýlanyp bilýär.

Funksiýa-router'ler üçin guradyjy ulanylanda ähli beýan edilen routlar bir RouterFunction'a birleşdirilýär, ol build() bilen yzyna berýär. Başga birnäçe funksiýa-router-i birine birleşdirmegiň başga ýollary:

  • add(RouterFunction) RouterFunctions.route() guradyjysyna

  • RouterFunction.and(RouterFunction)

  • RouterFunction.andRoute(RequestPredicate, HandlerFunction) - RouterFunction.and() bilen iç içe RouterFunctions.route() gaýtalamanyň gysga ýoly.

Aşakdaky mysalda dört rout birleşdirme görkezilýär:

Java
import static org.springframework.http.MediaType.APPLICATION_JSON;
import static org.springframework.web.servlet.function.RequestPredicates.*;
PersonRepository repository = ...
PersonHandler handler = new PersonHandler(repository);
RouterFunction<ServerResponse> otherRoute = ...
RouterFunction<ServerResponse> route = route()
    .GET("/person/{id}", accept(APPLICATION_JSON), handler::getPerson) 
    .GET("/person", accept(APPLICATION_JSON), handler::listPeople) 
    .POST("/person", handler::createPerson) 
    .add(otherRoute) 
    .build();
  1. GET /person/{id} Accept başlygy bilen JSON formata gabat, PersonHandler.getPerson'a ugurlanýar
  2. GET /person Accept başlygy bilen JSON formata gabat, PersonHandler.listPeople'a ugurlanýar
  3. POST /person goşmaça predikatlar ýok, PersonHandler.createPerson'a ugrukdyrylýar, we
  4. otherRoute – başga bir ýerde döredilýän we gurlan bir roud'a goşulýan funksiýa-router.
Kotlin
import org.springframework.http.MediaType.APPLICATION_JSON
import org.springframework.web.servlet.function.router
val repository: PersonRepository = ...
val handler = PersonHandler(repository);
val otherRoute = router {  }
val route = router {
    GET("/person/{id}", accept(APPLICATION_JSON), handler::getPerson) 
    GET("/person", accept(APPLICATION_JSON), handler::listPeople) 
    POST("/person", handler::createPerson) 
}.and(otherRoute) 
  1. GET /person/{id} Accept başlygy bilen JSON formata gabat, PersonHandler.getPerson'a ugurlanýar
  2. GET /person Accept başlygy bilen JSON formata gabat, PersonHandler.listPeople'a ugurlanýar
  3. POST /person goşmaça predikatlar ýok, PersonHandler.createPerson'a ugrukdyrylýar, we
  4. otherRoute – başga bir ýerde döredilýän we gurlan bir roud'a goşulýan funksiýa-router.

Çökdürilen routlar

Adatça, funksiýa-router'leriň topary umumy predikat bar, meselem, umumy ýol. Mysalda, umumy predikat /person ýol predikatydyr, ol üç rout üçin ulanylýar. Adatda, bu dublirleme @RequestMapping üçin ulanyp bolýar, type derejesinde, /person üznüşe gabat gelende. WebMvc.fn'de, ýol predikatlary path metody bilen funksiýa-router guradyjysy arkaly ulanyp bolýar. Mysal üçin, soňky mysalda, aşakdaky ýaly çökdürilen routlar ulanylýan yşaratlar goşup bolýar:

Java
RouterFunction<ServerResponse> route = route()
    .path("/person", builder -> builder 
        .GET("/{id}", accept(APPLICATION_JSON), handler::getPerson)
        .GET(accept(APPLICATION_JSON), handler::listPeople)
        .POST(handler::createPerson))
    .build();
  1. Uç predikatyň ikinji parametri path – bu bir guradyjy kabul edýän araçydyr.
Kotlin
import org.springframework.web.servlet.function.router
val route = router {
    "/person".nest {
        GET("/{id}", accept(APPLICATION_JSON), handler::getPerson)
        GET(accept(APPLICATION_JSON), handler::listPeople)
        POST(handler::createPerson)
    }
}

Ýol esasly çökdürme iň köp ulanylýan, ýöne nest metody bilen guradyjynyň üstünde islendik görnüş predikaty çökdürmek mümkin. accept metody bilen teklip edilýän kod ulanypnest metody bilen kody giňeldenip bolýar:

Java
RouterFunction<ServerResponse> route = route()
    .path("/person", b1 -> b1
        .nest(accept(APPLICATION_JSON), b2 -> b2
            .GET("/{id}", handler::getPerson)
            .GET(handler::listPeople))
        .POST(handler::createPerson))
    .build();
Kotlin
import org.springframework.web.servlet.function.router
val route = router {
    "/person".nest {
        accept(APPLICATION_JSON).nest {
            GET("/{id}", handler::getPerson)
            GET("", handler::listPeople)
            POST(handler::createPerson)
        }
    }
}

Serweriň işlemegi

Adatça, funksiýa-router'ler, DispatcherHandleriniň esaslandyrýan bir konfigurasýasynda işledilýär, bu bolsa Spring konfigurasýasyny açmak üçin talap edilen komponentleri beýan edýär. Java MVC konfigurasýasy, funksional endpoint'ler üçin aşakdaky infrastruktur komponentlerini açýar:

  • RouterFunctionMapping: Bir ýa-da birnäçe RouterFunction<?> bean'lerini Spring konfigurasýasynda tapýar, olary tertiplendirýär, RouterFunction.andOther bilen birleşdirýär we soraglary birleşdirilen RouterFunction funksiýasyna ugurlandyrýar.

  • HandlerFunctionAdapter: Ýönekeý adapter, DispatcherHandler'yň soraga HandlerFunction'a çagyryş mümkinçiligini berýär.

Öňde goýlan komponentler, funksional endpoint'lerin DispatcherServlet'iň sorag işleme durmuşy bilen "utgaşmagyna" mümkinçilik berýär, we eger-de belliklenen kontrolerler bar bolsa, bular bilen bilelikde işleşýär. Bu Spring Boot Web başlatma sistemasynda funksional endpoint'leri işjeňleşdirmegiň hem ýoludyr.

Aşakdaky mysal, WebFlux üçin Java konfigurasýasyny görkezýär:

Java
@Configuration
@EnableMvc
public class WebConfig implements WebMvcConfigurer {
    @Bean
    public RouterFunction<?> routerFunctionA() {
        // ...
    }
    @Bean
    public RouterFunction<?> routerFunctionB() {
        // ...
    }
    // ...
    @Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
        // habarlaryň konwertasiýasyny sazlaýarys...
    }
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        // CORS sazlamak...
    }
    @Override
    public void configureViewResolvers(ViewResolverRegistry registry) {
        // HTML reňk berişleri üçin düşündirişleri sazla...
    }
}
Kotlin
@Configuration
@EnableMvc
class WebConfig : WebMvcConfigurer {
    @Bean
    fun routerFunctionA(): RouterFunction<*> {
        // ...
    }
    @Bean
    fun routerFunctionB(): RouterFunction<*> {
        // ...
    }
    // ...
    override fun configureMessageConverters(converters: List<HttpMessageConverter<*>>) {
        // habarlaryň konwertasiýasyny sazlaýarys...
    }
    override fun addCorsMappings(registry: CorsRegistry) {
        // CORS sazlamak...
    }
    override fun configureViewResolvers(registry: ViewResolverRegistry) {
        // HTML reňk berişleri üçin düşündirişleri sazla...
    }
}

Handler filtrleýji funksiýalary

Funksiýa-router'leri guradyjyda before, after ýa-da filter metodlaryny ulanyp handler funksiýalaryny filtrlemäge bolýar. Adat bilen, bu funksiýanyň görnüdiren işini, @ControllerAdvice ýa-da ServletFilter ulanmak bilen döretmek mümkin. Filtrler ähli guradyjy bilen gurlan ähli routlara ulanylmak üçin serişdeleri hödürleýär. Bu, çökdürilen routlarda beýan edilen filtrleriň "ýokary derejede" routlara ulanylmaýandygyny aňladýar. Mysal üçin, aşakdaky mysaly göz öňüne tutuň:

Java
RouterFunction<ServerResponse> route = route()
    .path("/person", b1 -> b1
        .nest(accept(APPLICATION_JSON), b2 -> b2
            .GET("/{id}", handler::getPerson)
            .GET(handler::listPeople)
            .before(request -> ServerRequest.from(request) 
                .header("X-RequestHeader", "Value")
                .build()))
        .POST(handler::createPerson))
    .after((request, response) -> logResponse(response)) 
    .build();
  1. before filtr, täzelikli bir sorag başlygyny goşyp, diňe GET rout'laryna ulanylýar.
  2. after filtr, jogaby hasaba alýar, ähli routlara, şol sanda çökdürilenlere ulanylýar.
Kotlin
import org.springframework.web.servlet.function.router
val route = router {
    "/person".nest {
        GET("/{id}", handler::getPerson)
        GET(handler::listPeople)
        before { 
            ServerRequest.from(it)
                    .header("X-RequestHeader", "Value").build()
        }
    }
    POST(handler::createPerson)
    after { _, response -> 
        logResponse(response)
    }
}
  1. before filtr, täzelikli bir sorag başlygyny goşyp, diňe GET rout'laryna ulanylýar.
  2. after filtr, jogaby hasaba alýar, ähli routlara, şol sanda çökdürilenlere ulanylýar.

Router guradyjysynda filter metody HandlerFilterFunction kabul edýär: ServerRequest ve HandlerFunction kabul edip ServerResponse berýär. Funksiýa handler parametri zynjyrdaky indiki elementdir. Düzgün bolşy ýaly, bu soraga ugurlanan handlerdir, ýöne adatça başga bir filtr bolup biler, eger köp filtr ulanylýan bolsa.

Indi, adaty SecurityManager bilen belli bir ýol geçmäge rugsat edilip edilmeýändigini kesgitlemek üçin howpsuzlyk filtrini goşup bolýar. Aşakdaky mysal, bunu nädip etmekligi görkezýär:

Java
SecurityManager securityManager = ...
RouterFunction<ServerResponse> route = route()
    .path("/person", b1 -> b1
        .nest(accept(APPLICATION_JSON), b2 -> b2
            .GET("/{id}", handler::getPerson)
            .GET(handler::listPeople))
        .POST(handler::createPerson))
    .filter((request, next) -> {
        if (securityManager.allowAccessTo(request.path())) {
            return next.handle(request);
        }
        else {
            return ServerResponse.status(UNAUTHORIZED).build();
        }
    })
    .build();
Kotlin
import org.springframework.web.servlet.function.router
val securityManager: SecurityManager = ...
val route = router {
    ("/person" and accept(APPLICATION_JSON)).nest {
        GET("/{id}", handler::getPerson)
        GET("", handler::listPeople)
        POST(handler::createPerson)
        filter { request, next ->
            if (securityManager.allowAccessTo(request.path())) {
                next(request)
            }
            else {
                status(UNAUTHORIZED).build();
            }
        }
    }
}

Öňki mysal, next.handle(ServerRequest) çagyrylyşlarynyň çykarylyp bilinjekdigini görkezýär. Biz diňe, eger ýol goýberilýän bolsa handler funksiýasyna ýerine ýetirmäge rugsat berýäris.

Router guradyjysynyň filter metodynyň ulanylmagyndan başga, RouterFunction.filter(HandlerFilterFunction) arkaly bar bolan funksiýa-router'e filtr ulanyp bolýar.

Funksional endpoint'ler üçin CORS goldawy hususy CorsFilter bilen üpjün edilýär.
Teswirler
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION