天天看點

關系資料建構反應式的spring驅動程式

關系資料建構反應式的spring驅動程式

先說說什麼是響應式

響應式程式設計或反應式程式設計(英語:Reactive programming)是一種面向資料流和變化傳播的程式設計範式,直白的說就是:将變化的值通過資料流進行傳播。

反應式架構文章

WebFlux定點推送、全推送靈活websocket運用【推】

WebFlux前後端分離 -- 資料響應式展示 【推】

webflux+redis/mongodb提供響應式API【推】

WebFlux是什麼呢

WebFlux 子產品的名稱是 spring-webflux,名稱中的 Flux 來源于 Reactor 中的類 Flux。Spring webflux 有一個全新的非堵塞的函數式 Reactive Web 架構,可以用來建構異步的、非堵塞的、事件驅動的服務,在伸縮性方面表現非常好。

spring-webflux 子產品。該子產品包含對響應式 HTTP 和 WebSocket 用戶端的支援,以及對 REST,HTML 和 WebSocket 互動等程式的支援。一般來說,Spring MVC 用于同步處理,Spring Webflux 用于異步處理。

Spring Boot Webflux 有兩種程式設計模型實作,一種類似 Spring MVC 注解方式,另一種是基于 Reactor 的響應式方式。

R2DBC是什麼?

響應式關系資料庫連接配接的支援

主題

之前我有對非關系性資料庫的響應式api實作(傳送門),而今天我們要說說非關系型資料庫實作。

體驗spring boot  2.3.0.RC1 , 期待已久mysql  reactive 總算開始展露頭角了。 今天就來整合一下springboot 和r2dbc 與mysql。主要是采用 Spring Data R2DBC ,Spring Data R2DBC對R2DBC應用了熟悉的Spring抽象和存儲庫支援。它使在響應式應用程式堆棧中建構使用關系資料通路技術的Spring驅動的應用程式更加容易。

POM

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
    <groupId>com.gitee.occo</groupId>
    <artifactId>occo-parent</artifactId>
    <version>2.0.0-SNAPSHOT</version>
</parent>
<artifactId>occo-sso</artifactId>
<version>0.0.1-SNAPSHOT</version>

<dependencies>
    <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>
        <scope>runtime</scope>
    </dependency>
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <scope>runtime</scope>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
        <exclusions>
            <exclusion>
                <groupId>org.junit.vintage</groupId>
                <artifactId>junit-vintage-engine</artifactId>
            </exclusion>
        </exclusions>
    </dependency>
    <dependency>
        <groupId>io.projectreactor</groupId>
        <artifactId>reactor-test</artifactId>
        <scope>test</scope>
    </dependency>

    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <scope>provided</scope>
    </dependency>
</dependencies>

<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
        </plugin>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <configuration>
                <source>${java.version}</source>
                <target>${java.version}</target>
                <encoding>UTF-8</encoding>
            </configuration>
        </plugin>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-release-plugin</artifactId>
            <configuration>
                <tagNameFormat>v@{project.version}</tagNameFormat>
                <autoVersionSubmodules>true</autoVersionSubmodules>
                <indentSize>4</indentSize>
                <useEditMode>true</useEditMode>
                <localCheckout>true</localCheckout>
            </configuration>
        </plugin>
    </plugins>
</build>           

POM中的occo-parent可以替換成

<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.0.RC1</version>
<relativePath/> <!-- lookup parent from repository -->           
<repositories>
    <repository>
        <id>spring-milestones</id>
        <name>Spring Milestones</name>
        <url>https://repo.spring.io/milestone</url>
    </repository>
</repositories>
<pluginRepositories>
    <pluginRepository>
        <id>spring-milestones</id>
        <name>Spring Milestones</name>
        <url>https://repo.spring.io/milestone</url>
    </pluginRepository>
</pluginRepositories>           

application.yml

server:

port: 8000

spring:

application:

name: occo-sso           

r2dbc:

url: r2dbc:mysql://localhost:3306/occo
username: root
password: pwd2020           

logging:

level:

org.springframework.data.r2dbc: DEBUG            

實作一個簡單資料操作

repository:

import org.springframework.data.r2dbc.repository.Query;

import org.springframework.data.repository.reactive.ReactiveCrudRepository;

import org.springframework.stereotype.Repository;

import com.gitee.occo.sso.user.entity.User;

import reactor.core.publisher.Flux;

import reactor.core.publisher.Mono;

@Repository

public interface UserRepository extends ReactiveCrudRepository{

@Query("SELECT * FROM user WHERE state = :state")
Flux<User> findByState(Integer state);

@Query("SELECT * FROM user WHERE username = :username")
Mono<User> findByUsername(String username);

@Query("SELECT * FROM user WHERE username LIKE :username")
Flux<User> findByUsernameLike(String username);           

}

service

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.stereotype.Service;

import com.gitee.occo.sso.user.repository.UserRepository;

import com.gitee.occo.sso.user.service.UserService;

@Service

public class UserServiceImpl implements UserService {

@Autowired
private UserRepository userRepository;

@Override
public Mono<User> findById(Long id) {
    // TODO Auto-generated method stub
    return userRepository.findById(id);
}

@Override
public Mono<User> findByUsername(String username) {
    // TODO Auto-generated method stub
    return userRepository.findByUsername(username);
}

@Override
public Flux<User> findByUsernameLike(String username) {
    // TODO Auto-generated method stub
    return userRepository.findByUsernameLike(username);
}
           

controller:

import java.time.Duration;

import org.springframework.http.MediaType;

import org.springframework.web.bind.annotation.GetMapping;

import org.springframework.web.bind.annotation.PathVariable;

import org.springframework.web.bind.annotation.RequestMapping;

import org.springframework.web.bind.annotation.RestController;

@RestController

@RequestMapping("/user")

public class UserController {

@Autowired
UserService userService;

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

@GetMapping("/findByUsername")
public Mono<User> findByUsername(String username){
    return userService.findByUsername(username);
}

@GetMapping(value="/findByUsernameLike" ,produces = MediaType.APPLICATION_STREAM_JSON_VALUE)
public Flux<User> getByUsername(String username){
    return userService.findByUsernameLike(username+"%").delayElements(Duration.ofSeconds(2));
}           

PS:produces = MediaType.APPLICATION_STREAM_JSON_VALUE  要加上,不然就會等待完成,一個請求體傳回回去。

代碼:傳送門

原文位址

https://my.oschina.net/bianxin/blog/4277900