SpringAOP+SpringBoot事务管理

  • 项目搭建
  • SpringAOP
  • SpringBoot中管理事务
  • AOP案例实战-日志记录
  • 日志系统

一、项目搭建

第一步:构建项目

第二步:导入依赖

第三步:配置信息

  • 自动配置(项目自动生成的启动类)

    /**
     * 启动类:申明当前类是一个SpringBoot项目的启动类
     * 启动类会做一些自动配置,减少手动配置
     * 启动类启动时会扫描当前包及其子包下的某些注解
     */
    @MapperScan("cn.itsource.mapper") //扫描mapper接口 - 自动生成Mapper接口的实现类。-并交给Spring管理
    @SpringBootApplication
    public class AopApplication {
        public static void main(String[] args) {
            //使用启动类 运行 Spring程序或应用
            SpringApplication.run(AopApplication.class, args);
        }
    }
    
  • 手动配置(项目中的.yml配置)

    # 端口号配置
    server:
      port: 80
    # 连接数据库的四个必要参数=四大金刚
    spring:
      datasource:
        username: root  # 数据库连接账号
        password: 123456 # 数据库连接密码
        driver-class-name: com.mysql.cj.jdbc.Driver #数据库驱动类名称
        url: jdbc:mysql://localhost:3306/test # 数据库连接URL
    # 配置sql日志
    mybatis:
      configuration:
        # Mybatis日志配置,输出到控制台 
        log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
        # 开启驼峰自动转换 - 将数据库表的_下划线字段的数据自动映射到实体类的驼峰字段
        map-underscore-to-camel-case: true #注意配置了就会强制用驼峰转换,实体类必须写驼峰
        # 配置别名【只能配置实体类的包】-在xml中类型就可以使用三种写法:类名,类名首字母小写,完全限定名
      type-aliases-package: cn.itsource.domain
    

第四步:数据准备

后端数据:数据库,表,工具类等

第五步:项目开发

使用三层架构实现User表的基础方法,并使用Apifox测试

  1. domain
  2. Mapper接口和Sql文件
  3. Service接口和实现类
  4. Controller实现
  5. 测试

二. SpringAOP

概念 :

Spring两大核心机制:IOC控制反转、AOP面向切面编程

什么是AOP:

概念: 面向切面编程(面向方面编程) ,将共同的业务抽取出来,以xml或注解的方式作用到目标上

场景:抽取分散的公共代码就只有用AOP可以使用

    public void save(Product t) {
        try{
            EntityManager entityManager = JpaUtils.getEntityManager();
            //开启事务
            entityManager.getTransaction().begin();
            productDao.save(t); // 例如这种方法在中间,如果在多几个操作,下面就又要重新开启事务,就会有大量重复代码,就要想办法把他们公共的代码抽取出来
            //提交事务
            entityManager.getTransaction().commit();
        }catch{
            //回滚事务
            ..
        }finaly{..}
    }
  1. AOP入门

接下来我们使用AOP模拟事务控制。事务是把多个操作看成一个整体,三层架构中可以在Service层进行业务处理执行多个操作,所以事务都是控制在Service业务层。事务简单回顾:

  1. 事务是把多个操作看成一个整体,要么都成功,要么都不成功
  2. 事务的操作主要有三步:开启事务、提交事务、回滚事务、关闭事务
  3. 事务的四大特性ACID:原子性,一致性,隔离性,持久性

第一步: 导入AOP包

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-aop</artifactId>
</dependency>

第二步:AOP核心业务类(建一个包,包名叫aop,里面写核心业务类)

这些方法中以后可以针对不同的业务编写大量的业务代码,以实现最终需求。这里只是用AOP做事务管理测试,里面的方法仅仅打印一些字符串

package cn.itsource.aop;

import org.aspectj.lang.ProceedingJoinPoint;
import org.springframework.stereotype.Component;

@Component //将当前类交给Spring管理,方便在service中注入使用
public class TxManager {
    public void begin(){
        System.out.println("开启事务"); // 注意这里只是模拟事务管理,主要理解AOP的作用
    }
    public void commit(){
        System.out.println("提交事务");
    }
    public void rollback(){
        System.out.println("回滚事务");
    }
    public void close(){
        System.out.println("关闭事务");
    }
    public void around(ProceedingJoinPoint joinPoint){
        try {
            begin();
            //执行切入点指定的方法 - service中的方法  //java.lang.Throwable
            joinPoint.proceed(); //底层会去执行切入点指定的方法 - service中的方法
            commit();
        } catch (Throwable e) {
            e.printStackTrace();
            rollback();
        } finally {
            close();
        }
    }
}

