JavaRush /Kurslar /All lectures for UZ purposes /Funksional yakunlovchi nuqtalar (endpoints)

Funksional yakunlovchi nuqtalar (endpoints)

All lectures for UZ purposes
Daraja, Dars
Mavjud

Spring Web MVC WebMvc.fn ni o'z ichiga oladi, bu engil funksional dasturlash modeli bo'lib, unda funktsiyalar yo'naltirish va so'rovlarni qayta ishlash uchun ishlatiladi, va shartnomalar o'zgarmaslikni ta'minlash uchun ishlab chiqilgan. Bu annotatsiyalar asosidagi dasturlash modeliga muqobil bo'lib, boshqa jihatdan esa xuddi shu DispatcherServletda ishlaydi.

Qisqacha tavsif

WebMvc.fn da HTTP-so'rov HandlerFunction orqali qayta ishlanadi: bu funksiyasi ServerRequest ni qabul qiladi va ServerResponse ni qaytaradi. So'rov va javob obyektlari o'zgarmas shartnomalarga ega bo'lib, ular JDK 8 uchun qulay HTTP-so'rov va javobga kirish imkonini beradi. HandlerFunction – bu annotatsiya asosidagi dasturlash modelida @RequestMapping bilan belgilangan metod tanasining ekvivalenti.

Kirish so'rovlari RouterFunction orqali boshqaruvchi funktsiyaga yo'naltiriladi: bu funktsiyasi ServerRequest ni qabul qiladi va majburiy HandlerFunction ni qaytaradi (ya’ni, Optional<HandlerFunction>). Agar yo'naltiruvchi funksiya mos kelsa, boshqaruvchi funksiya qaytariladi, aks holda esa bo'sh Optional. RouterFunction – bu @RequestMapping annotatsiyasining ekvivalenti, lekin muhim farqi shundaki, yo'naltiruvchi funktsiyalar faqat ma'lumotlarni emas, balki ish logikasini ham uzatadi.

RouterFunctions.route() yo'naltiruvchi qurishni osonlashtiradigan vositani taqdim etadi, quyidagi misolda ko'rsatilganidek yo'naltiruvchilarni yaratishni osonlashtiradi:

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.

Agar RouterFunctionni bean sifatida ro'yxatdan o'tkazsangiz, masalan, uni @Configuration annotation bilan belgilangan sinfda ochsangiz, servlet tomonidan avtomatik ravishda aniqlanadi.

HandlerFunction

ServerRequest va ServerResponse – o'zgarmas interfeyslar bo'lib, ular HTTP-so'rov va javobga kirishni ta'minlaydi, shu jumladan sarlavhalar, tanalar, metodlar va holat kodlari, bu JDK 8 uchun qulay.

ServerRequest

ServerRequest HTTP-metodiga, URI-identifikatoriga, sarlavhalarga va so'rov parametrlarga kirishni ta'minlaydi va tanaga kirish body metodlari orqali amalga oshiriladi.

Quyidagi misolda so'rov tanasi String ga chiqariladi:

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

Quyidagi misolda tana List<Person> ga chiqariladi, bunda Person obyektlari JSON yoki XML kabi seriyalangan shakldan dekodlanadi:

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

Quyidagi misolda parametrga kirishni qanday amalga oshirish ko'rsatilgan:

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

ServerResponse

ServerResponse HTTP-javobiga kirishni ta'minlaydi va, chunki u o'zgarmas, uni yaratish uchun build metodidan foydalanish mumkin. Javob holatini sozlash, javob sarlavhalarini qo'shish yoki javob tanasini uzatish uchun qurilish vositasini ishlatishingiz mumkin. Quyidagi misolda JSON formatidagi kontent bilan 200 (OK) javobi yaratiladi:

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

Quyidagi misolda 201 (CREATED) javobini Location sarlavhasi bilan va tanasiz yaratish ko'rsatilgan:

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

Shuningdek, tanani asinxron natijani CompletableFuture, Publisher yoki ReactiveAdapterRegistry tomonidan qo'llab-quvvatlanadigan boshqa har qanday turda ishlatish mumkin. Masalan:

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)

