Spring5框架学习记录

Spring5框架学习记录

一、Spring概念

  1. Spring是一个轻量级的开源的JavaEE框架。
  2. Spring可以解决企业应用开发的复杂性。
  3. Spring有两个核心部分:IOC和AOP
    1. IOC:控制反转,把创建对象过程交给Spring进行管理。
    2. Aop:面向切面,不修改源代码进行功能增强。
  4. spring特点:
    1. 方便解耦,简化开发。
    2. Aop编程支持。
    3. 方便程序测试。
    4. 方便和其他框架进行整合。
    5. 方便进行事务操作。
    6. 降低API开发难度。

二、IOC容器

IOC概念和原理

概念
  1. 控制反转:把对象创建和对象之间的调用的过程交给Spring进行管理,使用IOC的目的是为了降低耦合度。
原理
  1. xml解析、工厂模式,反射
第一步,xml配置文件,配置创建对象
<bean id="dao" class="com.it.dao.UserDao"></bean>
第二步 有service类和dao类,创建工场类
class UserFactory{
 public static UserDao getDao(){
 String classValue = class属性值;// xml解析
 Class clazz = Class.forName(classValue);// 2 通过反射创建对象
 return (UserDao)clazz.newInstance();
 }
}
  1. IOC接口

    1. IOC思想基于IOC容器完成,IOC容器底层就是对象工场。

    2. Sping提供IOC容器实现两种方式(两个接口):

      一、BeanFactory:IOC容器基本实现,是Spring内部的使用接口,不提供开发人员使用。(注意:加载配置文件时候不会创建对象,在获取/使用对象时才会区创建对象。)

      二、ApplicationContext:BeanFactroy接口的子接口,提供更多更强大的功能,一般由开发人员进行使用。(注意:加载配置文件时就会把在配置文件里面的对象进行创建)

    3. ApplicationContext常用实现类:

      1. FileSystemXmlApplicationContext(指定文件实际路径)
      2. ClassPathXmlApplicationContext(指定相对的src目录下路径)

Bean容器管理

什么时Bean管理

​ Bean管理的两个操作:

	1. Spring创建对象。
		2. Spring注入属性。

