响应式Spring开发:从错误处理到路由配置
立即解锁
发布时间: 2025-08-19 02:30:36 阅读量: 18 订阅数: 15 

### 响应式Spring开发:从错误处理到路由配置
#### 1. Reactor错误处理方法
在响应式编程中,错误处理是至关重要的。Project Reactor为其响应式类型(Mono<T> 和 Flux<T>)提供了六种错误处理方法,下面为你详细介绍:
| 方法 | 描述 | 版本 |
| --- | --- | --- |
| onErrorReturn(..) | 声明一个默认值,当处理器中抛出异常时发出该值,不影响数据流,异常元素用默认值代替,后续元素正常处理。 | 1. 接收要返回的值作为参数<br>2. 接收要返回的值和应返回默认值的异常类型作为参数<br>3. 接收要返回的值和用于匹配异常的谓词作为参数 |
| onErrorResume() | 声明一个默认函数,当处理器中抛出异常时选择一个后备Publisher<T>,异常元素用所选Publisher<T>发出值,后续元素正常处理。 | 与onErrorReturn(..)类似的三种版本 |
| onErrorContinue(..) | 声明一个消费者,当处理器中抛出异常时执行该消费者,处理异常元素,正常元素的下游链保持不变。 | 与onErrorReturn(..)类似的三种版本 |
| doOnError(..) | 消费错误并停止流中后续元素的执行,消费者执行后,错误会继续传播。 | 与onErrorReturn(..)类似的三种版本 |
| onErrorMap(..) | 将一个错误转换为另一个错误,并停止流中后续元素的执行。 | 无 |
#### 2. 响应式控制器
响应式控制器是包含返回Flux<T>和Mono<T>的处理方法的控制器,这对于REST控制器很有意义。以下是一个管理Singer实例的REST控制器示例:
```kotlin
package com.apress.prospring6.twenty.boot.controller
import org.springframework.http.HttpStatus
import org.springframework.http.ResponseEntity
import reactor.core.publisher.Flux
import reactor.core.publisher.Mono
// other import statements omitted
@RestController
@RequestMapping(path = ["/reactive/singer"])
class ReactiveSingerController {
lateinit var singerService: SingerService
/* 1 */
@GetMapping(path = ["", "/"])
fun list(): Flux<Singer> {
return singerService.findAll()
}
/* 3 */
@GetMapping(path = ["/{id}"])
fun findById(@PathVariable id: Long): Mono<ResponseEntity<Singer>> {
return singerService.findById(id)
.map { s -> ResponseEntity.ok().body(s) }
.defaultIfEmpty(ResponseEntity.notFound().build())
}
/* 4 */
@PostMapping
@ResponseStatus(HttpStatus.CREATED)
fun create(@RequestBody singer: Singer): Mono<Singer> {
return singerService.save(singer)
}
/* 5 */
@PutMapping("/{id}")
fun updateById(@PathVariable id: Long, @RequestBody singer: Singer):
Mono<ResponseEntity<Singer>> {
return singerService.update(id, singer)
.map { s -> ResponseEntity.ok().body(s) }
.defaultIfEmpty(ResponseEntity.badRequest().build())
}
/* 2 */
@DeleteMapping("/{id}")
fun deleteById(@PathVariable id: Long): Mono<ResponseEntity<Void>> {
return singerService.delete(id)
.then(Mono.fromCallable{
ResponseEntity.noContent().build<Void>()
})
.defaultIfEmpty(ResponseEntity.notFound().build())
}
/* 6 */
@GetMapping(params = ["name"])
fun searchSingers(@RequestParam("name") name: String): Flux<Singer> {
if (name.isBlank()) {
throw IllegalArgumentException("Missing request parameter 'name'");
}
return singerService.findByFirstName(name)
}
/* 7 */
@GetMapping(params = ["fn", "ln"])
fun searchSinger(@RequestParam("fn") fn: String, @RequestParam("ln") ln: String):
Mono<Singer> {
if (fn.isBlank()) {
throw IllegalArgumentException("Missing request parameter 'fn'");
}
if (ln.isBlank()) {
throw IllegalArgumentException("Missing request parameter 'ln'");
}
return singerService.findByFirstNameAndLastName(fn, ln)
}
}
```
除了返回类型因使用响应式SingerService而必要外,这个控制器没有什么特别之处。使用curl、Postman等客户端测试时,它的行为与非响应式控制器没有区别,因为这些不是响应式客户端,且此示例较小,难以察觉差异。你可以尝试生成大量随机数据填充SINGER表,然后访问/reactive/singer端点观察数据流。
#### 3. 处理类和函数式端点
处理类是对处理函数进行逻辑分组的方式。处理函数必须实现HandlerFunction功能接口,并为其handle(..)方法提供实现,该方法接受一个org.springframework.web.reactive.function.server.ServerRequest参数并返回一个Mono<org.springframework.web.reactive.function.server.ServerResponse>。以下是HandlerFunction类的代码:
```java
package org.springframework.web.reactive.function.server;
import reactor.core.publisher.Mono;
@FunctionalInterface
public interface HandlerFunction<T extends ServerResponse> {
Mono<T> handle(ServerRequest request);
}
```
HandlerFunction<T>的实现表示处理请求的函数,可通过RouterFunction映射到请求路径。下面是SingerHandler类,它将所有处理函数分组,类似于前面介绍的ReactiveSingerController类中的处理方法:
```kotlin
package com.apress.prospring6.twenty.boot.handler
import org.springframework.http.MediaType
import org.springframework.web.reactive.function.server.HandlerFunction
import org.springframework.web.reactive.function.server.ServerRequest
import org.springframework.web.reactive.function.server.ServerResponse
import java.net.URI
import org.springframework.web.reactive.function.server.ServerResponse.*
// other import statements omitted
@Component
class SingerHandler(private val singerService: SingerService) {
/* 1 */
var list: HandlerFunction<ServerResponse> = HandlerFunction<ServerResponse> {
serverRequest: ServerRequest? ->
ServerResponse.ok()
.contentType(MediaType.APPLICATION_JSON)
.body(singerService.findAll(), Singer::class.java)
}
/* 2 */
var deleteById: HandlerFunction<ServerResponse> = HandlerFunction<ServerResponse> {
serverRequest: ServerRequest ->
ServerResponse.noContent()
.build(singerService.delete(serverRequest.pathVariable("id").toLong()))
}
/* 3 */
fun findById(serverRequest: ServerRequest): Mono<ServerResponse> {
val id = serverRequest.pathVariable("id").toLong()
return singerService.findById(id)
.flatMap { singer ->
ServerResponse.ok()
.contentType(MediaType.APPLICATION_JSON).bodyValue(singer)
}
.switchIfEmpty(ServerResponse.notFound().build())
}
/* 4 */
fun create(serverRequest: ServerRequest): Mono<ServerResponse> {
val singerMono = serverRequest.bodyToMono(
Singer::class.java
)
return singerMono
.flatMap<Any>(singerService::save)
.log()
.flatMap<ServerRes
```
0
0
复制全文
相关推荐









