增加 webflux mysql + 事务

This commit is contained in:
YunaiV
2019-11-26 22:55:35 +08:00
parent f6b91bb7e7
commit 3500a3cc68
12 changed files with 491 additions and 1 deletions

View File

@@ -0,0 +1,58 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
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">
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.1.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>lab-27-webflux-r2dbc</artifactId>
<dependencies>
<!-- 实现对 Spring WebFlux 的自动化配置 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
<version>2.2.1.RELEASE</version>
</dependency>
<!-- 自动化配置响应式的 Spring Data R2DBC -->
<dependency>
<groupId>org.springframework.boot.experimental</groupId>
<artifactId>spring-boot-starter-data-r2dbc</artifactId>
<version>0.1.0.M2</version>
</dependency>
<dependency>
<groupId>com.github.jasync-sql</groupId>
<artifactId>jasync-r2dbc-mysql</artifactId>
<version>1.0.11</version>
</dependency>
<!-- 方便等会写单元测试 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<repositories>
<!-- 引入 Spring 的快照仓库 -->
<repository>
<id>spring-libs-snapshot</id>
<url>https://repo.spring.io/libs-snapshot</url>
</repository>
<!-- 引入 Jcenter 的快照仓库 -->
<repository>
<id>jcenter</id>
<url>https://jcenter.bintray.com/</url>
</repository>
</repositories>
</project>

View File

@@ -0,0 +1,13 @@
package cn.iocoder.springboot.lab27.springwebflux;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}

View File

@@ -0,0 +1,35 @@
package cn.iocoder.springboot.lab27.springwebflux.config;
import com.github.jasync.r2dbc.mysql.JasyncConnectionFactory;
import com.github.jasync.sql.db.mysql.pool.MySQLConnectionFactory;
import io.r2dbc.spi.ConnectionFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.transaction.annotation.EnableTransactionManagement;
@Configuration
@EnableTransactionManagement
public class DatabaseConfiguration {
// @Bean
// @ConfigurationProperties("spring.jasync.r2dbc")
// public com.github.jasync.sql.db.Configuration configuration() {
// return new com.github.jasync.sql.db.Configuration("");
// }
@Bean
public ConnectionFactory connectionFactory() {
// com.github.jasync.sql.db.Configuration configuration
//// = URLParser.INSTANCE.parseOrDie("mysql://root:@localhost:3306/lab-27-webflux-r2dbc", StandardCharsets.UTF_8);
// = URLParser.INSTANCE.parseOrDie("mysql://lab-27-webflux-r2dbc:0ed86@11-r2Dbc123@47.112.193.81:3306/lab-27-webflux-r2dbc", StandardCharsets.UTF_8);
com.github.jasync.sql.db.Configuration configuration = new com.github.jasync.sql.db.Configuration(
"lab-27-webflux-r2dbc",
"47.112.193.81",
3306,
"0ed86@11-r2Dbc123",
"lab-27-webflux-r2dbc"
);
return new JasyncConnectionFactory(new MySQLConnectionFactory(configuration));
}
}

View File

