【JAVA进阶篇教学】第十六篇:Java中AOP使用

博主打算从0-1讲解下java进阶篇教学,今天教学第十五篇:Java中AOP使用。

AOP(Aspect-Oriented Programming)是一种编程范式,它允许开发者在不修改源代码的情况下,对代码进行横切关注点的分离和增强。在 Java 中,AOP 通常通过使用 Spring Framework 或 AspectJ 等框架来实现。

在这篇博客中,我们将介绍 AOP 的基本概念、使用场景以及如何在 Java 中使用 Spring Framework 实现 AOP。

目录

一、前言

二、AOP 的基本概念

三、AOP 的使用场景

四、实现 AOP

4.1新建注解@Log

4.2新建LogAspect类

4.1.1依赖

4.1.2表结构

4.1.3实体类

4.1.4说明

4.1.5怎么调用 

 4.1.6版本号

五、总结


一、前言

AOP(Aspect-Oriented Programming)是一种编程范式,它允许开发者在不修改源代码的情况下,对代码进行横切关注点的分离和增强。在 Java 中,AOP 通常通过使用 Spring Framework 或 AspectJ 等框架来实现。

二、AOP 的基本概念

AOP 是一种面向切面编程的思想,它将程序中的业务逻辑和系统级服务(如日志记录、事务管理、权限控制等)分离开来,使得系统级服务可以在不修改业务逻辑代码的情况下进行添加、修改或删除。

AOP 中的核心概念包括:

  • 切面(Aspect):切面是一个关注点的集合,它定义了在哪些地方需要进行增强。
  • 连接点(JoinPoint):连接点是程序执行过程中的一个点,如方法调用、异常抛出等。
  • 通知(Advice):通知是在连接点处执行的操作,它可以是前置通知、后置通知、异常通知等。
  • 切点(Pointcut):切点是定义在连接点上的一个表达式,用于匹配哪些连接点需要进行增强。

通过使用切面、连接点、通知和切点等概念,AOP 可以实现对程序的横切关注点的分离和增强,提高代码的可读性、可维护性和可扩展性。

三、AOP 的使用场景

AOP 可以用于以下场景:

  • 日志记录:可以在方法调用前后记录日志信息,方便进行调试和问题排查。
  • 事务管理:可以在方法调用前后进行事务的开启、提交和回滚,保证数据的一致性。
  • 权限控制:可以在方法调用前进行权限检查,确保只有授权的用户才能访问特定的资源。
  • 性能监控:可以在方法调用前后记录性能指标,方便进行性能优化。
  • 异常处理:可以在方法调用后进行异常处理,避免程序崩溃。

四、实现 AOP

Spring Framework 是一个轻量级的 Java 开发框架,它提供了对 AOP 的支持。在 Spring Framework 中,可以使用@AspectJ 注解来定义切面,使用@Pointcut 注解来定义切点,使用@Before、@After、@AfterReturning 和@AfterThrowing 等注解来定义通知。

那么今天就以日志记录来举例。

4.1新建注解@Log

import java.lang.annotation.*;@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Log {/*** 操作模块* @return*/String modul() default "";/*** 操作类型* @return*/String type() default "";/*** 操作说明* @return*/String desc() default "";
}

4.2新建LogAspect类


