三. JdbcTemplate
1.基本概念
Spring框架对Jdbc进行了封装形成了JdbcTemplate,使用它可以很方便的对数据库进行操作。
准备工作:首先要引入相关依赖包
<!--引入依赖-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.16</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.2.6</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.3.8</version>
</dependency>
<!--spring-tx:针对事务的一些操作-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>5.3.8</version>
</dependency>
<!--orm可用于对其他各种框架进行整合-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>5.3.8</version>
</dependency>
其次要对数据库进行操作,自然需要数据库连接池,因此需要配置连接池
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
">
<!--配置连接池-->
<context:property-placeholder location="classpath:jdbc.properties"/>
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="${prop.driverClassName}"></property>
<property name="url" value="${prop.url}"></property>
<property name="username" value="${prop.username}"></property>
<property name="password" value="${prop.password}"></property>
</bean>
</beans>
<!--jdbc.properties-->
prop.driverClassName=com.mysql.cj.jdbc.Driver
prop.url=jdbc:mysql:///user_db
prop.username=root
prop.password=root
配置JdbcTemplate对象,注入DataSource
jdbcTemplate是对jdbc的一个封装,在spring中使用jdbcTemplate需要创建jdbcTemplate的对象,查看JdbcTemplate的底层源码,有三个构造器,两个有参构造器一个无参构造器,在有参构造器中需要传入DataSource对象,但是其函数体内是采用setDataSource()方法,因此实际上是采用set方法。
<!--创建jdbcTemplate对象,注入dataSource-->
<bean id="jdbcTemplate" class="com.org.springframework.jdbc.core.JdbcTemplate">
<!--注入dataSource-->
<property name="dataSource" ref="dataSource"></property>
</bean>
2.一个完整的demo逻辑
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
">
<!--开启注解扫描-->
<context:component-scan base-package="com.alibaba.springExercise1"/>
<!--配置连接池-->
<context:property-placeholder location="classpath:jdbc.properties"/>
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="${prop.driverClassName}"></property>
<property name="url" value="${prop.url}"></property>
<property name="username" value="${prop.username}"></property>
<property name="password" value="${prop.password}"></property>
</bean>
<!--创建jdbcTemplate对象,注入dataSource-->
<bean id="jdbcTemplate" class="com.org.springframework.jdbc.core.JdbcTemplate">
<!--注入dataSource-->
<property name="dataSource" ref="dataSource"></property>
</bean>
</beans>
//创建AppClient类和AppService类,在AppClient中注入AppService对象,
//AppService中注入JdbcTemplate对象,AppService中实现一个addUser方法(借助JdbcTemplate对数据库
//进行操作)。AppClient中调用AppService中的addUser方法完成对数据库的操作
//创建一个UserInfo类用于管理数据库中的字段。
//AppClient类
@Component
public class AppClient {
//AppClient中注入AppService对象
@Autowired
private AppService appService;
public void addUser(UserInfo userInfo){
appService.addUser(userInfo);
}
}
//AppService类
@Component
public class AppService {
//注入jdbcTemplate
@Autowired
private JdbcTemplate jdbcTemplate;
public void addUser(UserInfo userInfo) {
//jdbcTemplate.update()的方法可以实现对数据库的增加和修改操作
//参数一:SQL语句,参数二:可变参数,设置sql语句值
//table_User是数据库表的值,values是该表的字段,一个问号表示一个字段
String sqlInsert = "insert into table_User values(?,?,?)";
Object[] args = {userInfo.getUserId(), userInfo.getUserName(), userInfo.getUserStatus()};
int update = jdbcTemplate.update(sqlInsert, args);
System.out.println(update);
}
}
//UserInfo类
public class UserInfo {
private String userId;
private String userName;
private String userStatus;
public void setUserId(String userId) {
this.userId = userId;
}
public void setUserName(String userName) {
this.userName = userName;
}
public void setUserStatus(String userStatus) {
this.userStatus = userStatus;
}
public String getUserId() {
return userId;
}
public String getUserName() {
return userName;
}
public String getUserStatus() {
return userStatus;
}
}
//测试demo
@Test
public void testJdbcTemplate(){
ApplicationContext context = new ClassPathXmlApplicationContext("beanjdbc.xml");
AppClient appClient = context.getBean("appClient", AppClient.class);
UserInfo userInfo = new UserInfo();
appClient.addUser(userInfo);
}
使用JdbcTemplate对数据库进行crud操作
//修改数据库
public void updateUser(UserInfo userInfo){
String sqlUpdate = "update table_User set userName=?,userStatus=? where userId=?";
Object[] args = { userInfo.getUserName(), userInfo.getUserStatus(),userInfo.getUserId()};
int update = jdbcTemplate.update(sqlUpdate, args);
System.out.println(update);
}
//根据id删除对象
public void deleteUser(String userId){
String sqlDelete = "delete from table_user where userId=?";
Object[] args = {userId};
int delete = jdbcTemplate.update(sqlDelete, args);
System.out.println(delete);
}
//查询表里面有多少条记录,返回是某个值
public int findCount(){
String sqlSelect = "select count(*) from table_user";
//queryForObject:参数一是sql语句,参数二是返回值类型
Integer count = jdbcTemplate.queryForObject(sqlSelect, Integer.class);
return count;
}
//查询返回对象
public UserInfo findObject(String id){
String sqlObject = "select * from table_user where userId=?";
Object[] args = {id};
UserInfo userInfo = jdbcTemplate.queryForObject(sqlObject, new BeanPropertyRowMapper<UserInfo>(UserInfo.class), args);
return userInfo;
}
//查询返回集合
public List<UserInfo> findAll(){
String sqlObject = "select * from table_user";
List<UserInfo> query = jdbcTemplate.query(sqlObject, new BeanPropertyRowMapper<UserInfo>(UserInfo.class));
return query;
}
使用JdbcTemplate实现批量操作
//批量添加
public void batchAdd(List<Object[]> args){
String sqlBatchAdd = "insert into table_User value(?,?,?)";
int[] ints = jdbcTemplate.batchUpdate(sqlBatchAdd, args);
System.out.println(Arrays.toString(ints));
}
public void batchUpdate(List<Object[]> args){
String sqlBatchupdate = "update table_User set userName=?,userStatus=? where userId=?";
int[] ints = jdbcTemplate.batchUpdate(sqlBatchupdate, args);
System.out.println(Arrays.toString(ints));
// Test
// List<Object[]> batchArgs = new ArrayList<>();
// Object[] o1 = {};
// Object[] o2 = {};
// batchArgs.add(o1);
// batchArgs.add(o2);
// batchUpdate(batchArgs);
}
public void batchDelete(List<Object[]> args){
String sqlDelete = "delete from table_User where userId=?";
int[] delete = jdbcTemplate.batchUpdate(sqlDelete,args);
System.out.println(delete);
}
四. 事务
1. 基本概念
事务是数据库操作的最基本单元,逻辑上是一组操作,要么都成功,如果有一个失败那么所有操作都失败。典型场景:银行转账。A给B转100,只有A少100 B才会多100。如果A少100的时候出现了问题,那么整个过程就会失败。
事务的四个基本特性(ACID)
(1)原子性:整个过程不可分割,要么都成功要么就失败。
(2)一致性:操作前后的总量不变
(3)隔离性:多事务操作时不会产生影响
(4)持久性:事务最终是要进行提交的,提交之后表中数据真正发生变化。
2. Spring中搭建事务操作环境
以银行转账为例,把整个project分为三层,web层、service层、DAO层,其中service层主要进行业务逻辑代码的编写,DAO层进行数据库操作的相关内容。
流程如下:
- 创建数据库表,添加记录; 2. 创建service,搭建dao,完成对象创建和属性注入。(service中注入dao,dao中注入jdbcTemplate,jdbcTemplate中注入datasource)参考上面jdbcTemplate的内容中的demo即可,只需要替换一下业务逻辑代码和对数据库的操作代码即可,整体的代码框架是一摸一样的,不赘述。
按照上述逻辑操作,如果不出现异常那么事务是会正常进行的,倘若出现异常,比如A转钱之后突然网络瘫痪或断电,那么此时B并没有收到钱,所以事务就失败。因此需要事务场景引入。Spring进行事务管理操作,有两种方式:编程式事务管理和声明式事务管理。 编程式事务管理一般就是按照以下的代码逻辑写每个事务,比较繁琐:
try{
//Step1: 开启事务操作
//Step2:执行业务操作
dao.addMoney();
dao.conductMoney();
//Step3:没有发生异常时则提交事务
}catch (Exception e){
//Step4:发生异常时则事务回滚
}
一般使用声明式事务管理(基于注解方式/基于xml配置文件方式),底层使用的是AOP原理。
3. Spring声明式事务管理
Spring事务管理API:提供了一个接口,代表事务管理器,该接口针对不同框架都有其实现类。
在代码中支持不同框架对应的相同功能的代码格式:在代码中支持不同框架对应的相同功能,可以先在本代码中声明一个顶层接口(在顶层接口下可以有一些子接口),然后定义实现该接口的实现父类,在该父类下针对不同框架的相同功能进行编写。比如Spring框架下支持操作数据库的不同框架,则创建一个顶层接口,在该顶层接口下有一些实现类,分别针对jdbc、mybatis等框架做一些api管理即可。
#### 3.1 基于注解的声明式事务管理 > 在Spring配置文件中配置事务管理器;在Spring配置文件中开启事务注解@Transactional(首先引入名称空间tx,开启事务注解);在service类上或service类的方法上添加事务注解。
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
">
<!--开启注解扫描-->
<context:component-scan base-package="com.alibaba.*"/>
<!--配置连接池-->
<context:property-placeholder location="classpath:jdbc.properties"/>
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="${prop.driverClassName}"></property>
<property name="url" value="${prop.url}"></property>
<property name="username" value="${prop.username}"></property>
<property name="password" value="${prop.password}"></property>
</bean>
<!--创建jdbcTemplate对象,注入dataSource-->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<!--注入dataSource-->
<property name="dataSource" ref="dataSource"></property>
</bean>
<!--创建事务管理器-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!--注入数据源-->
<property name="dataSource" ref="dataSource"></property>
</bean>
<!--利用名称空间tx开启事务注解-->
<tx:annotation-driven transaction-manager="transactionManager"></tx:annotation-driven>
</beans>
//DAO.java
@Component
public class DAO {
@Autowired
private JdbcTemplate jdbcTemplate;
public void addMoney() {
String sqlAdd = "update table_user set money=money+? where user_name=? ";
Object[] args={100,"marry"};
int update = jdbcTemplate.update(sqlAdd, args);
System.out.println(update);
}
public void conductMoney() {
String sqlConduct = "update table_user set money=money-? where user_name=? ";
Object[] args={100,"lucy"};
int update = jdbcTemplate.update(sqlConduct, args);
System.out.println(update);
}
}
//Service.java
@Component
@Transactional
public class Service {
@Autowired
private DAO dao;
public void countMoney(){
dao.conductMoney();
int i = 7/0;//即使这里发生异常,转账人的账户余额不会变
dao.addMoney();
// try{
// //Step1: 开启事务操作
// //Step2:执行业务操作
// dao.addMoney();
// dao.conductMoney();
// //Step3:没有发生异常时则提交事务
// }catch (Exception e){
// //Step4:发生异常时则事务回滚
// }
}
}
//Test
@Test
public void testJdbcTemplate(){
ApplicationContext context = new ClassPathXmlApplicationContext("beanjdbc.xml");
Service service = context.getBean("service", Service.class);
service.countMoney();
}
完全注解的方式
@Configuration
@ComponentScan(basePackages = "com.alibaba.springAffairs")
@EnableTransactionManagement
public class AffairsConfig {
//创建数据库连接池
@Bean
public DruidDataSource getDruidDataSource(){
DruidDataSource dataSource = new DruidDataSource();
dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
dataSource.setUrl("jdbc:mysql:///user_db");
dataSource.setUsername("root");
dataSource.setPassword("root");
return dataSource;
}
//创建JdbcTemplate对象
@Bean
public JdbcTemplate getJdbcTemplate(DataSource dataSource){
//到ioc容器中根据类型找到datasource
JdbcTemplate jdbcTemplate = new JdbcTemplate();
jdbcTemplate.setDataSource(dataSource);
return jdbcTemplate;
}
//创建事务管理器对象
@Bean
public DataSourceTransactionManager getDataSourceTransactionManager(DataSource dataSource){
DataSourceTransactionManager dataSourceTransactionManager = new DataSourceTransactionManager();
dataSourceTransactionManager.setDataSource(dataSource);
return dataSourceTransactionManager;
}
}
3.2 @Transactional事务注解的一些配置
propagation:事务传播行为
事务方法:对数据库表数据进行变化的操作的方法就叫事务方法。
事务传播行为指的是一个事务方法调用另一个事务方法,这一过程叫做事务传播行为。
Spring框架提供了7种事务传播行为:REQUIRES,REQUIRES_NEW,…有需要进一步查看即可
isolation:事务隔离级别
事务有一个隔离性的特性,多事务操作之间才不会产生影响,如果不考虑隔离性会产生很多问题。
有三个读的问题:脏读、不可重复读、虚读
脏读(一个比较严重的问题):一个未提交事务读取到另一个未提交事务的数据
比如现在数据表中有一条记录,“id=1,money=500”,现在有两个人同时去操作这一条记录。小明开启事务A去操作这个记录,要把这个money从500变到100,而此时小红开启事务B也要去操作这个记录,要把这个money从500变为5000,假设现在小红将其先变为了5000,而此时小明恰好去读这个数据,因此小明读到的是5000,但是由于小红目前还处于事务中并未提交事务,又进行了事务回滚,因此此时这条记录中的money变为了500,但是小明读到的是5000。
不可重复读:一个未提交事务读取到另一个提交事务已经修改后的数据
虚读:一个未提交事务读渠道另一个已提交事务添加数据。
timeout:超时时间
事务在一定时间内要进行提交,如果不提交就进行回滚。
默认值是-1,设置时间以秒为单位进行计算。
readOnly:是否只读
读:查询操作 写:修改添加删除
默认是false
rollbackFor:回滚
设置出现哪些异常进行事务回滚
noRollbackFor:不回滚
设置出现哪些异常不进行事务回滚
3.3 基于xml的声明式事务管理
<!--创建事务管理器-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!--注入数据源-->
<property name="dataSource" ref="dataSource"></property>
</bean>
<!--利用名称空间tx开启事务注解-->
<tx:annotation-driven transaction-manager="transactionManager"></tx:annotation-driven>
<!--配置通知-->
<tx:advice id="txadvice" >
<!--配置事务参数-->
<!--countMoney要创建事务的方法名-->
<tx:attributes>
<tx:method name="countMoney" propagation="REQUIRED"/>
</tx:attributes>
</tx:advice>
<!--配置切入点和切面-->
<aop:config>
<aop:pointcut id="servicepointcut" expression="execution(* com.alibaba.springAffairs.layerService.Service.*(..))"/>
<aop:advisor advice-ref="txadvice" pointcut-ref="servicepointcut"></aop:advisor>
</aop:config>
## 五. Spring5的新特性 ### 1. 通用的日志封装Log4j2
- 整个Spring5框架的代码基于Java8实现,运行时兼容JDK9,把jdk中不建议使用的类和方法已经删除。
- Spring5.0框架自带了通用的日志封装。
Spring5中已经移除Log4jConfigListener,官方建议使用Log4j2;Spring5框架整合Log4j2
定义一个log4j2.xml(名称不可变)
<?xml version="1.0" encoding="UTF-8"?>
<!-- 日志级别以及优先级排序:OFF>FATAL>ERROR>WARN>INFO>DEBUG>TRACE>ALL 从左到右优先级逐渐升高-->
<!-- Configuration后面的status用于设置log4j2自身内部的信息输出,可以不设置 -->
<configuration status="INFO">
<!--先定义所有的appenders-->
<appenders>
<!--输出日志信息到控制台-->
<console name="Console" target="SYSTEM_OUT">
<!--控制日志输出格式-->
<PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"> </PatternLayout>
</console>
</appenders>
<!--然后定义logger,只有定义了logger并引入appender的,appender才会生效-->
<!--root:用于指定项目的根日志,如果没有单独指定logger,则会使用root作为默认的日志输出-->
<loggers>
<root level="info">
<appender-ref ref="Console"/>
</root>
</loggers>
</configuration>
导入log4j2依赖包
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>2.11.2</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.11.2</version>
</dependency>
2. 支持@Nullable注解
可以作用在方法、属性、参数上,表示方法返回为空,属性可以为空,参数可以为空。
3. 支持函数式风格GenericApplicationContext
Spring中引入bean管理对对象进行管理,要在spring中使用对象自然需要在spring中注册对象,之前我们可以通过注解的方式来在spring中注册对象。spring5中支持函数式风格创建对象,从而交给spring进行管理。
public void test(){
GenericApplicationContext context = new GenericApplicationContext();
context.refresh();
context.registerBean(DAO.class,()->new DAO());
Object bean = context.getBean("com.alibaba.springAffairs.DAO");
}
4. 支持整合JUnit5
<!--test单元测试-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.3.8</version>
</dependency>
@RunWith(SpringJUnit4ClassRunner.class) //配置单元测试框架
@ContextConfiguration("classpath:beanjdbc.xml")//加载配置文件
//@SpringJUnitConfig(locations = "classpath:beanjdbc.xml") //使用一个复合注解代替上面两个注解
public class TestJunit {
@Autowired
private Service service; //注入属性
@Test
public void test(){
service.countMoney();
}
}
//之前需要这么写
@Test
public void testJdbcTemplate(){
ApplicationContext context = new ClassPathXmlApplicationContext("beanjdbc.xml");
Service service = context.getBean("service", Service.class);
service.countMoney();
}
5. Spring5框架新功能Webflux
1⃣️SpringWebflux是Spring5中添加的新的模块,用于web开发,功能与SpringMVC类似,Webflux使用当前一种比较流行的响应式编程出现的框架。
2⃣️web框架比如SpringMVC,这些都是基于Servlet容器,Webflux是一种异步非阻塞框架,异步非阻塞框架在Servlet3.1以后才支持,核心是基于Reactor的相关API实现的。
3⃣️异步非阻塞:同步和异步针对的是调用者,调用者发送请求如果等着对方回应之后才去做其他事情就是同步,如果发送请求之后不用等着对方回应就去做其他事情就是异步。阻塞和非阻塞针对的是被调用者,被调用者收到请求之后,做完请求任务之后才做出反馈就是阻塞,如果收到请求之后马上给出反馈然后再去做任务就是非阻塞。
4⃣️Webflux特点:第一非阻塞式,在有限资源下,提高系统吞吐量和伸缩性,以Reactor为基础实现响应式编程;第二函数式编程,Spring5框架基于java8,Webflux使用java8函数式编程方式实现路由请求。
Webflux响应式编程
所谓的响应式编程是面向数据流和变化传播的编程范式。电子表格就是其中一个典型例子,比如在excel中的列末端计算这一列的数字总和,当这一列的其中某个数字发生变化时,其sum值也会发生变化,这就是响应式编程的例子。Java8提供了观察者模式的两个类Observer和Observable。
Reactor实现响应式编程
- 响应式编程操作中都要满足Reactive规范框架,Reactor是满足Reactive规范的框架;Reactor(响应式标准流)有两个核心类,Mono和Flux,这两个类都实现了Publisher接口。Flux对象可以实现发布者,返回N个元素;Mono也可以实现发布者,返回0或1个元素。
- Flux和Mono都是数据流的发布者,使用Flux和Mono都可以发出三种数据信号:元素值,错误信号和完成信号,错误信号与完成信号都代表终止信号,终止信号用于告诉订阅者数据流结束了,错误信号终止数据流同时把错误信息传递给订阅者。
<dependency>
<groupId>io.projectreactor</groupId>
<artifactId>reactor-core</artifactId>
<version>3.1.5.RELEASE</version>
</dependency>
//举例
public static void main(String[] args) {
Flux<Integer> just = Flux.just(1, 12, 23, 2);
System.out.println("testea");
just.subscribe(System.out::println);
}
错误信号和完成信号都是终止信号,但是二者不能共存。如果没有发送任何元素值,而是直接发送错误信号或完成信号,表示是空数据流。如果没有错误信号,没有完成信号,表示是无限数据流。
操作符的概念:对数据流进行一道道操作,成为操作符,比如工厂流水线。常见的两种:map:把元素映射为新元素,flatMap是把元素映射为流。
SpringWebflux执行流程和核心API
SpringWebflux是基于Reactor,默认容器是Netty,Netty是高性能,NIO框架(是一个异步非阻塞框架)。
SpringWebflux中的DispatcherHandler负责请求的处理,实现函数式编程的两个接口:RouterFunction和HandlerFunction。
基于注解编程方式的Webflux的使用
添加相关依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
在application.properties中添加server.port
server.port=8081
//Entity类
public class Entity {
private String name;
private String gender;
public Entity(String name,String gender){
this.name = name;
this.gender=gender;
}
public String getGender() {
return gender;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public void setGender(String gender) {
this.gender = gender;
}
}
//ServiceClass类对Entity进行操作
@Repository
public class ServiceClass {
//创建map集合存储数据(当然数据来源也可以是数据库,这里仅仅是为了方便展示流程)
private final Map<Integer,Entity> entities = new HashMap<>();
public ServiceClass(){
this.entities.put(1,new Entity("lucy","woman"));
this.entities.put(2,new Entity("tom","man"));
}
public Mono<Entity> getUserById(int id){
return Mono.just(this.entities.get(1));
}
public Flux<Entity> getAllUser(){
return Flux.fromIterable(this.entities.values());
}
public Mono<Void> saveUserInfo(Mono<Entity> entity ){
//person的含义:把Mono流中的对象转换为一个实体对象,然后在map中放入
return entity.doOnNext(person ->{
//向map集合放值
int id = entities.size()+1;
entities.put(id,person);
}).thenEmpty(Mono.empty());//thenEmpty(Mono.empty())表示的实际上是一个终止信号
}
}
//ControllerClass类
@RestController
public class ControllerClass {
//注入service
@Autowired
private ServiceClass serviceClass;
@GetMapping("/user/{id}")
public Mono<Entity> getUserById(@PathVariable int id)
{
return serviceClass.getUserById(id);
}
@GetMapping("/user")
public Flux<Entity> getUsers(){
return serviceClass.getAllUser();
}
@PostMapping("/saveuser")
public Mono<Void> saveUser(@RequestBody Entity entity){
return serviceClass.saveUserInfo(Mono.just(entity));
}
}
//test
@SpringBootApplication
public class TestWebFlux {
public static void main(String[] args) {
SpringApplication.run(TestWebFlux.class,args);
}
}