使用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.mzph.cn/news/586604.shtml

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

相关文章

第3课 获取并播放音频流

本课对应源文件下载链接&#xff1a; https://download.csdn.net/download/XiBuQiuChong/88680079 FFmpeg作为一套庞大的音视频处理开源工具&#xff0c;其源码有太多值得研究的地方。但对于大多数初学者而言&#xff0c;如何快速利用相关的API写出自己想要的东西才是迫切需要…

【机器学习】卷积神经网络(一)

一、网络结构 典型CNN结构 卷积神经网络是一种能够从图像、声音或其他类型的数据中学习特征的人工智能模型。你可以把它想象成一个有很多层的过滤器&#xff0c;每一层都能够提取出数据中的一些有用的信息&#xff0c;比如边缘、形状、颜色、纹理等。这些信息可以帮助卷积神经网…

【Matlab】ELM极限学习机时序预测算法

资源下载&#xff1a; https://download.csdn.net/download/vvoennvv/88681649 一&#xff0c;概述 ELM&#xff08;Extreme Learning Machine&#xff09;是一种单层前馈神经网络结构&#xff0c;与传统神经网络不同的是&#xff0c;ELM的隐层神经元权重以及偏置都是随机产生的…

【Android12】Android Framework系列---tombstone墓碑生成机制

tombstone墓碑生成机制 Android中程序在运行时会遇到各种各样的问题&#xff0c;相应的就会产生各种异常信号&#xff0c;比如常见的异常信号 Singal 11&#xff1a;Segmentation fault表示无效的地址进行了操作&#xff0c;比如内存越界、空指针调用等。 Android中在进程(主要…

Apache-ActiveMQ 反序列化漏洞(CVE-2015-5254)复现

CVE-2016-3088 一、环境搭建 Java:jdk8 影响版本 Apache ActiveMQ < 5.13.0 二、用docker搭建漏洞环境 访问一下web界面 然后进入admin目录登录 账号:admin 密码:admin 三、工具准备 cd /opt wget https://github.com/matthiaskaiser/jmet/releases/download/0.1.0/jmet-0…

QT上位机开发(第一个应用)

【 声明&#xff1a;版权所有&#xff0c;欢迎转载&#xff0c;请勿用于商业用途。 联系信箱&#xff1a;feixiaoxing 163.com】 不管是软件&#xff0c;还是硬件&#xff0c;如果我们能够顺利启动第一个应用&#xff0c;点亮第一个电路的话&#xff0c;这对我们的信心来说会有…

如何恢复 iPhone 上永久删除的照片?

2007年&#xff0c;苹果公司推出了一款惊天动地的智能手机&#xff0c;也就是后来的iPhone。你会惊讶地发现&#xff0c;迄今为止&#xff0c;苹果公司已经售出了 7 亿部 iPhone 设备。根据最新一项调查数据&#xff0c;智能手机利润的 95% 都进了苹果公司的腰包。 如此受欢迎…

【Vue2+3入门到实战】(16)VUEVue路由的重定向、404、编程式导航、path路径跳转传参 详细代码示例

目录 一、Vue路由-重定向1.问题2.解决方案3.语法4.代码演示 二、Vue路由-4041.作用2.位置3.语法4.代码示例 三、Vue路由-模式设置1.问题2.语法 四、编程式导航-两种路由跳转方式1.问题2.方案3.语法4.path路径跳转语法5.代码演示 path跳转方式6.name命名路由跳转7.代码演示通过n…

2023十大编程语言及未来展望

2023十大编程语言及未来展望 1. 2023年十大编程语言排行榜2. 十大编程语言未来展望PythonCCJavaC#JavaScriptPHPVisual BasicSQLAssembly language 1. 2023年十大编程语言排行榜 TIOBE排行榜是根据互联网上有经验的程序员、课程和第三方厂商的数量&#xff0c;并使用搜索引擎&a…

阿里云PolarDB数据库优惠价格表11元一天起

阿里云数据库PolarDB租用价格表&#xff0c;云数据库PolarDB MySQL版2核4GB&#xff08;通用&#xff09;、2个节点、60 GB存储空间55元5天&#xff0c;云数据库 PolarDB 分布式版标准版2核16G&#xff08;通用&#xff09;57.6元3天&#xff0c;阿里云百科aliyunbaike.com分享…

