Spring5学习

1、Spring 概念

1)Spring框架概述

1、Spring是轻量级的开源的J2EE框架

2、Spring可以解决企业应用开发的复杂性

3、Spring有两个核心部分:IOC和AOP

  • IOC:控制反转,把创建对象的过程交给Spring进行管理
  • AOP:面向切面,不修改源代码进行功能增强(动态代理的实现)

4、Spring特点:

  • 方便解耦,简便开发
  • AOP编程的支持
  • 声明式的事物支持
  • 方便程序测试
  • 方便和其他框架进行整合
  • 降低API开发难度

5、构成图

在这里插入图片描述

2)Spring下载

官方下载地址
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

3)入门案例

​ 1、创建工程

​ 2、导入Spring5的jar包
在这里插入图片描述

以及commons-logging的jar包

3、创建一个普通的类

package com.daiju;

/**
 * @Author WDY
 * @Date 2020-07-07 16:22
 * @Description TODO
 */
public class User {
    public void add(){
        System.out.println("add...............");
    }
}

4、创建Spring文件,在配置文件配置创建对象

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <!--配置User对象创建-->
    <bean id="user" class="com.daiju.User"></bean>
</beans>

5、进行代码测试编写

 @Test
    public void testAdd(){

        //1、加载spring配置文件
        ApplicationContext context = new ClassPathXmlApplicationContext("application.xml");

        //2、获取配置创建对象
        User user = context.getBean("user", User.class);

        System.out.println(user);
        user.add();
        
    }

在这里插入图片描述

2、IOC容器

IOC概念

1、什么是IOC

  • 控制反转,把对象的创建和对象之间的调用过程都交给Spring进行管理
  • 目的是为了降低耦合度
  • 入门案例就是IOC的实现

1)IOC底层原理

底层技术:xml解析、工厂模式、反射

1、图解

在这里插入图片描述

2)IOC接口

1、IOC思想基于IOC容器完成,IOC容器底层就是对象工厂
2、Spring提供IOC容器实现的两种方式:(两个接口)
1)BeanFactory:IOC容器最基本实现,是Spring内部的使用接口,不提供给开发人员进行使用

BeanFactory加载配置文件时不会创建对象,在获取对象时才去创建对象

2)ApplicationContext :BeanFactory接口的子接口,提供更对更强大的功能,一般由开发人员使用

ApplicationContext加载配置文件的时候就会把在文件中配置的对象进项创建(推荐)

3)ApplicationContext接口实现类

在这里插入图片描述

3)IOC操作Bean管理(基于xml)

1、什么是Bean管理

1、Spring创建对象(默认执行无参构造方法)

2、Spring注入属性

2、Bean管理操作的两种方式

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

2、基于注解方式实现

3、IOC操作Bean管理

1、基于xml方式创建对象

 <!--配置User对象创建-->
    <bean id="user" class="com.daiju.User"></bean>

(1)在Spring配置文件中,使用bean标签,表现里面添加对应的属性,就可以实现对象的创

(2)在bean标签有很多属性,常用的属性如下:

  • id

    获取对象的唯一标识

  • class

    对象的类全路径(包类路径)

2、基于xml方式注入属性

(1)DI:依赖注入,就是注入属性

  • set方法注入

1、创建一个类

public class Book {
    //创建属性
    private String name;

    //创建属性对应的set方法
    public void setName(String name) {
        this.name = name;
    }
}

2、编写配置文件

<!--set方法注入属性-->
    <bean id="book" class="com.daiju.Book">
        <!--使用property完成属性注入-->
        <!--
            name:类里面属性的名称
            value:属性的值
        -->
        <property name="name" value="abc"></property>
    </bean>

3、测试

Book book = context.getBean("book", Book.class);
System.out.println(book);

在这里插入图片描述

  • 有参构造方法注入

1、创建一个类

public class Order {
    //创建属性
    private String name;
    private String address;

    //创建有参构造函数
    public Order(String name, String address) {
        this.name = name;
        this.address = address;
    }
}

2、编写配置文件

<!--有参构造方法注入属性-->
    <bean id="order" class="com.daiju.Order">
        <constructor-arg name="name" value="zhangsan"></constructor-arg>
        <constructor-arg name="address" value="test"></constructor-arg>
    </bean>

3、测试

Order order = context.getBean("order", Order.class);
System.out.println(order);

在这里插入图片描述

3、p名称空间注入(了解)

1、使用p名称空间注入可以简化基于xml配置方式

1、添加p名称空间在配置文件

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:p="http://www.springframework.org/schema/p"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
   

2、进行属性注入,在bean标签里面进行操作

<!--set方法注入属性-->
<bean id="book" class="com.daiju.Book" p:name="123"></bean>
4、xml注入其他类型属性
  • 字面量

1、null值

<!--在property便签中加入null标签-->
<bean id="book" class="com.daiju.Book">
       <property name="name">
           <null></null>
       </property>
   </bean>

2、属性包含特殊符号

<!--
        1、把<>进行转义,&lt,&gt
        2、把带特殊符号内容写到CDATA
    -->
    <bean id="book" class="com.daiju.Book">
       <property name="name">
           <value><![CDATA[<<南京>>]]></value>
       </property>
   </bean>
  • 注入属性-外部bean

1、创建两个类Service和Dao

public class UserService {

    //创建UserDao类型的属性,生成set方法
    UserDao userDao;

    public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
    }



    public void add(){
        System.out.println("service add.................");
    }
}

public interface UserDao {
    public void update();
}
public class UseeDaoImpl implements UserDao{
    @Override
    public void update() {
        System.out.println("implements update.................");
         userDao.update();
    }
}

2、在xml中配置

