Java Webflux中可分页的解析

Java Webflux中可分页的解析,java,spring,rest,spring-boot,kotlin,Java,Spring,Rest,Spring Boot,Kotlin,我花了很多时间在Webflux中寻找关于Pageable的解决方案,不幸的是,在撰写本文时,Webflux不支持Pageable,因此我提出了一个解决方案,这就是我所实现的。在Spring Boot中解决Webflux控制器/资源中的可分页和排序类型是一个很有技巧的解决方案 以下是解决方案:(我知道它可能很难看,但在Spring团队解决问题之前,您可以使用它,我们正在为此不断努力 此外,要点如下: 更新1:你也可以找到这篇文章 版本: Spring Boot: 2.0.2.RELEASE Gra

我花了很多时间在Webflux中寻找关于Pageable的解决方案,不幸的是,在撰写本文时,Webflux不支持Pageable,因此我提出了一个解决方案,这就是我所实现的。在Spring Boot中解决Webflux控制器/资源中的可分页和排序类型是一个很有技巧的解决方案

以下是解决方案:(我知道它可能很难看,但在Spring团队解决问题之前,您可以使用它,我们正在为此不断努力

此外,要点如下:

更新1:你也可以找到这篇文章

版本:

Spring Boot: 2.0.2.RELEASE
Gradle Kotlin: 1.2.41
请随时给我提示以改进它。(代码为Kotlin)

@配置
类PageableSerializer{
@豆子
@条件性缺豆
有趣的pageableCustomizer(属性:SpringDataWebProperties):PageableHandlerMethodArgumentResolverCustomizer{
返回PageableHandlerMethodArgumentResolverCustomizer{resolver->
val pageable=properties.pageable
resolver.setPageParameterName(pageable.pageParameter)
resolver.setSizeParameterName(pageable.sizeParameter)
解析程序.setOneIndexedParameters(可分页.isOneIndexedParameters)
resolver.setPrefix(pageable.prefix)
resolver.setQualifierDelimiter(可分页的.qualifierDelimiter)
resolver.setFallbackPageable(PageRequest.of(0,pageable.defaultPageSize))
resolver.setMaxPageSize(pageable.maxPageSize)
}
}
@豆子
@条件性缺豆
有趣的sortCustomizer(属性:SpringDataWebProperties):SortHandlerMethodArgumentResolverCustomizer{
返回SortHandlerMethodArgumentResolverCustomizer{resolver->
resolver.setSortParameter(properties.sort.sortParameter)
}
}
@豆子
有趣的pageableHandler(pageableResolver:可选,sortHandler:SortHandlerMethodArgumentResolver,reactiveAdapterRegistry:reactiveAdapterRegistry):PageableHandlerMethodArgumentResolver{
val handler=PageableHandlerMethodArgumentResolver(sortHandler)
pageableResolver.ifPresent{c->c.customize(处理程序)}
返回处理器
}
@豆子
有趣的sortHandler(sortResolver:可选):SortHandlerMethodArgumentResolver{
val handler=SortHandlerMethodArgumentResolver()
sortResolver.ifPresent{c->c.customize(handler)}
返回处理器
}
}
以及注册处理程序:

@Component
class PageableResolver(registry: ReactiveAdapterRegistry, private val resolver: PageableHandlerMethodArgumentResolver) : HandlerMethodArgumentResolverSupport(registry) {

    override fun resolveArgument(parameter: MethodParameter, bindingContext: BindingContext, exchange: ServerWebExchange): Mono<Any> {
        return Mono.just(resolver.resolveArgument(parameter, null, MockNative(exchange.request.queryParams), null))
    }

    override fun supportsParameter(parameter: MethodParameter): Boolean {
        return this.resolver.supportsParameter(parameter)
    }

    private class MockNative(private val parameters: MultiValueMap<String, String>) : NativeWebRequest {
        override fun getParameter(paramName: String): String? {
            return this.parameters.getFirst(paramName)
        }

        override fun getParameterValues(paramName: String): Array<String>? {
            return this.parameters[paramName]?.toTypedArray()
        }

        override fun isUserInRole(role: String): Boolean {
            return false
        }

        override fun getRemoteUser(): String? {
            return null
        }

        override fun getLocale(): Locale {
            return Locale.getDefault()
        }

        override fun getParameterMap(): MutableMap<String, Array<String>> {
            return mutableMapOf()
        }

        override fun getSessionId(): String {
            return ""
        }

        override fun getAttributeNames(scope: Int): Array<String> {
            return arrayOf()
        }

        override fun registerDestructionCallback(name: String, callback: Runnable, scope: Int) {

        }

        override fun resolveReference(key: String): Any? {
            return null
        }

        override fun getHeaderValues(headerName: String): Array<String>? {
            return null
        }

        override fun getUserPrincipal(): Principal? {
            return null
        }

        override fun getDescription(includeClientInfo: Boolean): String {
            return ""
        }

        override fun getSessionMutex(): Any {
            return ""
        }

        override fun getNativeResponse(): Any? {
            return null
        }

        override fun <T : Any?> getNativeResponse(requiredType: Class<T>?): T? {
            return null
        }

        override fun getParameterNames(): MutableIterator<String> {
            return mutableListOf<String>().iterator()
        }

        override fun getNativeRequest(): Any {
            return ""
        }

        override fun <T : Any?> getNativeRequest(requiredType: Class<T>?): T? {
            return null
        }

        override fun removeAttribute(name: String, scope: Int) {

        }

        override fun getHeader(headerName: String): String? {
            return null
        }

        override fun getContextPath(): String {
            return ""
        }

        override fun checkNotModified(lastModifiedTimestamp: Long): Boolean {
            return false
        }

        override fun checkNotModified(etag: String): Boolean {
            return false
        }

        override fun checkNotModified(etag: String?, lastModifiedTimestamp: Long): Boolean {
            return false
        }

        override fun getHeaderNames(): MutableIterator<String> {
            return mutableListOf<String>().iterator()
        }

        override fun getAttribute(name: String, scope: Int): Any? {
            return null
        }

        override fun setAttribute(name: String, value: Any, scope: Int) {
        }

        override fun isSecure(): Boolean {
            return false
        }
    }

}
@组件
类PageableResolver(注册表:ReactiveAdapterRegistry,专用val解析程序:PageableHandlerMethodArgumentResolver):HandlerMethodArgumentResolver支持(注册表){
重写参数(参数:MethodParameter,bindingContext:bindingContext,exchange:ServerWebExchange):Mono{
返回Mono.just(resolver.resolveragument(参数,null,MockNative(exchange.request.queryParams),null))
}
重写参数参数(参数:MethodParameter):布尔值{
返回此.resolver.supportsParameter(参数)
}
私有类MockNative(私有val参数:多值映射):NativeWebRequest{
重写参数(参数名:字符串):字符串{
返回此.parameters.getFirst(paramName)
}
覆盖有趣的getParameterValues(paramName:String):数组{
返回此.parameters[paramName]?.toTypedArray()
}
重写isUserInRole(角色:字符串):布尔值{
返回错误
}
重写getRemoteUser():字符串{
返回空
}
重写getLocale():区域设置{
返回Locale.getDefault()
}
重写getParameterMap():可变映射{
返回mutableMapOf()
}
重写getSessionId():字符串{
返回“”
}
重写GetAttributeName(作用域:Int):数组{
返回数组()
}
重写fun registerDestructionCallback(名称:String,回调:Runnable,作用域:Int){
}
重写引用(键:字符串):有吗{
返回空
}
覆盖有趣的GetHeaderValue(headerName:String):数组{
返回空
}
重写getUserPrincipal():主体{
返回空
}
重写fun getDescription(includeClientInfo:Boolean):字符串{
返回“”
}
重写getSessionMutex():任意{
返回“”
}
覆盖有趣的getNativeResponse():有吗{
返回空
}
覆盖有趣的getNativeResponse(requiredType:Class?):T{
返回空
}
重写getParameterNames():MutableIterator{
返回mutableListOf().iterator()
}
覆盖有趣的getNativeRequest():任意{
返回“”
}
覆盖有趣的getNativeRequest(requiredType:Class?):T{
返回空
}
重写fun removeAttribute(名称:字符串,作用域:Int){
}
覆盖有趣的getHeader(headerName:String):String{
返回空
}
重写getContextPath():字符串{
返回“”
}
override fun checkNotModified(lastModifiedTimestamp:Long):布尔值{
返回错误
}
override fun checkNotModified(etag:String):布尔值{
返回错误
}
override fun checkNotModified(etag:String?,lastModifiedTimestamp:Long):布尔值{
返回错误
}
重写有趣的getHeaderNames():可变迭代器{
返回mutableListOf().iterator()
}
override fun getAttribute(名称:String,作用域:Int):有吗{
返回空
}
重写fun setAttribute(名称:String,值:Any,作用域:Int){
}
override fun isSecure():布尔值{
返回错误
}
}
}
参见课程

WebFluxConfigure
示例:

@Configuration
@ConditionalOnClass(EnableWebFlux.class)
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.REACTIVE)
public class WebfluxConfig implements WebFluxConfigurer {
    @Override
    public void configureArgumentResolvers(ArgumentResolverConfigurer configurer) {
        configurer.addCustomResolver(new ReactivePageableHandlerMethodArgumentResolver());
    }
}

是的,这是最近在一次很长时间的github问题讨论后添加的,感谢您提到我不确定这一点
@Configuration
@ConditionalOnClass(EnableWebFlux.class)
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.REACTIVE)
public class WebfluxConfig implements WebFluxConfigurer {
    @Override
    public void configureArgumentResolvers(ArgumentResolverConfigurer configurer) {
        configurer.addCustomResolver(new ReactivePageableHandlerMethodArgumentResolver());
    }
}