【SpringWebFlux】WebFlux入门

本文介绍了如何使用Spring WebFlux进行响应式编程,包括引入依赖、配置数据源、创建实体类、定义DAO、Service及Controller层。通过ReactiveCrudRepository接口简化数据库操作,并展示了函数式WebFlux的使用方法以及WebClient的非阻塞HTTP客户端调用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

WebFlux内部使用的是响应式编程(Reactive Programming),以Reactor库为基础, 基于异步和事件驱动,可以让我们在不扩充硬件资源的前提下,提升系统的吞吐量和伸缩性。

WebFlux使用的技术栈:

1655083993730.png

1655084019160.png

使用

引入依赖

<dependency>
	<groupId>org.projectlombok</groupId>
	<artifactId>lombok</artifactId>
</dependency>

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-data-r2dbc</artifactId>
</dependency>

<dependency>
	<groupId>dev.miku</groupId>
	<artifactId>r2dbc-mysql</artifactId>
	<version>0.8.2.RELEASE</version>
</dependency>
  • webflux依赖会自动引入projectreactor依赖;
  • r2dbc依赖类似于jdbc。

配置文件

application.properties

# r2dbc:<driver>://<host>:<port>/<database>
spring.r2dbc.url=r2dbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=UTF-8&userSSL=false&serverTimezone=GMT%2B8
spring.r2dbc.username=user
spring.r2dbc.password=user

数据源的配置格式采用固定的r2dbc:<driver>://<host>:<port>/<database>

实体类

实体类中使用JPA的注解指定表名和主键字段。

package com.morris.spring.webflux.entity;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.data.annotation.Id;
import org.springframework.data.relational.core.mapping.Table;

@Table("t_user")
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {

    @Id
    private Long id;

    private String name;

    private Integer age;

}

DAO层

DAO接口组要继承ReactiveCrudRepository接口,这样就能使用JPA提供的一系列方法。

package com.morris.spring.webflux.dao;

import com.morris.spring.webflux.entity.User;
import org.springframework.data.repository.reactive.ReactiveCrudRepository;
import org.springframework.stereotype.Component;

@Component
public interface UserDao extends ReactiveCrudRepository<User, Long> {
}

Service层

Service层注入DAO,可以使用DAO继承过来的一系列操作数据库表的方法。

package com.morris.spring.webflux.service;

import com.morris.spring.webflux.dao.UserDao;
import com.morris.spring.webflux.entity.User;
import org.springframework.stereotype.Service;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import javax.annotation.Resource;

@Service
public class UserService {

    @Resource
    private UserDao userDao;

    public Flux<User> all() {
        return userDao.findAll();
    }

    public Mono<User> saveUser(User user) {
        return userDao.save(user);
    }

    public Mono<User> getById(Long id) {
        return userDao.findById(id);
    }

    public Mono<Void> deleteById(Long id) {
        return userDao.deleteById(id);
    }

}

Controller层

Controller层与传统的SpringMVC一样可以使用@RequestMapping注解来映射请求,方法的返回值类型一定要是响应式的Mono或Flux。

package com.morris.spring.webflux.controller;

import com.morris.spring.webflux.entity.User;
import com.morris.spring.webflux.service.UserService;
import org.springframework.web.bind.annotation.*;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import javax.annotation.Resource;

@RestController
@RequestMapping("user")
public class UserController {

    @Resource
    private UserService userService;

    @GetMapping("/")
    public Flux<User> list() {
        return userService.all();
    }

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

    @PutMapping("/{id}")
    public Mono<User> modifyUser(@RequestBody User user, @PathVariable("id") Long id) {
        user.setId(id);
        return userService.saveUser(user);
    }

    @GetMapping("/{id}")
    public Mono<User> getById(@PathVariable("id") Long id) {
        return userService.getById(id);
    }

    @DeleteMapping("/{id}")
    public Mono<Void> deleteById(@PathVariable("id") Long id) {
        return userService.deleteById(id);
    }

}

启动类

package com.morris.spring.webflux;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class SpringWebfluxDemoApplication {

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

}

函数式WebFlux的使用