<!--1、service和dao对象的创建-->
    <bean id="service" class="com.service.UserService">
        <!--
            注入UserDao对象
            name:属性名
            ref:创建userDao对象bean的id值
        -->
        <property name="userDao" ref="user"></property>
    </bean>

    <bean id="user" class="com.dao.UseeDaoImpl"></bean>

3、在Service中调用Dao中的方法

 @Test
    public void testAdd(){

        //1、加载spring配置文件
        ApplicationContext context = new ClassPathXmlApplicationContext("application.xml");

        UserService service = context.getBean("service", UserService.class);

        service.add();

    }

在这里插入图片描述

  • 注入属性-内部bean

1、一对多关系:

  • 实体类创建
//部门类
public class Dept {
    private String name;

    public void setName(String name) {
        this.name = name;
    }
}
//员工类
public class Emp {
    private String name;
    private String gender;

    //员工属于某一个部门,使用对象形式表示
    private Dept dept;

    public void setDept(Dept dept) {
        this.dept = dept;
    }

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

    public void setGender(String gender) {
        this.gender = gender;
    }
}
  • 配置文件编写
<bean id="emp" class="com.bean.Emp">
        <property name="name" value="zhangsan"></property>
        <property name="gender" value="nan"></property>

        <property name="dept">
            <bean id="dep" class="com.bean.Dept">
                <property name="name" value="baoan"></property>
            </bean>
        </property>
    </bean>
  • 测试
public void testAdd(){

        //1、加载spring配置文件
        ApplicationContext context = new ClassPathXmlApplicationContext("application.xml");

        Emp emp = context.getBean("emp", Emp.class);
        System.out.println(emp);


    }

在这里插入图片描述

  • 注入属性-级联赋值

    <bean id="emp" class="com.bean.Emp">
            <property name="name" value="zhangsan"></property>
            <property name="gender" value="nan"></property>
            <property name="dept" ref="dep"></property>
        </bean>
        
        <bean id="dep" class="com.bean.Dept">
            <property name="name" value="baoan"></property>
        </bean>
    <!--第二种写法-->
    <bean id="emp" class="com.bean.Emp">
            <property name="name" value="zhangsan"></property>
            <property name="gender" value="nan"></property>
            <property name="dept" ref="dep"></property>
         	<property name="dept.name" value="jishubu"></property>
        </bean>
        
        <bean id="dep" class="com.bean.Dept">
            <property name="name" value="baoan"></property>
        </bean>
    
5、xml注入集合属性
public class Stu {
    private String[] course;

    private List<String> list;

    private Map<String,String> map;

    private Set<String> set;

    public void setSet(Set<String> set) {
        this.set = set;
    }

    public void setList(List<String> list) {
        this.list = list;
    }

    public void setMap(Map<String, String> map) {
        this.map = map;
    }

    public void setCourse(String[] course) {
        this.course = course;
    }
}

  • 注入数组类型属性
<bean id="student" class="com.daiju.Stu">
        <property name="course">
            <array>
                <value>java</value>
                <value>c#</value>
                <value>python</value>
            </array>
        </property>
    </bean>
  • 注入List集合类型属性
<bean id="student" class="com.daiju.Stu">
        <property name="list">
            <list>
                <value>张三</value>
                <value>李四</value>
                <!--设置对象值-->
                <ref bean="course"></ref>
            </list>
        </property>
    </bean>
  • 注入Set集合类型属性
<bean id="student" class="com.daiju.Stu">
        <property name="set">
            <set>
                <value>one</value>
                <value>two</value>
            </set>
        </property>
    </bean>
  • 注入Map集合类型属性
<bean id="student" class="com.daiju.Stu">
        <property name="map">
            <map>
                <entry key="1" value="one"></entry>
                <entry key="2" value="two"></entry>
            </map>
        </property>
    </bean>
  • 把集合注入公共部分抽取出来

1、在配置文件中引入名称空间util

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:util="http://www.springframework.org/schema/util"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
                           http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd">

2、引入

<!--1提取list集合属性注入-->
    <util:list id="bookList">
        <value>java</value>
        <value>c#</value>
        <value>python</value>
    </util:list>
    <!--2提取部分的使用-->
    <bean id="student" class="com.daiju.Stu">
        <property name="list" ref="bookList"></property>
    </bean>
6、FactoryBean

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

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

  • 工厂bean:返回的类型可以不是配置文件中定义的类型

    1、创建类,让这个类作为工厂bean,实现接口FactoryBean

    public class Mybean implements FactoryBean<Stu> {
    
        //定义返回bean
        @Override
        public Stu getObject() throws Exception {
            return new Stu();
        }
    
        @Override
        public Class<?> getObjectType() {
            return null;
        }
    
        @Override
        public boolean isSingleton() {
            return false;
        }
    }
    

    2、实现接口里面的方法,在实现的方法中定义返回的bean类型

    <bean id="student" class="com.daiju.factoryBean.Mybean"></bean>
    
     @Test
        public void te(){
            ApplicationContext context = new ClassPathXmlApplicationContext("application.xml");
            Stu mybean = context.getBean("mybean", Stu.class);
            
        }
    
7、bean作用域

1、在Spring里面设置bean创建的实例是单例还是多例(默认情况下是单例)

2、如何设置是单例还是多例

<bean id="mybean" class="com.daiju.factoryBean.Mybean" scope="singleton"></bean>
<!--
	scope属性来设置是否是单例还是多例
		singleton:默认值,单例,此时加载配置文件时就会创建单例对象
		prototype:多例,在加载配置文件的时候不创建对象,在获取对象时才会创建对象
	
-->
8、bean生命周期

(1)通过构造器创建bean实例(无参构造函数)

(2)为bean的属性设置和对其他bean的引用(调用set方法)