​ Bean管理操作两种方式

  1. 基于xml配置文件方式实现。

    一、基于xml的对象注入
      <!--配置User对象创建-->
        <bean id="user" class="com.company.spring5.User"></bean>
      (1) 在spring配置文件中,使用bean标签,标签里面添加对应属性。就可以实现对象创建。
      (2) 在bean标签由很多属性。常用属性有。
       1. id属性:唯一标识。
       2. class属性:类全路径(包路径)
      (3) 创建对象默认执行无参构造方法。 
    二、  基于xml的属性注入
      (1) DI:依赖注入,就是属性注入。
      	传统依赖注入:1.使用set方法进行注入。2.使用有参数构造进行注入。
      	 <bean id="book" class="com.company.spring5.entry.Book" >
            <!--在bena标签里面使用 property-->
            <property name="bname" value="hjy"></property>
            <property name="bauthor" value="ljf"/>
            <property name="user" ref="user"/>
         </bean>
    三、xml注入其他类型属性
    1. 字面量
      (1)null值。
       <--!配置null值-->
       <property name="age"><null/></property>
      (2)属性值包含特殊符号。
          <!--1.使用转义字符-->
       <!--     <property name="age" value="&lt;南京&gt;"/>-->
            <!--2.使用value标签-->
            <property name="age">
                <value><![CDATA[<南京>]]></value>
            </property>
    2. 注入属性-外部bean 
     <bean id="userService" class="com.company.spring5.service.UserService">
            <property name="userDao" ref="userDao"/>
        </bean>
        <bean id="userDao" class="com.company.spring5.dao.UserDaoImpl"/>
    3. 注入属性-内部bean和级联赋值 
    实体类表示一对多关系
     <!--内部bean-->
        <bean id="emp" class="com.company.spring5.entry.Emp">
            <property name="ename" value="11"/>
            <property name="age"value="22"/>
            <property name="dept">
                <bean id="dept" class="com.company.spring5.entry.Dept">
                    <property name="dname" value="保安"/>
                </bean>
            </property>
        </bean>
        <!--级联赋值-->
        <bean id="emp" class="com.company.spring5.entry.Emp">
            <property name="ename" value="11"/>
            <property name="age"value="22"/>
            <property name="dept" ref="dept">
            </property>
        </bean>
        <bean id="dept" class="com.company.spring5.entry.Dept">
            <property name="dname" value="保安"/>
        </bean>
     xml注入list数据
      <bean id="dept" class="com.company.spring5.entry.Dept">
            <property name="dname" value="保安"/>
            <property name="list">
                <list>
                    <value></value>
                    <value></value>
                    <value></value>
                </list>
            </property>
        </bean>
     xml注入数组数据 
      <bean id="dept" class="com.company.spring5.entry.Dept">
            <property name="dname" value="保安"/>
            <property name="list">
                <array>
                    <value></value>
                    <value></value>
                    <value></value>
                </array>
            </property>
        </bean>
      xml注入map数据
       <bean id="dept" class="com.company.spring5.entry.Dept">
            <property name="dname" value="保安"/>
            <property name="list">
                <map>
                   <entry key="" value=""></entry>
                   <entry key="" value=""></entry>
                </map>
            </property>
        </bean>    
    

    FactroyBean

    Spring有两种bean,一种普通bean,另外一种工厂bean(FactoryBean)

    普通bean:在配置文件中定义的bean类型就是返回类型。

    工厂bean:在配置文件定义bean类型可以和返回类型不一样。

    Spring的作用域:单实例,多实例。

    spring在默认情况下为单实例对象。

    在spring配置文件bean标签里面有属性(scope)用于设置单实例还是多实例对象
    scope属性值:
    1. 默认值,singleton 单实例
    2. prototype 多实例
    3. request 为每一个请求创建一个实例。
    4. session 为每一个会话创建一个实例。
    singleton和prototype区别
    1. singleton为单实例,prototype为多实例。
    2. singleton在加载配置文件时就会创建单实例对象。而prototype只有在调用getBean方法时才会创建实例,每次创建实例不同。
    
    

    bean的生命周期

    概念:从对象创建到对象销毁的过程。

    bean生命周期
    1. 通过构造器创建bean实例。(无参数构造器)
    2. 为bean的属性设置值和对其他bean引用(设置set方法)
    3. 调用bean的初始化的方法(需要进行配置初始化的方法)
    4. bean可以使用了(对象获取到了)
    5. 当容器关闭时候,调用bean的销毁的方法(需要进行配置销毁的方法)
    

    xml自动装配

    <!--
    bean标签属性autowire配置自动装配
    autowire属性常用两个值:
    byName根据属性名称注入,注入值bean的id1
    byType根据属性类型注入
    -->
    

    xml外部装配

    通过导入context标签,实现读写.properties文件里面的配置信息。

  2. 基于注解方式实现。

    <!--开启组件扫瞄-->
    <context:component-scan base-package="com.company.spring5"/>
     <!--
        use-default-filters="false" 表示现在不使用默认filter,自己配置filter
        // 设置扫描哪些内容
         <context:include-filter type="annotation" expression="com.company.spring5.entry.Book"/>
         // 设置不扫描哪些内容
         <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Service"/>
    -->
    Spring针对Bean管理中创建对象提供注解
    @Component、@Service、@Controller、@Repository(四个注解功能一致)
    基于注解方式实现属性注入
    @Autowired(根据属性类型进行自动装配)、@Qualifier(根据属性名称进行注入)、@Resource(可以根据类型注入,也可以根据名称注入)、@Value(注入普通类型属性)
    通过注解替代xml文件
    @ComponentScan(组件扫描注解)
    

三、AOP

含义:面向切面,不修改远点进行功能增强。

什么是AOP

  1. 面向切面编程,利用AOP可以对业务逻辑的各个不发进行隔离,从而使业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高开发效率。

AOP底层原理

  1. AOP底层使用动态代理。

    第一种 有接口情况,使用JDK动态代理

    ​ 创建借口实现类代理对象。

    第二种 没有接口的情况,使用CGLIB动态代理

    ​ 创建当前类子类的代理对象。

AOP(JDK动态代理)

  1. 使用jdk动态代理,使用Proxy类里面的方法创建代理对象。

    1. 调用newProxyInstance方法

      方法有三个参数:

      ​ 第一个参数,类加载器。

      ​ 第二个参数,增强方法所在类,这类实习的接口,支持多个接口。

      ​ 第三个参数,实习这个接口InvocationHandler,创建代理对象,写增强方法。

    2. AOP术语

      1. 连接点 (所有可增强的方法都可以称为连接点)
      2. 切入点 (实际被增强的方法被称为切入点)
      3. 通知(增强) (实际增强的逻辑就被称之为通知,通知有5种通知,前置通知,后置通知,环绕通知,异常通知,异常通知,最终通知)
      4. 切面 (是一个动作,将通知应用到切入点的操作就叫做切面) 
      

