Spring AOP面向切面编程简单概述

一篇文章搞懂spring aop,什么是AOP,什么是面向切面编程,动态代理实现AOPSpring boot 实现Aopspring 实现aop,附代码图文演示(保姆级教程) springaop、oop、java 阅读详情

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


Spring AOP-Spring面向切面编程概述

一、AOP?

1.什么是 AOP

AOP (Aspect Orient Programming),直译过来就是 面向切面编程。AOP 是一种编程思想,是面向对象编程(OOP)的一种补充。面向对象编程将程序抽象成各个层次的对象,而面向切面编程是将程序抽象成各个切面。
在这里插入图片描述
所谓切面,相当于应用对象间的横切点,我们可以将其单独抽象为单独的模块。

2.为什么需要 AOP?

想象下面的场景,开发中在多个模块间有某段重复的代码,我们通常是怎么处理的?显然,没有人会靠“复制粘贴”吧。在传统的面向过程编程中,我们也会将这段代码,抽象成一个方法,然后在需要的地方分别调用这个方法,这样当这段代码需要修改时,我们只需要改变这个方法就可以了。然而需求总是变化的,有一天,新增了一个需求,需要再多出做修改,我们需要再抽象出一个方法,然后再在需要的地方分别调用这个方法,又或者我们不需要这个方法了,我们还是得删除掉每一处调用该方法的地方。实际上涉及到多个地方具有相同的修改的问题我们都可以通过 AOP 来解决。

3.AOP 实现分类

AOP 要达到的效果是,保证开发者不修改源代码的前提下,去为系统中的业务组件添加某种通用功能。AOP 的本质是由 AOP 框架修改业务组件的多个方法的源代码,看到这其实应该明白了,AOP 其实就是前面一篇文章讲的代理模式的典型应用。
按照 AOP 框架修改源代码的时机,可以将其分为两类:

  • 静态 AOP 实现, AOP 框架在编译阶段对程序源代码进行修改,生成了静态的 AOP 代理类(生成的 *.class文件已经被改掉了,需要使用特定的编译器),比如 AspectJ。
  • 动态 AOP 实现, AOP 框架在运行阶段对动态生成代理对象(在内存中以 JDK 动态代理,或 CGlib 动态地生成 AOP代理类),如 SpringAOP。
  • 在这里插入图片描述

4.AOP概念

  • 通知(Advice): AOP 框架中的增强处理。通知描述了切面何时执行以及如何执行增强处理。
  • 连接点(join point): 连接点表示应用执行过程中能够插入切面的一个点,这个点可以是方法的调用、异常的抛出。在 Spring AOP 中,连接点总是方法的调用。
  • 切点(PointCut): 可以插入增强处理的连接点。
  • 切面(Aspect): 切面是通知和切点的结合。
  • 引入(Introduction):引入允许我们向现有的类添加新的方法或者属性。
  • 织入(Weaving): 将增强处理添加到目标对象中,并创建一个被增强的对象,这个过程就是织入。概念看起来总是有点懵,不同的参考书籍上翻译还不一样,所以需要慢慢在应用中理解。

通知(Advice)的类型:

  • 前置通知(Before advice):在某个连接点(Join point)之前执行的通知,但这个通知不能阻止连接点的执行(除非它抛出一个异常)。
  • 返回后通知(After returning advice):在某个连接点(Join point)正常完成后执行的通知。例如,一个方法没有抛出任何异常正常返回。
  • 抛出异常后通知(After throwing advice):在方法抛出异常后执行的通知。
  • 后置通知(After(finally)advice):当某个连接点(Join point)退出的时候执行的通知(不论是正常返回还是发生异常退出)。
  • 环绕通知(Around advice):包围一个连接点(Join point)的通知,如方法调用。这是最强大的一种通知类型。环绕通知可以在方法前后完成自定义的行为。它也会选择是否继续执行连接点或直接返回它们自己的返回值或抛出异常来结束执行。

二、Spring AOP的使用