(3)调用bean的初始化的方法(需要进行配置初始化的方法)

(4)bean可以使用了(对象获取到了)

(5)当容器关闭的时候,调用bean的销毁方法(需要进行配置销毁的方法)

演示

  • 创建所需的类
/**
 * @Author WDY
 * @Date 2020-07-09 14:08
 * @Description TODO
 */
public class Order {
    private String onname;


    public Order() {
        System.out.println("第一步,执行无参构造创建bean实例");
    }

    public void setOnname(String onname) {
        this.onname = onname;
        System.out.println("第二步,调用set方法设置属性的值");
    }

    //创建执行初始化的方法
    public void initMethod(){
        System.out.println("第三步,执行初始化方法");
    }

    //创建执行销毁的方法
    public void destroyMethod(){
        System.out.println("第五步,执行销毁方法");
    }
}
  • 编辑配置文件
<bean id="order" class="com.daiju.factoryBean.Order" init-method="initMethod" destroy-method="destroyMethod">
        <property name="onname" value="test"></property>
</bean>
<!--
	init-method:类中自定义初始化方法的名称
	destroy-method:类中自定义销毁方法的名称
-->
  • 测试方法
@Test
    public void te(){
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("application.xml");

        Order order = context.getBean("order", Order.class);
        System.out.println("第四步,获取到创建bean的实例对象"+order);
        //手动销毁bean实例
        context.close();

    }
  • 结果

在这里插入图片描述

  • bean后置处理器,bean的生命周期有七步

    • (1)通过构造器创建bean实例(无参构造函数)

      (2)为bean的属性设置和对其他bean的引用(调用set方法)

      (3)把bean的实例传递给bean的后置处理器的方法(postProcessBeforeInitialization)

      (4)调用bean的初始化的方法(需要进行配置初始化的方法)

      (5)把bean的实例传递给bean的后置处理器的方法(postProcessAfterInitialization)

      (6)bean可以使用了(对象获取到了)

      (7)当容器关闭的时候,调用bean的销毁方法(需要进行配置销毁的方法)

    • 创建后置处理器(实现BeanPostProcessor接口)

      import org.springframework.beans.factory.config.BeanPostProcessor;
      
      /**
       * @Author WDY
       * @Date 2020-07-09 14:32
       * @Description TODO
       */
      public class MyBean implements BeanPostProcessor {
          @Override
          public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
              System.out.println("初始化之前执行的方法");
              return bean;
          }
      
          @Override
          public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
              System.out.println("初始化之后执行的方法");
              return bean;
          }
      }
      
    • 配置文件配置后置处理器(对配置文件中的所有bean都起作用)

       <!--配置后置处理器-->
          <bean id="myBean" class="com.daiju.factoryBean.MyBean"></bean>
      
    • 结果

在这里插入图片描述

9、xml方式自动装配

1、什么是自动装配

1、根据指定装配规则(属性名称或者属性类型),Spring自动将匹配的属性值进行注入

package com.daiju.aotuwire;

/**
 * @Author WDY
 * @Date 2020-07-09 14:45
 * @Description TODO
 */
public class Emp {
    private Dept dept;

    public void setDept(Dept dept) {
        this.dept = dept;
    }

    @Override
    public String toString() {
        return "Emp{" +
                "dept=" + dept +
                '}';
    }

    public void test(){
        System.out.println(dept);
    }
}
package com.daiju.aotuwire;

/**
 * @Author WDY
 * @Date 2020-07-09 14:45
 * @Description TODO
 */
public class Dept {
    @Override
    public String toString() {
        return "Dept{}";
    }
}
	<!--实现自动装配
        bean标签的autowire属性,配置自动装配
        常用值:
            byName:根据属性的名称注入,注入值bean的id和类属性名称一样
            byType:根据属性的类型注入
    -->
    <bean id="emp" class="com.daiju.aotuwire.Emp" autowire="byName"></bean>

    <bean id="dept" class="com.daiju.aotuwire.Dept"></bean>
10、外部属性文件

1、创建外部属性文件,properties格式

prop.driverClassName=com.mysql.cj.jdbc.Driver
prop.url=jdbc:mysql://localhost:3306/mydb
prop.username=root
prop.password=123456

2、把外部properties配置文件引入到spring配置文件中

1、引入context名称空间

<?xml version="1.0" encoding="UTF-8"?>
<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">

2、引入配置文件

<!--引入外部属性文件-->
    <context:property-placeholder location="classpath:config.properties"></context:property-placeholder>

3、配置

<!--配置连接池-->
    <bean id="druid" 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>

4)IOC操作Bean管理(基于注解)

1、什么是注解

1、注解是代码特殊标记,格式:@注解名称(属性名称=属性值…,属性名称=属性值)

2、使用注解,注解作用在类上面,方法上面,属性上面

3、使用注解目的:简化xml文件的配置

2、创建对象的注解
  • @Component(普通创建bean注解)
  • @Service(一般用在服务层)
  • @Controller(一般用在web层)
  • @Repository(一般用在持久层)

四个注解的功能是一样的,都可以创建bean实例

3、实现对象的创建

1、引入依赖

在这里插入图片描述

2、开启注解扫描

<!--
	base-package:指定需要扫描的包中的类
	用,分割指定多个包名
	其他属性:
		use-default-filters:表示是否使用默认的filter,自己配置的filter


	context:include-filter标签,设置扫描那些内容
-->
<context:component-scan base-package="com">
 
 <!--表示只扫描这个包下带Controller的注解-->
	<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
 
 <!--表示不扫描这个包下带Controller的注解-->
  <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
 
</context:component-scan>

3、创建类使用注解

/**
 * @Author WDY
 * @Date 2020-07-09 14:45
 * @Description TODO
 */
