使用SpringBoot AOP记录操作日志和异常日志

使用SpringBoot AOP记录操作日志和异常日志

平时我们在做项目时经常需要对一些重要功能操作记录日志,方便以后跟踪是谁在操作此功能;我们在操作某些功

能时也有可能会发生异常,但是每次发生异常要定位原因我们都要到服务器去查询日志才能找到,而且也不能对发

生的异常进行统计,从而改进我们的项目,要是能做个功能专门来记录操作日志和异常日志那就好了。

当然我们肯定有方法来做这件事情,而且也不会很难,我们可以在需要的方法中增加记录日志的代码,和在每个方

法中增加记录异常的代码,最终把记录的日志存到数据库中。听起来好像很容易,但是我们做起来会发现,做这项

工作很繁琐,而且都是在做一些重复性工作,还增加大量冗余代码,这种方式记录日志肯定是不可行的。

我们以前学过Spring 三大特性,IOC(控制反转),DI(依赖注入),AOP(面向切面),那其中AOP的主要功能

就是将日志记录,性能统计,安全控制,事务处理,异常处理等代码从业务逻辑代码中划分出来。今天我们就来用

springBoot Aop 来做日志记录,好了,废话说了一大堆还是上货吧。

1、创建日志记录表、异常日志表,表结构如下

操作日志表OperationLog