1.方法一:使用原生态Spring API接口

代码如下(示例):

配置pom.xml

<dependencies>
        <!--    AOP-->
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.9.4</version>
        </dependency>

        <!--    Spring框架依赖-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>4.3.14.RELEASE</version>
        </dependency>
    </dependencies>

创建接口(MasterService )

随机写几个方法

package com.java.ym.service;

/**
 * @Author: YuMi
 * @Date: 2020/10/9 11:00
 * ----------------------
 * @Comments:
 */
public interface MasterService {
    void add();
    void delete();
    void update();
    void select();
}

接口实现类(MasterServiceImpl )

package com.java.ym.service.impl;

import com.java.ym.service.MasterService;

/**
 * @Author: YuMi
 * @Date: 2020/10/9 11:02
 * ----------------------
 * @Comments:
 */
public class MasterServiceImpl implements MasterService {
    @Override
    public void add() {
        System.out.println("增加");
    }

    @Override
    public void delete() {
        System.out.println("删除");
    }

    @Override
    public void update() {
        System.out.println("修改");
    }

    @Override
    public void select() {
        System.out.println("查询");
    }
}

创建假例日志类

package com.java.ym.log;

import org.springframework.aop.MethodBeforeAdvice;

import java.lang.reflect.Method;

/**
 * @Author: YuMi
 * @Date: 2020/10/9 11:03
 * ----------------------
 * @Comments: 日志
 */
public class Log implements MethodBeforeAdvice {
    /**
     * method:  需要执行的目标对象的方法
     * objects: 参数
     * target:  目标对象
     * @param method
     * @param objects
     * @param target
     * @throws Throwable
     */
    @Override
    public void before(Method method, Object[] objects, Object target) throws Throwable {
        System.out.println(target.getClass().getName()+"的"+method.getName()+"被执行了");
    }
}

package com.java.ym.log;

import org.springframework.aop.AfterReturningAdvice;

import java.lang.reflect.Method;

/**
 * @Author: YuMi
 * @Date: 2020/10/9 11:07
 * ----------------------
 * @Comments:
 */
public class AfterLog implements AfterReturningAdvice {
    /**
     * returnValue: 返回值
     * @param returnValue
     * @param method
     * @param objects
     * @param target
     * @throws Throwable
     */
    @Override
    public void afterReturning(Object returnValue, Method method, Object[] objects, Object target) throws Throwable {
        System.out.println("执行了"+method.getName()+"返回结果为:"+returnValue);
    }
}

配置applicationContext.xml

<?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: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/aop
        http://www.springframework.org/schema/aop/spring-aop.xsd">

    <bean id="masterService" class="com.java.ym.service.impl.MasterServiceImpl"></bean>
    <bean id="log" class="com.java.ym.log.Log"></bean>
    <bean id="afterLog" class="com.java.ym.log.AfterLog"></bean>

        <!--方法一:使用原生态Spring API接口
        配置AOP:需要导入aop的约束-->
    <aop:config>
        <!--    切入点: expression: 表达式,expression(需要执行的位置 *代表所有)-->
        <aop:pointcut id="pointcut" expression="execution(* com.java.ym.service.impl.MasterServiceImpl.*(..))"/>

        <!--    执行环绕增加-->
        <aop:advisor advice-ref="log" pointcut-ref="pointcut"/>
        <aop:advisor advice-ref="afterLog" pointcut-ref="pointcut"/>
    </aop:config>

测试

import com.java.ym.service.MasterService;
import com.java.ym.service.impl.MasterServiceImpl;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * @Author: YuMi
 * @Date: 2020/10/9 11:32
 * ----------------------
 * @Comments:
 */
public class MyTest {
    public static void main(String[] args) {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
        //  动态代理,代理的是接口
        MasterService masterService = (MasterService) applicationContext.getBean("masterService");
        masterService.add();
    }
}

//	运行结果
com.java.ym.service.impl.MasterServiceImpl的add被执行了
增加
执行了add返回结果为:null

