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

news2024/11/16 6:53:16

博主打算从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<>();
    @Autowired
    private LogInfoService logInfoService;
    @Autowired
    private 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) {
        // 获取RequestAttributes
        RequestAttributes 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()); // 请求用户ID
            logInfo.setUserName(request.getAttribute("userName") == null ? "未知" : request.getAttribute("userName").toString()); // 请求用户名称
            logInfo.setIp(MyUtils.getIpAddr()); // 请求IP
            logInfo.setUri(request.getRequestURI()); // 请求URI
            logInfo.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) {
        // 获取RequestAttributes
        RequestAttributes 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说明

    @Autowired
    private LogInfoService logInfoService;
    @Autowired
    private 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 {
    @Autowired
    private 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.coloradmin.cn/o/1678245.html

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

相关文章

Linux上安装python指南

公司的linux服务器上只有自带的python2,折腾了一下安装python3,后来在网上搜发现装miniconda会更加方便。 1、 下载miniconda安装包 清华镜像下载&#xff1a;https://mirrors.tuna.tsinghua.edu.cn/anaconda/miniconda/ 点这里下载 2、 上传Linux安装 #安装在/usr/local/mini…

Spring AI默认gpt版本源码探究

Spring AI默认gpt版本源码探究 调试代码 通过调试&#xff0c;可以看到默认mdel为gpt-3.5-turbo 源码探究 进入OpenAiChatClient类查看具体的代码信息 可以看到如下代码&#xff0c;在有参构造方法中可以看到&#xff0c;model默认使用OpenAiApi.DEFAULT_CHAT_MODELpublic…

离子风机:静电防护的得力助手

在现代工业生产中&#xff0c;静电问题一直是困扰许多企业的难题。尤其是在电子生产线、维修台等敏感区域&#xff0c;静电的存在可能对产品质量造成严重影响&#xff0c;甚至导致设备损坏。为了解决这一问题&#xff0c;离子风机作为静电防护的得力助手&#xff0c;正逐渐受到…

制造企业数据管理:从数据到价值的转化

在数字化浪潮席卷全球的今天&#xff0c;制造企业面临着前所未有的机遇与挑战。如何从海量的数据中提取有价值的信息&#xff0c;将其转化为企业的核心竞争力&#xff0c;成为了每一个制造企业必须面对的问题。而数据管理&#xff0c;正是实现这一转化的关键所在。制造企业数据…

第01章 互联网的概述(发展历史+接入方法+应用)

1.1 本章目标 了解互联网发展的历史熟悉互联网的接入方式了解互联网的典型应用 1.2 互联网发展的历史(产生过程、发展过程) 1.2.1 互联网的起源与发展 1.2.2 互联网在中国的发展 1.3 互联网的接入

【虚拟仿真】Unity3D中实现对大疆无人机遥控器手柄按键响应

推荐阅读 CSDN主页GitHub开源地址Unity3D插件分享简书地址QQ群:398291828大家好,我是佛系工程师☆恬静的小魔龙☆,不定时更新Unity开发技巧,觉得有用记得一键三连哦。 一、前言 最近项目中需要用到大疆无人机遥控器对程序中无人机进行控制,遥控器是下图这一款: 博主发…

Django创建网站的地基

相关文档 1、为新网站创建一个文件夹&#xff08;这里是&#xff1a;locallibrary&#xff09; D:\django>mkdir locallibraryD:\django>cd locallibraryD:\django\locallibrary>dirVolume in drive D is 新加卷Volume Serial Number is B68C-03F7Directory of D:\dj…

网工路由基础——动态路由协议(RIP)

一、动态路由协议的分类 1.按工作区域分类&#xff1a; 动态路由协议按用途分类可以分为内部网关协议&#xff08;IGP&#xff09;和外部网关协议&#xff08;EGP&#xff09;。一个Internet网可以被分成多个域或多个自治系统&#xff0c;各自治系统通过一个核心路由器…

深入学习Linux内核之v4l2应用编程(二)

一&#xff0c;用户空间访问v4l2设备步骤 V4L2&#xff08;Video for Linux 2&#xff09;是Linux中关于视频设备的内核驱动&#xff0c;它使得Linux系统能够支持视频设备&#xff0c;如摄像头。对于Camera V4L2的应用编程&#xff0c;一般遵循以下步骤&#xff1a; 1&#x…

PADS:生成自交叉平面区域

根据板外形铺铜方法&#xff1a; pads根据板外形铺铜_铺铜如何根据板子形状改变-CSDN博客 根据板外形创建平面区域出现问题&#xff1a; 解决方法&#xff1a;去找结构&#xff0c;让他把出图之前把线合并了

上海市虹桥祥源希尔顿酒店屋顶气膜网球馆

上海市虹桥祥源希尔顿酒店屋顶气膜网球馆为高端酒店设施增添了现代化、环保的运动场所。这座网球馆不仅为酒店住客提供了一个全天候、舒适的运动空间&#xff0c;也为虹桥地区的居民带来了全新的健身体验。作为轻空间&#xff08;江苏&#xff09;膜科技有限公司&#xff08;以…

潮玩与游戏的结合点——潮玩宇宙App与链游

本文主要介绍了潮玩宇宙App的开发过程及其链游的开发&#xff0c;探讨了潮玩与游戏的结合点&#xff0c;分析了其市场前景和潜在风险&#xff0c;并提出了相应的建议。 一、潮玩宇宙App的开发背景 随着互联网的普及和人们对娱乐方式的多样化需求&#xff0c;潮玩市场逐渐崛起…

2024 年 4 月公链研报:比特币减半、市场回调以及关键进展

作者&#xff1a;stellafootprint.network 数据来源&#xff1a;Footprint Analytics 公链研究页面 四月&#xff0c;加密市场在经济环境变化中取得了重要进展。4 月 20 日的比特币完成减半&#xff0c;但市场整体低迷导致比特币及前 25 大公链加密货币价格下跌。与此同时&am…

Git系列:git log 掌握版本控制的精髓

&#x1f49d;&#x1f49d;&#x1f49d;欢迎莅临我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:「stormsha的主页」…

Unity WebGL全屏显示

一、删除footer节点 二、删除最下面点击事件绑定 修改Canvas宽高 canvas.style.width "960px"; canvas.style.height "600px"; 改成 canvas.style.width document.documentElement.clientWidth"px"; canvas.style.height document.document…

WebRTC 的核心:RTCPeerConnection

WebRTC 的核心&#xff1a;RTCPeerConnection WebRTC 的核心&#xff1a;RTCPeerConnection创建 RTCPeerConnection 对象RTCPeerConnection 与本地音视频数据绑定媒体协商ICE什么是 Candidate&#xff1f;收集 Candidate交换 Candidate尝试连接 SDP 与 Candidate 消息的互换远端…

python中cv2,等等如何修改为中文字体显示,这里以人脸表情识别中文标签为例

中文字体显示 首先下载字体包部署字体包代码实现部分 想必大家在使用python过程中都会遇到&#xff0c;想要显示中文的时候&#xff0c;但是py基本上都是英文字体&#xff0c;下面我将给大家提供一个比较好的解决方案&#xff1a; 首先下载字体包 方法&#xff1a; 我使用的是…

NGINX SPRING HTTPS证书

服务器&#xff1a;xxx.xxx.xxx.56 客户端器&#xff1a;xxx.xxx.xxx.94##生成服务器证书和密钥容器 keytool -genkey -alias tas-server -keypass 250250 -keyalg RSA -keysize 2048 -validity 3650 -keystore D:\https证书\tas-server.jks -storepass 250250 -dname "C…

喜茶·茶坊黑金首店入驻北京三里屯,率先引入珍稀娟姗奶制茶

发布 | 大力财经 近日&#xff0c;喜茶茶坊 BLACK 在北京三里屯开业&#xff0c;这是喜茶新业态的首家黑金店型。该店在延续喜茶茶坊“鲜、茶、纯”的精品茗茶特色和宋代茶文化审美意趣的基础上&#xff0c;首次升级呈现了铜锅手煮烹茶工艺、娟姗牛乳制茶等创新尝试&#xff0…

Vue.js 详细介绍

文章目录 一、Vue.js 简介1.1 什么是 Vue.js&#xff1f;1.2 Vue.js 的特点 二、快速上手 Vue.js2.1 安装 Vue.js使用 CDN使用 npm 或 yarn 2.2 创建一个 Vue 实例2.3 Vue.js 项目结构 三、Vue.js 核心概念3.1 数据绑定3.2 指令&#xff08;Directives&#xff09;3.3 组件&…