Spring Aop及事务管理

5 Spring AOP

AOP概述

    AOP:全称是 Aspect Oriented Programming 即:面向切面编程。简单的说它就是把我们程序重复的代码抽取出来,在需要执行的时候,使用动态代理的技术,在不修改源码的基础上,对我们的已有方法进行增强。
    Aop的作用:在程序运行期间,不修改源码对已有方法进行增强。
    Aop优势:减少重复代码、提高开发效率、维护方便
    AOP的实现方式:使用动态代理技术

Spring AOP常用术语

Joinpoint( 连接点)

所谓连接点是指那些被拦截到的点。在 spring 中,这些点指的是方法,因为 spring 只支持方法类型的连接点。即实际增强功能的方法

Pointcut( 切入点)

所谓切入点是指我们要对哪些 Joinpoint 进行拦截的定义。一个类中所有的方法都可以是切入点,Spring Aop中切入点只能是方法。所以我么你可以把切入点理解成:目标对象里面所有的方法都称为切入点

Advice( 通知/ 增强)

Advice可以翻译成通知,也有人称为增强。所谓通知是指拦截到 Joinpoint 之后所要做的事情就是通知。即我们要给目标方法实际提供的增强代码就是增强。

那么根据增强代码书写的位置不同,增强可以分为以下几类:

前置通知,后置通知,异常通知,最终通知,环绕通知。

Target( 目标对象)

 要被增强功能的对象就是目标对象。

Proxy(代理)

一个类被 AOP 织入增强后,就产生一个结果代理类。

Aspect( 切面)

Aspect称为切面。切面是切入点和增强的结合。通过代码会发现,增强功能所在的类称为切面类,里面配置的是增强和切入点的都是切面

案例:Spring AOP

  • pom.xml引入AOP的依赖

    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-aspects</artifactId>
        <version>5.2.25.RELEASE</version>
    </dependency>
    
  • 定义目标对象

    @Component
    public class Calculator {
        public int add(int num1,int num2){
            int sum = num1 + num2;
            return sum;
        }
        public int div(int num1,int num2){
            int sum = num1 / num2;
            return sum;
        }
    }
    
  • 定义切面类,增强功能所在的类称为切面类

    @Component
    @Aspect //切面
    public class LoggerAdvice {
        public void before(){
            System.out.println("xxx方法被调用了,传入的参数是:...");
        }
        public void after(){
            System.out.println("xxx方法执行完毕了,执行结果是:...");
        }
        public void afterThrowing(){
            System.out.println("xxx方法被执行出错了,出现的异常是:...");
        }
    }
    
  • 指定通知类型,通知就是指实际要增强的代码

    @Component
    @Aspect //切面
    public class LoggerAdvice {
        //指定增强代码实际织入位置:切入点代码执行前
        //    @Before(一个程序中有N个类,具体想给哪些类做增强) //定义切入点
        @Before("execution(* com.woniu.demo.Calculator.add(int,int))")
        public void before(){
            System.out.println("xxx方法被调用了,传入的参数是:...");
        }
    
        //指定增强代码实际织入位置:切入点代码执行后
        @AfterReturning("execution(* com.woniu.demo.Calculator.add(int,int))")
        public void after(){
            System.out.println("xxx方法执行完毕了,执行结果是:...");
        }
    
        //指定增强代码实际织入位置:切入点代码执行出错时
        @AfterThrowing("execution(* com.woniu.demo.Calculator.add(int,int))")
        public void afterThrowing(){
            System.out.println("xxx方法被执行出错了,出现的异常是:...");
        }
    }
    
  • 在Spring的配置类上开启spring aop的代理模式,并选择代理方式
    @Configuration //通知spring容器,这个类与别的类不一样,是一个配置类,用于初始化spring容器的一个类

    @ComponentScan(basePackages = {"com.woniu.dao","com.woniu.service","com.woniu.controller","com.woniu.target"}) 
    @EnableAspectJAutoProxy(proxyTargetClass = true) //开启aop代理 proxyTargetClass选择代码模式true:cglib false:jdk代理
    public class SpringConfig {
    }
    

    proxyTargetClass默认值是false,代表的是如果目标类是有接口的使用jdk的proxy代理,如果没有接口使用cglib;如果将proxyTargetClass设置为true,那么不管目标类是实现了接口,都会使用cglib进行代理。

  • 测试代理对象,观察增强功能是否增强成功

    //1.通知测试类,使用的spring的测试
    @RunWith(SpringJUnit4ClassRunner.class)  //通知测试类基于spring提供的单元测试
    //注解里面赋值,省略属性名,属性值赋值value,class指定配置类的字节码
    @ContextConfiguration(classes = SpringConfig.class)//指定测试时,基于哪个spring的配置文件测试
    public class MySpringTester {
        @Autowired
        private Calculator calculator; //最终注入时就是代理对象
        @Test //java的junit框架提供的注解
        public void test03(){
            //输出:class com.woniu.demo.Calculator$$EnhancerBySpringCGLIB$$d89ada67
            System.out.println(calculator.getClass());
            calculator.add(1,1);
        }
    }
    

    测试效果如下所示:
    在这里插入图片描述