@Component(value = "emp")
//value属性指定创建对象时的名字,默认是类名的首字母小写(小驼峰形式)
public class Emp {
    @Autowired//根据属性注入,不需要set方法
    private Dept dept;

    @Override
    public String toString() {
        return "Emp{" +
                "dept=" + dept +
                '}';
    }

    public void test(){
        System.out.println(dept);
    }
}

3、属性注入的注解

  • @AutoWired:根据属性类型进行自动装配
  • @Qualifier:根据属性名称进行注入
    • 需要和@AutoWired配合使用,用value属性指定需要注入的属性名称
  • @Resource:可根据类型注入也可根据属性名称注入
    • 使用name属性时是根据名称注入
    • 不使用时,默认是根据类型注入
  • @Value:注入普通属性
    • 使用value属性指定注入的属性
4、完全注解开发

1、创建配置类,替代xml配置文件

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

/**
 * @Author WDY
 * @Date 2020-07-09 16:29
 * @Description TODO
 */

@Configuration  //作为配置类,替代xml文件
@ComponentScan(basePackages = {"com.daiju"})    //自定扫描的包
public class config {

}

2、测试类编写

public class test {
    @Test
    public void te(){
        //1、加载配置类
        ApplicationContext context = new AnnotationConfigApplicationContext(config.class);
        //2、获取对象
        Order order = context.getBean("order", Order.class);
    }
}

3、AOP(Aspect Oriented Programming)

1、什么是AOP

  • 面向切面编程:利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率
  • 通俗来讲就是在不改变原有代码的基础之上,增加新的功能

2、AOP底层原理

1、采用动态代理实现

  • 有接口情况,使用JDK动态代理

在这里插入图片描述

底层实现原理

1、相关类

在这里插入图片描述

2、调用newProxyInstence方法

在这里插入图片描述

3、JDK动态代理代码

  • 创建接口,定义方法
/**
 * @Author WDY
 * @Date 2020-07-10 13:10
 * @Description TODO
 */
public interface UserDao {
    public int add(int a ,int b);
    public  String update(String id);
}
  • 创建接口实现类,实现方法
/**
 * @Author WDY
 * @Date 2020-07-10 13:11
 * @Description TODO
 */
public class UserDaoImpl implements UserDao{
    @Override
    public int add(int a, int b) {
        return a+b;
    }

    @Override
    public String update(String id) {
        return id;
    }
}
  • 创建代理对象
//创建代理对象代码
class UserDaoProxy implements InvocationHandler{

    //被代理的对象
    private Object object;

    //1、把创建的是谁的代理对象传过来
    //有参构造传递
    public UserDaoProxy(Object object){
        this.object = object;
    }


    //增强的逻辑
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

        //方法之前
        System.out.println("方法之前执行"+method.getName()+"------传递的参数"+ Arrays.toString(args));

        //原方法
        Object res = method.invoke(object,args);

        //方法之后
        System.out.println("方法之后执行"+ object);

        return res;
    }
}
  • 使用Proxy类创建接口代理对象测试
/**
 * @Author WDY
 * @Date 2020-07-10 13:14
 * @Description TODO
 */
public class JDKProxy {
    public static void main(String[] args) {
        Class[] interfaces = {UserDao.class};

        //返回值为代理对象
        UserDao userDao = (UserDao)Proxy.newProxyInstance(JDKProxy.class.getClassLoader(), interfaces, new UserDaoProxy(new UserDaoImpl()));
        int res = userDao.add(1, 2);
        System.out.println(res);

    }
}


  • 没有接口情况,使用CGLIB动态代理

在这里插入图片描述

3、AOP操作中的术语

  • 连接点
    • 类里面的哪些方法可以被增强,这些方法就称作连接点
  • 切入点
    • 实际真正被增强的方法,称为切入点
  • 通知(增强)
    • 实际增强的逻辑部分
    • 有多种类型
      • 前置通知
      • 后置通知
      • 环绕通知
      • 异常通知
      • 最终通知
  • 切面(是一个动作)
    • 把通知应用到切入点的过程

4、AOP操作

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

AspectJ不是Spring的组成部分,独立AOP框架,一般把AspectJ和Spring框架一起使用,进行AOP操作

2、基于AspectJ实现AOP操作

1、基于xml配置文件实现

2、基于注解方式实现

3、在项目中引入AOP依赖

在这里插入图片描述

4、切入点表达式

​ (1)切入点表达式的作用:知道对那个类里面的方法进行增强

​ (2)语法结构:

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

在这里插入图片描述

4-1、AOP操作(注解)

1、创建类

/**
 * @Author WDY
 * @Date 2020-07-10 14:30
 * @Description TODO
 */
public class User {
    public void add(){
        System.out.println("add..........");
    }
}

2、创建增强类(编写增强的逻辑)

​ 在增强类里面创建不同的方法,代表不同的类型通知

public class UserProxy {

    //前置通知
    public void before(){
        System.out.println("before..........");
    }
}

3、进行通知的配置

​ (1)开启注解扫描

<?xml version="1.0" encoding="UTF-8"?>
<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"
       xmlns:aop="http://www.springframework.org/schema/aop"
       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/aop http://www.springframework.org/schema/aop/spring-aop.xsd">



    <context:component-scan base-package="com.daiju.aop"></context:component-scan>

</beans>

​ (2)使用注解创建对象

@Component
public class User {
    public void add(){
        System.out.println("add..........");
    }
}

​ (3)在增强类上面添加注解@Aspect

@Component
@Aspect//生成代理对象
public class UserProxy {

    //前置通知
    public void before(){
        System.out.println("before..........");
    }
}

​ (4)开启生成代理对象