ansible管理windows测试

一、环境介绍 Ansible管理主机&#xff1a; 系统: redhat7.6 Linux管理服务器需安装pywinrm插件 Windows客户端主机&#xff1a; 系统: Server2012R2 Windows机器需要安装或升级powershell4.0以上版本&#xff0c;Server2008R2默认的版本是2.0&#xff0c;因此必须升…

使用flutter开发windows桌面软件读取ACR22U设备的nfc卡片id,5分钟搞定demo

最近有个需求&#xff0c;要使用acr122u读卡器插入电脑usb口&#xff0c;然后读取nfc卡片的id&#xff0c;并和用户账号绑定&#xff0c;调研了很多方式&#xff0c;之前使用rust实现过一次&#xff0c;还有go实现过一次&#xff0c;然后使用electron的时候遇到安装pcsc-lite失…

MacBook查看本机IP

嘚吧嘚 其实这也不是什么困难的问题&#xff0c;但是今年刚刚入坑Mac&#xff0c;外加用的频率不是很高&#xff0c;每次使用的时候都查&#xff0c;用完就忘&#xff0c;下次用的时候再查&#x1f92e;。真的把自己恶心坏了&#x1f648;。 所以写篇文章记录一下&#x1f92…

[C++] : 贪心算法专题(第一部分)

1.柠檬水找零&#xff1a; 1.思路一&#xff1a; 柠檬水找零 class Solution { public:bool lemonadeChange(vector<int>& bills) {int file0;int ten 0;for(auto num:bills){if(num 5) file;else if(num 10){if(file > 0)file--,ten;elsereturn false;}else{i…

产品经理学习-策略产品指标

目录&#xff1a; 数据指标概述 通用指标介绍 Web端常用指标 移动端常用指标 如何选择一个合适的数据指标 数据指标概述 指标是衡量目标的一个参数&#xff0c;指一项活动中预期达到的指标、目标等&#xff0c;一般用数据表示&#xff0c;因此又称为数据指标&#xff1b;…

Flask笔记

一&#xff1a;模板渲染 一般的话都序列化成字符串 二&#xff1a;项目拆分 2.1 项目拆分 app.py init.py views.py models.py 模型数据 2.2 蓝图 三&#xff1a;路由参数 3.1 String 重点 3.2 int 3.3 path 3.4 UUID 3.5 any 四&#xff1a;请求方式 五&#xff1a;Requ…

苹果CMS超级播放器专业版无授权全开源,附带安装教程

源码介绍 超级播放器专业版v1.0.8&#xff0c;内置六大主流播放器&#xff0c;支持各种格式的视频播放&#xff0c;支持主要功能在每一个播放器内核中都相同效果。 搭建教程 1.不兼容IE浏览器 2.php版本推荐7.4 支持7.1~7.4 3.框架引入不支持同时引入多个播放器 json对接教…

新版 macos下安装python 2.7 python 3.x多版本简单方法 pyenv python多版本管理工具

在新版本的macos中已经将默认的python升级成了3.x , 今天介绍一个简单的方法在新版本的macos中快速安装 python 2.7的方法, 就是使用brew安装python版本管理工具 pyenv来安装python2.7 # 安装pyenv版本管理工具 brew install pyenv # 安装python2.7 可以安装多个版本的ptyhon…

C#进阶-IIS应用程序池崩溃的解决方案

IIS是微软开发的Web服务器软件&#xff0c;被广泛用于Windows平台上的网站托管。在使用IIS过程中&#xff0c;可能会遇到应用程序池崩溃的问题&#xff0c;原因可能有很多&#xff0c;包括代码错误、资源不足、进程冲突等。本文将为大家介绍IIS应用程序池崩溃的问题分析和解决方…

【计算机毕业设计】python+django数码电子论坛系统设计与实现

本系统主要包括管理员和用户两个角色组成&#xff1b;主要包括&#xff1a;首页、个人中心、用户管理、分类管理、数码板块管理、数码评价管理、数码论坛管理、畅聊板块管理、系统管理等功能的管理系统。 后端&#xff1a;pythondjango 前端&#xff1a;vue.jselementui 框架&a…