我们选择 MongoDB 作为 Repository 来实现 CRUD 操作
依赖
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-webflux</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-mongodb-reactive</artifactId></dependency>
配置 application.properties
spring.data.mongodb.uri=mongodb://localhost:27017/webflux
开启 Reactive MongoDB 注解
@SpringBootApplication@EnableReactiveMongoRepositoriespublic class FluxApplication {public static void main(String[] args) {SpringApplication.run(FluxApplication.class, args);}}
定义 MongoDB 对应的实体类
@Data@Document(collation = "user")public class User {@Idprivate String id;private String name;private int age;}
定义仓库
@Repositorypublic interface UserRepository extends ReactiveMongoRepository<User, String> {}
编写 Controller
@RestController@RequestMapping("/user")public class UserController {private final UserRepository userRepository;public UserController(UserRepository userRepository) {this.userRepository = userRepository;}/*** 以数组形式,一次返回数据*/@GetMapping(value = "/all")public Flux<User> getAll() {return userRepository.findAll();}/*** 以 SSE 的形式,多次返回数据*/@GetMapping(value = "/stream/all", produces = MediaType.TEXT_EVENT_STREAM_VALUE)public Flux<User> streamGetAll() {return userRepository.findAll();}/*** 添加用户** @param user user*/@PostMapping("/add")public Mono<User> createUser(@RequestBody User user) {user.setId(null);return this.userRepository.save(user);}/*** 根据 ID 删除用户* 存在的时候返回 200* 不存在返回 404** @param id id*/@DeleteMapping("/delete/{id}")public Mono<ResponseEntity<Void>> deleteUser(@PathVariable("id") String id) {return this.userRepository.findById(id)// 当需要操作数据,并返回 Mono,这个时候需要使用 flatMap// 如果不需要操作数据,只是对数据进行转换,就用 map.flatMap(user -> this.userRepository.delete(user).then(Mono.just(new ResponseEntity<Void>(HttpStatus.OK)))).defaultIfEmpty(new ResponseEntity<>(HttpStatus.NOT_FOUND));}/*** 更新用户* 存在的时候返回 200 和 用户数据* 不存在返回 404** @param id id* @param user user*/@PutMapping("/update/{id}")public Mono<ResponseEntity<User>> updateUser(@PathVariable("id") String id, @RequestBody User user) {return this.userRepository.findById(id)// flatMap 操作数据.flatMap(u -> {u.setName(user.getName());u.setAge(user.getAge());return this.userRepository.save(u);})// map 转换数据.map(u -> new ResponseEntity<>(u, HttpStatus.OK)).defaultIfEmpty(new ResponseEntity<>(HttpStatus.NOT_FOUND));}/*** 查找数据** @param id id*/@GetMapping("/get/{id}")public Mono<ResponseEntity<User>> getUser(@PathVariable("id") String id) {return this.userRepository.findById(id)// map 转换数据.map(u -> new ResponseEntity<>(u, HttpStatus.OK)).defaultIfEmpty(new ResponseEntity<>(HttpStatus.NOT_FOUND));}}
参数校验
POM 依赖
<dependency><groupId>javax.validation</groupId><artifactId>validation-api</artifactId></dependency><dependency><groupId>org.hibernate.validator</groupId><artifactId>hibernate-validator</artifactId><version>6.1.5.Final</version></dependency>
实体类
使用 Hibernat validator 进行参数校验
@Data@Document(collection = "user")public class User {@Idprivate String id;@NotBlank(message = "姓名不能为空")private String name;@Range(min = 10, max = 120, message = "超出年龄限定值")private int age;}
Controller
使用 @Valid 注解,标记需要校验的实体类
public Mono<User> createUser(@Valid @RequestBody User user){CheckUtils.checkName(user.getName()); // 自定义校验异常// ...}public Mono<ResponseEntity<User>> updateUser(@PathVariable("id") String id, @Valid @RequestBody User user) {CheckUtils.checkName(user.getName()); // 自定义校验异常// ...}// 校验工具类public class CheckUtils {private static final String[] INVALID_NAMES = {"admin", "root", "super"};public static void checkName(String name) {Stream.of(INVALID_NAMES).filter(value -> value.equalsIgnoreCase(name)).findAny().ifPresent(value -> {throw new CheckException("name", value);});}}
自定义异常
@Getter@Setterpublic class CheckException extends RuntimeException {private String filedName;private String filedValue;public CheckException(String filedName, String filedValue) {this.filedName = filedName;this.filedValue = filedValue;}}
切面
@ControllerAdvicepublic class CheckAdvice {// 全局异常捕获@ExceptionHandler(Exception.class)public ResponseEntity<String> handleException(Exception exception) {System.out.println(exception.getClass());return new ResponseEntity<>(exception.getMessage(), HttpStatus.BAD_REQUEST);}@ExceptionHandler(WebExchangeBindException.class)public ResponseEntity<String> handleBindException(WebExchangeBindException exception) {return new ResponseEntity<>(toStr(exception), HttpStatus.BAD_REQUEST);}// 自定义异常捕获@ExceptionHandler(CheckException.class)public ResponseEntity<String> handleBindException(CheckException exception) {return new ResponseEntity<>(toStr(exception), HttpStatus.BAD_REQUEST);}/*** 把校验异常转换为字符串** @param exception 异常*/private String toStr(WebExchangeBindException exception) {return exception.getFieldErrors().stream().map(e -> e.getField() + ":" + e.getDefaultMessage()).reduce("", (s1, s2) -> s1 + "\n" + s2);}private String toStr(CheckException exception) {return exception.getFiledName() + ": 错误的值 " + exception.getFiledValue();}}