<?xml version="1.0" encoding="UTF-8"?>
<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"
       xmlns:aop="http://www.springframework.org/schema/aop"
       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/aop http://www.springframework.org/schema/aop/spring-aop.xsd">



    <aop:aspectj-autoproxy></aop:aspectj-autoproxy>

</beans>

​ (5)配置不同类型的通知

//前置通知
    @Before(value = "execution(* com.daiju.aop.User.add(..))")
    public void before(){
        System.out.println("before..........");
    }

​ (6)测试

@Test
    public void tesr(){
        ApplicationContext context = new ClassPathXmlApplicationContext("application.xml");
        User user = context.getBean("user", User.class);
        user.add();
    }

在这里插入图片描述

​ (7)其他类型通知

@Component
@Aspect//生成代理对象
public class UserProxy {

    //前置通知
    @Before(value = "execution(* com.daiju.aop.User.add(..))")
    public void before(){
        System.out.println("before..........");
    }

    //最终通知
    @After(value = "execution(* com.daiju.aop.User.add(..))")
    public void after(){
        System.out.println("after..........");
    }

    //后置通知(返回通知)
    @AfterReturning(value = "execution(* com.daiju.aop.User.add(..))")
    public void afterReturning(){
        System.out.println("afterReturning..........");
    }

    //异常通知
    @AfterThrowing(value = "execution(* com.daiju.aop.User.add(..))")
    public void afterThrowing(){
        System.out.println("afterThrowing..........");
    }

    //环绕通知
    @Around(value = "execution(* com.daiju.aop.User.add(..))")
    public void aroud(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        System.out.println("环绕之前..........");

        //被增强的方法执行
        proceedingJoinPoint.proceed();

        System.out.println("环绕之后..........");
    }
}

在这里插入图片描述

​ (8)相同切入点抽取

@Component
@Aspect//生成代理对象
public class UserProxy {

    @Pointcut(value = "execution(* com.daiju.aop.User.add(..))")
    public void pointdemo(){
    }


    //前置通知
    @Before(value = "pointdemo()")
    public void before(){
        System.out.println("before..........");
    }

    //最终通知
    @After(value = "pointdemo()")
    public void after(){
        System.out.println("after..........");
    }

    //后置通知
    @AfterReturning(value = "pointdemo()")
    public void afterReturning(){
        System.out.println("afterReturning..........");
    }

    //异常通知
    @AfterThrowing(value = "pointdemo()")
    public void afterThrowing(){
        System.out.println("afterThrowing..........");
    }

    //环绕通知
    @Around(value = "pointdemo()")
    public void aroud(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        System.out.println("环绕之前..........");

        //被增强的方法执行
        proceedingJoinPoint.proceed();

        System.out.println("环绕之后..........");
    }
}

​ (9)有多个增强类对同一个方法进行增强,设置增强类优先级

​ 在增强类上添加@Order注解(数字类型),值越小优先级越高

@Component
@Aspect//生成代理对象
@Order(3)
4-1、AOP操作(xml配置文件)
<bean id="user" class="com.daiju.aop.User"></bean>
<bean id="userProxy" class="com.daiju.aop.UserProxy"></bean>
<!--配置aop增强-->
<aop:config>
    <!--切入点-->
    <aop:pointcut id="p" expression="execution(* com.daiju.aop.User(..))"/>

    <!--配置切面-->
    <aop:aspect ref="userProxy">
        <!--增强作用在那个方法上面-->
        <aop:before method="before" pointcut-ref="p"></aop:before>
    </aop:aspect>
</aop:config>

4、JDBCTemplate

1、什么是JDBCTemplate

Spring框架对JDBC进行了封装,从而能够更加简单的实现对数据库的操作

2、导入依赖

在这里插入图片描述

3、配置连接池

<context:property-placeholder location="classpath:config.properties"></context:property-placeholder>
<context:component-scan base-package="com.daiju"></context:component-scan>

    <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="password" value="${prop.password}"></property>
        <property name="username" value="${prop.username}"></property>
    </bean>

4、创建JDBCTemplate对象

<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
    <!--注入数据源-->
    <property name="dataSource" ref="dataSource"></property>
</bean>

5、创建Service类,dao类,在dao注入JDBCTemplate对象

package com.daiju.service;

import com.daiju.dao.BookDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

/**
 * @Author WDY
 * @Date 2020-07-11 13:28
 * @Description TODO
 */
@Service
public class BookService {
    @Autowired
    private BookDao bookDao;
}
package com.daiju.dao;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;

/**
 * @Author WDY
 * @Date 2020-07-11 13:29
 * @Description TODO
 */
@Repository
public class BookDaoImpl implements BookDao{

    @Autowired
    private JdbcTemplate jdbcTemplate;
}
  • 创建数据表和实体类
public class Book {
    private Integer user_id;
    private String username;
    private String userstatus;

    @Override
    public String toString() {
        return "User{" +
                "user_id=" + user_id +
                ", username='" + username + '\'' +
                ", userstatus='" + userstatus + '\'' +
                '}';
    }

    public User() {
    }

    public User(Integer user_id, String username, String userstatus) {
        this.user_id = user_id;
        this.username = username;
        this.userstatus = userstatus;
    }

    public Integer getUser_id() {
        return user_id;
    }

    public void setUser_id(Integer user_id) {
        this.user_id = user_id;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getUserstatus() {
        return userstatus;
    }

    public void setUserstatus(String userstatus) {
        this.userstatus = userstatus;
    }
}
  • 编写service和dao
@Service
public class BookService {
    @Autowired
    private BookDao bookDao;

    public void addBook(Book book){
        bookDao.addBook(book);
    }
}
@Repository
public class BookDaoImpl implements BookDao{