2.方法二:自定义类

代码如下(示例):

创建接口(MasterService )

随机写几个方法

package com.java.ym.service;

/**
 * @Author: YuMi
 * @Date: 2020/10/9 11:00
 * ----------------------
 * @Comments:
 */
public interface MasterService {
    void add();
    void delete();
    void update();
    void select();
}

接口实现类(MasterServiceImpl )

package com.java.ym.service.impl;

import com.java.ym.service.MasterService;

/**
 * @Author: YuMi
 * @Date: 2020/10/9 11:02
 * ----------------------
 * @Comments:
 */
public class MasterServiceImpl implements MasterService {
    @Override
    public void add() {
        System.out.println("增加");
    }

    @Override
    public void delete() {
        System.out.println("删除");
    }

    @Override
    public void update() {
        System.out.println("修改");
    }

    @Override
    public void select() {
        System.out.println("查询");
    }
}

创建自定义切入点类

package com.java.ym.diy;

/**
 * @Author: YuMi
 * @Date: 2020/10/9 11:39
 * ----------------------
 * @Comments: 自定义切入点
 */
public class DiyPointCut {
    public void diyFront(){
        System.out.println("方法执行前***");
    }
    public void diyLater(){
        System.out.println("方法执行后***");
    }
}

配置applicationContext.xml

<?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: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/aop
        http://www.springframework.org/schema/aop/spring-aop.xsd">

    <bean id="masterService" class="com.java.ym.service.impl.MasterServiceImpl"></bean>
    <bean id="log" class="com.java.ym.log.Log"></bean>
    <bean id="afterLog" class="com.java.ym.log.AfterLog"></bean>

    <!--    方法二:自定义类-->
    <bean id="diy" class="com.java.ym.diy.DiyPointCut"></bean>
    <aop:config>
        <!--    自定义切面 ref:需要引用的类-->
        <aop:aspect ref="diy">
            <!--    切入点-->                                  <!-- 匹配所有MasterServiceImpl包下面的所有类的所有方法-->
            <aop:pointcut id="point" expression="execution(* com.java.ym.service.impl.MasterServiceImpl.*(..)) "/>
            <!--    前置通知-->
            <aop:before method="diyFront" pointcut-ref="point"></aop:before>
            <!--    后置通知-->
            <aop:after method="diyLater" pointcut-ref="point"></aop:after>
        </aop:aspect>
    </aop:config>
</beans>

测试

import com.java.ym.service.MasterService;
import com.java.ym.service.impl.MasterServiceImpl;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * @Author: YuMi
 * @Date: 2020/10/9 11:32
 * ----------------------
 * @Comments:
 */
public class MyTest {
    public static void main(String[] args) {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
        //  动态代理,代理的是接口
        MasterService masterService = (MasterService) applicationContext.getBean("masterService");
        masterService.add();
    }
}

//	运行结果
方法执行前***
增加
方法执行后***

3.方法三:以注解的形式实现

这里我就不再写接口和接口实现类了,还是引用上面两个方法的接口和实现类。

创建注解类

package com.java.ym.diy;

/**
 * @Author: YuMi
 * @Date: 2020/10/10 9:58
 * ----------------------
 * @Comments:
 */

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;

/**
 * 方法三:使用注解实现AOP
 * Aspect: 表示这个类是一个切面
 */

//  声明事务
@Aspect
public class Annotate {
    /**
     *      切入点                                  匹配所有MasterServiceImpl包下面的所有类的所有方法&ndash;&gt;
     * <aop:pointcut id="point" expression="execution(* com.java.ym.service.impl.MasterServiceImpl.*(..)) "/>
     */
    @Before("execution(* com.java.ym.service.impl.MasterServiceImpl.*(..))")
    public void before(){
        System.out.println("方法执行前***");
    }

    @After("execution(* com.java.ym.service.impl.MasterServiceImpl.*(..))")
    public void after(){
        System.out.println("方法执行后***");
    }

