SpringBoot 项目实现操作日志的记录(使用 AOP 注解模式)

news2025/6/9 7:51:08

本文是博主在做关于如何记录用户操作日志时做的记录,常见的项目中难免存在一些需要记录重要日志的部分,例如权限和角色设定,重要数据的操作等部分。

博主使用 Spring 中的 AOP 功能,结合注解的方式,对用户操作过的一些重要方法做日志记录,存储到数据库中,可以随时查阅。

本文使用技术:SpringBoot 3 + JDK17 + MyBatis-Plus + MySQL。


文章目录

    • 01、PostMan 测试结果
    • 02、数据库存储数据后展示样式
    • 03、数据库表创建语句
    • 04、项目结构图
    • 05、代码:application.yml
    • 06、代码:pom.xml
    • 07、代码:注解 LogRecord
    • 08、代码:LogRecordAop
    • 09、代码:OperateTypeEnum
    • 10、代码:TestController
    • 11、代码:LogRecordMapper(使用 MyBatis-Plus)
    • 12、代码:ProjectLog(实体类)
    • 13、代码:UserInfo
    • 14、代码:UserServiceImpl
    • 15、代码:IUserService
    • 16、代码:LogAopUtils
    • 17、代码:LogHolder
    • 18、代码:UserHolder
    • 19、代码:Application
    • 20、代码:LogRecordMapper.xml

01、PostMan 测试结果

青灯文案-测试

02、数据库存储数据后展示样式

在这里插入图片描述

03、数据库表创建语句

CREATE TABLE project_log (
  id bigint(20) NOT NULL AUTO_INCREMENT COMMENT '日志ID',
  company_id varchar(36) DEFAULT NULL COMMENT '公司ID',
  company varchar(200) DEFAULT NULL COMMENT '公司',
  uname varchar(100) DEFAULT NULL COMMENT '用户名',
  uid bigint(20) DEFAULT NULL COMMENT '用户ID',
  operate_type int(10) DEFAULT NULL COMMENT '操作类型',
  operate_module varchar(64) DEFAULT NULL COMMENT '操作模块',
  operate_desc varchar(255) DEFAULT NULL COMMENT '操作描述',
  operate_param text DEFAULT NULL COMMENT '操作参数',
  operate_time bigint(20) DEFAULT NULL COMMENT '操作时间',
  operate_result tinyint(10) DEFAULT NULL COMMENT '操作结果',
  PRIMARY KEY (id)
);

create index idx_operate_type
    on project_log (operate_type);

create index idx_operate_module
    on project_log (operate_module);

create index idx_uid
    on project_log (uid);

create index idx_company
    on project_log (company);

create index idx_uname
    on project_log (uname);

04、项目结构图

青灯文案-项目结构

05、代码:application.yml

server:
  port: 8089

spring:
  datasource:
    url: jdbc:mysql://10.100.4.163:3306/test?allowMultiQueries=true&useUnicode=true&characterEncoding=UTF-8&zeroDateTimeBehavior=convertToNull&serverTimezone=Asia/Shanghai
    driver-class-name: com.mysql.cj.jdbc.Driver
    username: root
    password: 123456

06、代码:pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
         
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.wen</groupId>
    <artifactId>Test-Operate-Log</artifactId>
    <version>1.0-SNAPSHOT</version>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.4.1</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

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

        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-jsqlparser</artifactId>
            <version>3.5.9</version>
        </dependency>

        <!--mybatis-->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-spring-boot3-starter</artifactId>
            <version>3.5.9</version>
        </dependency>

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

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

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

        <dependency>
            <groupId>org.mybatis.generator</groupId>
            <artifactId>mybatis-generator-core</artifactId>
            <version>1.3.5</version>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>com.mysql</groupId>
            <artifactId>mysql-connector-j</artifactId>
        </dependency>

        <dependency>
            <groupId>com.fhs-opensource</groupId>
            <artifactId>easy-trans-mybatis-plus-extend</artifactId>
            <version>3.0.6</version>
        </dependency>

        <dependency>
            <groupId>com.oracle.database.jdbc</groupId>
            <artifactId>ojdbc8</artifactId>
        </dependency>

        <dependency>
            <groupId>org.mybatis.dynamic-sql</groupId>
            <artifactId>mybatis-dynamic-sql</artifactId>
            <version>1.4.0</version>
        </dependency>

        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.8.1</version>
        </dependency>

        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.83</version>
        </dependency>
        
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
        
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-jar-plugin</artifactId>
                <configuration>
                    <archive>
                        <!--生成的jar 不要包含pom.xml pom.properties 这2个文件-->
                        <addMavenDescriptor>false</addMavenDescriptor>
                        <manifest>
                            <!--是否要不第三番jar放到manifest的classpath中-->
                            <addClasspath>true</addClasspath>
                            <!--生成的manifest中的classpath的前缀,因为要把第三方jar放到lib目录下,所以classpath前缀是lib/-->
                            <classpathPrefix>lib/</classpathPrefix>
                            <!--应用的main class -->
                            <mainClass>cn.com.wind.server.Application</mainClass>
                        </manifest>
                    </archive>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>