在 spring 中,框架会根据目标类是否实现了接口来决定采用哪种动态代理的方式。

切入点表达式【会读会用】

语法:
execution( [权限修饰符] 返回值类型 包名.类名.方法名(参数列表) )
举例:
    execution(public int com.woniu.Calculator.div(int,int))
    简化
    execution(int com.woniu.Calculator.div(int,int))
提示:
    语法中出现[]包裹的内容都是可选的

常见的切入点案例

1. execution(public * *(..)) 所有的public的方法

2. execution(* com.spring.aop.*(..))所有的aop包下的所有类的方法(不包含子包) 

3. execution(* com.spring.aop..*(..))所有的aop包及其子包下的所有类的方法.
  切入点表达式:execution(* com.woniu..*(..))  *表示返回值类型、类名、方法名不限  (..)参数列表不限制

4. execution(* com.spring.aop.IOrderService.*(..))IOrderService接口中定义的所有方法

5. execution(* com.spring.aop.IOrderService+.*(..))匹配实现特定接口所有类的方法 IOrderService
 IOrderService+ 举例:IOrderService1 IOrderServiceImpl 不能匹配IOrderService   
 IOrderService* 举例:IOrderService1 IOrderServiceImpl 匹配IOrderService   

6. execution(* save*(..))去匹配所有以save开头的方法 save save1 save2

AOP增强分类

前置通知@Before

作用 用于配置前置通知。指定增强的方法在切入点方法之前执行
属性:
    method:用于指定通知类中的增强方法名称
    ponitcut-ref:用于指定切入点的表达式的引用
    poinitcut:用于指定切入点表达式
执行时间点: 切入点方法执行之前执行

后置通知@AfterReturning

作用:用于配置后置通知
属性:
    method:指定通知中方法的名称。
    pointct:定义切入点表达式
    pointcut-ref:指定切入点表达式的引用
执行时间点:切入点方法正常执行之后。它和异常通知只能有一个执行

异常通知@AfterThrowing

作用:用于配置异常通知,切入点方法发生异常时才执行
    
属性:
    method:指定通知中方法的名称。
    pointcut:定义切入点表达式
    pointcut-ref:指定切入点表达式的引用
执行时间点:切入点方法执行产生异常后执行。它和后置通知只能执行一个

注意:目标行为只有抛出了异常之后才会执行这个增强方法

最终通知@After

作用:用于配置最终通知
属性:
    method:指定通知中方法的名称。
    pointct:定义切入点表达式
    pointcut-ref:指定切入点表达式的引用
执行时间点: 无论切入点方法执行时是否有异常,它都会在其后面执行。

无论是否有异常,最终通知都会执行