@@ -0,0 +1,161 @@
package cn.iocoder.springboot.lab27.springwebflux.controller;
import cn.iocoder.springboot.lab27.springwebflux.dao.UserRepository;
import cn.iocoder.springboot.lab27.springwebflux.dataobject.UserDO;
import cn.iocoder.springboot.lab27.springwebflux.dto.UserAddDTO;
import cn.iocoder.springboot.lab27.springwebflux.dto.UserUpdateDTO;
import cn.iocoder.springboot.lab27.springwebflux.vo.UserVO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import java.util.Date;
import java.util.Objects;
import java.util.function.Function;
/**
* 用户 Controller
*/
@RestController
@RequestMapping("/users")
public class UserController {
private static final UserDO USER_NULL = new UserDO();
@Autowired
private UserRepository userRepository;
/**
* 查询用户列表
*
* @return 用户列表
*/
@GetMapping("/list")
public Flux<UserVO> list() {
// 返回列表
return userRepository.findAll()
.map(userDO -> new UserVO().setId(userDO.getId()).setUsername(userDO.getUsername()));
}
/**
* 获得指定用户编号的用户
*
* @param id 用户编号
* @return 用户
*/
@GetMapping("/get")
public Mono<UserVO> get(@RequestParam("id") Integer id) {
// 返回
return userRepository.findById(id)
.map(userDO -> new UserVO().setId(userDO.getId()).setUsername(userDO.getUsername()));
}
/**
* 添加用户
*
* @param addDTO 添加用户信息 DTO
* @return 添加成功的用户编号
*/
@PostMapping("add")
// @Transactional
public Mono<Integer> add(UserAddDTO addDTO) {
// 查询用户
Mono<UserDO> user = userRepository.findByUsername(addDTO.getUsername());
// 执行插入
return user.defaultIfEmpty(USER_NULL) // 设置 USER_NULL 作为 null 的情况,否则 flatMap 不会往下走
.flatMap(new Function<UserDO, Mono<Integer>>() {
@Override
public Mono<Integer> apply(UserDO userDO) {
if (userDO != USER_NULL) {
// 返回 -1 表示插入失败。
// 实际上,一般是抛出 ServiceException 异常。因为这个示例项目里暂时没做全局异常的定义,所以暂时返回 -1 啦
return Mono.just(-1);
}
// 将 addDTO 转成 UserDO
userDO = new UserDO()
.setUsername(addDTO.getUsername())
.setPassword(addDTO.getPassword())
.setCreateTime(new Date());
// 插入数据库
return userRepository.save(userDO).map(UserDO::getId);
}
});
}
/**
* 更新指定用户编号的用户
*
* @param updateDTO 更新用户信息 DTO
* @return 是否修改成功
*/
@PostMapping("/update")
public Mono<Boolean> update(UserUpdateDTO updateDTO) {
// 查询用户
Mono<UserDO> user = userRepository.findById(updateDTO.getId());
// 执行更新
return user.defaultIfEmpty(USER_NULL) // 设置 USER_NULL 作为 null 的情况,否则 flatMap 不会往下走
.flatMap(new Function<UserDO, Mono<Boolean>>() {
@Override
public Mono<Boolean> apply(UserDO userDO) {
// 如果不存在该用户,则直接返回 false 失败
if (userDO == USER_NULL) {
return Mono.just(false);
}
// 查询用户是否存在
return userRepository.findByUsername(updateDTO.getUsername())
.defaultIfEmpty(USER_NULL) // 设置 USER_NULL 作为 null 的情况,否则 flatMap 不会往下走
.flatMap(new Function<UserDO, Mono<? extends Boolean>>() {
@Override
public Mono<? extends Boolean> apply(UserDO usernameUserDO) {
// 如果用户名已经使用(该用户名对应的 id 不是自己,说明就已经被使用了)
if (usernameUserDO != USER_NULL && !Objects.equals(updateDTO.getId(), usernameUserDO.getId())) {
return Mono.just(false);
}
// 执行更新
userDO.setUsername(updateDTO.getUsername());
userDO.setPassword(updateDTO.getPassword());
return userRepository.save(userDO).map(userDO -> true); // 返回 true 成功
}
});
}
});
}
/**
* 删除指定用户编号的用户
*
* @param id 用户编号
* @return 是否删除成功
*/
@PostMapping("/delete") // URL 修改成 /delete RequestMethod 改成 DELETE
public Mono<Boolean> delete(@RequestParam("id") Integer id) {
// 查询用户
Mono<UserDO> user = userRepository.findById(id);
// 执行删除。这里仅仅是示例,项目中不要物理删除,而是标记删除
return user.defaultIfEmpty(USER_NULL) // 设置 USER_NULL 作为 null 的情况,否则 flatMap 不会往下走
.flatMap(new Function<UserDO, Mono<Boolean>>() {
@Override
public Mono<Boolean> apply(UserDO userDO) {
// 如果不存在该用户,则直接返回 false 失败
if (userDO == USER_NULL) {
return Mono.just(false);
}
// 执行删除
return userRepository.deleteById(id).map(aVoid -> true); // 返回 true 成功
}
});
}
}

View File

