WebFlux系列之MongoDB数据操作

概述

WebFlux对于数据库操作的支持,尤其是函数式CRUD编程。

实例

直入主题,引入依赖Spring Data Reactive MongoDB。配置文件:

spring.data.mongodb.port=27017
spring.data.mongodb.host=127.0.0.1
spring.data.mongodb.username=madmin
spring.data.mongodb.password=m123
spring.data.mongodb.database=test
spring.data.mongodb.authentication-database=admin

实体类:

@Document
@Data
public class User {
    @Id
    private String id;
    private String username;
    private String address;
}

继承自ReactiveMongoRepository的空接口,即可完成绝大多数实体类操作,当然支持自定义:

@EnableMongoRepositories
public interface UserRepository extends ReactiveMongoRepository<User,String> {
	Flux<User> findUserByUsernameContaining(String name);
}

简单CRUD

@RestController
@RequestMapping("/user")
public class UserController {
    @Autowired
    private UserRepository userRepository;

    @PostMapping("/")
    public Mono<User> addUser(@RequestBody User user) {
        return userRepository.save(user);
    }

	@GetMapping("/")
	public Flux<User> getAll() {
	    return userRepository.findAll();
	}
	
	@GetMapping(value = "/stream/all", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
	public Flux<User> streamGetAll() {
	    return userRepository.findAll();
	}

	@GetMapping("/byname")
	public Flux<User> getUserByName(String name) {
	    return userRepository.findUserByUsernameContaining(name);
	}

	@DeleteMapping("/{id}")
	public Mono<ResponseEntity<Void>> deleteUser(@PathVariable String id) {
	    return userRepository.findById(id)
	            .flatMap(user -> userDao.delete(user).then(Mono.just(new ResponseEntity<Void>(HttpStatus.OK))))
	            .defaultIfEmpty(new ResponseEntity(HttpStatus.NOT_FOUND));
	}

	@PutMapping("/")
	public Mono<ResponseEntity<User>> updateUser(@RequestBody User user) {
	    return userRepository.findById(user.getId())
	            .flatMap(u -> userDao.save(user))
	            .map(u->new ResponseEntity<User>(u,HttpStatus.OK))
	            .defaultIfEmpty(new ResponseEntity(HttpStatus.NOT_FOUND));
	}
}

提供两个查询接口,一个返回 Flux,里边包含多个对象;一个设置响应Content-Type 为 text/event-stream,通过响应式流返回数据
在这里插入图片描述
可见两种不同的查询方式返回的数据格式也有差异。前者是以数组形式一次性返回数据,后者是以 SSE 的形式多次返回数据。

请求地址路由

在 SpringMVC 中,可以通过如下一些注解来控制请求 URL 和处理器之间的映射关系:
@RequestMapping
@GetMapping
@PostMapping
@DeleteMapping
@PutMapping

这些注解在 WebFlux 中依然还可以继续使用,WebFlux 也提供了自己的方案–Router。

开发处理器

@Component
public class UserHandler {
    @Autowired
    private UserRepository userRepository;

	public Mono<ServerResponse> addUser(ServerRequest serverRequest) {
        return ok().contentType(APPLICATION_JSON)
                .body(userRepository.saveAll(serverRequest.bodyToMono(User.class)), User.class);
    }

    public Mono<ServerResponse> deleteUser(ServerRequest serverRequest) {
        return userRepository.findById(parseLong(serverRequest.pathVariable("id")))
                .flatMap(p -> userRepository.delete(p).then(ok().build()))
                .switchIfEmpty(notFound().build());
    }
    
    public Mono<ServerResponse> getAllUser(ServerRequest serverRequest) {
        return ok().contentType(APPLICATION_JSON)
                .body(userRepository.findAll(), User.class);
    }
}
  • 处理器需要使用@Component注入到 Spring 容器中
  • 所有方法的返回值类型都是Mono<ServerResponse>,参数类型都是 ServerRequest,因为一会配置 Router 时涉及到的 HandlerFunction 里边就是这样定义的,换句话说,这里定义的每一个方法都满足 HandlerFunction 函数式接口

配置路由
将请求的 URL 地址和这些处理器之间关联起来:

@Configuration
public class RouterConfiguration {
    @Bean
    RouterFunction<ServerResponse> userRouter(UserHandler userHandler) {
        return RouterFunctions.nest(RequestPredicates.path("/user"), 
                        RouterFunctions.route(RequestPredicates.POST("/"), userHandler::addUser)
                                .andRoute(RequestPredicates.GET("/"), userHandler::getAllUser)
                                .andRoute(RequestPredicates.DELETE("/{id}"), userHandler::deleteUser));
    }
}
  • 配置类类似于SpringMVC 中的 DispatcherServlet,负责请求的分发,根据不同的请求 URL找到对应的处理器去处理
  • 通过RouterFunctions工具类来创建 RouterFunction 实例,nest方法第一个参数配置地址的前缀,类似于在 Controller 类上直接写 @RequestMapping 注解去配置地址
  • nest 方法的第二个参数就是 RouterFunction 实例,每一个 RouterFunction 实例通过 RouterFunctions.route 方法来构建,第一个参数就是请求的 URL 地址(注意配置地址都有一个共同前缀),第二个参数通过方法引用的方式配置HandlerFunction,即当前请求对应的处理器
  • 通过 addRoute 方法可以配置多个路由策略

参考

posted @ 2021-06-21 21:06  johnny233  阅读(16)  评论(0编辑  收藏  举报  来源