2024年9月26日--- Spring-AOP

SpringAOP

在学习编程过程中,我们对于公共方法的处理应该是这样的一个过程,初期阶段如下

f1(){Date now = new Date();System.out.println("功能执行之前的各种前置工作"+now)//...功能代码//...功能代码System.out.println("功能执行之前的各种后置工作")
}
​
f2(){System.out.println("功能执行之前的各种前置工作")//...功能代码//...功能代码System.out.println("功能执行之前的各种后置工作")
}
.....

然后中期阶段,我们学会了封装

public class AspectConfig{static void before(){System.out.println("功能执行之前的各种前置工作")}static void after(){System.out.println("功能执行之前的各种后置工作")}
}   
AspectConfig.before()
f1()
AspectConfig.after()AspectConfig.before()---切面--  块  -份--模块
f2()
AspectConfig.after()

现在,我们可以采用另外一种更简单的方式,AOP思想,对代码进行无侵入式实现,这样更高级了。

public class AspectConfig{@express(*f*)static void before(){System.out.println("功能执行之前的各种前置工作")}//@expres(*f*)static void after(){System.out.println("功能执行之前的各种后置工作")}
}   
m(){f1()
}
n(){f2()
}

1.1 AOP思想概述

1.1.1 思想简介

AOP(Aspect Oriented Programming)意为:面向切面编程,它是一种思想,是对某⼀类事情的集中处理。

它的核心思想是 将方法在执行过程中切分为多个部分,也就是多个横切关注点,这样可以与业务逻辑代码分离开来,使代码模块化,进而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。

AOP是OOP(面向对象编程)的一个补充,它允许开发者以声明方式实现关注点,而不是通过在业务逻辑代码中散布大量重复代码。

1.1.2 AOP的实现方式

AOP 可以通过多种方式实现,包括:

  • 编译时增强:在编译期间通过修改字节码来实现AOP。

  • 类加载时增强:在类加载到JVM时通过字节码操作实现AOP。

  • 动态代理:在程序运行时,通过代理对象来实现AOP。

1.1.3 AOP的应用场景

1)日志记录

2)声明式事务管理

3)登录安全验证

4)统一异常处理

1.1.3 AOP中的核心概念

1)横切关注点

在程序中,可以跨越多个模块的方法或功能。即是,与我们业务逻辑无关的,但是我们需要关注的部分,就是横切关注点。如日志 , 安全 , 缓存 , 事务等等 … 简单来说,就是程序员要关注的事情,抽象概念

2)切面(Aspect)

横切关注点被模块化的一个体现,它是一个类。这个类由通知(Advice)和切点(Pointcut)组成,既包含了横切逻辑的定义,也包含了连接点的定义。

3)通知(Advice)

通知,实际上是一个拦截器,它定义了切面是做什么以及何时使用,即在某个特定的连接点上执行的动作,它是切面的具体实现

以目标方法为参照点,根据放置位置的地方不同,通知分为如下5种类型通知:

  • 前置通知(Before):在方法执行前执行。

  • 后置通知(After):在方法执行后执行。

  • 返回通知(After Returning):在方法成功返回后执行。

  • 异常通知(After Throwing):在方法抛出异常后执行。

  • 环绕通知(Around):包围方法执行的前后。

4)切入点(PointCut)

Advice 执行的 “地点”的定义。 简单理解:就是用来定义位置

5)连接点(JointPoint)

与切入点匹配的执行点。这个点可以是方法调用时,抛出异常时,甚至修改字段时。切面代码可以利用这些点插入到应用的正常流程之中,并添加新的行为。 简单理解:就是具体切入的位置

6)目标(Target)

就是被切面作用的对象,包含连接点的对象

1.2 Spring AOP简介

AOP是一个思想,是一个编程范式。SpringAOP是对这个思想的实现。

Spring AOP 是构建在动态代理基础上的。因此 Spring 对 AOP 的⽀持局限于⽅法级别的拦截。 Spring AOP ⽀持 JDK ProxyCGLIB ⽅式实现动态代理。默认情况下,实现了接⼝的类,使⽤ AOP 会基于 JDK ⽣成代理类,没有实现接⼝的类,会基于 CGLIB ⽣成代理类。