07、代码:注解 LogRecord

package com.wen.common;

import com.wen.common.OperateTypeEnum;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * @author : rjw
 * @date : 2025-05-19
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface LogRecord {
    OperateTypeEnum operateType() default OperateTypeEnum.OTHER;
}

08、代码:LogRecordAop

package com.wen.common;

import cn.hutool.core.util.ArrayUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.wen.mapper.LogRecordMapper;
import com.wen.model.UserInfo;
import com.wen.model.ProjectLog;
import com.wen.service.IUserService;
import com.wen.utils.LogAopUtils;
import com.wen.utils.LogHolder;
import com.wen.utils.UserHolder;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
import java.util.Arrays;

/**
 * @author : rjw
 * @date : 2025-05-07
 */
@Aspect
@Component
@Slf4j
public class LogRecordAop {

    @Autowired
    private IUserService userService;
    
    @Autowired
    private LogRecordMapper logRecordMapper;

    /**
     * 切入点 使用注解路径
     */
    @Pointcut("@annotation(com.wen.common.LogRecord)")
    public void record() {
    }

	/**
     * 前置操作
     * @param point 切入点
     */
    @Before("record() && @annotation(logRecord)")
    public void before(JoinPoint point, LogRecord logRecord) {
        ProjectLog logInfo = new ProjectLog();
        UserInfo user = UserHolder.getCurrentUser();
        // id 自增
        if (user != null) {
            logInfo.setUid(user.getUid());
            logInfo.setUname(user.getName());
            logInfo.setCompanyId(user.getCompanyId() == null ? "" : user.getCompanyId());
            logInfo.setCompany(user.getCompany());
        } else {
            // 如果为null,则说明开发人员使用接口调用
            logInfo.setUid(-1L);
            logInfo.setUname("开发人员");
            logInfo.setCompanyId("");
            logInfo.setCompany("tx");
        }
        logInfo.setOperateType(logRecord.operateType().getCode());
        logInfo.setOperateModule(logRecord.operateType().getModule());
        logInfo.setOperateTime(System.currentTimeMillis());
        Object[] args = LogAopUtils.removeUnnecessaryArgs(point.getArgs());
        logInfo.setOperateDesc(genOperateDesc(logRecord.operateType(), args, logInfo));
        if (ArrayUtil.isNotEmpty(args)) {
            if (logRecord.operateType() == OperateTypeEnum.EXPORT) {
                logInfo.setOperateParam(JSON.toJSONString(args[0]));
            } else {
                logInfo.setOperateParam(JSON.toJSONString(args));
            }
        }
        LogHolder.setProjectLog(logInfo);
    }

    private String genOperateDesc(OperateTypeEnum operateType, Object[] args, ProjectLog projectLog) {
        String operateDesc = String.format("【%s】-%s", operateType.getModule(), operateType.getFunction());
        if (ArrayUtil.isEmpty(args)) {
            return operateDesc;
        }
        switch (operateType) {
            case OPERATE:
                operateDesc = String.format(operateDesc, Arrays.toString(args));
                break;
            default:
                JSONObject req = JSONObject.parseObject(JSON.toJSONString(args[0]));
                operateDesc = String.format(operateDesc, req.toJSONString());
                break;
        }
        log.info("operateDesc: {}", operateDesc);
        return operateDesc;
    }

    @AfterReturning(value = "record()", returning = "response")
    public void afterReturning(Object response) {
        try {
            ProjectLog logInfo = LogHolder.getProjectLog();
            //   ======== 这里要求要使用返回值   
            if (logInfo == null || response == null) {
                return;
            }
            logInfo.setOperateResult((byte) 400);
            if (!checkParam(logInfo)) {
                log.warn("add log to DB failed cause param error! complianceLog:{}", logInfo);
                return;
            }
            addPrivateQuoteLog(logInfo);
        } finally {
            LogHolder.removeProjectLog();
        }
    }

	@AfterThrowing(value = "record()", throwing = "t")
    public void afterThrowing(Throwable t) {
        try {
            ProjectLog infoLog = LogHolder.getProjectLog();
            if (infoLog == null) {
                return;
            }
            infoLog.setOperateResult((byte) 400);
            if (!checkParam(infoLog)) {
                log.warn("add log to DB failed cause param error! complianceLog:{}", infoLog);
                return;
            }
            addPrivateQuoteLog(infoLog);
        } finally {
            LogHolder.getProjectLog();
        }
    }

    @Async
    private void addPrivateQuoteLog(ProjectLog projectLog) {
        logRecordMapper.insert(projectLog);
    }

    private boolean checkParam(ProjectLog projectLog) {
        return projectLog != null &&
                projectLog.getCompanyId() != null &&
                projectLog.getCompany() != null &&
                projectLog.getUid() != null &&
                projectLog.getOperateResult() != null &&
                projectLog.getOperateTime() != null &&
                projectLog.getOperateType() != null &&
                projectLog.getUname() != null;
    }
}

09、代码:OperateTypeEnum

package com.wen.common;

import lombok.Getter;

/**
 * @author : rjw
 * @date : 2025-05-19
 */
@Getter
public enum OperateTypeEnum {
    OTHER(0, "系统","其它类型"),
    OPERATE(1, "内部接口—操作", "操作"),
    EXPORT(2, "内部接口—导出", "导出"),
    MAX(100, "", "")
    ;

    private final int code;
    private final String module;
    private final String function;

    OperateTypeEnum(int code, String module, String function) {
        this.code = code;
        this.module = module;
        this.function = function;
    }
}

10、代码:TestController

package com.wen.controller;

import com.wen.common.LogRecord;
import com.wen.common.OperateTypeEnum;
import com.wen.model.UserInfo;
import com.wen.service.IUserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

/**
 * @author : rjw
 * @date : 2025-05-19
 */
@Slf4j
@RestController
@RequestMapping("/system")
public class TestController {

    @Autowired
    private IUserService userService;
    
    @GetMapping("/testLog")
    @LogRecord(operateType = OperateTypeEnum.OPERATE)
    public UserInfo updateQuoteChannelPush(@RequestParam("id") long id, @RequestParam("name") String name,
                @RequestParam("company") String company, @RequestParam("companyId") String companyId) {
        userService.getCurrentUser();
        // 和内部数据无关
        UserInfo userInfo = new UserInfo();
        userInfo.setUid(id);
        userInfo.setName(name);
        userInfo.setCompany(company);
        userInfo.setCompanyId(companyId);
        log.info("userInfo is {}", userInfo);
        // 要有返回值,不然不能记录,可以在AOP中自己调
        return userInfo;
    }
}

11、代码:LogRecordMapper(使用 MyBatis-Plus)

package com.wen.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.wen.model.ProjectLog;

/**
 * @author : rjw
 * @date : 2025-05-19
 */
public interface LogRecordMapper extends BaseMapper<ProjectLog> {

}

12、代码:ProjectLog(实体类)

package com.wen.model;

import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;

/**
 * @author : rjw
 * @date : 2025-05-19
 */
@Data
@TableName("project_log")
public class ProjectLog {

    /**
     * 日志 ID
     */
    @TableId(value = "id", type = IdType.AUTO)
    private Long logId;

    /**
     * 公司ID
     */
    private String companyId;

    /**
     * 公司
     */
    private String company;

    /**
     * 用户名
     */
    private String uname;

    /**
     * 用户ID
     */
    private Long uid;

    /**
     * 操作类型
     */
    private Integer operateType;

    /**
     * 操作模块
     */
    private String operateModule;

    /**
     * 操作描述
     */
    private String operateDesc;

    /**
     * 操作参数
     */
    private String operateParam;

    /**
     * 操作时间
     */
    private Long operateTime;

    /**
     * 操作结果
     */
    private Byte operateResult;
}

13、代码:UserInfo

package com.wen.model;

import lombok.Data;

/**
 * @author : rjw
 * @date : 2025-05-19
 */
@Data
public class UserInfo {

    private long uid;

    private String name;

    private String company;
    
    private String companyId;
}

14、代码:UserServiceImpl

package com.wen.service.impl;

import com.wen.model.UserInfo;
import com.wen.service.IUserService;
import com.wen.utils.UserHolder;
import org.springframework.stereotype.Service;

/**
 * @author : rjw
 * @date : 2025-05-19
 */
@Service
public class UserServiceImpl implements IUserService {

    @Override
    public UserInfo getCurrentUser() {
        /**
         * 一般是登陆的时候设置当前用户
         * 下线的时候删除当前用户
         */
        UserInfo userInfo = new UserInfo();
        userInfo.setUid(1000001);
        userInfo.setName("张三");
        userInfo.setCompany("tx");
        userInfo.setCompanyId("tx");
        UserHolder.setCurrentUser(userInfo);
        return userInfo;
    }
}

15、代码:IUserService

package com.wen.service;

import com.wen.model.UserInfo;

/**
 * @author : rjw
 * @date : 2025-05-19
 */
public interface IUserService {

    UserInfo getCurrentUser();

}

16、代码:LogAopUtils

package com.wen.utils;

import jakarta.servlet.ServletRequest;
import jakarta.servlet.ServletResponse;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.apache.catalina.connector.RequestFacade;
import org.apache.catalina.connector.ResponseFacade;
import org.springframework.web.multipart.MultipartFile;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

public class LogAopUtils {
    public final static Set<Class<?>> UNNECESSARY_CLASS = new HashSet<Class<?>>(){
        {
            add(ServletRequest.class);
            add(ServletResponse.class);
            add(HttpServletRequest.class);
            add(HttpServletResponse.class);
            add(RequestFacade.class);
            add(ResponseFacade.class);
        }
    };

    public final static Set<Class<?>> UNNECESSARY_SUPER_CLASSES = new HashSet<Class<?>>() {
        {
            add(MultipartFile.class);
        }
    };

    public static Object[] removeUnnecessaryArgs(Object[] args) {
        List<Object> list = new ArrayList<>();
        outer: for (Object arg : args) {
            if (UNNECESSARY_CLASS.contains(arg.getClass())) {
                continue;
            }
            for (Class<?> superClass : UNNECESSARY_SUPER_CLASSES) {
                if(superClass.isAssignableFrom(arg.getClass())) {
                    continue outer;
                }
            }
            list.add(arg);
        }
        return list.toArray();
    }
}

17、代码:LogHolder

package com.wen.utils;

import com.wen.model.ProjectLog;

public class LogHolder {

    private static final ThreadLocal<ProjectLog> LOCAL_PROJECT_LOG = new ThreadLocal<>();

    public static ProjectLog getProjectLog() {
        return LOCAL_PROJECT_LOG.get();
    }

    public static void setProjectLog(ProjectLog user) {
        LOCAL_PROJECT_LOG.set(user);
    }

    public static void removeProjectLog() {
        LOCAL_PROJECT_LOG.remove();
    }
}

18、代码:UserHolder

package com.wen.utils;

import com.wen.model.UserInfo;

/**
 * @author : rjw
 * @date : 2025-05-07
 */
public class UserHolder {

    private static final ThreadLocal<UserInfo> CURRENT_USER = new ThreadLocal<>();

    public static UserInfo getCurrentUser() {
        return CURRENT_USER.get();
    }
    
    public static void setCurrentUser(UserInfo user) {
        CURRENT_USER.set(user);
    }
    
    public static void removeCurrentUser() {
        CURRENT_USER.remove();
    }
}

19、代码:Application

package com.wen;

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

/**
 * @author : rjw
 * @date : 2025-05-19
 */
@SpringBootApplication
@MapperScan(basePackages = {"com.wen.mapper"})
public class Application {

    public static void main(String[] args) {
        SpringApplication.run(Application.class);
    }
}

20、代码:LogRecordMapper.xml

<?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="com.wen.mapper.LogRecordMapper">


</mapper>

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

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

相关文章

AI|Java开发 IntelliJ IDEA中接入本地部署的deepseek方法

目录 连接本地部署的deepseek&#xff1a; IntelliJ IDEA中使用deepseek等AI&#xff1a; 用法一&#xff1a;让AI写代码 用法二&#xff1a;选中这段代码&#xff0c;右键&#xff0c;可以让其解释这段代码的含义。这时显示的解释是英文的。 连接本地部署的deepseek&#…

【1——Android端添加隐私协议(unity)1/3】

前言&#xff1a;这篇仅对于unity 发布Android端上架国内应用商店添加隐私协议&#xff0c;隐私协议是很重要的东西&#xff0c;没有这个东西&#xff0c;是不上了应用商店的。 对于仅仅添加隐私协议&#xff0c;我知道有三种方式,第一种和第二种基本一样 1.直接在unity里面新…

Linux之概述和安装vm虚拟机

文章目录 操作系统概述硬件和软件操作系统常见操作系统 初识LinuxLinux的诞生Linux内核Linux发行版 虚拟机介绍虚拟机 VMware WorkStation安装虚拟化软件VMware WorkStation 安装查看VM网络连接设置VM存储位置 在VMware上安装Linux(发行版CentOS7)安装包获取CentOS7 安装 Mac系…

LeetCode热题100--19.删除链表的倒数第N个结点--中等

1. 题目 给你一个链表&#xff0c;删除链表的倒数第 n 个结点&#xff0c;并且返回链表的头结点。 示例 1&#xff1a; 输入&#xff1a;head [1,2,3,4,5], n 2 输出&#xff1a;[1,2,3,5] 示例 2&#xff1a; 输入&#xff1a;head [1], n 1 输出&#xff1a;[] 示例…

git学习与使用(远程仓库、分支、工作流)

文章目录 前言简介git的工作流程git的安装配置git环境&#xff1a;git config --globalgit的基本使用新建目录初始化仓库&#xff08;repository&#xff09;添加到暂存区新增/修改/删除 文件状态会改变 提交到仓库查看提交&#xff08;commit&#xff09;的历史记录git其他命令…

《Android 应用开发基础教程》——第十四章:Android 多线程编程与异步任务机制(Handler、AsyncTask、线程池等)

目录 第十四章&#xff1a;Android 多线程编程与异步任务机制&#xff08;Handler、AsyncTask、线程池等&#xff09; &#x1f538; 14.1 为什么需要多线程&#xff1f; &#x1f538; 14.2 Handler Thread 模型 ✦ 使用 Handler 与 Thread 进行线程通信 ✦ 简要说明&am…

【JVM 01-引言入门篇】

JVM 引言篇01 笔记记录 1. 什么是JVM&#xff1f;2. 学习JVM有什么用&#xff1f;3. 常见的JVM4. 学习路线 学习资料来源-b站黑马 1. 什么是JVM&#xff1f; 定义&#xff1a;Java虚拟机&#xff08;Java Virtual Machine 简称JVM&#xff09;是运行所有Java程序的抽象计算机&a…

Pandas数据规整

&#xff08;1&#xff09;层次化索引 1.创建带层次化索引的df 第一种&#xff0c;直接创建 import pandas as pd import numpy as npdata pd.Series(np.random.randn(9),index [[a, a, a, b, b, c, c, d, d],[1, 2, 3, 1, 3, 1, 2, 2, 3]]) print(data) # a 1 -0.6416…

ThreadLocal线程本地变量在dubbo服务使用时候遇到的一个坑

我昨天遇到一个问题&#xff0c;就是我springboot项目里面有一个提供代办服务审核的dubbo接口&#xff0c;这个接口给房源项目调用&#xff0c;但是碰到一个问题就是&#xff0c;房源项目每天凌晨5点会查询满足条件过期的数据&#xff0c;然后调用我这边的代办审核dubbo接口&am…

从 0 到 1:Spring Boot 与 Spring AI 深度实战(基于深度求索 DeepSeek)

在人工智能技术与企业级开发深度融合的今天&#xff0c;传统软件开发模式与 AI 工程化开发的差异日益显著。作为 Spring 生态体系中专注于 AI 工程化的核心框架&#xff0c;Spring AI通过标准化集成方案大幅降低 AI 应用开发门槛。本文将以国产大模型代表 ** 深度求索&#xff…

upload-labs通关笔记-第20关 文件上传之杠点绕过

系列目录 upload-labs通关笔记-第1关 文件上传之前端绕过&#xff08;3种渗透方法&#xff09; upload-labs通关笔记-第2关 文件上传之MIME绕过-CSDN博客 upload-labs通关笔记-第3关 文件上传之黑名单绕过-CSDN博客 upload-labs通关笔记-第4关 文件上传之.htacess绕过-CSDN…

Vscode +Keil Assistant编译报错处理

Vscode Keil Assistant编译报错处理 1.报错图片内容 所在位置 行:1 字符: 25 chcp.com 65001 -Command & c:\Users\92170.vscode\extensions\cl.keil-a … ~ 不允许使用与号(&)。& 运算符是为将来使用而保留的&#xff1b;请用双引号将与号引起来(“&”)&…

VSCode C/C++ 开发环境完整配置及一些扩展用途(自用)update:2025/3/31

这里主要记录了一些与配置相关的内容。由于网上教程众多&#xff0c;部分解决方法并不能完全契合我遇到的问题&#xff0c;因此我选择以自己偏好的方式&#xff0c;对 VSCode 进行完整的配置&#xff0c;并记录在使用过程中遇到的问题及解决方案。后续内容也会持续更新和完善。…

Docker系列(二):开机自启动与基础配置、镜像加速器优化与疑难排查指南

引言 docker 的快速部署与高效运行依赖于两大核心环节&#xff1a;基础环境搭建与镜像生态优化。本期博文从零开始&#xff0c;系统讲解 docker 服务的管理配置与镜像加速实践。第一部分聚焦 docker 服务的安装、权限控制与自启动设置&#xff0c;确保环境稳定可用&#xff1b…

a16z:AI带来了全新的9种开发软件的模式

非常有启发的9条新兴模式&#xff0c;推荐给已经上手 vibeCoding 的读者们。 开发者正在将 AI 从简单的工具转变为构建软件的新基础。许多核心概念&#xff0c;如版本控制、模板、文档&#xff0c;甚至用户的定义&#xff0c;都在被重新思考。代理&#xff08;Agent&#xff09…

在 Excel 使用macro————仙盟创梦IDE

Dim filePath As StringDim fileContent As StringDim lines() As StringDim dataArray() As StringDim lineCount As LongDim maxCols As LongDim i As Long, j As Long 文件路径filePath "" 检查文件是否存在If Dir(filePath) "" ThenMsgBox "文件…

鸿蒙devEco studio如何创建模拟器

官网原文链接&#xff1a;https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/ide-emulator-create 操作步骤 点击菜单栏的Tools > Device Manager&#xff0c;点击右下角的Edit设置模拟器实例的存储路径Local Emulator Location&#xff0c;Mac默认存储在~/…

鸿蒙路由参数传递

页面test.ets 代码如下&#xff1a; import router from ohos.router Entry Component struct Test {State message: string Hello WorldState username: string huState password: string 1build() {Row() {Column() {Text(this.message).fontSize(50).fontWeight(FontWe…

springboot 控制层调用业务逻辑层,注入报错,无法自动装配 解决办法

报错&#xff1a; 解决&#xff1a;愿意是业务逻辑层&#xff0c;即service层的具体实现类没有加注解Service导致的&#xff0c;加上解决了&#xff01;&#xff01;

MySQL:11_事务

事务 一.CURD不加控制&#xff0c;会有什么问题&#xff1f; 二.什么是事务&#xff1f; 事务就是一组DML语句组成&#xff0c;这些语句在逻辑上存在相关性&#xff0c;这一组DML语句要么全部成功&#xff0c;要么全部失败&#xff0c;是一个整体。MySQL提供一种机制&#xf…