案例1:利用前置、后置、异常和最终增强完成日志管理

  • 目标类

    @Component
    public class Calculator implements ICalculator{
        public int sum(int num1,int num2){
            System.out.println("......目标方法sum执行");
            int sum = num1 + num2;
            return sum;
        }
        public int sub(int num1,int num2){
            int result = num1 - num2;
            return result;
        }
        public int plus(int num1,int num2){
            int result = num1 * num2;
            return result;
        }
        public int div(int num1,int num2){
            int result = num1 / num2;
            return result;
        }
    }
    
  • 切面类

    @Aspect 
    @Component
    public class LoggerAdvance {
        //抽取公共切入点
        @Pointcut("execution(* com.woniu.target..*(..))")
        public void myPointCut(){}
        /**
         *
         * @param jp 连接点,AOP实际增强功能的哪个方法 不用程序员传值,spring aop赋值
         */
        //前置增强(切入点表达式)
        @Before("myPointCut()")
        public void before(JoinPoint jp){
            //方法签名
            Signature signature = jp.getSignature();
            String methodName = signature.getName();
            //实参列表
            Object[] args = jp.getArgs();
            System.out.println(methodName+"方法被调用了,用户传入的参数分别是:"+ Arrays.toString(args));
        }
        /**
         *
         * @param jp
         * @param result @AfterReturning后置增强,用来接收即将返回的值,程序员不管,spring aop注入
         */
        @AfterReturning(value = "myPointCut()",returning = "result")//returning属性作用将方法执行结果注入程序员指定的参数中
        public void afterReturning(JoinPoint jp, Object result){
            System.out.println(jp.getSignature().getName()+"方法执行完毕,执行结果是:"+result);
        }
    
        /**
         * 异常增强,切入点方法执行出错时,实现的增强
         * @param e  用来保存spring aop做异常增强时,实际发生的异常对象
         */
        @AfterThrowing(value = "myPointCut()",throwing = "e")
        public void afterThrowing(JoinPoint jp,Throwable e){
            System.out.println(jp.getSignature().getName()+"执行出错啦,出现的错误是:"+e);
        }
    
        /**
         * 最终增强,切入点方法执行过程不管有没有异常,始终会执行的代码 finally{}中的代码
         */
        @After("myPointCut()")
        public void after(){
            System.out.println("无论代码是否出错,你都可以看到这行输出语句 释放哪些资源");
        }
    }
    
  • 测试代码

    @Autowired
    private ICalculator proxy; //代理对象 JDK:代理类 implements ICalculator  CGLIB extends Calculator
    @Test
    public void mt02(){
        proxy.div(12,0);
    }
    

使用@Pointcut注解定义公用切入点

在每一个通知中定义切点,工作量大,不方便维护,我们可以使用@pointcut来声明切点

切点允许逻辑运算 例如mypointcut()||mypointcut1()

6 环绕增强

环绕通知@Around

环绕增强功能是spring aop五种增强里面最厉害!!使用最灵活!!

作用:环绕通知,它是spring框架为我们提供的一种可以在代码中手动控制增强方法何时执行的方式。
属性:method:指定通知中方法的名称。
     pointcut:定义切入点表达式
     pointcut-ref:指定切入点表达式的引用

注意:通常情况下,环绕通知都是独立使用的

案例:利用环绕增强完成日志管理

  • 目标类

    @Component
    public class Calculator implements ICalculator{
        public int sum(int num1,int num2){
            System.out.println("......目标方法sum执行");
            int sum = num1 + num2;
            return sum;
        }
        public int sub(int num1,int num2){
            int result = num1 - num2;
            return result;
        }
        public int plus(int num1,int num2){
            int result = num1 * num2;
            return result;
        }
        public int div(int num1,int num2){
            int result = num1 / num2;
            return result;
        }
    }
    
  • 切面类

    @Component
    @Aspect
    public class LoggerAdvicer {
        @Around("execution(* com.woniu.demo..*(..))")
        public Object around(ProceedingJoinPoint pjp){
            try {
                System.out.println(pjp.getSignature().getName()+"方法被调用了xxx传入的参数是:"+ Arrays.toString(pjp.getArgs()));
                //指定目标对象的方法正在执行
                Object result=pjp.proceed(pjp.getArgs());
                System.out.println(pjp.getSignature().getName()+"方法执行完毕了xxx执行结果是:"+result);
                return result;
            } catch (Throwable e) {
                System.out.println(pjp.getSignature().getName()+"方法被执行出错了xxx出现的异常是:"+e);
                throw new RuntimeException(e);
            } finally {
                System.out.println(pjp.getSignature().getName()+"方法不管有没有异常xxx都会执行的代码");
            }
        }
    }
    
  • 测试代码

    @Autowired
    private Calculator calculator; //最终注入时就是代理对象
    @Test //java的junit框架提供的注解
    public void test03(){
        System.out.println(calculator.getClass());
        calculator.add(1,0);//连接点
    }
    