织⼊(Weaving):代理的⽣成时机

织入就是什么时候把代理的代码放进运行的代码中。在⽬标对象的⽣命周期⾥有多个点可以进⾏织⼊:

编译期(编译阶段):

切⾯在⽬标类编译时被织⼊。这种⽅式需要特殊的编译器。AspectJ的织⼊编译器就 是以这种⽅式织⼊切⾯的。

类加载期:

切⾯在⽬标类加载到JVM时被织⼊。这种⽅式需要特殊的类加载器 (ClassLoader),它可以在⽬标类被引⼊应⽤之前增强该⽬标类的字节码。AspectJ5的加载 时织⼊(load-time weaving. LTW)就⽀持以这种⽅式织⼊切⾯。

运⾏期:

切⾯在应⽤运⾏的某⼀时刻被织⼊。⼀般情况下,在织⼊切⾯时,AOP容器会为⽬标对象动态创建⼀个代理对象。SpringAOP就是以这种⽅式织⼊切⾯的。

1.3 XML配置方式

1.3.1 导入依赖

<dependency><groupId>org.aspectj</groupId><artifactId>aspectjweaver</artifactId><version>1.9.4</version>
</dependency>

1.3.2 案例1

UserService.java

public interface UserService {void add();void delete();void update();void search();
}

UserServiceImpl.java

public class UserServiceImpl implements UserService{@Overridepublic void add() {System.out.println("---增加用户---");}
​@Overridepublic void delete() {System.out.println("---删除用户---");}
​@Overridepublic void update() {System.out.println("---修改用户---");}
​@Overridepublic void search() {System.out.println("---查询用户---");}
}
​

编写两个通知类型,一个前置通知,一个后置通知

import org.springframework.aop.MethodBeforeAdvice;
import java.lang.reflect.Method;
public class Log implements MethodBeforeAdvice {/**** @param method    目标对象的方法* @param objects   被调用的方法的参数* @param o             目标对象* @throws Throwable*/@Overridepublic void before(Method method, Object[] objects, Object o) throws Throwable {System.out.println(o.getClass().getName()+"的"+method.getName()+"正在执行····");}
}
import org.springframework.aop.AfterReturningAdvice;
import java.lang.reflect.Method;
​
public class AfterLog implements AfterReturningAdvice {/**** @param o             方法的返回值* @param method        目标对象的方法* @param objects       目标对象的方法的参数* @param o1            目标对象* @throws Throwable*/@Overridepublic void afterReturning(Object o, Method method, Object[] objects, Object o1) throws Throwable {System.out.println("执行了"+o1.getClass().getName()+"的"+method.getName()+"方法," +"返回值:"+o);}
}

注册bean,实现aop切入 , 注意导入约束

<?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/beanshttp://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">
​<!--注册--><bean id="userService" class="com.shuilidianli.service.UserServiceImpl"></bean><bean id="log" class="com.shuilidianli.aop.Log"></bean><bean id="afterLog" class="com.shuilidianli.aop.AfterLog"></bean>
​<!--aop配置--><aop:config><!--切入点 expression: 表达式匹配要执行的方法--><aop:pointcut id="pointcut" expression="execution(* com.shuilidianli.service.UserServiceImpl.*(..))"/><!--执行环绕:advice-ref执行方法,pointcut-ref:切入点--><aop:advisor advice-ref="log" pointcut-ref="pointcut"/><aop:advisor advice-ref="afterLog" pointcut-ref="pointcut"/></aop:config>
</beans>
​

测试

import com.shuilidianli.service.UserService;
import com.shuilidianli.web.EmpController;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
​
public class AopTest2 {@Testpublic void test1(){ApplicationContext ctx =new ClassPathXmlApplicationContext("beans.xml");UserService us =(UserService) ctx.getBean("userService");us.search();
​}
}

测试结果:

Aop的重要性 : 很重要 . 一定要理解其中的思路 , 主要是思想的理解这一块 .

Spring的Aop就是将公共的业务 (日志 , 安全等) 和领域业务结合起来 , 当执行领域业务时 , 将会把公共业务加进来 . 实现公共业务的重复利用 . 领域业务更纯粹 , 程序员专注领域业务 , 其本质还是动态代理