import com.alibaba.fastjson.JSON;
import com.hvit.user.util.MyUtils;
import com.hvit.user.yst.config.annotation.Log;
import com.hvit.user.yst.entity.LogErrorInfoEntity;
import com.hvit.user.yst.entity.LogInfoEntity;
import com.hvit.user.yst.service.LogErrorInfoService;
import com.hvit.user.yst.service.LogInfoService;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.*;/**** 切面处理类,操作日志异常日志记录处理*/
@Aspect
@Component
public class LogAspect {/****项目发布版本号*/@Value("${version}")private String version;/*** 统计请求的处理时间*/ThreadLocal<Long> startTime = new ThreadLocal<>();@Autowiredprivate LogInfoService logInfoService;@Autowiredprivate LogErrorInfoService logErrorInfoService;/*** @methodName:logPoinCut* @description:设置操作日志切入点 记录操作日志 在注解的位置切入代码* @author:caozhen* @dateTime:2024-05-15* @Params: []* @Return: void* @editNote:*/@Pointcut("@annotation(com.hvit.user.yst.config.annotation.Log)")public void logPoinCut() {}/*** @methodName:exceptionLogPoinCut* @description:设置操作异常切入点记录异常日志 扫描所有controller包下操作* @author:caozhen* @dateTime:2024-05-15* @Params: []* @Return: void* @editNote:*/@Pointcut("execution(* com.hvit.user.yst.controller..*.*(..))")public void exceptionLogPoinCut() {}@Before("logPoinCut()")public void doBefore() {// 接收到请求,记录请求开始时间startTime.set(System.currentTimeMillis());}/*** @methodName:doAfterReturning* @description:正常返回通知,拦截用户操作日志,连接点正常执行完成后执行, 如果连接点抛出异常,则不会执行* @author:caozhen* @dateTime:2024-05-15* @Params: [joinPoint, keys]* @Return: void* @editNote:*/@AfterReturning(value = "logPoinCut()", returning = "keys")public void doAfterReturning(JoinPoint joinPoint, Object keys) {// 获取RequestAttributesRequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();// 从获取RequestAttributes中获取HttpServletRequest的信息HttpServletRequest request = (HttpServletRequest) requestAttributes.resolveReference(RequestAttributes.REFERENCE_REQUEST);LogInfoEntity logInfo = LogInfoEntity.builder().build();try {// 从切面织入点处通过反射机制获取织入点处的方法MethodSignature signature = (MethodSignature) joinPoint.getSignature();// 获取切入点所在的方法Method method = signature.getMethod();// 获取请求的类名String className = joinPoint.getTarget().getClass().getName();// 获取操作Log log = method.getAnnotation(Log.class);if (Objects.nonNull(log)) {logInfo.setModule(log.modul());logInfo.setType(log.type());logInfo.setMessage(log.desc());}logInfo.setMethod(className + "." + method.getName()); // 请求的方法名logInfo.setReqParam(JSON.toJSONString(converMap(request.getParameterMap()))); // 请求参数//logInfo.setResParam(JSON.toJSONString(keys)); // 返回结果logInfo.setUserId(request.getAttribute("uuid") == null ? "未知" : request.getAttribute("uuid").toString()); // 请求用户IDlogInfo.setUserName(request.getAttribute("userName") == null ? "未知" : request.getAttribute("userName").toString()); // 请求用户名称logInfo.setIp(MyUtils.getIpAddr()); // 请求IPlogInfo.setUri(request.getRequestURI()); // 请求URIlogInfo.setCreateTime(new Date()); // 创建时间logInfo.setVersion(version); // 操作版本logInfo.setTakeUpTime(System.currentTimeMillis() - startTime.get()); // 耗时logInfoService.save(logInfo);} catch (Exception e) {e.printStackTrace();}}/*** @methodName:doAfterThrowing* @description:异常返回通知,用于拦截异常日志信息 连接点抛出异常后执行* @author:caozhen* @dateTime:2024-05-15* @Params: [joinPoint, e]* @Return: void* @editNote:*/@AfterThrowing(pointcut = "exceptionLogPoinCut()", throwing = "e")public void doAfterThrowing(JoinPoint joinPoint, Throwable e) {// 获取RequestAttributesRequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();// 从获取RequestAttributes中获取HttpServletRequest的信息HttpServletRequest request = (HttpServletRequest) requestAttributes.resolveReference(RequestAttributes.REFERENCE_REQUEST);try {// 从切面织入点处通过反射机制获取织入点处的方法MethodSignature signature = (MethodSignature) joinPoint.getSignature();// 获取切入点所在的方法Method method = signature.getMethod();// 获取请求的类名String className = joinPoint.getTarget().getClass().getName();logErrorInfoService.save(LogErrorInfoEntity.builder().reqParam(JSON.toJSONString(converMap(request.getParameterMap()))) // 请求参数.method(className + "." + method.getName()) // 请求方法名.name(e.getClass().getName()) // 异常名称.message(stackTraceToString(e.getClass().getName(), e.getMessage(), e.getStackTrace())) // 异常信息.userId(request.getAttribute("uuid") == null ? "未知" : request.getAttribute("uuid").toString()) // 操作员ID.userName(request.getAttribute("userName") == null ? "未知" : request.getAttribute("userName").toString()) // 操作员名称.uri(request.getRequestURI()) // 操作URI.ip(MyUtils.getIpAddr()) // 操作员IP.version(version) // 版本号.createTime(new Date()) // 发生异常时间.build());} catch (Exception e2) {e2.printStackTrace();}}/*** @methodName:converMap* @description:转换request 请求参数* @author:caozhen* @dateTime:2024-05-15* @Params: [paramMap]* @Return: java.util.Map<java.lang.String, java.lang.String>* @editNote:*/public Map<String, String> converMap(Map<String, String[]> paramMap) {Map<String, String> rtnMap = new HashMap<String, String>();for (String key : paramMap.keySet()) {rtnMap.put(key, paramMap.get(key)[0]);}return rtnMap;}/*** @methodName:stackTraceToString* @description:转换异常信息为字符串* @author:caozhen* @dateTime:2024-05-15* @Params: [exceptionName, exceptionMessage, elements]* @Return: java.lang.String* @editNote:*/public String stackTraceToString(String exceptionName, String exceptionMessage, StackTraceElement[] elements) {StringBuffer strbuff = new StringBuffer();for (StackTraceElement stet : elements) {strbuff.append(stet + "<br/>");}String message = exceptionName + ":" + exceptionMessage + "<br/>" + strbuff.toString();return message;}
}

4.1.1依赖

在LogAspect我们有用fastjson这个依赖包