除了可以使用穿透的@RequestMapping注解映射请求外,还可以使用函数式方法来映射请求,这也是WebFlux所推荐的。

Handler相当于Controller层。

package com.morris.spring.webflux.handler;

import com.morris.spring.webflux.entity.User;
import com.morris.spring.webflux.service.UserService;
import org.springframework.stereotype.Component;
import org.springframework.web.reactive.function.server.ServerRequest;
import org.springframework.web.reactive.function.server.ServerResponse;
import reactor.core.publisher.Mono;

import javax.annotation.Resource;

/**
 * 函数式WebFlux的使用
 */
@Component
public class UserHandler {

    @Resource
    private UserService userService;

    public Mono<ServerResponse> list(ServerRequest serverRequest) {
        return ServerResponse.ok().body(userService.all(), User.class);
    }

    public Mono<ServerResponse> addUser(ServerRequest serverRequest) {
        return serverRequest.bodyToMono(User.class)
                .flatMap(u -> ServerResponse.ok().body(userService.saveUser(u), User.class));
    }

    public Mono<ServerResponse> modifyUser(ServerRequest serverRequest) {
        String id = serverRequest.pathVariable("id");
        return serverRequest.bodyToMono(User.class)
                .flatMap(u -> {
                    u.setId(Long.valueOf(id));
                    return ServerResponse.ok().body(userService.saveUser(u), User.class);
                });
    }

    public Mono<ServerResponse> getById(ServerRequest serverRequest) {
        String id = serverRequest.pathVariable("id");
        return ServerResponse.ok().body(userService.getById(Long.valueOf(id)), User.class);
    }

    public Mono<ServerResponse> deleteById(ServerRequest serverRequest) {
        String id = serverRequest.pathVariable("id");
        return ServerResponse.ok().build(userService.deleteById(Long.valueOf(id)));
    }

}

配置路由,相当于@RequestMapping的功能。

package com.morris.spring.webflux.handler;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.MediaType;
import org.springframework.web.reactive.function.server.RouterFunction;
import org.springframework.web.reactive.function.server.RouterFunctions;
import org.springframework.web.reactive.function.server.ServerResponse;

import static org.springframework.web.reactive.function.server.RequestPredicates.*;

@Configuration
public class UserRoute {

    @Bean
    public RouterFunction<ServerResponse> userRouterFunction(UserHandler userHandler) {
        return RouterFunctions
                .route(GET("/user2/").and(accept(MediaType.APPLICATION_JSON)), userHandler::list)
                .andRoute(POST("/user2/").and(accept(MediaType.APPLICATION_JSON)), userHandler::addUser)
                .andRoute(PUT("/user2/{id}").and(accept(MediaType.APPLICATION_JSON)), userHandler::modifyUser)
                .andRoute(GET("/user2/{id}").and(accept(MediaType.APPLICATION_JSON)), userHandler::getById)
                .andRoute(DELETE("/user2/{id}").and(accept(MediaType.APPLICATION_JSON)), userHandler::deleteById);
    }

}

WebClient的使用

WebClient类似于HttpClient,只不过WebClient是非阻塞的,而HttpClient是阻塞的。

package com.morris.spring.webflux.handler;

import com.morris.spring.webflux.entity.User;
import com.morris.spring.webflux.service.UserService;
import org.springframework.stereotype.Component;
import org.springframework.web.reactive.function.BodyInserters;
import org.springframework.web.reactive.function.client.WebClient;
import org.springframework.web.reactive.function.server.ServerRequest;
import org.springframework.web.reactive.function.server.ServerResponse;
import reactor.core.publisher.Mono;

import javax.annotation.Resource;

/**
 * WebClient的使用
 */
@Component
public class WebClientHandler {

    public Mono<ServerResponse> webClient(ServerRequest serverRequest) {

        return serverRequest.bodyToMono(User.class).flatMap(u ->
                WebClient.create("http://localhost:8080/user/")
                .post()
                .body(BodyInserters.fromValue(u))
                .exchangeToMono(t -> t.bodyToMono(User.class))
                .flatMap(t -> ServerResponse.ok().body(BodyInserters.fromValue(t))));
    }

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

morris131

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值