AOP操作

  1. Spring框架一般都是基于AspectJ实现AOP操作

    (注意:AspectJ不是Spring组成部分,独立AOP框架,一般把AspectJ和Spring框架一起使用,进行AOP操作。)

  2. 基于AspectJ实现AOP操作

    (一)、基于xml配置文件实现。

    (二)、基于注解方式实现(主要使用方式)

  3. 切入点表达式

    一、 切入点表达式作用:知道对哪个类里面的哪个方法进行增强

    二、语法结构:execution([权限修饰符] [返回类型] [类全路径] [方法名称] ([参数列表]))

四、JdbcTemplate

五、事务管理

什么是事务

  1. 事务是数据库操作最基本单元,逻辑上一组操作,要么都成功,如果有一个失败则全失败。

事务的四大特性

  1. 原子性。
  2. 一致性。
  3. 隔离性。
  4. 持久性。

事务操作

在spring进行事务管理的两种方式
  1. 编程式事务管理。
  2. 声明式事务管理。
    1. 基于注解方式
    2. 基于xml配置文件方式

在spring进行声明式事务管理,底层原理使用AOP原理。

声明式事务管理参数配置
1. 在service类上添加注解@Transactional,在这个注解里面可以配置事务相关参数。
propagetion:事务传播行为
 1. PROPAGATION_REQUIRED 表示当前方法必须在一个具有事务的 上下文中运行,如有客户端有事务在进行,那么被调用端将在该事务中运行,否则的话重新     开启一个事务。( 如果被调用端发生异常,那么调用端和被调用端事务都将回滚)
 2. PROPAGATION_SUPPORTS 表示当前方法不必需要具有一个事务 上下文,但是如果有一个事务的话,它也可以在这个事务中运行
 3. PROPAGATION_MANDATORY 表示当前方法必须在一个事务中运行,如果没有事务,将抛出异常
 4. PROPAGATION_REQUIRES_NEW 总是开启一个新的事务。如果一个事务已经存在,则将这个存在的事务挂起。
 5. PROPAGATION_NOT_SUPPORTED 总是非事务地执行,并挂起任何存在的事务。
 6. PROPAGATION_NEVER 总是非事务地执行,如果存在一个活动事务,则抛出异常
 7. PROPAGATION_NESTED表示如果当前方法正有一个事务在运行中,则该方法应该运行在一个嵌套事务中 ,被嵌套的事务可以独立于被封装的事务中进行提交或     者回滚。如果封装事务存在,并且外层事务抛出异常回滚,那么内层事务必须回滚,反之,内层事务并不影响外层事务。如果封装事务不存在,
    则propagation. required的一样
ioslation:事务隔离级别
          ISOLATION_READ_UNCOMMITTED:读未提交
          ISOLATION_READ_COMMITTED:读已提交
          ISOLATION_REPEATABLE_READ:可重复读 
          ISOLATION_SERIALIZABLE:串行化
timeout:超时时间
 1. 事务需要在一定时间内进行提交,如果不提交进行回滚。
 2. 默认值是-1,设置时间以秒单位进行计算。
readOnly:是否只读
 1. 读:查询操作,写:添加/修改/删除操作。
 2. readOnley默认值为false,表示可以查询也可以添加修改删除操作。
 3. 设置readOnly值是true,设置成true之后,只能查询。
rollbackFor:回滚
noRollbackFor:不回滚

六、Spring5新特性

1.@Nullable注解
Spring5框架核心容器支持@Nullable注解
  1. @Nullable注解可以使用在方法上面,属性上面,参数上面,表示方法可以为null,属性值可以为null,参数值可以为null。
2.支持候选组件索引
3.函数式风格GenericApplicationContext AnnotationConfigApplicationContext
4.基本支持beanAPI注册。
5.在接口层面使用CGLIB动态代理的时候,提供事务,缓存,异步注解检测。
6.XML配置作用域流式
7.Spring WebMVC
8.全部都Servlet3.1签名支持在Spring-provied Filter实现。
9.在Srping MVC Controller方法里支持Servlet4.0 PushBuilder参数。
10.多个不可变对象的数据绑定(Kotkin/Lombok/@ConstructorPorties)
11.支持jackson2.9
12.支持JSON绑定API
13.支持protobuf3
14.支持Reactor3.1 Flux和Mono