        <dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>1.2.83</version></dependency>

4.1.2表结构


SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;-- ----------------------------
-- Table structure for t_log_error_info
-- ----------------------------
DROP TABLE IF EXISTS `t_log_error_info`;
CREATE TABLE `t_log_error_info`  (`uuid` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,`req_param` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '请求参数',`name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '异常名称',`message` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL COMMENT '异常信息',`user_id` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '操作用户id',`user_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '操作用户名称',`method` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '请求方法',`uri` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '请求url',`ip` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '请求IP',`version` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '版本号',`create_time` datetime NULL DEFAULT NULL COMMENT '创建时间',PRIMARY KEY (`uuid`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '操作日志异常信息' ROW_FORMAT = DYNAMIC;-- ----------------------------
-- Table structure for t_log_info
-- ----------------------------
DROP TABLE IF EXISTS `t_log_info`;
CREATE TABLE `t_log_info`  (`uuid` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,`module` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '功能模块',`type` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '操作类型',`message` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '操作描述',`req_param` text CHARACTER SET utf8 COLLATE utf8_general_ci NULL COMMENT '请求参数',`res_param` longtext CHARACTER SET utf8 COLLATE utf8_general_ci NULL COMMENT '响应参数',`take_up_time` int(10) NULL DEFAULT NULL COMMENT '耗时',`user_id` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '操作用户id',`user_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '操作用户名称',`method` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '操作方面',`uri` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '请求url',`ip` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '请求IP',`version` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '版本号',`create_time` datetime NULL DEFAULT NULL COMMENT '创建时间',PRIMARY KEY (`uuid`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '操作日志表' ROW_FORMAT = DYNAMIC;SET FOREIGN_KEY_CHECKS = 1;

4.1.3实体类

LogInfoEntity:

import com.baomidou.mybatisplus.annotations.TableName;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.hvit.user.yst.entity.base.IdEntity;
import io.swagger.annotations.ApiModelProperty;
import lombok.*;
import lombok.experimental.Accessors;
import org.springframework.format.annotation.DateTimeFormat;import java.io.Serializable;
import java.util.Date;/*** <p>* 操作日志表* </p>** @author 曹震* @since 2024-05-15*/
@TableName("t_log_info")
@Data
@JsonInclude
@Builder
public class LogInfoEntity extends IdEntity implements Serializable {public LogInfoEntity(String module, String type, String message, String reqParam, String resParam, Long takeUpTime, String userId, String userName, String method, String uri, String ip, String version, Date createTime) {this.module = module;this.type = type;this.message = message;this.reqParam = reqParam;this.resParam = resParam;this.takeUpTime = takeUpTime;this.userId = userId;this.userName = userName;this.method = method;this.uri = uri;this.ip = ip;this.version = version;this.createTime = createTime;}public LogInfoEntity(){}private static final long serialVersionUID=1L;/*** 功能模块*/@ApiModelProperty(name = "module", value = "功能模块")private String module;/*** 操作类型*/@ApiModelProperty(name = "type", value = "操作类型")private String type;/*** 操作描述*/@ApiModelProperty(name = "message", value = "操作描述")private String message;/*** 请求参数*/@ApiModelProperty(name = "reqParam", value = "请求参数")private String reqParam;/*** 响应参数*/@ApiModelProperty(name = "resParam", value = "响应参数")private String resParam;/*** 耗时*/@ApiModelProperty(name = "takeUpTime", value = "耗时")private Long takeUpTime;/*** 操作用户id*/@ApiModelProperty(name = "userId", value = "操作用户id")private String userId;/*** 操作用户名称*/@ApiModelProperty(name = "userName", value = "操作用户名称")private String userName;/*** 操作方面*/@ApiModelProperty(name = "method", value = "操作方面")private String method;/*** 请求url*/@ApiModelProperty(name = "uri", value = "请求url")private String uri;/*** 请求IP*/@ApiModelProperty(name = "ip", value = "请求IP")private String ip;/*** 版本号*/@ApiModelProperty(name = "version", value = "版本号")private String version;/*** 创建时间*/@ApiModelProperty(name = "createTime", value = "创建时间")@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss", iso = DateTimeFormat.ISO.DATE)@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")private Date createTime;}

LogErrorInfoEntity:


import com.baomidou.mybatisplus.annotations.TableName;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.hvit.user.yst.entity.base.IdEntity;
import io.swagger.annotations.ApiModelProperty;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.format.annotation.DateTimeFormat;import java.io.Serializable;
import java.util.Date;/*** <p>* 操作日志异常信息* </p>** @author 曹震* @since 2024-05-15*/
@TableName("t_log_error_info")
@Data
@JsonInclude
@Builder
public class LogErrorInfoEntity extends IdEntity implements Serializable {public LogErrorInfoEntity(String reqParam, String name, String message, String userId, String userName, String method, String uri, String ip, String version, Date createTime) {this.reqParam = reqParam;this.name = name;this.message = message;this.userId = userId;this.userName = userName;this.method = method;this.uri = uri;this.ip = ip;this.version = version;this.createTime = createTime;}public LogErrorInfoEntity(){}private static final long serialVersionUID=1L;/*** 请求参数*/@ApiModelProperty(name = "reqParam", value = "请求参数")private String reqParam;/*** 异常名称*/@ApiModelProperty(name = "name", value = "异常名称")private String name;/*** 异常信息*/@ApiModelProperty(name = "message", value = "异常信息")private String message;/*** 操作用户id*/@ApiModelProperty(name = "userId", value = "操作用户id")private String userId;/*** 操作用户名称*/@ApiModelProperty(name = "userName", value = "操作用户名称")private String userName;/*** 请求方法*/@ApiModelProperty(name = "method", value = "请求方法")private String method;/*** 请求url*/@ApiModelProperty(name = "uri", value = "请求url")private String uri;/*** 请求IP*/@ApiModelProperty(name = "ip", value = "请求IP")private String ip;/*** 版本号*/@ApiModelProperty(name = "version", value = "版本号")private String version;/*** 创建时间*/@ApiModelProperty(name = "createTime", value = "创建时间")@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss", iso = DateTimeFormat.ISO.DATE)@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")private Date createTime;}

IdEntity:

import com.baomidou.mybatisplus.annotations.TableId;
import com.baomidou.mybatisplus.enums.IdType;import java.io.Serializable;public class IdEntity implements Serializable {@TableId(type = IdType.INPUT)private String uuid;public String getUuid() {return uuid;}public void setUuid(String uuid) {this.uuid = uuid;}
}

4.1.4说明

    @Autowiredprivate LogInfoService logInfoService;@Autowiredprivate LogErrorInfoService logErrorInfoService;

Service类自行建立,其实也就是mybatis-plus生成的代码。你们可以自行生成!

4.1.5怎么调用 


import com.hvit.user.util.Constants;
import com.hvit.user.util.R;
import com.hvit.user.yst.config.annotation.Log;
import com.hvit.user.yst.service.AppServicesService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;/**** 测试*/
@RestController
@RequestMapping("/xxxx/api/")
public class ApiController {@Autowiredprivate AppServicesService appServicesService;/*** 获取二维码门牌地址*/@Log(modul = "日志-数字门牌对外接口", type = Constants.SELECT, desc = "数字门牌对外接口")@RequestMapping(value = "/v1/getQrcodeAddressInfo", method = RequestMethod.GET)@ApiOperation(value = "数字门牌对外接口")public ResponseEntity<?> getQrcodeAddressInfo(String code, String appKey, String appSecret) {return ResponseEntity.ok(appServicesService.getQrcodeAddressInfo(code, appKey, appSecret));}}

这样,只要调用了这个接口,那么正常调用日志或者异常日志都会保存进数据库中。

4.1.6版本号

代码中有获取版本号的,直接在yml文件新增如下配置

version: 2.0

五、总结

AOP 是一种强大的编程范式,它可以帮助开发者将系统级服务从业务逻辑中分离出来,提高代码的可读性、可维护性和可扩展性。在 Java 中,可以使用 Spring Framework 或 AspectJ 等框架来实现 AOP。通过使用 AOP,可以实现日志记录、事务管理、权限控制、性能监控和异常处理等功能,使代码更加健壮和易于维护。

点个关注,不会迷路!

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

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

相关文章

CNAME记录

CNAME记录 维基百科&#xff0c;自由的百科全书 &#xff08;重定向自CNAME&#xff09; 真实名称记录&#xff08;英语&#xff1a;Canonical Name Record&#xff09;&#xff0c;即CNAME记录&#xff0c;是域名系统&#xff08;DNS&#xff09;的一种记录。CNAME记录用于…

mysqldump: Error 2013 导致mysql停止运行

https://www.cnblogs.com/DataArt/p/10173957.html 1 查询表大小 SELECT table_name AS "表名", round(((data_length index_length) / 1024 / 1024), 2) AS "大小(MB)" FROM information_schema.tables WHERE table_schema your_database_name AND …

Togaf培训简介

Togaf简单讲 1.定义事物&#xff0c;方便大家互相理解 2.做好现状和愿景设计 3.做好现状到愿景的计划 1.togaf 首先是统一语言。大家互相能理解&#xff0c;比如各种定义。 togaf源自美国军方理论 2.没有架构设计&#xff0c;烟囱式系统是必然的。 就跟之前去政府办户籍一…

抖店曝光率高,转化低,不知道怎么提升转化率?试试这四个方法

大家好&#xff0c;我是醒醒团队电商花花。 我们现在做抖音小店的商家或多或少都会遇到不出单&#xff0c;转化低的各种问题。 明明店铺的曝光不低&#xff0c;访客也不少&#xff0c;就是没转化。 下面我根据我们做店的经验&#xff0c;给大家分享一些问题所在&#xff0c;…

Git—安装及介绍

下载Git 官网地址&#xff1a;Git - Downloads (git-scm.com) 安装 双击安装包 点击 next 检查安装 桌面&#xff0c;右键鼠标&#xff0c;是否出现 Git GUI Here 和 Git Bash Here 打开Git Bash Here 输入命令 git --verison

NX/UG软件使用—策略OK回调环境变量

新建环境变量UGII_CAM_OPERATION_OK_EXIT&#xff0c;变量值为需要执行的xx.dll路径&#xff0c;设置后&#xff0c;重启NX&#xff0c;那么在每次点击策略OK之后&#xff0c;会自动执行xx.dll(注意这个dll需要在配置好的工具目录里&#xff0c;也就是说NX能手动加载这个dll)。…

finallyshell激活-支持所有版本(老版 + 最新版) + 所有平台(mac + windows)

一&#xff1a;打开finally shell的激活页面 二&#xff1a;点击离线激活 三&#xff1a;复制机器码&#xff0c;然后执行一下代码 原文&#xff1a;大哥原文&#xff0c;但是这个大佬是用java实现的&#xff0c;执行因为依赖的问题一直报错 基于以上问题&#xff0c;所以使…

YoLov9目标检测算法的使用

目录 一、环境安装 1、创建虚拟环境 2、安装依赖库 二、数据集准备 1、数据集的文件名 2、划分数据集 3、配置数据文件 4、修改模型结构文件的类别 5、下载模型预训练权重 三、训练 1、训练的三个文件介绍 2、训练 3、验证 4、检测单张图片 四、附录 1、训练参…

C#数据库密码加密保存和登录验证方法

目录 1. 使用哈希算法加密密码 2. 用户注册时加密密码并保存到数据库 3. 用户登录时验证密码 注意事项 如何实现加盐处理 安装BCrypt.Net包 密码哈希和验证 用户注册时加盐并哈希密码 用户登录时验证密码 1. 使用哈希算法加密密码 可以使用C#中的System.Security.Cryp…

01 区块链-- Smart Contract

Concept of Smart Contract 1. 智能合约并非区块链的专属 智能合约&#xff0c;就是一段部署在区块链里的代码。 合约有自己的地址&#xff0c;与该地址进行交易会触发代码运行&#xff0c;一旦某个事件触发合约中的条款&#xff0c;代码即自动执行。 也就是说&#xff0c;满…

上海市计算机学会竞赛平台2024年1月月赛丙组成绩等第

题目描述 给定一个在 00 到 100100 之间的整数 &#x1d44e;a&#xff0c;请将它转成等第&#xff0c;规则如下&#xff1a; 9090 或以上为 A8080 或以上为 B7070 或以上为 C6060 或以上为 D5959 或以下为 F 输入格式 单个数字表示 &#x1d44e;a 输出格式 单个字符表示…

c++快读快写

一般来讲&#xff0c;快读快写在针对数据量不是很大的输入输出的时候显得比较无力&#xff0c;但如果是多组数据或者输入量较多&#xff0c;就可以显著提升效率。 快读 一个一个字符读取比读入一个数字&#xff08;int&#xff09;快 inline int read(){int x 0, f 1;//in…

【前端】LayUI监听事件汇总

一、监听单选按钮事件 点击资源类型单选按钮时&#xff0c;请求后台接口&#xff0c;把接口返回的内容追加到选择资源下拉框内 HTML <div class"layui-form-item"><label class"layui-form-label">资源类型&#xff1a;</label><d…

【Python快速上手(二十四)】-Python3 JSON数据解析

目录 Python快速上手&#xff08;二十四&#xff09;Python3 JSON数据解析编码&#xff08;序列化&#xff09;解码&#xff08;反序列化&#xff09;读写JSON文件 Python快速上手&#xff08;二十四&#xff09; Python3 JSON数据解析 在Python 3中&#xff0c;使用JSON&…

6. 神经网络的内积

目录 1. 准备知识 1.1 NumPy 的多维数组 1.2 矩阵乘法 1.2.1 矩阵乘法顺序 1.2.2 矩阵乘法范例 2. 神经网络的内积 2.1 使用场合 2.2 Python 实现 1. 准备知识 1.1 NumPy 的多维数组 大家应该对多维数组都很熟悉&#xff0c;我不再多言。在 NumPy 模块中&#xff0c;…

声纹识别在无人机探测上的应用

无人机在民用和军事领域的应用越来越广泛。然而&#xff0c;随着无人机数量的增加&#xff0c;"黑飞"现象也日益严重&#xff0c;对公共安全和隐私构成了威胁。因此&#xff0c;开发有效的无人机探测与识别技术变得尤为重要。及时发现黑飞无人机的存在进而对其型号进…

AI地名故事:鸦岗村

鸦岗村&#xff0c;位于广州市白云区石井镇&#xff0c;是一个历史悠久、文化底蕴深厚的村落。据《广州地名志》记载&#xff0c;南宋时期&#xff0c;南雄珠玑巷的凌氏家族迁移至此地&#xff0c;并在此建立村落。由于村子周边的山岗上常有乌鸦栖息&#xff0c;因此得名“鸦岗…

Redisson中分布式锁的实现原理

redisson版本&#xff1a;3.27.2 简介 锁归根结底就是对同一资源的竞争抢夺&#xff0c;不管是在单体的应用亦或者集群的服务中&#xff0c;上锁都是对同一资源进行修改的操作。至于分布式锁&#xff0c;那就是多个服务器或资源&#xff0c;同时抢占某一单体应用的同个资源了。…

什么是Google SEO优化,如何做好谷歌seo排名?2024年谷歌搜索引擎优化(谷歌SEO)3分钟速通教程指南

1 - 什么是SEO&#xff1f; 谷歌排名优化&#xff08;SEO&#xff1a;Search Engine Optimization&#xff09;是指当您在谷歌搜索那里输入一个您正在推广的产品或服务的关键词时&#xff0c;如何在使您的站在Google里获得一个较高的排名位置而做的优化过程。谷歌排名优化的意…

算法学习笔记(LCA)

L C A LCA LCA&#xff1a;树上两个点的最近公共祖先。&#xff08;两个节点所有公共祖先中&#xff0c;深度最大的公共祖先&#xff09; L C A LCA LCA的性质&#xff1a; 在所有公共祖先中&#xff0c; L C A ( x , y ) LCA(x,y) LCA(x,y)到 x x x和 y y y的距离都最短。 x …