使用 WebFlux 代替 Spring MVC

认识 WebFlux

什么是 WebFlux

  • 用于构建基于 Reactive 技术栈之上的 Web 应用程序
  • 基于 Reactive Streams API ,运行在非阻塞服务器上

为什么会有 WebFlux

  • 对于非阻塞 Web 应用的需要

  • 函数式编程(Java8中引入的lambda表达式)

关于 WebFlux 的性能

  • 单次请求的耗时并不会有很大的改善
  • 仅需少量固定数量的线程和较少的内存即可实现扩展,并发的处理,提升并发的容量(基于Reactive )

WebMVC 和 WebFlux 应用场景

  • 已有 Spring MVC 应用,运行正常,就别改了
  • 依赖了大量阻塞式持久化 API 和网络 API,比如说,使用mysql,建议使用 Spring MVC
  • 已经使用了非阻塞技术栈(使用redis MongoDB),可以考虑使用 WebFlux
  • 想要使用 Java 8 Lambda 结合轻量级函数式框架,可以考虑 WebFlux

WebFlux 中的编程模型

两种编程模型

  • 基于注解的控制器器
  • 函数式 Endpoints

基于注解的控制器
常用注解

  • @Controller @RestController
  • @RequestMapping 及其等价注解(delete put get post)
  • @RequestBody / @ResponseBody (结果和请求的正文)

返回值

  • Mono(0或者1个返回) / Flux(多个返回)

例子

目录结构如下:
在这里插入图片描述
代码:

@Controller
@RequestMapping("/coffee")
@Slf4j
public class CoffeeController {
    @Autowired
    private CoffeeService coffeeService;

    @GetMapping(path = "/", params = "!name")
    @ResponseBody
    public Flux<Coffee> getAll() {
        return coffeeService.findAll();
    }

    @RequestMapping(path = "/{id}", method = RequestMethod.GET)
    @ResponseBody
    public Mono<Coffee> getById(@PathVariable Long id) {
        return coffeeService.findById(id);
    } //@PathVariable 将id注入

    @GetMapping(path = "/", params = "name")
    @ResponseBody
    public Mono<Coffee> getByName(@RequestParam String name) {
        return coffeeService.findByName(name);
    }
}

@RestController
@RequestMapping("/order")
@Slf4j
public class CoffeeOrderController {
    @Autowired
    private OrderService orderService;
    @Autowired
    private CoffeeService coffeeService;

    @GetMapping("/{id}")
    public Mono<CoffeeOrder> getOrder(@PathVariable("id") Long id) { //只是将返回变了
        return orderService.getById(id);
    }

    @PostMapping(path = "/", consumes = MediaType.APPLICATION_JSON_VALUE,
            produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
    @ResponseStatus(HttpStatus.CREATED)
    public Mono<CoffeeOrder> create(@RequestBody NewOrderRequest newOrder) {
        log.info("Receive new Order {}", newOrder);
        return orderService.create(newOrder.getCustomer(), newOrder.getItems())
                .flatMap(id -> orderService.getById(id));
    }
}

@Repository
public class CoffeeOrderRepository {
    @Autowired
    private DatabaseClient databaseClient;

    public Mono<CoffeeOrder> get(Long id) {
        return databaseClient.execute()
                .sql("select * from t_order where id = " + id)
                .map((r, rm) ->
                            CoffeeOrder.builder()
                                    .id(id)
                                    .customer(r.get("customer", String.class))
                                    .state(OrderState.values()[r.get("state", Integer.class)])
                                    .createTime(r.get("create_time", Date.class))
                                    .updateTime(r.get("update_time", Date.class))
                                    .items(new ArrayList<Coffee>())
                                    .build()  //用map方式 把order对象拼装出来
                )
                .first()
                .flatMap(o ->
                        databaseClient.execute()
                                .sql("select c.* from t_coffee c, t_order_coffee oc " +
                                    "where c.id = oc.items_id and oc.coffee_order_id = " + id)
                                .as(Coffee.class)
                                .fetch()//将FetchSpec转换为Flux
                                .all()
                                .collectList()//取出所有的 转换成Mono<List<Coffee>>
                                .flatMap(l -> {
                                    o.getItems().addAll(l);
                                    return Mono.just(o); //这个方法的返回为Mono
                                })
                );
    }

    public Mono<Long> save(CoffeeOrder order) {
        return databaseClient.insert().into("t_order")
                .value("customer", order.getCustomer())
                .value("state", order.getState().ordinal())
                .value("create_time", new Timestamp(order.getCreateTime().getTime()))
                .value("update_time", new Timestamp(order.getUpdateTime().getTime()))
                .fetch()
                .first()
                .flatMap(m -> Mono.just((Long) m.get("ID")))   //根据ID注解取出id
                .flatMap(id -> Flux.fromIterable(order.getItems())
                        .flatMap(c -> databaseClient.insert().into("t_order_coffee")
                                .value("coffee_order_id", id)
                                .value("items_id", c.getId())
                                .then()).then(Mono.just(id)));
    }
}

public interface CoffeeRepository extends R2dbcRepository<Coffee, Long> {
    @Query("select * from t_coffee where name=$1")
    Mono<Coffee> findByName(String name);
}
@Service
public class CoffeeService {
    @Autowired
    private CoffeeRepository coffeeRepository;


    public Mono<Coffee> findById(Long id) {
        return coffeeRepository.findById(id);
    }

    public Flux<Coffee> findAll() {
        return coffeeRepository.findAll();
    }

    public Mono<Coffee> findByName(String name) {
        return coffeeRepository.findByName(name);
    }
}
@Service
public class OrderService {
    @Autowired
    private CoffeeOrderRepository orderRepository;
    @Autowired
    private CoffeeRepository coffeeRepository;

    public Mono<CoffeeOrder> getById(Long id) {
        return orderRepository.get(id);
    }

    public Mono<Long> create(String customer, List<String> items) {
        return Flux.fromStream(items.stream())  //将所有的咖啡名转为Flux<String>
                .flatMap(n -> coffeeRepository.findByName(n))
                .collectList()//转换为 Mono List<Coffee>
                .flatMap(l ->
                        orderRepository.save(CoffeeOrder.builder()
                                .customer(customer)
                                .items(l)
                                .state(OrderState.INIT)
                                .createTime(new Date())
                                .updateTime(new Date())
                                .build())
                );
    }
}

@SpringBootApplication
@EnableR2dbcRepositories
public class WaiterServiceApplication extends AbstractR2dbcConfiguration {

	public static void main(String[] args) {
		SpringApplication.run(WaiterServiceApplication.class, args);
	}

	@Bean
	public ConnectionFactory connectionFactory() {
		return new H2ConnectionFactory(  //连接h2
				H2ConnectionConfiguration.builder()
						.inMemory("testdb")
						.username("sa")
						.build());
	}

	@Bean
	public R2dbcCustomConversions r2dbcCustomConversions() {
		Dialect dialect = getDialect(connectionFactory());
		CustomConversions.StoreConversions storeConversions =
				CustomConversions.StoreConversions.of(dialect.getSimpleTypeHolder());
		return new R2dbcCustomConversions(storeConversions,
				Arrays.asList(new MoneyReadConverter(), new MoneyWriteConverter()));
	}

	@Bean
	public Jackson2ObjectMapperBuilderCustomizer jacksonBuilderCustomizer() {
		return builder -> builder.indentOutput(true)
				.timeZone(TimeZone.getTimeZone("Asia/Shanghai"));
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值