七、Spring5整合日志

<?xml version="1.0" encoding="UTF-8"?>
<!--日志级别以及优先级排序: OFF > FATAL > ERROR > WARN > INFO > DEBUG > TRACE > ALL -->
<!--Configuration后面的status用于设置log4j2自身内部的信息输出,可以不设置,当设置成trace时,可以看到log4j2内部各种详细输出-->
<configuration status="INFO">
    <!--先定义所有的appender-->
    <appenders>
        <!--输出日志信息到控制台-->
        <console name="Console" target="SYSTEM_OUT">
            <!--控制日志输出的格式-->
            <PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
    </console>
    </appenders>
    <!--然后定义logger,只有定义了logger并引入的appender,appender才会生效-->
    <!--root:用于指定项目的根日志,如果没有单独指定Logger,则会使用root作为默认的日志输出-->
    <loggers>
        <root level="info">
            <appender-ref ref="Console"/>
        </root>
    </loggers>
</configuration>

八、Spring中Webflux

1. SpringWebflux介绍

(1)是Spring5添加新的模块,用于web开发的,功能和SpringMVC类似的,Webflux使用当前一种比较流程响应式编程出现的框架。

(2)使用传统web框架,比如SpringMVC,这些基于Servlet容器,Webflux是一种异步非阻塞的框架,异步非阻塞的框架在Servlet3.1以后才支持,核心是基于Reactor的相关API实现的。

​ 异步非阻塞:

​ 异步与同步。

​ 阻塞和非阻塞。

Webflux特点:

第一 非阻塞: 在有限资源下,提高系统吞吐量和伸缩性,以Reactor为基础实现响应式编程。

第二 函数式编程:Spring5框架基于JDK8,即Webflux可以体验Java8新特性。

SpringMVC和Webflux比较
  1. 两个框架都可以使用注解方式,都可以允许在tomcat等容器中。
  2. SpringMVC使用的是命令式编程,Webflux采用异步响应式编程。
  3. SpringMVC方式实现,同步阻塞的方式,基于SpringMVC+Servlet+Tomcat。SpringWebflux方式实现,异步非阻塞方式,基于SpringWebflux+Reactor+Netty。

2. 响应式编程

(1)什么是响应式编程

响应式编程是一种面向数据流和变化传播的编程范式。这意味着可以在编程语言中很方便地表达静态或动态的数据流,而相关的计算模型会自动将变化的值通过数据流进行传播。

Java8及之前版本提供的观察者模式两个类Observer和Observable。

public class ObserverDome extends Observable {
    public static void main(String[] args) {
        ObserverDome observerDome = new ObserverDome();
        // 创建观察者
        observerDome.addObserver((o,arg)->{ System.out.println("发生了变化"); });
        observerDome.addObserver((o,arg)->{ System.out.println("手动被观察者通知,准备改变"); });
        // 数据变化
        observerDome.setChanged();
        // 通知
        observerDome.notifyObservers();
    }
}

Java8之后

public class Main {

    public static void main(String[] args) {
        Flow.Publisher<String> publisher = subscriber -> {
            subscriber.onNext("1");
            subscriber.onNext("2");
            subscriber.onError(new RuntimeException("出错了!!!"));
        };

        publisher.subscribe(new Flow.Subscriber<String>() {
            @Override
            public void onSubscribe(Flow.Subscription subscription) {
                subscription.cancel();
            }

            @Override
            public void onNext(String item) {
                System.out.println(item);
            }

            @Override
            public void onError(Throwable throwable) {
                System.out.println(throwable.getMessage());
            }

            @Override
            public void onComplete() {
                System.out.println("publish complete");
            }
        });

    }
}
Reactor实现响应式编程
  1. 响应式编程操作中,Reactor是满足Reactive规范框架。

  2. Reactor有两个核心类,Mono和Flux,这两个类实现接口Publisher,提供丰富操作符。Flux对象实现发布者,返回N个元素;Mono实现翻发布者,返回0或者1个元素。

  3. Flux和Mono都是数据流的发布者,使用Flux和Mono都可以发出三种数据信号。

    元素值,错误信号,完成信号,错误信号和完成信号都代表终止信号,终止信号用于告诉订阅者数据流结束了,错误信号终止数据流同时会把错误信息传递给订阅者。

    代码演示

    public class TestReactor {
        public static void main(String[] args) {
            // just方法直接声明
            Flux.just(1,3,4,5,6);
            Mono.just(1);
            // 其他方法
            Integer[] array = {1,2,3,4};
            Flux.fromArray(array);
    
            List<Integer> list = Arrays.asList(array);
            Flux.fromIterable(list);
    
            Stream<Integer> stream = list.stream();
            Flux.fromStream(stream);
        }
    }
    

    三种信号特点:

    错误信号和完成信号都是终止信号,不能共存的,如果没有发送任何元素,而是直接发送错误或者完成,表示是一个空数据流,如果没有错误信号,没有完成信号,表示是无限数据流。

  4. 调用just或者其他方法只是声明数据流,数据流并没有发出,只有进行订阅之后才会触发数据流,不订阅什么都不会发生的。

  5. 操作符

    对数据流进行一道道操作,称为操作符,比如工厂流水线。

    第一 map 元素映射为新元素

    第二 flatMap元素映射为流