Agar nafaqat tana, balki holat yoki sarlavhalar asinxron turga asoslangan bo'lsa, ServerResponse uchun async statik metodidan foydalanishingiz mumkin, bu CompletableFuture<ServerResponse>, Publisher<ServerResponse> yoki ReactiveAdapterRegistry tomonidan qo'llab-quvvatlanadigan har qanday asinxron turini qabul qiladi. Masalan:

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

Serverdan yuborilgan hodisalar ServerResponse uchun sse statik metodi orqali uzatilishi mumkin. Ushbu metod tomonidan taqdim etilgan qurilish vositasi matnlar yoki JSON formatidagi boshqa obyektlarni yuborish imkonini beradi. Masalan:

Java
public RouterFunction<ServerResponse> sse() {
    return route(GET("/sse"), request -> ServerResponse.sse(sseBuilder -> {
                // SsxBuilder ob'ektini qaerdadir saqlaymiz...
            }));
}
// Boshqa bir oqimda, matnni yuborish
sseBuilder.send("Hello world");
// Yoki JSON ga aylantiriladigan ob'yekti
Person person = ...
sseBuilder.send(person);
// Hodisani boshqa metodlar yordamida sozlaymiz
sseBuilder.id("42")
        .event("sse event")
        .data(person);
// va bir necha paytda tayyor bo'ladi
sseBuilder.complete();
Kotlin
fun sse(): RouterFunction<ServerResponse> = router {
    GET("/sse") { request -> ServerResponse.sse { sseBuilder ->
        // SsxBuilder ob'ektini qaerdadir saqlaymiz...
    }
}
// Boshqa bir oqimda, matnni yuborish
sseBuilder.send("Hello world")
// Yoki JSON ga aylantiriladigan ob'yekti
val person = ...
sseBuilder.send(person)
// Hodisani boshqa metodlar yordamida sozlaymiz
sseBuilder.id("42")
        .event("sse event")
        .data(person)
// va bir necha paytda tayyor bo'ladi
sseBuilder.complete()

Handler sinflar

Boshqaruvchi funksiya yozishimiz mumkin, lambda ifodasida, quyidagi misol ko'rsatilganidek:

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

Bu qulay, lekin ilova ichida bir nechta funksiyalar talab etiladi, va bir nechta joylashtirilgan lambda ifodalari hammasini chalkashtirib yuborishi mumkin. Shuning uchun, aloqador boshqaruvchi funksiyalarni bir joyda to'plash foydali bo'ladi, bu handler klassida, bu annotatsiyaga asoslangan ilovadagi @Controller annotation bilan o'xshash rol o'ynaydi. Masalan, quyidagi klass Person reaktiv omborini ifodalaydi:

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 funktsiyasi, bu repository ichida topilgan barcha Person obyektlarni JSON formatida qaytaradi.
  2. createPerson – bu handler funktsiyasi, bu so'rov tanasida joylashtirilgan yangi Person obyektini saqlaydi.
  3. getPerson – bu handler funktsiyasi, bu id yo'l o'zgaruvchisi orqali aniqlangan bir kishini qaytaradi. Biz bu Person obyektini ombordan chiqaramiz va agar topilgan bo'lsa, JSON formatida javob yaratamiz. Agar topilmasa, 404 Not Found javobini qaytaramiz.
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 funktsiyasi, bu repository ichida topilgan barcha Person obyektlarni JSON formatida qaytaradi.
  2. createPerson – bu handler funktsiyasi, bu so'rov tanasida joylashtirilgan yangi Person obyektini saqlaydi.
  3. getPerson – bu handler funktsiyasi, bu id yo'l o'zgaruvchisi orqali aniqlangan bir kishini qaytaradi. Biz bu Person obyektini ombordan chiqaramiz va agar topilgan bo'lsa, JSON formatida javob yaratamiz. Agar topilmasa, 404 Not Found javobini qaytaramiz.

Validatsiya

Funksional yakunlovchi nuqtalar Spring validatsiya dasturlaridan foydalanishi mumkin, so'rov tanasini validatsiyalash uchun. Masalan, Person uchun Springdan olingan custom Validator dasturi:

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 ni yaratamiz.
  2. Validatsiyani qo'llaymiz.
  3. 400 javobi uchun istisno qo'shiladi.
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 ni yaratamiz.
  2. Validatsiyani qo'llaymiz.
  3. 400 javobi uchun istisno qo'shiladi.

Boshqaruvchilar standart JSR-303 bean validatsiya API-dan foydalanishi mumkin, global Validator nusxasini LocalValidatorFactoryBean asosida yaratish va ulash orqali.

RouterFunction

Yo'naltiruvchi funktsiyalar HandlerFunction larga mos keladigan so'rovlarni yo'naltirish uchun ishlatiladi. Umuman olganda, yo'naltiruvchi funksiyalar o'zlari yozilmaydi, balki ularni yaratish uchun RouterFunctions yordamchi klass metodidan foydalaniladi. RouterFunctions.route() (parametrlarsiz) yo'naltiruvchi funktsiyasini yaratish uchun qulay vositani taqdim etadi, RouterFunctions.route(RequestPredicate, HandlerFunction) esa yo'naltiruvchini yaratishning to'g'ridan-to'g'ri usulini taklif etadi.

Qachonki to'g'ri bo'lganda, route() vositasidan foydalanishni tavsiya etiladi, chunki u statik elementlarni import qilishni talab qilmasdan, odatiy xaritmaning ssenariylari uchun qulay qisqartmalarni taqdim etadi, bu topish qiyin. Masalan, yo'naltiruvchi funktsiyalar uchun qurilish vositasi GET so'rovlar uchun xarita yaratish uchun GET(String, HandlerFunction) metodini, POST so'rovlar uchun esa POST(String, HandlerFunction) ni taklif etadi.

HTTP-metodlar asosidagi xaritalashdan tashqari, yo'naltiruvchi vosita joylashtirilgan so'rovlar uchun qo'shimcha predicatlar kiritish imkoniyatini taklif etadi. Har bir HTTP-metod uchun, qo'shimcha cheklovlarni ifodalash mumkin bo'lgan RequestPredicate ni qabul qiladigan marta bor.

Predikatlar

Siz o'zingizning RequestPredicate ni yozishingiz mumkin, lekin RequestPredicates yordamchi klassi yo'l so'rovi, HTTP-metodi, kontent turi va hokazo asosidagi tez-tez ishlatiladigan implementatsiyalarni taqdim etadi. Quyidagi misolda Accept sarlavhasiga asoslangan cheklovni yaratish uchun so'rov predikati ishlatilgan:

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")
    }
}