第三步:在service层手动管理事务

@Override
public void delete(Integer id) {
    try {
        txManager.begin();
        userMapper.delete(id);   // 代码跟下面的重复
        txManager.commit();
    } catch (Exception e) {
        e.printStackTrace();
        txManager.rollback();
    } finally {
        txManager.close();
    }
}
@Override
public void add(User user) {
    try {
        txManager.begin();
        userMapper.add(user);
        txManager.commit();
    } catch (Exception e) {
        e.printStackTrace();
        txManager.rollback();
    } finally {
        txManager.close();
    }
}
  1. AOP入场

2.1有两个核心注解:

  • @Aspect:定义切面,作用在Aop核心业务类上

  • @Pointcut:定义切点,指定此切面作用在哪些方法上

2.2 核心业务类改造

package cn.itsource.aop;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

@Aspect//申明当前类AOP的切面类-AOP的核心业务类
@Component  // 将此类交给spring管理
public class TxManager {
    //作用到cn.itsource.service.I*Service的所有方法上
    //第一个*表示任意返回值,最后一个*表示所有方法,(..)任意参数
    @Pointcut("execution(* cn.itsource.service.I*Service.*(..))") // execution是方法限定表达式
    public void pointcut(){}

    @Before("pointcut()") //作用在业务方法之前-【前置通知】
    public void begin(){
        System.out.println("开启事务");
    }
    @AfterReturning("pointcut()") //作用在业务方法之后-【后置通知】
    public void commit(){
        System.out.println("提交事务");
    }
    @AfterThrowing("pointcut()") //除了异常之后作用-【异常通知】
    public void rollback(){
        System.out.println("回滚事务");
    }
    @After("pointcut()") //无论是否出异常最终都会执行-【最终通知】
    public void close(){
        System.out.println("关闭事务");
    }

    
    @Around // 环绕通知   如果写了这个,上面的before和其他几个注解就不用写了
    public void around(ProceedingJoinPoint joinPoint){  //这个参数非常重要
        try {
            begin();
            //执行切入点指定的目标方法 - service中的方法都是目标方法   
            joinPoint.proceed(); //底层会去执行切入点指定的方法 - service中的方法 
            commit();
        } catch (Throwable e) {
            e.printStackTrace();
            rollback();
        } finally {
            close();
        }
    }
}
  1. Aop相关术语

3.1. 核心概念

名称说明
Joinpoint:连接点连接点指的是可以被Aop控制的方法,例如:入门程序当中所有的Service层方法都是可以被Aop控制的
Pointcut:切入点切入点指的是哪些类、方法要被拦截,也就是哪些连接点要被拦截,例如:入门程序中切入点就是Service层所有方法
Advice:通知通知指的是要作用到连接点的功能,例如:入门程序中的通知
Target:目标目标指的是被代理的对象,例如:入门案例中的UserService就是目标对象
Aspect:切面切面指的是切入点和通知的结合,例如:入门案例中的TxManager就被定义为切面
Proxy:代理代理指的是被增强后的对象,也就是织入了增强处理的类,在程序运行时看的到

3.2. 通知分类

通知说明
before:前置通知通知方法在目标方法调用之前执行
after:最终通知通知方法在目标方法执行后执行,核心方法是否异常都会执行
after-returning:后置通知通知方法会在目标方法执行后执行,核心方法异常后不执行
after-throwing:异常通知通知方法会在目标方法抛出异常后执行
around:环绕通知通知方法会将目标方法封装起来
  1. 代理模式

概念:代理模式的英文叫做Proxy或Surrogate,中文都可译为代理。所谓代理,就是一个人或者一个机构代表另一个人或者另一个机构采取行动。在一些情况下,一个客户不想或者不能够直接引用一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用

在这里插入图片描述

分类:

  • 静态代理(在执行之前就要为业务类生成代理类,业务类是否运行都会生成代理类,非常不灵活,添加一个业务类,也需要添加相应的代理类。)

  • 动态代理(Java1.3就提供了动态代理,让咱们可以在代码运行期动态生成代理类。)

    • jdk的动态代理只允许完成有接口的类的代理,如果没有就需要用第三发的CGLIB的方式实现

      1. 如果代理的类有接口,默认采用原生JDK的方式实现动态代理
      2. 如果代理的类没有接口,只能采用第三方的CGLIB的方式实现动态代理
      注意:其实有接口的也可以强制采用使用CGLIB的动态代理模式,不过需要单独配置
      