    @Autowired
    private JdbcTemplate jdbcTemplate;

    @Override
    public void addBook(Book book){

        String sql = "insert into t_book values (?,?,?)";
        Object[] args = {book.getUser_id(), book.getUsername(), book.getUserstatus()};
        int update = jdbcTemplate.update(sql, args);
        System.out.println(update);
    }
}
  • 测试

      public void tesr(){
            ApplicationContext context = new ClassPathXmlApplicationContext("application.xml");
            BookService bookService = context.getBean("bookService", BookService.class);
            Book book = new Book();
            book.setUser_id(1);
            book.setUsername("java");
            book.setUserstatus("Y");
    
            bookService.addBook(book);
        }
    
  • 查询所有操作

 //查询表记录数
    @Override
    public void findBook() {
        String sql = "select count(*) from t_book";
        int update = jdbcTemplate.queryForObject(sql,Integer.class);
        System.out.println(update);
    }

//查询某个对象
    @Override
    public void findBook(Integer id) {
        String sql = "select * from t_book where user_id=?";
        Book update = jdbcTemplate.queryForObject(sql,new BeanPropertyRowMapper<Book>(Book.class),id);
        System.out.println(update);
    }
 //查询集合
    @Override
    public void findBook() {
        String sql = "select * from t_book";
        List<Book> update = jdbcTemplate.query(sql,new BeanPropertyRowMapper<Book>(Book.class));
        System.out.println(update);
    }
  • 批量操作
//批量添加
 public void addBook(){

        List<Object[]> args = new ArrayList<>();
        
        Object[] obj1 = {"1","C#","Y"};
        Object[] obj2 = {"2","Java","Y"};
        Object[] obj3 = {"3","Js","Y"};
        
        args.add(obj1);
        args.add(obj2);
        args.add(obj3);
        
        String sql = "insert into t_book values (?,?,?)";
        int[] update = jdbcTemplate.batchUpdate(sql, args);
        System.out.println(update);
    }

5、事务管理

1、什么是事务

事务是数据库操作的最基本单元,逻辑上的一组操作,要么都成功,要么都失败(转账)

2、事务四大特性(ACID)

  • 原子性
  • 一致性
  • 隔离性
  • 持久性

3、搭建操作环境

在这里插入图片描述

  • 创建数据表

在这里插入图片描述

  • 创建相应的实体类
@Service
public class UserService {

    @Autowired
    private UserDao userDao;
}
public interface UserDao {
}
@Repository
public class UserDaoImpl implements UserDao{


    @Autowired
    private JdbcTemplate jdbcTemplate;


}
  • 在dao创建多钱和少钱的方法,在service创建转账的方法
//多钱
    public void addMoney();
    //少钱
    public void reduceMoney();
 @Override
    public void addMoney() {
        String sql = "update account set money=money+? where id=?";
        jdbcTemplate.update(sql,100,1);
    }

    @Override
    public void reduceMoney() {
        String sql = "update account set money=money-? where id=?";
        jdbcTemplate.update(sql,100,2);
    }
//转账的方法
    public void account(){
        userDao.addMoney();
        userDao.reduceMoney();
    }

4、Spring事务管理介绍

1、事务添加到JavaEE三层架构中的Service层

2、在Spring中进行事务管理操作有两种方式

  • 编程式事务管理(会造成代码臃肿)
  • 声明式事务管理(推荐使用)

3、声明式事务管理

  • 基于注解
  • 基于xml配置文件

4、在Spring中进行声明式事务管理,底层使用AOP原理

5、Spring事务管理API

  • 提供一个接口,代表事务管理器,这个接口针对不同的框架提供不同的实现类

-在这里插入图片描述

5、基于注解实现

1、创建事务管理器

    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <!--注入数据源-->
        <property name="dataSource" ref="dataSource"></property>
    </bean>

2、开启事务注解

  • 引入名称空间tx

    • <?xml version="1.0" encoding="UTF-8"?>
      <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"
             xmlns:aop="http://www.springframework.org/schema/aop"
             xmlns:tx="http://www.springframework.org/schema/tx"
             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/aop http://www.springframework.org/schema/aop/spring-aop.xsd
                                 http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">
      
      
<!--开启事务注解
	transaction-manager:指定创建的事务管理器
-->
    <tx:annotation-driven transaction-manager="transactionManager"></tx:annotation-driven>

3、在service类上面(或者service类里面的方法上面)添加事务注解==@Transactional==

@Service
@Transactional
public class UserService {
    ....

4、配置==@Transactional==的参数

  • propagation:事务传播行为

    • 多事务方法1之间进行调用,这个过程中事务是如何进行管理的

      在这里插入图片描述

  • isolation:事务隔离级别

    • 事务有特性称为隔离性,多事务操作之间不会产生影响,不考虑隔离性会产生一系列问题
      • 脏读:一个未提交的事务读取到另一个未提交事务的数据
      • 幻(虚)读:一个未提交的事务读取到另一个提交事务添加的数据
      • 不可重复读:一个未提交的事务读取到另一个提交事务修改的数据
    • 在这里插入图片描述
  • timeout:超时时间

    • 事务需要在一定的时间内进行提交,超时则不提交进行回滚操作
    • 默认值-1,单位:秒
  • readOnly:是否只读

    • 默认是false
  • rollbackFor:回滚

    • 设置出现哪些异常进行事务的回滚
  • noRollbackFor:不回滚

    • 设置出现哪些异常不进行事务的回滚

6、基于xml配置文件实现

1、配置事务管理器(详情5-1)

2、配置通知