运行测试代码,控制台输出add方法的日志增强代码:

经验分享:

Spring Aop应用的场景

日志记录,性能统计,安全控制,事务处理,异常处理等等。

利用AOP可以将日志记录,性能统计,安全控制,事务处理,异常处理等代码从业务逻辑代码中划分出来,通过对这些行为的分离,我们希望可以将它们独立到非主导业务逻辑的方法中,进而改变这些行为的时候不影响业务逻辑的代码。

AOP与OOP区别

OOP(面向对象编程)针对业务处理过程的实体及其属性和行为进行抽象封装,以获得更加清晰高效的逻辑单元划分。

而AOP则是针对业务处理过程中的切面进行提取,它所面对的是处理过程中的某个步骤或阶段,以获得逻辑过程中各部分之间低耦合性的隔离效果。这两种设计思想在目标上有着本质的差异。

换而言之,OOD/OOP面向名词领域,AOP面向动词领域。

学习 spring中的aop要明确的事

	a 、开发阶段(我们做的):编写核心业务代码(开发主线):大部分程序员来做,要求熟悉业务需求。把公用代码抽取出来,制作成通知。(开发阶段最后再做):AOP 编程人员来做。在配置文件中,声明切入点与通知间的关系,即切面。:AOP 编程人员来做。

	b 、运行阶段(Spring  框架完成的):Spring 框架监控切入点方法的执行。一旦监控到切入点方法被运行,使用代理机制,动态创建目标对象的代理对象,根据通知类别,在代理对象的对应位置,将通知对应的功能织入,完成完整的代码逻辑运行。

7 spring AOP完成事务管理

引入案例:转账业务

需求:基于atm数据库的cardInfo表完成两个账户之间的转账业务

参考代码

  • CardInfoDao.java完成转账sql

    @Repository
    public class CardInfoDaoImpl implements CardInfoDao {
        @Autowired
        private JdbcTemplate jdbcTemplate;
    
        @Override
        public int updateIn(String cardId, BigDecimal inMoney) {
            return jdbcTemplate.update(
                    "UPDATE cardinfo SET balance=balance+? WHERE card_id=?",
                    inMoney,cardId
            );
        }
    
        @Override
        public int updateOut(String cardId, BigDecimal outMoney) {
            return jdbcTemplate.update(
                    "UPDATE cardinfo SET balance=balance-? WHERE card_id=?",
                    outMoney,cardId
            );
        }
    }
    
  • CardInfoService.java完成转账业务

    @Service
    public class CardInfoServiceImpl implements CardInfoService {
        @Autowired
        private CardInfoDao cardInfoDao;
    
        /**
         * @param outCardId 转出账户
         * @param inCardId 转入账户
         * @param money 交易金额
         */
        @Override
        public void transfer(String outCardId, String inCardId, BigDecimal money) {
            cardInfoDao.updateOut(outCardId,money);
            cardInfoDao.updateIn(inCardId,money);
        }
    }
    
  • 测试转账业务

    @RunWith(SpringJUnit4ClassRunner.class)  
    @ContextConfiguration(classes = SpringConfig.class)
    public class MySpringTester {
        @Autowired
        private CardInfoService cardInfoService;
        @Test
        public void query() {
            cardInfoService.transfer("2394916393","2416932602",new BigDecimal(100));
        }
    }
    

    运行代码,两个账户金额发生变化:账户“2394916393”金额更新为900,账户“2416932602”金额更新为1100,转账成功!!
    我们尝试将CardInfoDao的sql故意写错试一试:

     @Override
        public int updateIn(String cardId, BigDecimal inMoney) {
            return jdbcTemplate.update(
                //此处ST是故意写错的
                    "UPDATE cardinfo ST balance=balance+? WHERE card_id=?",
                    inMoney,cardId
            );
        }
    

    运行代码,两个账户金额依然发生变化:账户“2394916393”金额更新为800,账户“2416932602”金额却依然是1100,转账貌似有一个”成功了“,这种现象符合实际转账功能的需求么????当然不合理!!!转账是一定要保证:两个用户的钱同时变化的。所以转账业务有问题!怎么解决呢?依靠数据库的事务管理。