1.3.2 案例2

自定义类来实现Aop

目标业务类不变依旧是userServiceImpl

1)自己定义一个切入类

package com.shuilidianli.aop;
​
public class DiyPointcut {public void before(){System.out.println("---------方法执行前---------");}public void after(){System.out.println("---------方法执行后---------");}
}

2)注册配置

<!--第二种方式自定义实现-->
<!--注册bean-->
​
<bean id="diy" class="com.shuilidianli.aop.DiyPointcut"></bean>
<!--aop的配置-->
<aop:config><!--第二种方式:使用AOP的标签实现--><aop:aspect ref="diy"><aop:pointcut id="diyPointcut" expression="execution(* com.shuilidianli.service.UserServiceImpl.*(..))"/><aop:before method="before" pointcut-ref="diyPointcut"/><aop:after method="after" pointcut-ref="diyPointcut"/></aop:aspect>
</aop:config>

3)测试

package com.shuilidianli.test;
​
import com.shuilidianli.service.UserService;
import com.shuilidianli.web.EmpController;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
​
public class AopTest2 {@Testpublic void test1(){ApplicationContext ctx =new ClassPathXmlApplicationContext("beans.xml");UserService us =(UserService) ctx.getBean("userService");us.search();
​}
}

测试结果:

1.4 注解方式

1.4.1 导入依赖,开启注解扫描

<dependency><groupId>org.aspectj</groupId><artifactId>aspectjweaver</artifactId><version>1.9.4</version>
</dependency>
<context:component-scan base-package="com"/>
​
<!-- 开启aop组件注解扫描 -->
<aop:aspectj-autoproxy proxy-target-class="true"></aop:aspectj-autoproxy>

aop:aspectj-autoproxy:说明

通过aop命名空间的<aop:aspectj-autoproxy />声明自动为spring容器中那些配置@aspect切面的bean创建代理,织入切面。
​
当然,spring 在内部依旧采用AnnotationAwareAspectJAutoProxyCreator进行自动代理的创建工作,但具体实现的细节已经被<aop:aspectj-autoproxy />隐藏起来了
​
<aop:aspectj-autoproxy />有一个proxy-target-class属性,默认为false,表示使用jdk动态代理织入增强,
​
当配为<aop:aspectj-autoproxy  poxy-target-class="true"/>时,表示使用CGLib动态代理技术织入增强。
​
不过即使proxy-target-class设置为false,如果目标类没有声明接口,则spring将自动使用CGLib动态代理。
​

1.4.2 切入点表达式语法

1)语法如下:

"execution(修饰词 返回值类型 类全限定名.方法名(形参列表) 异常)"public int f1(int a,int b)throw Exception{}

2)Spring AOP的切入点表达式非常灵活,支持模糊配置。

eg1 : execution(* 全类名.*(..))第一个 "*" 表示支持任意修饰符及返回值类型;第二个 "*" 表示支持该类中的任意方法;形参列表中的".."则表示可以匹配任意数量和类型的参数。(PS : 若目标类、接口与当前切面类在同一个包下,可以省略包名,只写类名)
​
eg2 : execution(public * 全类名.*(..))表示支持该类中的所有公有的方法
​
eg3 : execution(public double 全类名.*(..))表示支持该类中所有公有的且返回值为double的方法
​
eg4 : execution(public double 全类名.*(double, ..))表示支持该类中所有形参列表第一个参数为double类型,且后续参数可以是任意数量任意类型的,公有的返回值为double的方法。
​
eg5 : execution(double 全类名.*(double, double)表示支持该类中所有形参列表为两个double类型,公有的且返回值为double类型的方法。

3) 在AspectJ(另一个框架)中,切入点表达式可以通过"&&","||","!"等操作符结合起来。

eg : execution(* *.add(int, ..)) || execution(* *.subtract(int, ..))——表示支持任意类中的任意访问修饰符和任意返回值类型的,且形参列表第一个参数为int类型的add 或 subtract方法。

4)注意事项:

(1) 当切入点表达式直接指向了接口某个实现类的方法(非实现类特有方法),这时切入点表达式仅会对该实现类生效(动态代理 + 反射),即接口的其他实现类不会生效(不会得到代理对象,即使你以接口类型作为接收)。
​
(2) 当切入点表达式指向接口的方法时,切入表达式会对该接口的所有实现类生效。
​
(3) 切入点表达式也可以切入到没有实现接口的类的横切关注点中。(CGlib动态代理模式)
​
PS : JDK Proxy动态代理和CGlib动态代理的区别
​
- JDK动态代理是面向接口的,只能增强实现类中重写了接口中的方法。而CGlib是面向父类的,可以增强父类的所有方法。
- JDK得到的对象是JDK代理对象实例,而CGlib得到的对象是被代理对象的子类。

1.4.3 案例3

AnnotationPointcut.java

package com.shuilidianli.aop;
​
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;
import org.springframework.stereotype.Component;
​
@Component
@Aspect
public class AnnotationPointcut {@Before("execution(* com.shuilidianli.service.UserServiceImpl.*(..))")public void before(){System.out.println("---------方法执行前---------");}@After("execution(* com.shuilidianli.service.UserServiceImpl.*(..))")public void after(){System.out.println("---------方法执行后---------");}@Around("execution(* com.shuilidianli.service.UserServiceImpl.*(..))")public void around(ProceedingJoinPoint joinPoint) throws Throwable {System.out.println("---环绕前---");System.out.println("调用的方法:"+joinPoint.getSignature());//执行目标方法Object proceed = joinPoint.proceed();System.out.println("---环绕后---");System.out.println(proceed);}
}
​

测试: 注意给UserServiceImpl添加注解

package com.shuilidianli.test;
​
import com.shuilidianli.service.UserService;
import com.shuilidianli.web.EmpController;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
​
public class AopTest2 {@Testpublic void test1(){ApplicationContext ctx =new ClassPathXmlApplicationContext("beans.xml");UserService us =(UserService) ctx.getBean("userServiceImpl");us.search();
​}
}
​

测试结果:

1.4.4 案例4

1)EmpController.java

package com.sldl.controller;
​
import org.springframework.stereotype.Controller;
​
@Controller   //添加Bean注解
public class EmpController {
​public void findAll(){System.out.println("---正在查询所有员工信息---");}
​public void addEmp(){System.out.println("---正在添加一个员工信息---");String str = null;System.out.println(str.length());}
}
​

2)Operation.java

package com.sldl.log;
​
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
​
@Component   // 添加Bean注解
@Aspect      // 添加Aop注解
public class OperationLog {//后置通知注解@After("within(com.sldl.controller..*)")public void log(){System.out.println("记录日志");}//环绕通知注解@Around("within(com.sldl.controller..*)")public Object log1(ProceedingJoinPoint p) throws Throwable{//获取目标组件的名字String className = p.getTarget().getClass().getName();//获取目标组件里执行的方法名String methodName = p.getSignature().getName();System.out.println("------------");//执行目标组件Object obj = p.proceed();System.out.println("xxx正在执行"+className+"里的"+methodName+"方法");return obj;}//异常抛出通知@AfterThrowing(pointcut="within(com.sldl.controller..*)",throwing="e")public void log2(Exception e){System.out.println(e.toString());StackTraceElement[] eles =e.getStackTrace();System.out.println(eles[0]);System.out.println(eles[1]);}
}
​

3)beans.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:context="http://www.springframework.org/schema/context"xmlns:aop="http://www.springframework.org/schema/aop"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://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.sldl"/>
​<!--开启AOP注解扫描--><aop:aspectj-autoproxy proxy-target-class="true"/>
​
</beans>

4)AOPTest

package com.sldl.test;
​
import com.sldl.controller.EmpController;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
​
public class AOPTest {@Testpublic void test1(){ApplicationContext ctx =new ClassPathXmlApplicationContext("beans.xml");
​EmpController ec =ctx.getBean("empController", EmpController.class);
​//ec.findAll();ec.addEmp();
​}
}

测试结果:

1.4.5 多个通知的执行顺序

五个通知都有的情况下,先后执行顺序

  1. 一定限制性环绕前一步:

  2. 再执行前置通知

  3. 目标方法

  4. 环绕通知的后一部分

  5. 在执行后置通知

  6. 在执行返回通知

  7. 最后执行异常通知

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/436444.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