Birinchi predikatdan boshlab bir nechta so'rov predicatlarni birgalikda ishlatishingiz mumkin:

  • RequestPredicate.and(RequestPredicate) – ikkala predikat ham mos kelishi kerak.

  • RequestPredicate.or(RequestPredicate) – ulardan biri mos kelishi mumkin.

Ko'pchilik RequestPredicates predikatlari majmuaviydir. Masalan, RequestPredicates.GET(String) RequestPredicates.method(HttpMethod) va RequestPredicates.path(String) majmuasidan iborat. O'xshash misolni keltirgan misolda ham qurilish vositasi RequestPredicates.GET ni ichki darajada ishlatganlik dasturlash va uni accept predikati bilan birlashtirgan.

Marshrutlar

Yo'naltiruvchi funktsiyalar tartibli hisoblanadi: agar birinchi marshrut mos kelmasa, ikkinchi marshrut hisoblanadi va hokazo. Shuning uchun, aniqroq marshrutlarni umumiylardan oldin e'lon qilishni mantiqiy qiladi. Bu yo'naltiruvchi funktsiyalarning Spring bean sifatida ro'yxatdan o'tkazilishi, bu keyinchalik tasvirlanadigan bo'lgani kabi ham muhimdir. Bunday ish mantiqi annotatsiyalarga asoslangan dasturlash modelidan farq qiladi, bu yerda "eng aniq" nazoratchi metodi avtomatik ravishda tanlanadi.

Yo'naltiruvchi funktsiyalar uchun qurilish vositasi ishlatilganda, belgilangan barcha marshrutlar bir RouterFunction ga birlashtiriladi, bu build() dan qaytariladi. Bir nechta yo'naltiruvchi funktsiyalarni birga tuzishning boshqa usullari ham mavjud:

  • add(RouterFunction) ga RouterFunctions.route() vositasida qo'shish

  • RouterFunction.and(RouterFunction)

  • RouterFunction.andRoute(RequestPredicate, HandlerFunction) - bu RouterFunction.and() yordamida ichki RouterFunctions.route() bilan qisqartma.