spring事务控制我们首先要认知到以下几个点:

第一:JavaEE 体系进行分层开发,事务处理位于业务层,Spring 提供了分层设计 业务层的事务处理解决方案。

第二:spring 框架为我们提供了一组事务控制的接口。具体在后面的第二小节介绍。这组接口是在spring-tx-xx.jar 中。

第三:spring 的事务控制都是基于 AOP 的,它既可以使用编程的方式实现,也可以使用配置的方式实现。我们学习的重点是使用配置的方式实现。

spring中事务管理机制依靠aop实现,那么完成事务管理也是遵循aop开发流程:首先我们需要定义事务管理的切面类,切面里面写什么代码呢?回忆之前自己管理事务,在核心业务代码基础上就是要提供事务提交、回滚相关的功能,

  • 事务切面类
    • commit
    • rollback
    • 。。。。

这个所谓的事务切面类,在spring中其实已经定义并提供了,称为事务管理器。

在转账案例中我们已经知道了spring中存在的事务问题,接下来我们使用aop技术让spring自动帮我们控制事务。

Spring 中事务控制的 API 介绍

  • PlatformTransactionManage:此接口是 spring 的事务管理器,它里面提供了我们常用的操作事务的方法,如下图:

因为PlatformTransactionManage是一个接口,并没有提供实际的方法实现。Spring为什么会抽取这样一个接口呢?有一个原因我们可以了解一下:

现下持久层框架众多,Spring没有办法提供一套事务的实现能够满足各大持久层框架的需求,比如MyBatis和Hibernate两大持久层框架,实现机制区别很大。所以spring的想法就是我把功能抽取出来,项目中结合自己实际使用的持久层来提供对应的代码实现:

案例:基于spring aop完成事务管理处理转账业务

分析:

我们现在的案例使用的持久层框架是spring内置的Spring-jdbc,所以事务切面类就应该根据上图指示,使用“DataSourceTransactionManager”。这个实现类spring-jdbc已经提供

我们要做的事情,就是让自己项目的spring容器可以扫描到这个事务管理类,但是因为这个类不是我们自己编写,无法直接添加@Component注解,只能在SpringConfig配置类中利用@Bean注入到spring容器中,详细代码如下所示:

  • pom.xml导入事务管理的依赖

    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-tx</artifactId>
        <version>5.2.25.RELEASE</version>
    </dependency>
    
  • SpringConfig配置类:配置DataSourceTransactionManager事务管理器对象,利用@EnableTransactionManagement开启事务管理

    @ComponentScan(basePackages = {"com.woniu.dao","com.woniu.service","com.woniu.controller","com.woniu.target","com.woniu.advance"}) //spring不管理实体类entity
    @PropertySource("classpath:db.properties")
    //开启spring AOP代理 proxyTargetClass默认值是false,就是JDK true启用cglib
    @EnableAspectJAutoProxy(proxyTargetClass = true) //开启spring aop动态代理
    @EnableTransactionManagement(proxyTargetClass = true)  //开启spring事务管理
    @Import({JdbcConfig.class}) //导入其他的配置类
    public class SpringConfig {
        @Bean
        public JdbcTemplate jdbcTemplate(HikariDataSource dataSource){
            JdbcTemplate jdbcTemplate=new JdbcTemplate();
            jdbcTemplate.setDataSource(dataSource);
            return jdbcTemplate;
        }
    
        /**
         * 事务管理器,即利用spring AOP管理事务时的增强类
         * @param dataSource
         * @return
         */
        @Bean
        public DataSourceTransactionManager dataSourceTransactionManager(HikariDataSource dataSource){
            DataSourceTransactionManager dataSourceTransactionManager=new DataSourceTransactionManager();
            dataSourceTransactionManager.setDataSource(dataSource);
            return dataSourceTransactionManager;
        }
    }
    
  • 业务层哪个方法需要事务管理,添加spring提供事务注解@Transactional

    @Service
    public class CardInfoServiceImpl implements CardInfoService {
        @Autowired
        private CardInfoDao cardInfoDao;
        //注解:spring提供注解
        @Transactional
        @Override
        public void transfer(String inCardId, String outCardId, BigDecimal money) {
            cardInfoDao.updateOut(outCardId,money);
            cardInfoDao.updateIn(inCardId,money);
        }
    }
    

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Linux--MQTT(一)简介