 <!--配置通知-->
    <tx:advice id="txAdvice">
        <!--配置事务参数-->
        <tx:attributes>
            <!--指定在哪种方法上面添加事务-->
            <tx:method name="account" isolation="DEFAULT"/>
        </tx:attributes>
    </tx:advice>

3、配置切入点和切面

<!--配置切入点和切面-->
    <aop:config>
        <!--配置切入点-->
        <aop:pointcut id="pt" expression="execution(* com.daiju.service.UserService.*(..))"/>
        <!--配置切面-->
        <aop:advisor advice-ref="txAdvice" pointcut-ref="pt"></aop:advisor>
    </aop:config>

6、Spring5新特性

1、整个框架基于java8,运行时兼容jdk9,许多不建议使用的类和方法在代码库中进行了删除

2、Spring5框架自带了通用的日志封装

1、Spring5已经移除了Log4jConfigListener,官方建议使用Log4j2(Logback)

2、Spring5整合Log4j2

  • 引入jar包
  • 在这里插入图片描述
  • 创建log4j2.xml配置文件
<?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>

3、Spring5核心容器支持==@Nullable==注解

1、该注解可以使用在方法上面,属性上面,参数上面,表示方法返回值可以为空,属性值可以为空,参数值可以为空

4、Spring5核心容器支持函数式风格GenericApplicationContext

@Test
    //函数式风格创建对象,交给spring管理
    public void test(){
        //1、创建GenericApplicationContext对象
        GenericApplicationContext applicationContext = new GenericApplicationContext();
        //2、调用applicationContext的方法进行对象注册
        applicationContext.refresh();
        applicationContext.registerBean("user",User.class,()->new User());
        //3、获取在spring注册的对象
        User bean = applicationContext.getBean("user",User.class);
    }

5、支持整合JUnit5

1、整合JUnit4

  • 引入spring针对测试相关的依赖在这里插入图片描述
  • 创建测试类,使用注解方式实现测试
@RunWith(SpringJUnit4ClassRunner.class)//单元测试框架
@ContextConfiguration("classpath:application.xml")//加载配置文件
public class Test {

    public void tesr(){
        ..........

    }
}

2、整合JUnit5

  • 引入JUnit5的jar包
  • 创建测试类,使用注解方式实现测试
@ExtendWith(SpringExtension.class)
@ContextConfiguration("classpath:application.xml")
//@SpringJUnitConfig(locations = "classpath:application.xml")可以替代上面两个注解
public class Test1 {


    @Test
    public void tesr(){
        ApplicationContext context = new ClassPathXmlApplicationContext("application.xml");

    }
}

6、SpringWebFlux

6.1、介绍

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

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

3、特点:

  • 非阻塞可以在有限资源情况下,提高系统的吞吐量和伸缩性,以Reactor为基础实现响应式编程
  • 函数式编程,WebFlux使用jdk8函数式编程方式实现路由请求

4、比较SpringMVC

在这里插入图片描述

  • 都可以使用注解方式,也可以运行在Tomcat等容器中
  • SpringMVC采用命令式编程,WebFlux采用异步响应式编程
6.2、响应式编程

1、什么是响应式编程

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

2、java8及之前版本

提供的观察者模式的两个类Observer和Observable

public class ObserverDemo extends Observable {

    public static void main(String[] args) {
        ObserverDemo observerDemo = new ObserverDemo();

        //添加观察者
        observerDemo.addObserver((o,arg)->{
            System.out.println("发生了变化");
        });

        observerDemo.addObserver((o,arg)->{
            System.out.println("手动被观察者通知,准备改变");
        });

        //数据变化
        observerDemo.setChanged();
        //通知
        observerDemo.notifyObservers();
    }
}

3、响应式编程(Reactor实现)

1、响应式编程操作中,Reactor是满足Reactive规范的框架

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

3、Flux和Mono都是数据流的发布者,使用Flux和Mono都可以发出三种数据信号,元素值,错误信号,完成信号,错误信号和完成信号都代表终止信号,终止信号用于告诉订阅者数据流结束了,错误信号终止数据流同时把错误信息传递给订阅者

4、代码演示Flux和Mono

  • 引入依赖
<dependency>
            <groupId>io.projectreactor</groupId>
            <artifactId>reactor-core</artifactId>
            <version>3.3.3.RELEASE</version>
</dependency>
  • 编写代码
public class TestReactor {
    public static void main(String[] args){
        //just方法直接声明
        Flux.just(1,2,3,4).subscribe(System.out::println);//订阅
        Mono.just(1);

        //其他方法
        Integer[] array = {1,2,3,4};
        Flux.fromArray(array);

        List<Integer> list = Arrays.asList(1,2,3,4);
        Flux.fromIterable(list);

        Stream<Integer> stream = list.stream();
        Flux.fromStream(stream);
    }
}

5、三种信号特点

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

6、调用just或者其他方法只是声明数据流,数据流并没有发出,只有订阅后才会触发数据流

7、操作符

  • 对数据流进行一道道的操作,称为操作符,比如流水线
  • map:元素映射为新的元素
    • 在这里插入图片描述
  • flatmap:元素映射为流
    • 把每个元素转换成流,把转换后的多个流合并成一个大的流
    • 在这里插入图片描述
6.3、执行流程和核心API

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

1、Netty

  • BIO(阻塞)

在这里插入图片描述

  • NIO(非阻塞)

在这里插入图片描述

2、SpringWebFlux执行过程和SpringMVC相似

  • SpringWebFlux核心控制器DispatchHandler,实现接口WebHandler
  • 在这里插入图片描述

3、SpringWebFlux里面的DispatchHandler负责请求的处理

  • HandlerMapping:请求查询到的处理的方法
  • HandlerAdapter:真正负责请求处理
  • HandlerResultHandler:响应结果处理

4、SpringWebFlux实现函数式编程,两个接口