vue3使用Teleport 控制台报警告:Invalid Teleport target on mount: null (object)

Failed to locate Teleport target with selector “.demon”. Note the target element must exist before the component is mounted - i.e. the target cannot be rendered by the component itself, and ideally should be outside of the entire Vue component tree main.…

OpenStack Yoga版安装笔记(十五)Horizon安装

1、官方文档 OpenStack Installation Guidehttps://docs.openstack.org/install-guide/ 本次安装是在Ubuntu 22.04上进行&#xff0c;基本按照OpenStack Installation Guide顺序执行&#xff0c;主要内容包括&#xff1a; 环境安装 &#xff08;已完成&#xff09;OpenStack…

ndb9300public-ndb2excel简介

1 引言 ndb9300是一个自己定义的机载导航数据库劳作&#xff08;不敢称为项目&#xff09;代号&#xff0c;其中3表示是第3种数据库。 多年前&#xff0c;对在役民航客机中的某型机载导航数据库的二进制文件进行分析&#xff0c;弄明白它的数据结构后做了几个工具&#xff0c…

仿真设计|基于51单片机的土壤温湿度监测及自动浇花系统仿真

目录 具体实现功能 设计介绍 51单片机简介 资料内容 仿真实现&#xff08;protues8.7&#xff09; 程序&#xff08;Keil5&#xff09; 全部内容 资料获取 具体实现功能 &#xff08;1&#xff09;DS18B20实时检测环境温度&#xff0c;LCD1602实时显示土壤温湿度&…

<使用生成式AI对四种冒泡排序实现形式分析解释的探讨整理>

<使用生成式AI对四种冒泡排序实现形式分析解释的探讨整理> 文章目录 <使用生成式AI对四种冒泡排序实现形式分析解释的探讨整理>1.冒泡排序实现形式总结1.1关于冒泡排序实现形式1的来源&#xff1a;1.2对四种排序实现形式使用AI进行无引导分析&#xff1a;1.3AI&…

正交阵的概念、性质与应用

正交阵是线性代数中一种重要的特殊矩阵&#xff0c;它在很多领域都有广泛的应用。 1. 概念 一个实数方阵 Q 被称为正交阵&#xff0c;如果它的转置等于它的逆矩阵&#xff1a; 这意味着&#xff1a; 其中&#xff0c;Q T 表示矩阵 Q 的转置&#xff0c;I 表示单位矩阵。 2…

Linux:磁盘管理

一、静态分区管理 静态的分区方法不可以动态的增加或减少分区的容量。 1、磁盘分区-fdisk 该命令是用于查看磁盘分区情况&#xff0c;和分区管理的命令 命令格式&#xff1a;fdisk [选项] 设备文件名常用命令&#xff1a; -h&#xff1a;查看分区信息 fdisk系统常用命令&…

GIT安装及集成到IDEA中操作步骤

最近深感GIT使用技能太差&#xff0c;我只会些皮毛&#xff0c;还是得看官网&#xff0c;总结一下常用的操作方法吧。 GIT环境配置到IDEA中安装 一、GIt的基本的安装 这个不在这里赘述了&#xff0c;自己装一个git吧 二、给IDEA指定本地GIT的安装路径 1、下图这个是我本地的…

05-函数传值VS传引用

函数传值 一、没法改变值的方式&#xff1a; 一个变量拷贝到另一个变量, 这种形式的函数调用被称为: 传值调用 局部变量的生命周期在函数的运行期间会一直存在. void Increment(int a)//假设一个 x(只是为了验证实参会被映射到形参这件事情),a的值会被拷贝到x {a a 1; //1…

vscode开发uniapp安装插件指南

安装vuets的相关插件 首先是vue的相关插件&#xff0c;目前2024年9月应该是vue-offical 安装uniapp开发插件 uni-create-view &#xff1a;快速创建 uni-app 页面 安装uni-create-view之后修改插件拓展设置 勾选第一个选择创建视图时创建同名文件夹 选择第二个创建文件夹中生…

【RockyLinux 9.4】安装新版 QQ for Linux(不再是 QQ2008 那种老款了!)

