package luck.spring.boot.webflux;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.validation.BeanPropertyBindingResult;
import org.springframework.validation.Errors;
import org.springframework.validation.Validator;
import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;
import org.springframework.web.reactive.function.server.RouterFunction;
import org.springframework.web.reactive.function.server.ServerRequest;
import org.springframework.web.reactive.function.server.ServerResponse;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.ServerWebInputException;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import java.nio.charset.StandardCharsets;
import java.util.function.BiFunction;
import static org.springframework.http.MediaType.APPLICATION_JSON;
import static org.springframework.web.reactive.function.server.RequestPredicates.accept;
import static org.springframework.web.reactive.function.server.RouterFunctions.route;
import static org.springframework.web.reactive.function.server.ServerResponse.notFound;
import static org.springframework.web.reactive.function.server.ServerResponse.ok;
@Configuration
public class CurdRouterFunctionConfig {
// 定义使用CRUD的handler进行逻辑处理的嵌套路由
@Bean
public RouterFunction<ServerResponse> nestPersonRouterFunction(PersonHandler handler) {
// 定义嵌套路由
return route()
.path("/person", b1 -> b1
.nest(accept(APPLICATION_JSON), b2 -> b2
// 使用CRUD的handler进行逻辑处理
.GET("/{id}", handler::getPerson)
.GET("", handler::listPeople))
.POST("/person", handler::createPerson))
.build();
}
@Component
static class PersonRepository {
public Flux<Person> allPeople() {
return Flux.just(new Person(1, "luck"), new Person(2, "java"));
}
public Mono<Person> getPerson(int personId) {
return Mono.just(new Person(1, "luck"));
}
public BiFunction<ServerWebExchange, ServerResponse.Context, Mono<Void>> savePerson(Mono<Person> person) {
return (exchange, context) -> {
ServerHttpResponse response = exchange.getResponse();
DataBuffer buffer = response.bufferFactory().wrap("保存成功".getBytes(StandardCharsets.UTF_8));
return response.writeWith(Mono.just(buffer));
};
}
}
@Component
static class PersonHandler {
private final Validator validator;
private final PersonRepository repository;
public PersonHandler(PersonRepository repository) {
this.repository = repository;
this.validator = new LocalValidatorFactoryBean();
}
public Mono<ServerResponse> listPeople(ServerRequest request) {
Flux<Person> people = repository.allPeople();
return ok().contentType(APPLICATION_JSON).body(people, Person.class);
}
public Mono<ServerResponse> createPerson(ServerRequest request) {
Mono<Person> person = request.bodyToMono(Person.class).doOnNext(this::validate);
return ok().build(repository.savePerson(person));
}
public Mono<ServerResponse> getPerson(ServerRequest request) {
int personId = Integer.parseInt(request.pathVariable("id"));
return repository.getPerson(personId)
.flatMap(person -> ok().contentType(APPLICATION_JSON).bodyValue(person))
.switchIfEmpty(notFound().build());
}
private void validate(Person person) {
Errors errors = new BeanPropertyBindingResult(person, "person");
validator.validate(person, errors);
if (errors.hasErrors()) {
throw new ServerWebInputException(errors.toString());
}
}
}
}