@@ -0,0 +1,13 @@
package cn.iocoder.springboot.lab27.springwebflux.dao;
import cn.iocoder.springboot.lab27.springwebflux.dataobject.UserDO;
import org.springframework.data.r2dbc.repository.query.Query;
import org.springframework.data.repository.reactive.ReactiveCrudRepository;
import reactor.core.publisher.Mono;
public interface UserRepository extends ReactiveCrudRepository<UserDO, Integer> {
@Query("SELECT id FROM users u WHERE u.username = :username")
Mono<UserDO> findByUsername(String username);
}

View File

@@ -0,0 +1,75 @@
package cn.iocoder.springboot.lab27.springwebflux.dataobject;
import org.springframework.data.annotation.Id;
import org.springframework.data.relational.core.mapping.Table;
import java.util.Date;
/**
* 用户 DO
*/
@Table(value = "users")
public class UserDO {
@Id
private Integer id;
/**
* 账号
*/
private String username;
/**
* 密码
*/
private String password;
/**
* 创建时间
*/
private Date createTime;
public Integer getId() {
return id;
}
public UserDO setId(Integer id) {
this.id = id;
return this;
}
public String getUsername() {
return username;
}
public UserDO setUsername(String username) {
this.username = username;
return this;
}
public String getPassword() {
return password;
}
public UserDO setPassword(String password) {
this.password = password;
return this;
}
public Date getCreateTime() {
return createTime;
}
public UserDO setCreateTime(Date createTime) {
this.createTime = createTime;
return this;
}
@Override
public String toString() {
return "UserDO{" +
"id=" + id +
", username='" + username + '\'' +
", password='" + password + '\'' +
", createTime=" + createTime +
'}';
}
}

View File

@@ -0,0 +1,35 @@
package cn.iocoder.springboot.lab27.springwebflux.dto;
/**
* 用户添加 DTO
*/
public class UserAddDTO {
/**
* 账号
*/
private String username;
/**
* 密码
*/
private String password;
public String getUsername() {
return username;
}
public UserAddDTO setUsername(String username) {
this.username = username;
return this;
}
public String getPassword() {
return password;
}
public UserAddDTO setPassword(String password) {
this.password = password;
return this;
}
}

View File

@@ -0,0 +1,45 @@
package cn.iocoder.springboot.lab27.springwebflux.dto;
public class UserUpdateDTO {
/**
* 编号
*/
private Integer id;
/**
* 账号
*/
private String username;
/**
* 密码
*/
private String password;
public Integer getId() {
return id;
}
public UserUpdateDTO setId(Integer id) {
this.id = id;
return this;
}
public String getUsername() {
return username;
}
public UserUpdateDTO setUsername(String username) {
this.username = username;
return this;
}
public String getPassword() {
return password;
}
public UserUpdateDTO setPassword(String password) {
this.password = password;
return this;
}
}

View File

@@ -0,0 +1,35 @@
package cn.iocoder.springboot.lab27.springwebflux.vo;
/**
* 用户 VO
*/
public class UserVO {
/**
* 编号
*/
private Integer id;
/**
* 账号
*/
private String username;
public Integer getId() {
return id;
}
public UserVO setId(Integer id) {
this.id = id;
return this;
}
public String getUsername() {
return username;
}
public UserVO setUsername(String username) {
this.username = username;
return this;
}
}

View File

@@ -0,0 +1,10 @@
spring:
jasync:
r2dbc:
host: 47.112.193.81
port: 3306
database: lab-27-webflux-r2dbc
username: lab-27-webflux-r2dbc
password: 0ed86@11-r2Dbc123

View File

@@ -0,0 +1,10 @@
spring:
jasync:
r2dbc:
host: 47.112.193.81
port: 3306
database: lab-27-webflux-r2dbc
username: lab-27-webflux-r2dbc
password: 0ed86@11-r2Dbc123

View File

@@ -18,7 +18,7 @@
<module>lab-27-webflux-mongodb</module>
<module>lab-27-webflux-redis</module>
<module>lab-27-webflux-elasticsearch</module>
<module>lab-27-webflux-jpa</module>
<module>lab-27-webflux-r2dbc</module>
</modules>