    /**
     * 在环绕增强中,可以定一个参数,代表需要处理切入的点
     */
    @Around("execution(* com.java.ym.service.impl.MasterServiceImpl.*(..))")
    public void around(ProceedingJoinPoint point) throws Throwable {
        System.out.println("环绕前");

        //  执行方法
        Object proceed = point.proceed();
        System.out.println("环绕后");
    }
}

配置applicationContext.xml

<?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: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/aop
        http://www.springframework.org/schema/aop/spring-aop.xsd">

    <bean id="masterService" class="com.java.ym.service.impl.MasterServiceImpl"></bean>
    
<!--    方法三-->
    <bean id="annotate" class="com.java.ym.diy.Annotate"></bean>
    <!--    开启注解 jdk(默认)proxy-target-class="false"  如果改为true就会使用cglib实现 (结果一样)-->
    <aop:aspectj-autoproxy proxy-target-class="false"/>
</beans>

测试

import com.java.ym.service.MasterService;
import com.java.ym.service.impl.MasterServiceImpl;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * @Author: YuMi
 * @Date: 2020/10/9 11:32
 * ----------------------
 * @Comments:
 */
public class MyTest {
    public static void main(String[] args) {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
        //  动态代理,代理的是接口
        MasterService masterService = (MasterService) applicationContext.getBean("masterService");
        masterService.add();
    }
}

//	执行结果
环绕前
方法执行前***
增加
环绕后
方法执行后***

SpringAOP面向切面编程 横切关注点从每个方法中抽取出来的同一类非核心业务。在同一个项目中,我们可以使用多个横切关注点对相关方法进行多个不同方面的增强。有十个附加功能,就有十个横切关注点。AOP核心关注点和横切关注点。业务处理的主要流程是核心关注点,非核心代码是横切关注点。横切关注点的一个特点是,他们经常发生在核心关注点的多处,而各处基本相似,比如权限认证、日志、事务、异常等。AOP的作用在于分离系统中的各种关注点,将核心关注点和横切关注点分离开来。(分离核心业务代码与非核心代码通知(增强)每一个横切关注点。 阅读详情

相关推荐

vue3接入大华摄像头

┃ ┃ ┣ 📜PlaybackModal.vue 回放列表模态框。┃ ┃ ┗ 📜VideoGrid.vue 视频播放区域。┃ ┃ ┣ 📜ControlPanel.vue 控制面板。┃ ┃ ┣ 📜DeviceList.vue 设备列表。┃ ┣ 📂module //大华摄像头文件。

💻 专注 Vue 前端与 Java 后端技术 🌱 目前正在深入 Spring Boot、微服务与性能优化 📝 定期分享实战踩坑经验与学习笔记 🤝 欢迎交流,共同进步 857

spring注解:spring aop注解详解

AOP的基本概念、切面、切点、通知、环绕通知

weixin_37862824的博客 1万+

【软考中级网络工程师】知识点之常用网络诊断和配置命令

本文聚焦软考中级网络工程师必备的网络诊断和配置命令,详细解析 ipconfig、ping、arp 等 11 类核心命令。涵盖各命令的功能、语法、常用参数及应用场景,如 ipconfig 查看配置、ping 测试连通性等。还通过图呈现命令执行逻辑与流程,助读者理解原理。最后结合软考考点回顾重点并提供真题练习,为备考和实际运维提供全面指导,是掌握网络命令的实用参考。

邓邓子的博客 1389

SpringAOP系列--将类上的注解作为切点(用@Pointcut)

本文介绍SpringSpringBoot)的AOP的用法:自定义注解,在Controller的类上使用此注解,然后在AOP中获得注解和方法的相关信息,并获取返回值信息。 本文使用@Pointcut+@Before+@AfterReturning。

IT利刃出鞘的博客 4772

AOP和动态代理之间的关系

