Spring WebFlux Route всегда возвращает 404 - PullRequest
1 голос
/ 05 октября 2019

Я работаю над простым проектом, который использует Spring Boot 2 с Spring WebFlux с использованием Kotlin. Я написал тест для своей функции-обработчика (в которой я смоделирую зависимости, используя Mockito).

Однако, похоже, что моя функция маршрута не запускает обработчик, так как все мои запросы возвращают HTTP 404 NOT FOUND (даже если маршрут правильный).

Я смотрел на различные другиепроекты, чтобы выяснить, как эти тесты должны быть написаны ( здесь , здесь ), но проблема сохраняется.

Код выглядит следующим образом (и можеттакже можно найти на GitHub ):

UserRouterTest

@ExtendWith(SpringExtension::class, MockitoExtension::class)
@Import(UserHandler::class)
@WebFluxTest
class UserRouterTest {

    @MockBean
    private lateinit var userService: UserService

    @Autowired
    private lateinit var userHandler: UserHandler

    @Test
    fun givenExistingCustomer_whenGetCustomerByID_thenCustomerFound() {
        val expectedCustomer = User("test", "test")
        val id = expectedCustomer.userID

        `when`(userService.getUserByID(id)).thenReturn(Optional.ofNullable(expectedCustomer))

        val router = UserRouter().userRoutes(userHandler)
        val client = WebTestClient.bindToRouterFunction(router).build()

        client.get()
                .uri("/users/$id")
                .accept(MediaType.ALL)
                .exchange()
                .expectStatus().isOk
                .expectHeader().contentType(MediaType.APPLICATION_JSON_UTF8)
                .expectBody(User::class.java)
    }
}

Пользователь

@Entity
class User(var username : String, var password: String) {

    @Id
    val userID = UUID.randomUUID()
}

UserRepository

@Repository
interface UserRepository : JpaRepository<User, UUID>{
}

UserService

@Service
class UserService(
        private val userRepository: UserRepository
) {
    fun getUserByID(id: UUID): Optional<User> {
        return Optional.of(
                try {
                    userRepository.getOne(id)
                } catch (e: EntityNotFoundException) {
                    User("test", "test")
                }
        )
    }

    fun addUser(user: User) {
        userRepository.save(user)
    }
}

UserHandler

@Component
class UserHandler(
        private val userService: UserService
) {
    fun getUserWithID(request: ServerRequest): Mono<ServerResponse> {
        val id = try {
            UUID.fromString(request.pathVariable("userID"))
        } catch (e: IllegalArgumentException) {
            return ServerResponse.badRequest().syncBody("Invalid user id")
        }
        val user = userService.getUserByID(id).get()
        return ServerResponse.ok().contentType(MediaType.APPLICATION_JSON_UTF8)
                .body(BodyInserters.fromObject(user))
    }
}

UserRouter

@Configuration
class UserRouter {
    @Bean
    fun userRoutes(userHandler: UserHandler) = router {
        contentType(MediaType.APPLICATION_JSON_UTF8).nest {
            GET("/users/{userID}", userHandler::getUserWithID)
            GET("") { ServerResponse.ok().build() }
        }
    }
}

РЕДАКТИРОВАТЬ

Для маршрутизации на основе наличия одного или нескольких параметров запроса (независимо от их значений) мы можем сделатьследующее: UserRouter

@Configuration
class UserRouter {
    @Bean
    fun userRoutes(userHandler: UserHandler) = router {

        GET("/users/{userID}", userHandler::getUserWithID)
        (GET("/users/")
                and queryParam("username") { true }
                and queryParam("password") { true }
                )
                .invoke(userHandler::getUsers)
    }
}

Обратите внимание, что GET("/users/?username={username}", userHandler::getUsersWithUsername) не работает.

1 Ответ

2 голосов
/ 06 октября 2019

Способ настройки маршрутизатора - contentType(MediaType.APPLICATION_JSON_UTF8).nest - будет соответствовать только запросам , имеющим этот тип контента, поэтому вам придется либо удалить предварительное условие contentType, либо изменить тест, чтобы включить его

client.get()
                .uri("/users/$id")
                .accept(MediaType.ALL)
                .header("Content-Type", "application/json;charset=UTF-8")
                .exchange()
                .expectStatus().isOk
                .expectHeader().contentType(MediaType.APPLICATION_JSON_UTF8)
                .expectBody(User::class.java)
...