总览 还记得两年之前的时候&#xff0c;当初用的还是那种 QQ2008 一样的 LinuxQQ 啥也干不了&#xff0c;还不如 QQ2008 最近寻思自己装个服务器玩&#xff0c;想下载一个 QQ 用来文件传输&#xff0c;没想到现在的 QQ Linux 这么棒&#xff01; 一、下载 1.下载网址 https…

神经网络激活函数

神经网络的激活函数&#xff08;Activation Function&#xff09; 神经网络可以用在分类问题和回归问题上&#xff0c;不过需要根据情况改变输出层的激活函数。一般而言&#xff0c;回归问题用恒等函数&#xff0c;分类问题用softmax函数。 神经网络的激活函数必须使用非线性函…

Trilium Notes笔记本地化部署与简单使用指南打造个人知识库

文章目录 前言1. 安装docker与docker-compose2. 启动容器运行镜像3. 本地访问测试4.安装内网穿透5. 创建公网地址6. 创建固定公网地址 前言 今天和大家分享一款在G站获得了26K的强大的开源在线协作笔记软件&#xff0c;Trilium Notes的中文版如何在Linux环境使用docker本地部署…

828华为云征文 | 利用FIO工具测试Flexus云服务器X实例存储性能

目录 一、Flexus云服务器X实例概要 1.1 Flexus云服务器X实例摘要 1.2 产品特点 1.3 存储方面性能 1.4 测评服务器规格 二、FIO工具 2.1 安装部署FIO 2.2 主要性能指标概要 三、进行压测 3.1 测试全盘随机读IO延迟 3.2 测试全盘随机写IO延迟 3.3 测试随机读IOPS 3.4…

基于Leaflet和天地图的细直箭头和突击方向标绘实战

目录 前言 一、细直箭头和突击方向的类设计 1、总体类图 2、对象区别 二、标绘绘制的具体实现 1、绘制时序图 2、相关点的具体绘制 3、最终的成果 三、总结 前言 今天是10月1日国庆节&#xff0c;迎来我们伟大祖国75周年的华诞。有国才有家&#xff0c;在这里首先祝我们…

详细整理!!html5常用标签

文章目录 前言一、HTML简介1.HTML文件结构2.各标签意义 二、HTML标签介绍1.标题标签2.段落标签3. 换行标签4.hr标签5. span标签6.div标签7.img标签8.超链接标签9.注释标签10.空格11.格式化标签12.sup上标和sub下标13. pre预格式化标签14.table 表格标签table 标签基础内容合并单…

在Java中使用GeoTools解析POI数据并存储到PostGIS实战

目录 前言 一、POI数据相关介绍 1、原始数据说明 2、空间数据库表设计 二、POI数据存储的设计与实现 1、对应的数据模型对象的设计 2、属性表数据和空间信息的读取 3、实际运行结果 三、总结 前言 POI点&#xff0c;全称为Point of Interest&#xff08;兴趣点&#xf…

MySQL基础篇 part1

为什么使用数据库和数据库基本概念 想在vscode用markdown了&#xff0c;为什么不直接拿pdf版本呢&#xff1f; DB:数据库(Database) 即存储数据的“仓库”&#xff0c;其本质是一个文件系统。它保存了一系列有组织的数据。 DBMS:数据库管理系统(Database Management System)…

YOLO11震撼发布!

非常高兴地向大家介绍 Ultralytics YOLO系列的新模型&#xff1a; YOLO11&#xff01; YOLO11 在以往 YOLO 模型基础上带来了一系列强大的功能和优化&#xff0c;使其速度更快、更准确、用途更广泛。主要改进包括 增强了特征提取功能&#xff0c;从而可以更精确地捕捉细节以更…

二维环境下的TDOA测距定位的MATLAB代码,带中文注释

TDOA测距定位程序介绍 概述 本MATLAB程序实现了基于时间差到达&#xff08;TDOA&#xff09;技术的二维测距定位&#xff0c;能够处理4个或任意数量&#xff08;大于3个&#xff09;的锚节点。在无线定位和导航系统中&#xff0c;TDOA是一种常用的定位方法&#xff0c;通过测量…