1.什么是AOP AOP的全称是Aspect-Oriented Programming,即面向切面编程(也称面向方面编程)。它是面向对象编程(OOP)的一种补充,目前已成为一种比较成熟的编程方式。 在传统的业务处理代码中,通常都会进行事务处理、日志记录等操作。虽然使用OOP可以通过组合或者继承的方式来达到代码的重用,但如果要实现某个功能(如日志记录),同样的代码仍然会分散到各个方法中。这样,如果想...

qq_37745636的博客 9744

Spring AOP 中,切点有多少种定义方式?

这应该是是小伙伴们日常工作中使用最多的两种切点定义方式了。但是除了这两种还有没有其他的呢?今天松哥就来和大家聊一聊这个话题。

qq_21305943的专栏 1343

SpringAOP系列--将方法上的注解做为切点(用@Around)

本文介绍SpringSpringBoot)的AOP的用法:自定义注解,在Controller的方法上使用此注解,然后在AOP中获得注解的相关信息。 本文使用@Around。

IT利刃出鞘的博客 3521

面试必备:一文读懂Spring AOP面向切面编程

AOP,Aspect Oriented Programming,面向切面编程。在很多时候我们写一些功能的时候,不需要用到继承这么重的方法,例如对每个方法在执行前打log,在没有AOP的情况下,我们只能对每个方法都写一句打log的语句。如果是一个复杂点的功能,那么将会产生许多重复的代码,而且会对模块之间有更多的耦合。 然而,在AOP下,我们只需要通过特定的方法,就能直接切入代码,添加自定义的功能(后续再讲AOP里面的概念点)。 下面将从一个简单的示例入手,拆解示例的内容,通过源码分析,一步步带大家...

Java烂猪皮 390

Spring AOP 面向切面编程

Spring AOP(Aspect-Oriented Programming,面向切面编程)是Spring框架中的一个核心功能,用于在应用程序中实现横切关注点(cross-cutting concerns)的模块化。在传统的面向对象编程(OOP)中,横切关注点(如日志记录、性能监控、事务管理、安全控制等)往往散布在整个代码库中,导致代码的复用性和可维护性下降。AOP提供了一种将这些关注点从它们所服务的业务逻辑中分离出来的方式。切面(Aspect)切面是描述横切关注点的模块。它封装了影响多个类的行为。

zhzjn的博客 1878

AOP面向切面编程

本文介绍了Spring AOP的基本概念和应用。AOP面向切面编程)是一种横向切割关注点的编程范式,用于解耦日志、事务等横切关注点。文章对比了Spring AOP和AspectJ框架的特点,Spring AOP基于动态代理实现,AspectJ则更强大但复杂。详细讲解了AOP核心术语(切面、切入点、通知等)和五种通知类型的使用方法,包括前置、后置、环绕等通知。通过一个简单案例演示了AOP的实际应用,展示了如何在不修改原有代码的情况下增强方法功能。

xg_960的博客 1589

Spring——面向切面编程(AOP)

本文介绍了切向切面编程(AOP)中的各个概念,并用两个案例分别讲解了如何通过注解和XML配置的方式使用AOP

行者无疆的博客 4330

Spring AOP面向切面编程

面向切面编程是希望能够将通用需求功能从不相关的类当中分离出来,能够使得很多类共享一个行为,一旦发生变化,不必修改很多类,而只是修改这个行为即可。AOP通过提供另一种思考程序结构的方式来补充了面向对象编程(OOP)。OOP中模块化的基本单元是类(class),而AOP中模块化的基本单元是切面(aspect)。可以这么理解,OOP是解决了纵向的代码复用问题,AOP是解决了横向的代码复用问题。Spring的关键组件之一是AOP框架。

深入Java世界:探索编程之美与技术深度 1010

Spring核心思想之—AOP面向切面编程

IoC概述(详情)AOP:Aspect Oriented Programming (面向切面编程)什么是切面编程呢?切面编程指的是某一类特定问题 所以AOP也可以理解为面向特定方法编程。什么是面向特定方法编程呢?统一功能处理之拦截器、统一数据返回格式、统一异常处理这类的问题的统一处理, 所以拦截器也是AOP的一种应用, AOP是一种思想, 拦截器就是AOP思想的一种实现,. Spring框架实现了这种思想, 提供了拦截器技术的相关接⼝。同样统一数据返回格式、统一异常处理 都是AOP思想的一种实现。