3. SpringWebflux执行流程和核心API

SpringWebflux基于Reactot,默认容器是Netty,Netty是高性能的NIO框架,异步非阻塞框架。

SpringWebflux执行过程和SpringMVC相似的。SpringWebflux核心控制器DispatchHandler,实现接口是WebHandler。

代码原理:

在WebHandler类中有一个handle方法返回值是Mono<void> 参数为ServerWebExchange
//public interface WebHandler {
//   Mono<Void> handle(ServerWebExchange exchange);
//}


    public Mono<Void> handle(ServerWebExchange exchange) { 
    // ServerWebExchange 里面存放的是http里面的请求响应信息和相关参数
    // 通过判断this.handlerMapping 判断接口映射是否为null 为null创建一个NotFound的错误
        if (this.handlerMappings == null) {
            return this.createNotFoundError();
        } else {
        // 判断参数是否为是飞行前请求。如果为则返回相关参数,否则根据请求地址,得到mapping值,调用具体的业务方法,最后返回处理结果。
            return CorsUtils.isPreFlightRequest(exchange.getRequest()) ? this.handlePreFlight(exchange) : Flux.fromIterable(this.handlerMappings).concatMap((mapping) -> {
                return mapping.getHandler(exchange);
            }).next().switchIfEmpty(this.createNotFoundError()).flatMap((handler) -> {
                return this.invokeHandler(exchange, handler);
            }).flatMap((result) -> {
                return this.handleResult(exchange, result);
            });
        }
    }

SpringWebflux里面

  • DispatcherHandler,负责请求的处理。

  • HandlerMapping,请求查询到处理的方法。

  • HandlerAdapter,真正负责请求处理。

  • HandlerResultHandler,响应结果处理。

SpringWebflux实现函数式编程

两个接口:

  • RouterFunction(路由处理)
  • HandlerFunction(处理函数)

九、SpringWebflux实现方式

SpringWebflux实现方式有两种:注解编程模型和函数编程模型,使用注解编程模型方式,和之前的SpringMVC使用类似,只需要把相关依赖配置到项目中,Springboot自动配置相关运行容器,默认情况下使用Netty服务器。

SpringWebflux(基于注解编程模型)

controller类

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


    private UserService userService;

    @Autowired
    public void setUserService(UserService userService) {
        this.userService = userService;
    }

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

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

    @PostMapping("/add")
    public Mono<Void> saveUserInfo(@RequestBody User user){
        return userService.saveUserInfo(Mono.just(user));
    }

}

service类

public interface UserService {

    /**
     * 根据id查询用户
     * @param id 用户id
     * @return 返回值
     */
    Mono<User> getUserById(int id);

    /**
     * 查询所有用户
     * @return 返回所有用户信息
     */
    Flux<User> getAllUser();

    /**
     * 添加用户信息
     * @param user 用户信息
     */
    Mono<Void> saveUserInfo(Mono<User> user);
}

service实现类

@Service
public class UserServiceImpl implements UserService {

    // 创建一个map集合,存储数据
    private final Map<Integer, User> userMap = new HashMap<>();

    public UserServiceImpl() {
        this.userMap.put(1, new User("lucy", "男", 20));
        this.userMap.put(2, new User("mary", "女", 18));
        this.userMap.put(3, new User("tom", "女", 30));
        this.userMap.put(4, new User("jack", "男", 24));
        this.userMap.put(5, new User("hjy", "女", 16));
    }

    @Override
    public Mono<User> getUserById(int id) {
        return Mono.justOrEmpty(this.userMap.get(id));
    }