AOP的代理模式:

概念:Aop底层是通过动态代理实现,而动态代理底层可以通过原生的JDK方式和第三方cglib的方式实现

  1. Aop的使用场景
  • 日志记录:记录用户的所有操作到数据库中

  • 事务管理:在Service层管理事务

  • 权限验证:在执行业务代码前执行权限校验

  • 性能监控:记录Service层方法执行耗时

    注意:AOP可以拦截指定的方法,并且对方法增强,比如:事务、日志、权限、性能监测等增强,而且无需侵入到业务代码中,使业务与非业务处理逻辑分离

三、SpringBoot中管理事务

概念:Spring事务管理分为编程式和声明式的两种方式

  • 编程式:是指在写业务代码中将事务代码也写进去,这是很古老的做法了(几乎不用了)
  • 声明式:基于AOP将具体业务逻辑与事务处理解耦,声明式事务管理使业务代码逻辑不受污染 (现在都用这个声明式)

3.1 声明式事务有两种方式

  • 配置文件中做相关的事务规则声明
  • 基于@Transactional 注解的方式(主流)

3.2 Transactional注解作用

概念:Spring提供的用来控制事务回滚/提交的一个注解,属于声明式事务的实现。

作用域:@Transactional可以写在类和方法上

  • 当标注在类上的时候,表示给该类所有的public方法添加上@Transactional注解

  • 当标注在方法上的时候,事务的作用域就只在该方法上生效,并且如果类及方法上都配置@Transactional注解时,方法的注解会覆盖类上的注解

    注意:Transactional注解的底层实现原理基于AOP和代理模式

3.3 Transactional注解使用&事务传播机制

  1. 注解使用:

第一步:在Service层实现类上加上@Transaction注解

第二步:直接测试即可

  1. 事务传播机制

概念:以后Service业务都会控制事务,但是当一个方法调用其他方法时就会设计到事务的传播,因为一个业务方法中只能有一个事务

事务传播机制有如下几种:

  • Propagation.REQUIRED: 默认,支持当前事务,如果当前没有事务,就创建一个事务,保证一定有事务 – 增删改方法使用
  • Propagation.SUPPORTS: 支持当前事务,如果当前没有事务,就不使用事务 – 查询方法使用
  • Propagation.REQUIRES_NEW:新建事务,如果当前有事务,就挂起 – 不常用
  • Propagation.NAVEN: 不支持事务,如果当前有事务,就抛出异常 – 不常用

@Transactional的属性

  • propagation:事务传播机制,通常与readOnly搭配配置,默认值是Propagation.REQUIRED
  • readOnly:事务是否是只读,通常与propagation搭配使用,默认值是false
    • false:不只读、可修改
    • true:只读、不可修改

3.4 事务最终配置

在真实开发中,一个类的查询方法占比最多,所以在类上使用查询的全局配置,增删改在方法上单独配置:

1. 在类上配置查询的事务控制方式:@Transactional(readOnly = true, propagation = Propagation.SUPPORTS) //事务注解:指定为只读并且是否有事务都可以
2. 在方法上配置增删改的事务控制方式:@Transactional  // 由于就近原则,所以方法上的事务控制,是听这个的

四. Aop案例实战-日志记录

4.1 需求分析

1. 将用户对于Service层的所有增删改操作记录在数据库中,不用记录查询操作,因为查询不对系统造成影响,无需后期进行追踪
2. 记录的操作日志当中包括:操作人、操作时间,访问的是哪个类、哪个方法、方法运行时参数、方法的返回值、方法的运行时长
  • 使用什么通知:要记录目标方法的返回值,只有环绕通知可以获取到,所以采用环绕通知
  • 切入点如何编写:在模拟事务案例中切入点我们使用的是execution切入点表达式的方式,这种方式特点是比较简单。但是目前的需求是只对增删改操作进行增强,execution切入点表达式就无法很方便的编写,所以要使用切入点的第二种写法叫做annotation切入点表达式
  • @Annotation切入点表达式:用于匹配标识有特定注解的方法,也就是我们可以在需要增强的方法上加上指定注解,然后annotation切入点表达式指定扫描这个注解即可