2401_83177222的博客 1295

使用注解作为AOP的切入点(@Pointcut)

修改代码:把注解移到mapper接口中的方法。(因为@mapper注释了mapper接口,这个@mapper注解会被用于spring和mybatis链接的@MapperScan扫描)检查代码发现,如果你使用的是 controller->service->mapper 在接口中定义的方法添加。,我们的aop在容器中找注解时会找不到,因为service接口没有注入到spring ioc中。在使用aop的注解切入时…为什么aop没有生效?

nidimyger的博客 1155

面试中关于Spring AOP和代理模式的那些事

我们知道,SpringAOP 是一大核心技术,也是面试中经常会被问到的问题,最近我在网上也看到很多面试题,其中和 Spring AOP 相关的就有不少,这篇文章主要来总结下相关的技术点,希望对大家有用。 0. 几个常见的问题 针对这一块的东西,一般下面几个问题面试官问的比较多: Spring AOP用的是哪种设计模式? 谈谈你对代理模式的理解? 静态代理和动态代理有什么区别? 如何实现动态...

1万+

java代理与aop理解

目录 一、代理 1、静态代理 2、JDK动态代理 3、CGLIB代理 4、代理模式和装饰器模式的区别 二、aop与动态代理的关系 按照代理类的创建时期,可分为静态代理和动态代理: 静态:由程序员创建代理类或特定工具自动生成源代码再对其编译。在程序运行前代理类的.class文件就已经存在了。 动态:在程序运行时运用反射机制动态创建而成。在程序运行前不存在代理类。 一、代理 1、静态代理 public interface Flyable { void fly(long m.

Cxf007200的博客 482

SpringAOP系列--将类上的注解作为切点(用@Before)

本文介绍SpringSpringBoot)的AOP的用法:自定义注解,在Controller的类上使用此注解,然后在AOP中获得注解的相关信息。 本文使用@Before。

IT利刃出鞘的博客 2923

动态代理与SpringAOP

1.动态代理与SpringAOP的关系 动态代理其实就是用InvocationHandler接口和Proxy类来实现的一种代理模式 SpringAOP面向切面编程,它对 AOP 进⾏了封装,使用面向对象的思想来实现,所以AOP的底层是用动态代理实现的 2. java中的动态代理 java中提供了一个InvocationHandler接口,用来继承实现动态代理 public interface InvocationHandler { public Object invoke(Object proxy,

qq_43564410的博客 796

细说Spring——AOP详解和动态代理

在软件业,AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期间动态代理实现程序功能的统一维护的一种技术。AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。

m0_68758365的博客 1618

河南省四大流域一二级流域树gis矢量shp数据,包含:1、四大流域的树结构数据库表 2.用于渲染各流域范围的gis矢量数据,包括合并版本和拆分版本

数据预览地址:https://blog.csdn.net/yinchoushi8780/article/details/156909188W全流域一级流域:WC海河流域WD黄河流域WE淮河流域WF长江流域二级流域:WCF漳卫南运河水系WCG徒骇、马颊河水系WDA黄河主干水系WDA黄河干流水系WDA金堤河水系WDA沁河水系WDA伊洛河水系WEA淮干水系WEA淮河干流水系WEA洪汝河水系WEB沂沭泗水系WEA2沙颍河水系WFA长江干流水系WEA3涡惠河水系WFG汉江水系WFG3唐白河水系WFG2丹江水系WCF10漳河WCF11卫河WCG10马颊河WCG11徒骇河WFA03长江

上一篇: IDEA简单操作Spring-MyBatis整合
下一篇: IDEA简单概述操作Spring注解Component
Mr_YuMi
博客等级 码龄7年 37粉丝 20原创
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值