    @Override
    public Flux<User> getAllUser() {
        return Flux.fromIterable(this.userMap.values());
    }

    @Override
    public Mono<Void> saveUserInfo(Mono<User> user) {
        return user.doOnNext(person -> {
            // 向map中添加值
            int i = userMap.size() + 1;
            userMap.put(i,person);
        }).thenEmpty(Mono.empty());
    }
}

User类

public class User {

    private String name;
    private String gender;
    private Integer age;

    public User() {
    }

    public User(String name, String gender, Integer age) {
        this.name = name;
        this.gender = gender;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getGender() {
        return gender;
    }

    public void setGender(String gender) {
        this.gender = gender;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                ", gender='" + gender + '\'' +
                ", age=" + age +
                '}';
    }
}

SpringWebflux(基于函数式编程模型)

  1. 在使用函数式编程模型操作时候,需要自己初始化服务器。
  2. 基于函数式编程模型时候,有两个核心接口:RouterFunction(实现路由功能,请求转发给对应的handler)和HandlerFunction(处理请求生产响应的函数)。核心任务定义两个函数式接口的实现并且启动需要的服务器。
  3. SpringWebflux请求和响应不再是ServletRequest和ServletResponse,而是ServerRequest和ServerResponse。

实现,其中service和实体类一样

Handler类

public class UserHandler {

    private final UserService userService;
    public UserHandler(UserService userService){
        this.userService = userService;
    }

    // 根据id查询
    public Mono<ServerResponse> getUserById(ServerRequest request){
        int id = Integer.valueOf(request.pathVariable("id"));
        // null值处理
        Mono<ServerResponse> notFound = ServerResponse.notFound().build();
        // 调用service方法
        Mono<User> userMono = this.userService.getUserById(id);
        // 把userMono转换 使用Reactor操作符flatMap
        return userMono.flatMap(person -> 
                ServerResponse.ok().contentType(MediaType.APPLICATION_JSON).body(fromObject(person)))
                .switchIfEmpty(notFound);
    }
    
    public Flux<ServerResponse> getUserList(){
        Flux<User> allUser = this.userService.getAllUser();
        
        return allUser.flatMap(person ->
                ServerResponse.ok().contentType(MediaType.APPLICATION_JSON).body(fromObject(person)));
    }
    
    public Mono<ServerResponse> getAllUser(){
        Flux<User> allUser = this.userService.getAllUser();
        return ServerResponse.ok().contentType(MediaType.APPLICATION_JSON).body(allUser,User.class);
    }
    
    
    public Mono<ServerResponse> saveUser(ServerRequest request){
        // 得到user对象
        Mono<User> userMono = request.bodyToMono(User.class);
        Mono<Void> voidMono = this.userService.saveUserInfo(userMono);
        return ServerResponse.ok().build(voidMono);
    }
    

}

Server类

public class Server {

    public static void main(String[] args) throws IOException {
        Server server = new Server();
        server.createReactorServer();
        System.out.println("enter to exit");
        System.in.read();
    }

    // 1. 创建Router路由
    public RouterFunction<ServerResponse> routerFunction(){
        UserService userService = new UserServiceImpl();
        UserHandler userHandler = new UserHandler(userService);

        return RouterFunction.route(GET("/user/getId/{id}").and(accept(APPLICATION_JSON)),userHandler::getUserById)
                .andRoute(GET("/user/list").and(accept(APPLICATION_JSON)),userHandler::getAllUser)
                .andRoute(GET("/user/list1").and(accept(APPLICATION_JSON)),userHandler::getUserList);
    }

    // 创建服务器完成适配
    public void  createReactorServer(){
        // 路由和handler适配
        RouterFunction<ServerResponse> serverResponseRouterFunction = routerFunction();
        HttpHandler httpHandler = toHttpHandler(serverResponseRouterFunction);
        ReactorHttpHandlerAdapter reactorHttpHandlerAdapter = new ReactorHttpHandlerAdapter(httpHandler);
        // 创建服务器
        HttpServer httpServer = HttpServer.create();
        httpServer.handle(reactorHttpHandlerAdapter).bindNow();
    }

}

Client类

public class Client {

    public static void main(String[] args) {
        WebClient webClient = WebClient.create("http://localhost:5794");
        // 根据id查询
        User block = webClient.get().uri("/user/getId/{id}", 1).accept(MediaType.APPLICATION_JSON).retrieve().bodyToMono(User.class).block();

        System.out.println(block);

    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值