  • RouterFunction:路由
  • HandlerFunction:处理函数
6.4、基于注解编程模型

1、导入依赖

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

2、配置启动端口号

server.port=8081

3、创建相关的类和接口

package com.entity;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

/**
 * @Author WDY
 * @Date 2020-07-12 16:27
 * @Description TODO
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
    private String name;
    private String gender;
    private Integer age;
}

/**
 * @Author WDY
 * @Date 2020-07-12 16:29
 * @Description TODO
 */
//用户操作接口
public interface UserService {
    //根据id查询用户
    Mono<User> getUserById(Integer id);

    //查询所有用户
    Flux<User> getAllUser();

    //添加用户
    Mono<Void> saveUserInfo(Mono<User> user);
}
@Repository
public class UserServiceImpl implements UserService {


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

    public UserServiceImpl(){
        this.users.put(1, new User("Lucy", "男", 20));
        this.users.put(2, new User("Marry", "女", 30));
        this.users.put(3, new User("Tom", "男", 22));
        this.users.put(4, new User("Jack", "女", 25));
        this.users.put(5, new User("Dacy", "男", 29));
    }

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

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

    @Override
    public Mono<Void> saveUserInfo(Mono<User> user) {
        return user.doOnNext(person->{
            int i = users.size()+ 1;
            users.put(i, person);
        }).thenEmpty(Mono.empty());
    }
}

@RestController
public class UserController {

    @Autowired
    private UserService userService;

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

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

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

}

  • SpringMVC方式实现,同步阻塞的方式,基于SpringMVC+Tomcat
  • SpringWebFlux方式实现,异步非阻塞方式,基于SpringWebFlux+Reactor+Netty
6.5、基于函数是编程模型

1、需要我们自己初始化服务器

2、两个核心接口:RouterFunction和HandlerFunction

  • RouterFunction:实现路由功能,请求转发给相应的Handler
  • HandlerFunction:处理请求生成响应的函数,核心任务定义两个函数式接口的实现并启动需要的服务器

3、SpringWebFlux请求和响应不再是ServletRequest和ServletResponse,而是ServerRequest和ServerResponse

1、创建Handler

public class UserHandler {

    private final UserService userService;

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

    //根据id查询
    public Mono<ServerResponse> getUserById(ServerRequest request){
        //获取id
        Integer id = Integer.valueOf(request.pathVariable("id"));
        //空值处理
        Mono<ServerResponse> notFound = ServerResponse.notFound().build();

        //调用service方法
        Mono<User> userMono = this.userService.getUserById(id);
        //把userMono进行转换返回
        //使用Reactor操作flatMap
        return userMono
                .flatMap(user ->
                        ServerResponse
                                .ok()
                                .contentType(MediaType.APPLICATION_JSON)
                                .body(fromObject(user)))
                                .switchIfEmpty(notFound);
    }
    //查询所有
    public Mono<ServerResponse> getAllUser(ServerRequest request){
        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);

        return ServerResponse.ok().build(this.userService.saveUserInfo(userMono));
    }

}

2、初始化服务器,编写Router

public class Server {
    //1创建路由
    public RouterFunction<ServerResponse> routerFunction(){
        UserService userService = new UserServiceImpl();

        //创建Handler对象
        UserHandler handler = new UserHandler(userService);

        //设置路由
        return RouterFunctions.route(
           GET("/user/{id}").and(accept(MediaType.APPLICATION_JSON)),handler::getUserById)
                .andRoute(GET("/user").and(accept(MediaType.APPLICATION_JSON)),handler::getAllUser);

    }
}

3、创建服务器完成适配

//2创建服务器完成适配
    public void createReactorServer(){
        //路由和Handler适配
        RouterFunction<ServerResponse>route = routerFunction();
        HttpHandler httpHandler = toHttpHandler(route);
        ReactorHttpHandlerAdapter adapter = new ReactorHttpHandlerAdapter(httpHandler);

        //创建服务器
        HttpServer httpServer = HttpServer.create();
        httpServer.handle(adapter).bindNow();
    }

4、最终调用

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

5、完整代码

public class Server {
    //1创建路由
    public RouterFunction<ServerResponse> routerFunction(){
        UserService userService = new UserServiceImpl();

        //创建Handler对象
        UserHandler handler = new UserHandler(userService);

        //设置路由
        return RouterFunctions.route(
           GET("/user/{id}").and(accept(MediaType.APPLICATION_JSON)),handler::getUserById)
                .andRoute(GET("/user").and(accept(MediaType.APPLICATION_JSON)),handler::getAllUser);

    }
    //2创建服务器完成适配
    public void createReactorServer(){
        //路由和Handler适配
        RouterFunction<ServerResponse>route = routerFunction();
        HttpHandler httpHandler = toHttpHandler(route);
        ReactorHttpHandlerAdapter adapter = new ReactorHttpHandlerAdapter(httpHandler);

        //创建服务器
        HttpServer httpServer = HttpServer.create();
        httpServer.handle(adapter).bindNow();

    }

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

6、使用WebClient调用

public class test {
    public static void main(String[] args) {
        //调用服务器地址
        WebClient client = WebClient.create("http://localhost:54906");

        //请求路径
        String id = "1";
        User block = client.get().uri("/user/{id}", id)
                .accept(MediaType.APPLICATION_JSON)
                .retrieve()
                .bodyToMono(User.class)
                .block();
        System.out.println(block);


        Flux<User> users = client.get().uri("/user")
                .accept(MediaType.APPLICATION_JSON)
                .retrieve()
                .bodyToFlux(User.class);

       users.buffer().doOnNext(System.out::println).blockFirst();
    }
}

  1. 事务方法是对数据库表数据进行变化的操作 ↩︎

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值