一、简介 MQTT &#xff08; Message Queuing Telemetry Transport&#xff0c;消息队列遥测传输&#xff09;&#xff0c; 是一种基于客户端服务端架构的发布/订阅模式的消息传输协议。 与 HTTP 协议一样&#xff0c; MQTT 协议也是应用层协议&#xff0c;工作在 TCP/IP 四…

在笔记本电脑上使用 LLMs 的 5 种方法

在网上使用 ChatGPT 很简单&#xff0c;只需有网络连接和好的浏览器即可。但这样做可能会泄露您的隐私和数据。OpenAI 存储了您的提示和其他元数据以重新训练模型。对于一些人来说可能不成问题&#xff0c;但注重隐私的人可能更愿意在本地使用这些模型&#xff0c;不受外部跟踪…

如何用AI提高产品经理的工作效率

最近我跟几个产品经理聊天&#xff0c;发现有些人居然还没有使用过ChatGPT、MidJourney、NotionAI 等AI工具。 产品经理有个重要的素质是好奇心&#xff0c;好奇心能够帮助产品经理发现新机会、了解用户需求、学习新知识和探索竞争对手&#xff0c;从而更好地完成产品开发和管…

Redis 主从集群 哨兵原理

一. Redis 主从集群 1.1 基本概念 主从架构&#xff1a;Redis主从集群采用“一主多从”的架构模式&#xff0c;其中主节点&#xff08;Master&#xff09;负责处理客户端的读写请求&#xff0c;而从节点&#xff08;Slave&#xff09;则负责处理读请求。这种读写分离的设计使…

Java中List流式转换为Map的终极指南

哈喽&#xff0c;大家好&#xff0c;我是木头左&#xff01; 在Java编程中&#xff0c;经常需要将一个List对象转换为另一个Map对象。这可能是因为需要根据List中的元素的某些属性来创建一个新的键值对集合。在本文中&#xff0c;我将向您展示如何使用Java 中的流式API轻松地实…

非关系型数据库NoSQL数据层解决方案 之 Mongodb 简介 下载安装 springboot整合与读写操作

MongoDB 简介 MongoDB是一个开源的面向文档的NoSQL数据库&#xff0c;它采用了分布式文件存储的数据结构&#xff0c;是当前非常流行的数据库之一。 以下是MongoDB的主要特点和优势&#xff1a; 面向文档的存储&#xff1a; MongoDB是一个面向文档的数据库管理系统&#xff0…

C++多线程:生产者消费者模式

文章目录 一、模式简介二、头文件、全局变量2.1 仓库类的设计2.1.1 关于仓库类的分析2.1.2 仓库类的设计代码 2.2 工厂类的设计2.2.1 关于工厂类的分析2.2.2 工厂类的设计代码a 将产品item放到仓库repob 将产品item从仓库repo取出c 生产者操作d 消费者操作 2.2.3 主函数代码 三…

LVS_Director + KeepAlived + 邮件报警

目录 一. 环境准备 二. 对master和backup操作 三. 配置master主机 四. 配置backup主机 六. 验证虚拟IP 七. 配置后端两个web服务器 对web1和web2主机都进行如下操作&#xff1a; 单独修改web1主机 单独修改web2主机 验证 八. 设置邮件报警 一. 环境准备 KeepAlive…

STM32单片机选型方法

一.STM32单片机选型方法 1.首先要确定需求&#xff1a; 性能需求&#xff1a;根据应用的复杂度和性能要求&#xff0c;选择合适的CPU性能和主频。 内存需求&#xff1a;确定所需的内存大小&#xff0c;包括RAM和Flash存储空间。 外设需求&#xff1a;根据应用所需的功能&…

六大维度全面焕新升级!麒麟信安服务器操作系统V3.6.1引领未来计算

昨日&#xff0c;openEuler 24.03 LTS 正式发布&#xff0c;麒麟信安作为openEuler社区重要贡献者和参与者&#xff0c;充分发挥自身在国产操作系统领域的技术优势&#xff0c;在打造安全可靠、极致体验的操作系统上与社区共同努力&#xff0c;同步推出服务器操作系统V3.6.1&am…

misc刷题记录(1)陇剑杯

[陇剑杯 2021]签到 题目内容&#xff1a;此时正在进行的可能是__________协议的网络攻击。&#xff08;如有字母请全部使用小写&#xff0c;填写样例&#xff1a;http、dns、ftp&#xff09;。得到的flag请使用NSSCTF{}格式提交。 打开统计&#xff0c;找到协议分级&#xff…

二层弹出框,点掉小弹出框后,遮罩层没有消失

解决办法把 父元素的vue实例对象的&#xff0c;最后一个元素删除。删除的就是遮罩层元素 thus.$ refs.dialig.$ parent.$ el.lastChild. remove()

dbForge Studioor MySQL v6 解锁版 安装教程(MYSQL数据库客户端)

前言 dbForge Studioor MySQL是一个在Windows平台被广泛使用的MySQL客户端&#xff0c;它能够使MySQL开发人员和管理人员在一个方便的环境中与他人一起完成创建和执行查询&#xff0c;开发和调试MySQL程序&#xff0c;自动化管理MySQL数据库对象等工作。 一、下载地址 下载链…

香橙派AIpro测试SPI通信

香橙派AIpro开发板上有一个SPI接口&#xff0c;如下图红框所示&#xff0c; 系统启动后&#xff0c;其对应的设备是 /dev/spidev0.0 一 硬件回环测试 香橙派AIpro上的系统自带spidev_test工具&#xff0c;非常方便&#xff0c;可以查看其帮助信息&#xff0c;如下&#xff0c…

探索AIGC与3D技术的融合:从图像到可探索的3D动态场景

随着人工智能和计算机图形技术的飞速发展,AIGC(人工智能生成内容)与3D技术的结合正在为我们打开一扇全新的创意之门。最近,我深入研究了几个令人兴奋的AIGC+3D方案,它们不仅展示了从单张图片或文本提示生成3D点云的强大能力,还进一步实现了AI虚拟试穿和生成高保真3D数字人…

金融与大模型:引领行业未来的创新融合

前言 在数字化浪潮席卷全球的今天&#xff0c;金融与大模型的结合正成为行业发展的新引擎。这种融合不仅为金融机构带来了前所未有的效率和准确性&#xff0c;也为金融市场的稳定与发展注入了新的活力。本文将基于当前的市场现状&#xff0c;结合金融环境的发展&#xff0c;深…

【docker实战】使用代理的坑

在docker公共仓库被封禁的日子里&#xff0c;大多数人更喜欢使用镜像仓库代理源。 网上教程一大把&#xff0c;似乎不使用代理&#xff0c;就不会使用docker一样。 上图就是我设置的代理源镜像仓库。通常是设置/etc/docker/daemon.json这个文件实现的。 这样设置之后&#xff0…

【MySQL】索引(上)

https://www.wolai.com/curry00/fzTPy3kSsMDEgEcdvo4G5w https://www.bilibili.com/video/BV1Kr4y1i7ru/?p69 https://jimhackking.github.io/%E8%BF%90%E7%BB%B4/MySQL%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/#%E7%B4%A2%E5%BC%95 索引是一种用于快速查询和检索数据的数据结构…

echarts写某个市地图

const geoJSON {"type":"FeatureCollection","features":[{"type":"Feature","properties":{"adcode":440303,"name":"罗湖区","center":[114.123885,22.555341],"…

照明灯具哪个品牌好,一文详细带你了解照明灯具种类有哪些

在孩子学习过程中&#xff0c;有一样物品的重要性不容忽视&#xff0c;那就是一盏提供舒适光源的照明灯具。那么照明灯具哪个品牌好&#xff1f;面对不断增加的学业负担&#xff0c;孩子们经常需要在夜晚借助台灯的光亮进行学习&#xff0c;这已经成为了家庭生活中普遍的情景。…
最新文章