4.2 功能实战

第一步:准备日志记录表

SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;

-- ----------------------------
-- Table structure for t_logs
-- ----------------------------
DROP TABLE IF EXISTS `t_logs`;
CREATE TABLE `t_logs`  (
  `id` bigint UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '主键',
  `user_id` bigint NULL DEFAULT NULL COMMENT '操作人ID',
  `user_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '操作人名称',
  `create_time` datetime NULL DEFAULT NULL COMMENT '操作时间',
  `class_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '操作的类名',
  `method_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '操作的方法名',
  `method_params` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '方法参数',
  `return_value` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '返回值',
  `cost_time` bigint NULL DEFAULT NULL COMMENT '方法执行耗时, 单位:ms',
  `ip` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '操作Ip',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '操作日志表' ROW_FORMAT = Dynamic;

SET FOREIGN_KEY_CHECKS = 1;

第二步:编写日志domain

package cn.zy.domain;

import lombok.Data;

import java.util.Date;

@Data
public class Logs {
    private Long id;
    private Long userId;
    private String userName;
    private Date createTime;
    private String className;
    private String methodName;
    private String methodParams;
    private String returnValue;
    private Long costTime;
    private String ip;
}

第三步:,编写mapper中的新增方法&编写日志表新增方法

新增方法:

package cn.zy.mapper;

import cn.zy.domain.Logs;

public interface LogsMapper {
    void add(Logs logs);
}

新增方法

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC
        "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="cn.zy.mapper.LogsMapper">


    <insert id="add">
        insert into t_logs(user_id, user_name, create_time, class_name,
                           method_name, method_params, return_value, cost_time, ip)
        VALUES (#{userId},#{userName},#{createTime},#{className},#{methodName},
                #{methodParams},#{returnValue},#{costTime},#{ip})
    </insert>
</mapper>

第四步:自定义@Log注解

package cn.zy.anno;

import org.springframework.stereotype.Component;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Component
public @interface Log {

}

第四步:定义日志记录切面类,切面类一般放在aop包下,类以Aspect结尾

package cn.itsource.aop;

import cn.itsource.domain.Logs;
import cn.itsource.mapper.LogsMapper;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import java.util.Arrays;
import java.util.Date;

@Component
@Aspect
public class LogManager {

    @Autowired
    private HttpServletRequest request;  // 用来获取ip的
    @Autowired
    private LogsMapper logsMapper;  // 给类中属性赋值

    //只有有@Logs注解的方法才作用 - around方法作用到使用了@Logs注解的方法
    @Around("@annotation(cn.itsource.anno.Logs)")  // @annotation
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {  //注意这里需要返回值,否则
        Logs logs = new Logs();
        logs.setUserId(1L);
        logs.setUserName("张三");
        logs.setCreateTime(new Date());
        //获取类名
        String className = joinPoint.getTarget().getClass().getName();
        logs.setClassName(className);
        //通过方法签名获取方法名
        String methodName = joinPoint.getSignature().getName();
        logs.setMethodName(methodName);
        //获取方法参数
        Object[] args = joinPoint.getArgs();
        logs.setMethodParams(Arrays.toString(args));
        //返回值 @TODO
        Signature signature = joinPoint.getSignature();
        if (signature instanceof MethodSignature) {
            MethodSignature methodSignature = (MethodSignature) signature;
            // 实例化
            String returnType = methodSignature.getReturnType().getName();
            logs.setReturnValue(returnType);
        }

        //操作业务方法时间
        long start = System.currentTimeMillis();
        //执行目标方法 - 如果不返回一个对象,调用方就会接收到一个null值
        Object result = joinPoint.proceed();
        long end = System.currentTimeMillis();
        logs.setCostTime(end-start);
        //获取ip地址
        String ip = request.getRemoteAddr();
        logs.setIp(ip);
        logsMapper.add(logs);
        return result;  // 这里返回值给调用方
    }
}

第五步:改造Service层方法

  • 给增删改方法增加@Logs注解
  • 注释掉前面写的TxManager切面,以免影响测试
    @Override
    @Log
    public void add(User user) {
        userMapper.add(user);
    }

= System.currentTimeMillis();
//执行目标方法 - 如果不返回一个对象,调用方就会接收到一个null值
Object result = joinPoint.proceed();
long end = System.currentTimeMillis();
logs.setCostTime(end-start);
//获取ip地址
String ip = request.getRemoteAddr();
logs.setIp(ip);
logsMapper.add(logs);
return result; // 这里返回值给调用方
}
}


第五步:改造Service层方法

> - 给增删改方法增加@Logs注解
> - 注释掉前面写的TxManager切面,以免影响测试

~~~java
    @Override
    @Log
    public void add(User user) {
        userMapper.add(user);
    }

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

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

相关文章

模拟被观察物体的位置和方向

开发环境&#xff1a; Windows 11 家庭中文版Microsoft Visual Studio Community 2019VTK-9.3.0.rc0vtk-example demo解决问题&#xff1a;模拟被观察物体的位置和方向&#xff0c;以帮助用户理解相机在观察特定对象时的位置和朝向。vtkCameraOrientationWidget 模拟的是被观察…

Redis核心技术与实战【学习笔记】 - 17.Redis 缓存异常:缓存雪崩、击穿、穿透

概述 Redis 的缓存异常问题&#xff0c;除了数据不一致问题外&#xff0c;还会面临其他三个问题&#xff0c;分别是缓存雪崩、缓存击穿、缓存穿透。这三个问题&#xff0c;一旦发生&#xff0c;会导致大量的请求积压到数据库。若并发量很大&#xff0c;就会导致数据库宕机或故…

九州金榜|如何做好家庭教育

孩子的家庭教育是每个家庭都要做的&#xff0c;也是每个家长面临的事情&#xff0c;同样不同的家庭教育教育出来的孩子性格也各不相同&#xff0c;有时候家长看别别人家的孩子品学兼优非常羡慕&#xff0c;很多家长会把问题归结到孩子身上&#xff0c;其实有没有想过是家庭教育…

C++之函数重载,默认参数,bool类型,inline函数,异常安全

函数重载 在实际开发中&#xff0c;有时候需要实现几个功能类似的函数&#xff0c;只是细节有所不同。如交换两个变量的值&#xff0c;但这两种变量可以有多种类型&#xff0c;short, int, float等。在C语言中&#xff0c;必须要设计出不同名的函数&#xff0c;其原型类似于&am…

【新书推荐】6.2节 段寄存器

在16位汇编语言的源程序中&#xff0c;我们将源程序按照不同的功能和作用划分为若干个逻辑段&#xff0c;如数据段用来存储数据&#xff0c;代码段用来存储代码&#xff0c;堆栈段用来保存临时数据&#xff0c;附加段用来拷贝数据。我们可以把汇编语言的源程序抽象地理解为数据…

TCP与UDP:传输层协议的差异与选择

在计算机网络中&#xff0c;传输控制协议&#xff08;TCP&#xff09;和用户数据报协议&#xff08;UDP&#xff09;是两种常用的传输层协议。然而&#xff0c;随着互联网的快速发展&#xff0c;传统的TCP和UDP在某些场景下存在一些限制。为了解决这些问题&#xff0c;出现了新…

如何使用VS Code编写小游戏并实现公网游玩本地游戏【内网穿透】

文章目录 前言1. 编写MENJA小游戏2. 安装cpolar内网穿透3. 配置MENJA小游戏公网访问地址4. 实现公网访问MENJA小游戏5. 固定MENJA小游戏公网地址 前言 本篇教程&#xff0c;我们将通过VS Code实现远程开发MENJA小游戏&#xff0c;并通过cpolar内网穿透发布到公网&#xff0c;分…

No matching client found for package name ‘com.unity3d.player‘

2024年2月5日更新 必须使用Unity方式接入Unity项目&#xff01;一句话解决所有问题。&#xff08;真的别玩Android方式&#xff09; 大致这问题出现原因是我在Unity采用了Android方式接入Firebase&#xff0c;而Android接入实际上和Unity接入方式有配置上的不一样&#xff0c;我…

爬虫工作量由小到大的思维转变---<第四十五章 Scrapyd 关于gerapy遇到问题>

前言: 本章主要是解决一些gerapy遇到的问题,会持续更新这篇! 正文: 问题1: 1400 - build.py - gerapy.server.core.build - 78 - build - error occurred (1, [E:\\项目文件名\\venv\\Scripts\\python.exe, setup.py, clean, -a, bdist_uberegg, -d, C:\\Users\\Administrat…

链表经典算法(+OJ刷题)

文章目录 前言一、移除链表元素二、链表的中间节点三.反转链表四.合并两个有序链表五.分割链表六.环形链表的约瑟夫问题总结 创作不易&#xff0c;点赞收藏一下呗&#xff01;&#xff01;&#xff01; 前言 在上一节&#xff0c;我们介绍了单链表的增&#xff0c;删&#xff…

机器学习基础、数学统计学概念、模型基础技术名词及相关代码个人举例

1.机器学习基础 &#xff08;1&#xff09;机器学习概述 机器学习是一种人工智能&#xff08;AI&#xff09;的分支&#xff0c;通过使用统计学和计算机科学的技术&#xff0c;使计算机能够从数据中学习并自动改进性能&#xff0c;而无需进行明确的编程。它涉及构建和训练机器…

用Python实现MD5加密

用Python实现MD5加密 用Python实现MD5加密时用到的是hashlib模块&#xff0c;可以通过hashlib标准库使用 多种Hash算法&#xff0c;如SHA1 、SHA224 、SHA256 、SHA384 、SHA512和MD5算法 等。下面是通过调用hashlib模块对字符串进行MD5加密的简单实例&#xff1a; from hash…

[UI5 常用控件] 06.Splitter,ResponsiveSplitter

文章目录 前言1. Splitter1.1 属性 2. ResponsiveSplitter 前言 本章节记录常用控件Splitter,ResponsiveSplitter。主要功能是分割画面布局。 其路径分别是&#xff1a; sap.ui.layout.Splittersap.ui.layout.ResponsiveSplitter 1. Splitter 1.1 属性 orientation &#x…

DBeaver连接达梦数据库

1、下载驱动文件 可官网下载Hibernate 框架 | 达梦技术文档 (dameng.com) 1. 打开DBeaver软件&#xff0c;点击“数据库”&#xff0c;选择“驱动管理器” 2. 点击“新建”进行达人大金仓驱动管理器配置。 3、创建驱动-设置&#xff1a;驱动名称、类名、url 驱动名称&#…

(2017|ICLR,EBGAN,AE 鉴别器,正则化)基于能量的 GAN

Energy-based Generative Adversarial Network 公和众和号&#xff1a;EDPJ&#xff08;进 Q 交流群&#xff1a;922230617 或加 VX&#xff1a;CV_EDPJ 进 V 交流群&#xff09; 目录 0. 摘要 2. EBGAN 模型 2.1 目标函数 2.2 解决方案的最优解 2.3 使用自动编码器 2.…

Android Button background 失效

问题 Android Button background 失效 详细问题 笔者开发Android项目&#xff0c;期望按照 android:background中所要求的颜色展示。 实际显示按照Android 默认颜色展示 解决方案 将xml的Button 组件修改为<android.widget.Button> 即将代码 <Buttonandroid:l…

RCS-YOLO复现

复现结果–Precision&#xff1a;0.941&#xff0c;Recall&#xff1a;0.945&#xff0c;AP 50 _{50} 50​&#xff1a;0.941&#xff0c;AP 50 : 95 _{50:95} 50:95​&#xff1a;0.693&#xff0c;误差在5个点内&#xff0c;可以接受 感想 第5篇完全复现的论文

Facebook与全球文化:多元化视角下的社交体验

在数字时代的今天&#xff0c;Facebook如一座横跨全球的桥梁&#xff0c;将人们从世界各地连接在一起。这个社交媒体平台已经不仅仅是一个在线社交的工具&#xff0c;更是一个全球化时代的文化交汇点。本文将深入研究Facebook在全球文化中的作用&#xff0c;以及它如何在多元文…

[python] 过年燃放烟花

目录 新年祝福语 一、作品展示 二、作品所用资源 三、代码与资源说明 四、代码库 五、完整代码 六、总结 新年祝福语 岁月总是悄然流转&#xff0c;让人感叹时间的飞逝&#xff0c;转眼间又快到了中国传统的新年&#xff08;龙年&#xff09;。 回首过去&#xf…

AUTOSAR内存篇 -EEPROM Abstraction(EA)

文章目录 功能介绍一般行为寻址机制和分段地址计算擦/写次数限制“立即” 数据的处理管理块一致性信息总结本文介绍关于EEPROM Abstraction相关的内容。下图所示为内存硬件抽象层的模块架构图。 EEPROM抽象(EA)从器件特定的寻址方案和分段中抽象出来,并为上层提供虚拟寻址方…