Quyidagi misolda to'rt marshrutdan iborat kompozitsiya ko'rsatilgan:

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} va Accept sarlavhasi, JSON formatiga mos keladigan, PersonHandler.getPerson ga yo'naltiriladi.
  2. GET /person va Accept sarlavhasi, JSON formatiga mos keladigan, PersonHandler.listPeople ga yo'naltiriladi.
  3. POST /person qo'shimcha predikatlarsiz PersonHandler.createPerson ga ko'rsatiladi, va
  4. otherRoute boshqa joyda yaratilgan yo'naltiruvchi funktsiyadir va yaratishdan qo'shiladi.
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} va Accept sarlavhasi, JSON formatiga mos keladigan, PersonHandler.getPerson ga yo'naltiriladi.
  2. GET /person va Accept sarlavhasi, JSON formatiga mos keladigan, PersonHandler.listPeople ga yo'naltiriladi.
  3. POST /person qo'shimcha predikatlarsiz PersonHandler.createPerson ga ko'rsatiladi, va
  4. otherRoute boshqa joyda yaratilgan yo'naltiruvchi funktsiyadir va yaratishdan qo'shiladi.

Ichki marshrutlar

Odatda, yo'naltiruvchi funktsiyalar guruhi umumiy predikatga ega, masalan, umumiy yo'l. Yuqoridagi misoldagi umumiy predikat /person ga mos keladigan yo'l predikati, uchta marshrutda ishlatilgan. Annotatsiyalar yordamida bu takrorlanishni bartaraf etish mumkin, @RequestMapping annotationdan foydalanib, tur darajasida, bu /person ga ko'rsatiladi. WebMvc.fn da yo'l predikatlari path metodidan foydalanib, yo'naltiruvchi funktsiyalar uchun vositada birga foydalanilishi mumkin. Masalan, yuqoridagi misolning oxirgi bir necha qatorlarini quyidagicha to'ldirish mumkin, ichki marshrutlar yordamida:

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. Qarating, path ikkinchi parametri yo'naltiruvchi vositasida qabul qiladi.
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)
    }
}

Yo'l asosidagi ichki joylashtirish eng keng tarqalgan bo'lsa-da, qurilish vositasining nest metodidan foydalanib, har qanday turdagi predikatni joylashtirish mumkin. Yuqoridagi variant hali ham Accept-header umumiy predikat shaklida biroz dublicatsiyani o'z ichiga oladi. Biz kodni nest metodidan foydalanib to'ldirishni davom etamiz, accept yordamida:

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)
        }
    }
}

Serverni ishga tushirish

Odatda, yo'naltiruvchi funktsiyalar DispatcherHandler asosida konfiguratsiya orqali ishga tushiriladi, bu so'rovlarni qayta ishlash uchun zaruriy komponentlarni e'lon qilish uchun Spring konfiguratsiyasini jalb qiladi. Java MVC konfiguratsiyasi funksional yakunlovchi nuqtalarni qo'llab-quvvatlash uchun quyidagi infrastruktura komponentlarini e'lon qiladi:

  • RouterFunctionMapping: Spring konfiguratsiyasida bir yoki bir nechta RouterFunction<?> beanlarini aniqlaydi, ularni tartiblantiradi, RouterFunction.andOther yordamida birlashtiradi va so'rovlarni yakuniy majmuaviy RouterFunction ga yo'naltiradi.

  • HandlerFunctionAdapter: oddiy adapter, DispatcherHandler ga HandlerFunction, ulangani bo'lgan so'rovni chaqirish imkonini beradi.

Oldingi komponentlar funksional yakunlovchi nuqtalarga DispatcherServlet so'rovlarni qayta ishlash sikli ichiga "moslash" imkonini beradi, shuningdek, agar mavjud bo'lsa, annotatsiyalangan nazoratchilar bilan yonma-yon ishlash, (potensial) imkonini beradi. Bu shuningdek, Spring Boot Web zavod tizimida funksional yakunlovchi nuqtalarni faollashtirish usuli.