CREATE TABLE `OperationLog` (`oper_id` varchar(64) DEFAULT NULL COMMENT '主键id',`oper_modul` varchar(64) DEFAULT NULL COMMENT '功能模块',`oper_type` varchar(64) DEFAULT NULL COMMENT '操作类型',`oper_desc` varchar(500) DEFAULT NULL COMMENT '操作描述',`oper_requ_param` text COMMENT '请求参数',`oper_resp_param` text COMMENT '返回参数',`oper_user_id` varchar(64) DEFAULT NULL COMMENT '操作员ID',`oper_user_name` varchar(64) DEFAULT NULL COMMENT '操作员名称',`oper_method` varchar(255) DEFAULT NULL COMMENT '操作方法',`oper_uri` varchar(255) DEFAULT NULL COMMENT '请求URI',`oper_ip` varchar(64) DEFAULT NULL COMMENT '请求ID',`oper_create_time` datetime DEFAULT NULL COMMENT '操作时间',`oper_ver` varchar(64) DEFAULT NULL COMMENT '操作版本号',PRIMARY KEY (`oper_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

在这里插入图片描述

异常日志表ExceptionLog

CREATE TABLE `ExceptionLog` (`exp_id` varchar(64) NOT NULL DEFAULT "" COMMENT '主键id',`exp_requ_param` text COMMENT '请求参数',`exp_name` varchar(255) COMMENT '异常名称',`exp_message` text COMMENT '异常信息',`oper_user_id` varchar(64) DEFAULT NULL COMMENT '操作员ID',`oper_user_name` varchar(64) DEFAULT NULL COMMENT '操作员名称',`oper_method` varchar(255) DEFAULT NULL COMMENT '操作方法',`oper_uri` varchar(255) DEFAULT NULL COMMENT '请求URI',`oper_ip` varchar(64) DEFAULT NULL COMMENT '请求ID',`oper_create_time` datetime DEFAULT NULL COMMENT '操作时间',`oper_ver` varchar(64) DEFAULT NULL COMMENT '操作版本号',PRIMARY KEY (`exp_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

在这里插入图片描述

2、添加Maven依赖

<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.5.6</version><relativePath/></parent><groupId>com.aop.log</groupId><artifactId>spring-boot-aop-log</artifactId><version>0.0.1-SNAPSHOT</version><name>spring-boot-aop-log</name><description>spring-boot-aop-log</description><properties><java.version>1.8</java.version></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-aop</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></dependency><!-- mybatis-plus依赖 --><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.3.1.tmp</version></dependency><dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>1.2.58</version></dependency><!-- mysql依赖 --><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.22</version></dependency></dependencies><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build></project>

3、创建实体类

ExceptionLog实体

package com.aop.log.entity;import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;import java.util.Date;/*** @author zhangshixing* @date 2021年11月05日 10:04*/
@Data
@NoArgsConstructor
@AllArgsConstructor
@TableName("ExceptionLog")
public class ExceptionLog {// 主键id@TableId(value = "exp_id", type = IdType.ASSIGN_UUID)private String expId;// 请求参数private String expRequParam;// 异常名称private String expName;// 异常信息private String expMessage;// 操作员IDprivate String operUserId;// 操作员名称private String operUserName;// 操作方法private String operMethod;// 请求URIprivate String operUri;// 请求IDprivate String operIp;// 操作时间private Date operCreateTime;// 操作版本号private String operVer;
}

OperationLog实体

package com.aop.log.entity;import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;import java.io.Serializable;
import java.util.Date;/*** @author zhangshixing* @date 2021年11月05日 9:52*/@Data
@NoArgsConstructor
@AllArgsConstructor
@TableName("OperationLog")
public class OperationLog implements Serializable {// 主键id@TableId(value = "oper_id", type = IdType.ASSIGN_UUID)private String operId;// 功能模块private String operModul;// 操作类型private String operType;// 操作描述private String operDesc;// 请求参数private String operRequParam;// 返回参数private String operRespParam;// 操作员IDprivate String operUserId;// 操作员名称private String operUserName;// 操作方法private String operMethod;// 请求URIprivate String operUri;// 请求IDprivate String operIp;// 操作时间private Date operCreateTime;// 操作版本号private String operVer;
}

OrderInfo订单实体类

package com.aop.log.entity;import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;/*** @author zhangshixing* @date 2021年11月05日 10:33*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class OrderInfo {/*** 这里只是为了测试所以只添加了两个参数*/// 订单编号private String orderid;// 订单金额private int price;}

RespBean公共返回对象

package com.aop.log.entity;import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;/*** @author zhangshixing* @date 2021年11月05日 10:31*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class RespBean {private long code;private String message;private Object obj;public static RespBean success(String message) {return new RespBean(200, message, null);}public static RespBean success(String message, Object obj) {return new RespBean(200, message, obj);}public static RespBean error(String message) {return new RespBean(500, message, null);}public static RespBean error(String message, Object obj) {return new RespBean(500, message, obj);}
}

4、创建Mapper

OperationLogMapper

package com.aop.log.mapper;import com.aop.log.entity.OperationLog;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;@Mapper
public interface OperationLogMapper extends BaseMapper<OperationLog> {}

ExceptionLogMapper

package com.aop.log.mapper;import com.aop.log.entity.ExceptionLog;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;@Mapper
public interface ExceptionLogMapper extends BaseMapper<ExceptionLog> {}

5、创建service

OperationLogService

package com.aop.log.service;import com.aop.log.entity.OperationLog;
import com.baomidou.mybatisplus.extension.service.IService;public interface OperationLogService extends IService<OperationLog> {
}

ExceptionLogService

package com.aop.log.service;import com.aop.log.entity.ExceptionLog;
import com.baomidou.mybatisplus.extension.service.IService;public interface ExceptionLogService extends IService<ExceptionLog> {}

OperationLogServiceImpl

package com.aop.log.service.impl;import com.aop.log.entity.OperationLog;
import com.aop.log.mapper.OperationLogMapper;
import com.aop.log.service.OperationLogService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;/*** @author zhangshixing* @date 2021年11月05日 10:10*/
@Service
public class OperationLogServiceImpl extends ServiceImpl<OperationLogMapper, OperationLog>implements OperationLogService {
}

ExceptionLogServiceImpl

package com.aop.log.service.impl;import com.aop.log.entity.ExceptionLog;
import com.aop.log.mapper.ExceptionLogMapper;
import com.aop.log.service.ExceptionLogService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;/*** @author zhangshixing* @date 2021年11月05日 10:10*/
@Service
public class ExceptionLogServiceImpl extends ServiceImpl<ExceptionLogMapper, ExceptionLog>implements ExceptionLogService {
}

6、创建操作日志注解类OperLog

package com.aop.log.annotation;import java.lang.annotation.*;/*** @author zhangshixing* @date 2021年11月05日 9:43* 自定义操作日志注解*/
//注解放置的目标位置,METHOD是可注解在方法级别上
@Target(ElementType.METHOD)
//注解在哪个阶段执行
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface OperLog {// 操作模块String operModul() default "";// 操作类型String operType() default "";// 操作说明String operDesc() default "";
}
package com.aop.log.annotation;public class OprLogConst {public static final String ADD = "add";public static final String INSERET = "insert";public static final String UPDATE = "update";public static final String DELETE = "delete";
}

7、创建切面类记录操作日志

package com.aop.log.aop;import com.alibaba.fastjson.JSON;
import com.aop.log.annotation.OperLog;
import com.aop.log.entity.ExceptionLog;
import com.aop.log.entity.OperationLog;
import com.aop.log.service.ExceptionLogService;
import com.aop.log.service.OperationLogService;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
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.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;/*** @author zhangshixing* @date 2021年11月05日 9:46* 切面处理类,操作日志异常日志记录处理*/
@Aspect
@Component
public class OperLogAspect {/*** 操作版本号* 项目启动时从命令行传入,例如:java -jar xxx.war --version=201902*/@Value("${version}")private String operVer;@Autowiredprivate OperationLogService operationLogService;@Autowiredprivate ExceptionLogService exceptionLogService;/*** 设置操作日志切入点 记录操作日志 在注解的位置切入代码*/@Pointcut("@annotation(com.aop.log.annotation.OperLog)")public void operLogPoinCut() {}/*** 设置操作异常切入点记录异常日志 扫描所有controller包下操作*/@Pointcut("execution(* com.aop.log.controller..*.*(..))")public void operExceptionLogPoinCut() {}/*** 正常返回通知,拦截用户操作日志,连接点正常执行完成后执行, 如果连接点抛出异常,则不会执行** @param joinPoint 切入点* @param keys      返回结果*/@AfterReturning(value = "operLogPoinCut()", returning = "keys")public void saveOperLog(JoinPoint joinPoint, Object keys) {// 获取RequestAttributesRequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();// 从获取RequestAttributes中获取HttpServletRequest的信息HttpServletRequest request = (HttpServletRequest) requestAttributes.resolveReference(RequestAttributes.REFERENCE_REQUEST);// 创建OperationLog对象OperationLog operlog = new OperationLog();try {// 主键IDString uuid = UUID.randomUUID().toString();System.out.println("saveOperLog:" + uuid);operlog.setOperId(uuid);// 从切面织入点处通过反射机制获取织入点处的方法MethodSignature signature = (MethodSignature) joinPoint.getSignature();// 获取切入点所在的方法Method method = signature.getMethod();// 获取操作OperLog opLog = method.getAnnotation(OperLog.class);if (opLog != null) {String operModul = opLog.operModul();String operType = opLog.operType();String operDesc = opLog.operDesc();// 操作模块operlog.setOperModul(operModul);// 操作类型operlog.setOperType(operType);// 操作描述operlog.setOperDesc(operDesc);}// 获取请求的类名String className = joinPoint.getTarget().getClass().getName();// 获取请求的方法名String methodName = method.getName();methodName = className + "." + methodName;// 请求方法operlog.setOperMethod(methodName);// 请求的参数Map<String, String> rtnMap = converMap(request.getParameterMap());// 将参数所在的数组转换成jsonString params = JSON.toJSONString(rtnMap);// 请求参数operlog.setOperRequParam(params);// 返回结果operlog.setOperRespParam(JSON.toJSONString(keys));// 请求用户ID// operlog.setOperUserId(UserShiroUtil.getCurrentUserLoginName());// 这里写一个固定的用户IDoperlog.setOperUserId("100293784");// 请求用户名称// operlog.setOperUserName(UserShiroUtil.getCurrentUserName());// // 这里写一个固定的用户名operlog.setOperUserName("yiyiyi");// 请求IP// operlog.setOperIp(IPUtil.getRemortIP(request));// 这里写一个固定的IPoperlog.setOperIp("127.0.0.1");// 请求URIoperlog.setOperUri(request.getRequestURI());// 创建时间operlog.setOperCreateTime(new Date());// 操作版本operlog.setOperVer(operVer);// 将数据插入到数据库operationLogService.save(operlog);} catch (Exception e) {e.printStackTrace();}}/*** 异常返回通知,用于拦截异常日志信息 连接点抛出异常后执行** @param joinPoint 切入点* @param e         异常信息*/@AfterThrowing(pointcut = "operExceptionLogPoinCut()", throwing = "e")public void saveExceptionLog(JoinPoint joinPoint, Throwable e) {// 获取RequestAttributesRequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();// 从获取RequestAttributes中获取HttpServletRequest的信息HttpServletRequest request = (HttpServletRequest) requestAttributes.resolveReference(RequestAttributes.REFERENCE_REQUEST);ExceptionLog excepLog = new ExceptionLog();try {// 从切面织入点处通过反射机制获取织入点处的方法MethodSignature signature = (MethodSignature) joinPoint.getSignature();// 获取切入点所在的方法Method method = signature.getMethod();String uuid = UUID.randomUUID().toString();System.out.println("saveExceptionLog:" + uuid);excepLog.setExpId(uuid);// 获取请求的类名String className = joinPoint.getTarget().getClass().getName();// 获取请求的方法名String methodName = method.getName();methodName = className + "." + methodName;// 请求的参数Map<String, String> rtnMap = converMap(request.getParameterMap());// 将参数所在的数组转换成jsonString params = JSON.toJSONString(rtnMap);// 请求参数excepLog.setExpRequParam(params);// 请求方法名excepLog.setOperMethod(methodName);// 异常名称excepLog.setExpName(e.getClass().getName());// 异常信息excepLog.setExpMessage(stackTraceToString(e.getClass().getName(), e.getMessage(), e.getStackTrace()));// 操作员ID// excepLog.setOperUserName(UserShiroUtil.getCurrentUserName());excepLog.setOperUserId("100293784");// 操作员名称excepLog.setOperUserName("yiyiyi");// 操作URIexcepLog.setOperUri(request.getRequestURI());// 操作员IP// excepLog.setOperIp(IPUtil.getRemortIP(request));excepLog.setOperIp("127.0.0.1");// 操作版本号excepLog.setOperVer(operVer);// 发生异常时间excepLog.setOperCreateTime(new Date());exceptionLogService.save(excepLog);} catch (Exception e2) {e2.printStackTrace();}}/*** 转换request 请求参数** @param paramMap request获取的参数数组*/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;}/*** 转换异常信息为字符串** @param exceptionName    异常名称* @param exceptionMessage 异常信息* @param elements         堆栈信息*/public String stackTraceToString(String exceptionName, String exceptionMessage, StackTraceElement[] elements) {StringBuffer strbuff = new StringBuffer();for (StackTraceElement stet : elements) {strbuff.append(stet + "\n");}String message = exceptionName + ":" + exceptionMessage + "\n\t" + strbuff.toString();return message;}
}

8、在Controller层方法添加@OperLog注解

package com.aop.log.controller;import com.aop.log.annotation.OperLog;
import com.aop.log.annotation.OprLogConst;
import com.aop.log.entity.OrderInfo;
import com.aop.log.entity.RespBean;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;/*** @author zhangshixing* @date 2021年11月05日 10:25*/
@Controller
public class OrderController {/*** 新增订单信息*/@RequestMapping(value = "addOrderInfo")@ResponseBody@OperLog(operModul = "销售管理-订单新增", operType = OprLogConst.ADD, operDesc = "订单新增功能")public RespBean addOrderInfo(OrderInfo orderInfo) {if (orderInfo.getPrice() < 0) {System.out.println(1 / 0);return RespBean.error("提交失败!!!");} else if (orderInfo.getPrice() < 30) {return RespBean.success("提交成功!!!");} else {return RespBean.error("提交失败!!!");}}
}

9、启动类和配置文件

version = 2.1.1
server.port = 9000
spring.datasource.driver-class-name = com.mysql.cj.jdbc.Driver
spring.datasource.url = jdbc:mysql://localhost:3306/log?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai
spring.datasource.username = root
spring.datasource.password = root
package com.aop.log;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplication
public class SpringBootAopLogApplication {public static void main(String[] args) {SpringApplication.run(SpringBootAopLogApplication.class, args);}}

10、操作日志、异常日志查询功能

10.1 记录操作日志

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

10.2 记录异常日志

在这里插入图片描述

在这里插入图片描述

11、execution 表达式

学习Spring中的aop组装切面时遇到的execution表达式,下面是execution表达式的详解。

切入点表达式:

整个表达式可以分为五个部分:

1、execution(): 表达式主体。

2、第一个*号:方法返回类型, *号表示所有的类型。

3、包名:表示需要拦截的包名。

4、第二个*号:表示类名,*号表示所有的类。

5、*(..):最后这个星号表示方法名,*号表示所有的方法,后面( )里面表示方法的参数,两个句点表示任

何参数。

表达式语法:

execution(* 包名.*.*(..))

规范写法:execution(* com.baizhi.service.UserServiceImpl.*(..))

这个表达式是重点 ,是最通用的,表示执行接口下的所有接口方法。

execution表达式举例:

书写接口实现方法:UserServiceImpl

方法类型:

add(); query(); add(String name); add(User user); add(String name,Integer age);

execution(* service.UserServiceImpl.add(..))        //执行add()方法
execution(* service.UserServiceImpl.add(String))    //执行add(String name)方法
execution(* service.UserServiceImpl.add(com.baizhi.entity.User))   //执行add(User user)方法
execution(* service.UserServiceImpl.add(String , Integer))    //执行add(String name,Interger age)方法

execution表达式的一般用法:

execution(* service.UserServiceImpl.*(java.util.List))
返回值:任意
包:com.baizhi.service
类:UserServiceImpl
方法:任意
参数:必须是List集合
execution(* service.UserServiceImpl.add*(..))  重点
返回值:任意
包:com.baizhi.service
类:UserServiceImpl
方法:以add关键字开头的方法
参数:任意
execution(* service.UserServiceImpl.*.*(..))  重点
返回值:任意
包:com.baizhi.service
类:当前包下的所有类
方法:所有类中的所有方法
参数:任意
execution(* service..*.*(..))  重点
返回值:任意
包:service包以及它下面所有子包
类:所有包中的所有类
方法:所有类中的所有方法
参数:任意
execution(* *(..))   重点,不建议这样写,栈溢出

注意:要尽可能精准的切入。

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

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

相关文章

【LeetCode每日一题】1599. 经营摩天轮的最大利润(模拟)—2024新年快乐!

2024-1-1 文章目录 [1599. 经营摩天轮的最大利润](https://leetcode.cn/problems/maximum-profit-of-operating-a-centennial-wheel/)思路&#xff1a; 1599. 经营摩天轮的最大利润 思路&#xff1a; 1.对摩天轮的运转情况进行模拟&#xff0c; 2.遍历数组&#xff0c;分别计…

springcloud alibaba整合sentinel并结合dashboard控制面板设置规则

目录 一、springcloud alibaba整合sentinel二、采用代码方式设置流控规则三、结合dashboard控制面板设置规则3.1、准备工作3.2、设置全局异常处理3.3、编写测试接口3.4、结合dashboard控制面板设置规则3.4.1、流控规则设置并测试——QPS3.4.2、流控规则设置并测试——线程数3.4…

微信小程序使用echarts报错 ReferenceError: Image is not defined 解决

报错 ReferenceError: Image is not defined 在用uni-app开发微信小程序时&#xff0c;使用到了echarts&#xff08;V4.6.0&#xff09;配置项中的icon属性&#xff0c;微信开发者工具报错如下&#xff1a; 定位问题 定位问题到了压缩echarts文件中的new Image 使用非压缩…

【JavaFX】JDK11 基于Gson、hutool、Jackson持久化存储实体类数据的解决方案 (读取、追加、去重、写入json对象)

文章目录 开发环境效果前言一、Gson是什么?二、使用步骤1.引入依赖2.创建实体类创建 JsonFileService类创建JsonFileService的实现类 JsonFileServiceImpl三、实现效果开发环境 JDK11IDEA 2023.3Gson、hutool、JacksonJavaFX 11效果 前言 使用JDK1

用通俗易懂的方式讲解大模型:在 CPU 服务器上部署 ChatGLM3-6B 模型

大语言模型&#xff08;LLM&#xff09;的量化技术可以大大降低 LLM 部署所需的计算资源&#xff0c;模型量化后可以将 LLM 的显存使用量降低数倍&#xff0c;甚至可以将 LLM 转换为完全无需显存的模型&#xff0c;这对于 LLM 的推广使用来说是非常有吸引力的。 本文将介绍如何…

C# windows服务程序开机自启动exe程序

我们使用传统的Process.Start(".exe")启动进程会遇到无法打开UI界面的问题&#xff0c;尤其是我们需要进行开启自启动程序设置时出现诸多问题&#xff0c;于是我们就想到采用windows服务开机自启动来创建启动一个新的exe程序&#xff0c;并且是显式运行。 首先是打开…

【一文入门】Git常用命令集锦--分支操作和版本管理篇

前言 Git 是一种分布式版本控制系统&#xff0c;可以帮助团队协作开发、管理和维护代码&#xff0c;提高代码质量和效率&#xff0c;掌握常用版本管理命令可以帮助我们更好地管理代码变更和历史记录。下面我将介绍开发中常用的一些Git分支操作和版本管理命令 1 分支操作 1.1 …

centos7安装nacos

一、前言 centos 7.9上部署nacos 2.0.3 二、部署步骤 1、下载nacos wget -P /opt/software/ https://github.com/alibaba/nacos/releases/download/2.0.3/nacos-server-2.0.3.tar.gz 2、解压并改变nacos部署目录 cd /opt/software/ tar -zxf nacos-server-2.0.3.tar.gz mv…

Sam Altman的一天被曝光!每天15小时禁食、服用小剂量安眠药,尽可能避免开会

Sam Altman在经历了几天混乱的管理重组后&#xff0c;重新回到了OpenAI的CEO位置。在日常生活中&#xff0c;奥特曼与许多科技行业高管一样&#xff0c;痴迷于延长自己的寿命。 据报道&#xff0c;他还为应对末日场景&#xff08;致命合成病毒的释放、核战争和人工智能攻击等&…

静态代理、JDK动态代理、CGLIB动态代理以及JDK和CGLIB动态代理的区别

代理 什么是代理&#xff1f;两个设计原则三要素 静态代理静态代理的实现定义接口-定义行为静态代理 -> 目标角色静态代理-> 代理角色静态代理测试 特点 JDK动态代理newProxyInstance获取代理对象通过代理对象实现目标对象的功能特点 Java动态代理类中的invoke是怎么调用…

复试 || 就业day03(2024.01.03)项目一

文章目录 前言scikit-learn实现简单线性回归scikit-learn实现多元线性回归&#xff08;二元&#xff09;总结 前言 &#x1f4ab;你好&#xff0c;我是辰chen&#xff0c;本文旨在准备考研复试或就业 &#x1f4ab;本文内容来自某机构网课&#xff0c;是我为复试准备的第一个项…

生活中危险的气体:一氧化碳与二氧化碳中毒的症状及安全预防措施

一氧化碳和血红蛋白亲和力超过氧气&#xff0c;会占用血红蛋白&#xff0c;导致缺氧。 二氧化碳会和血浆结合&#xff0c;导致血液pH值不正常&#xff0c;抑制呼吸&#xff0c;导致窒息。 通俗点说&#xff1a;一氧化碳是中毒&#xff0c;二氧化碳则是窒息。 一氧化碳中毒 …