Quyidagi misolda WebFlux Java konfiguratsiyasi ko'rsatilgan:

Java
@Configuration
@EnableMvc
public class WebConfig implements WebMvcConfigurer {
    @Bean
    public RouterFunction<?> routerFunctionA() {
        // ...
    }
    @Bean
    public RouterFunction<?> routerFunctionB() {
        // ...
    }
    // ...
    @Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
        // xabarlarni konvertatsiya konfiguratsiyasi...
    }
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        // CORS konfiguratsiyasi...
    }
    @Override
    public void configureViewResolvers(ViewResolverRegistry registry) {
        // HTML tasviri uchun ko'rinishni konfiguratsiyalashni hal qilish...
    }
}
Kotlin
@Configuration
@EnableMvc
class WebConfig : WebMvcConfigurer {
    @Bean
    fun routerFunctionA(): RouterFunction<*> {
        // ...
    }
    @Bean
    fun routerFunctionB(): RouterFunction<*> {
        // ...
    }
    // ...
    override fun configureMessageConverters(converters: List<HttpMessageConverter<*>>) {
        // xabarlarni konvertatsiya konfiguratsiyasi...
    }
    override fun addCorsMappings(registry: CorsRegistry) {
        // CORS konfiguratsiyasi...
    }
    override fun configureViewResolvers(registry: ViewResolverRegistry) {
        // HTML tasviri uchun ko'rinishni konfiguratsiyalashni hal qilish...
    }
}

Filterlash boshqarish funksiyalari

Yo'naltiruvchi funksiyalarni before, after yoki filter vositasida qurilish metodi yordamida filterlashingiz mumkin. Annotatsiyalar bilan, siz @ControllerAdvice, ServletFilter yoki ikkalasidan foydalanib, shunga o'xshash funksionallikni amalga oshirishingiz mumkin. Filter qurilish vositasi tomonidan yarat ilgan barcha marshrutlarga qo'llaniladi. Bu shuni anglatadiki, ichki marshrutlarda aniqlangan filterlar "yuqori darajali" marshrutlarga qo'llanilmaydi. Masalan, quyidagi misolni ko'rib chiqing:

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 filtri, maxsus so'rov sarlavhasini qo'shayotgan, faqat ikki GET marshrutiga qo'llaniladi.
  2. after filtri, javobni ro'yxatga olayotgan, barcha marshrutlarga, shu jumladan, ichki marshrutlarga qo'llaniladi.
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 filtri, maxsus so'rov sarlavhasini qo'shayotgan, faqat ikki GET marshrutiga qo'llaniladi.
  2. after filtri, javobni ro'yxatga olayotgan, barcha marshrutlarga, shu jumladan, ichki marshrutlarga qo'llaniladi.

Yo'naltiruvchi qurilish vositasidagi filter metodi HandlerFilterFunction ni qabul qiladi: bu funksiyasi ServerRequest va HandlerFunctionni qabul qiladi va ServerResponse ni qaytaradi. Funktsiya parametri keyingi zanjir elementini ifodalaydi. Bu so'rov yo'naltirilgan boshqaruvchi bo'lishi odatda, lekin agar bir nechta qo'llanilsa, boshqa filter ham bo'lishi mumkin.

Endi biz SecurityManager tasavvur qilib, uni yo'lning ma'lum bir qismini tasdiqlashga imkon beradigan oddiy xavfsizlik filtrini qo'shishimiz mumkin. Quyidagi misolda buning qanday amalga oshirilishi ko'rsatilgan:

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();
            }
        }
    }
}

Yuqoridagi misolda next.handle(ServerRequest) chaqiruvining majburiy emasligi ko'rsatilgan. Biz boshqaruvchi funksiyasini faqat ruxsat berilgan bo'lsa bajarishga imkon beramiz.

Yo'naltiruvchi funktsiyalar uchun qurilish vositasida filter metodidan foydalanishdan tashqari, mavjud yo'naltiruvchi funktsiyaga RouterFunction.filter(HandlerFilterFunction) orqali filter qo'llash mumkin.

Funksional yakunlovchi nuqtalar uchun CORS ni qo'llab-quvvatlash CorsFilter maxsus qo'rg'oshin bilan ta'minlanadi.
Izohlar
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION