当前位置: 首页 > ai >正文

写了一个关于SpringAop记录用户操作的功能

1:先思考自己的需要记录什么功能,创建对应的数据库表。

        各位开发人员如果在公司一定要写关于建表注释,方便同事观看,对于自己来说是最基础的代码素养,对于自己的职业来说这是职业最基本的规范。当然如果是那样的,对吧,懂的都懂。不懂就以后就会的懂了。
        代码仅供参考,实际请根据自身工作内容来做。

-- 建表语句
CREATE TABLE sys_oper_log (id BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT '主键ID,自增',module VARCHAR(50) COMMENT '系统模块(如订单模块,商品管理,员工及达人等)',operation_type VARCHAR(20) COMMENT '操作类型(生成删除、修改,新增,查询等)',operator VARCHAR(50) COMMENT '操作人员(如admin)',operator_id VARCHAR(32) COMMENT '操作人员ID',ip VARCHAR(50) COMMENT '操作IP',location VARCHAR(100) COMMENT '操作地点(如广东省广州市)',status VARCHAR(20) COMMENT '操作状态(成功/失败)',operation_time DATETIME COMMENT '操作时间',api_interface VARCHAR(200) COMMENT '操作接口(如/api/xxx/xxxxx)',duration BIGINT COMMENT '消耗时间(毫秒)',remark VARCHAR(200) COMMENT '备注(如中继)',create_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间(记录插入时的时间)'
)COMMENT='操作系统记录表:记录系统中用户对模块的操作信息(如操作类型、操作人员、操作时间等)';-- 索引
CREATE INDEX idx_operator ON sys_oper_log(operator);
CREATE INDEX idx_status ON sys_oper_log(status);
CREATE INDEX idx_operation_time ON sys_oper_log(operation_time);

2:创建自定义注解,自定义注解在很多的时候都会有用,例如日志审计,权限控制,数据校验,API文档生产,事务与缓存控制,代码生成与测试等等。

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
@Documented
public @interface SysLogModuleAnno {// 定义接口描述,默认为空String descrption() default "";
}

3:因为我这次写的是一个模块监控,监控当前登录人进行了哪些操作。
 

@Aspect
@Component
public class SysLogModuleAop {// 日志记录器private static final Logger log= LoggerFactory.getLogger(SysLogModuleAop.class);// 日志服务@Resourceprivate  sysLogService sysLogService;/*** 定义切点:拦截所有带有@SysLogModuleAnno注解的方法*/@Pointcut("@annotation(com.lion.mall.base.annotation.SysLogModuleAnno)")public void sysLogModulePointCut() {//pointcut}/*** 环绕通知:在目标方法执行前后进行日志记录* @param point 连接点* @return 目标方法执行结果* @throws Throwable 可能抛出的异常*/@Around("sysLogModulePointCut()")public Object around(ProceedingJoinPoint point) throws Throwable {// 1. 获取日志请求信息SysLogModuleSaveRequest sysLogModuleRequest = this.getSysLogModuleSaveRequest(point);Object result = null;try {// 2. 执行目标方法result = point.proceed();// 3. 如果没有异常,设置操作状态为成功 (0)sysLogModuleRequest.setOperStatus("0"); // 成功}catch (Throwable e){// 4. 如果有异常,设置操作状态为失败 (1)sysLogModuleRequest.setOperStatus("1"); // 失败sysLogModuleRequest.setRemark(e.toString()); // 记录异常信息throw e; // 继续抛出异常,不影响原有逻辑}finally {// 5. 解析结果并设置操作结果(即使发生异常也可以记录部分信息)if (result != null) {Map parseObject = JSONObject.parseObject(JSON.toJSONString(result), Map.class);sysLogModuleRequest.setOperResult(MapUtils.getString(parseObject, "resultMessage"));}// 6. 异步保存日志new SysLogModuleAddThread(sysLogService, sysLogModuleRequest).start();}return result;}/*** 异常通知:当目标方法抛出异常时记录日志* @param point 连接点* @param e 抛出的异常*/@AfterThrowing(pointcut="sysLogModulePointCut()",throwing="e")public void doAfterThrowing(JoinPoint point, Throwable e) {// 1. 获取日志请求信息SysLogModuleSaveRequest sysLogModuleRequest = this.getSysLogModuleSaveRequest(point);// 2. 设置异常信息sysLogModuleRequest.setRemark(e.toString());// 3. 异步保存日志new SysLogModuleAddThread(sysLogService,sysLogModuleRequest).start();}/*** 构建日志保存请求对象* @param point 连接点* @return 日志保存请求对象*/private SysLogModuleSaveRequest getSysLogModuleSaveRequest(JoinPoint point) {// 1. 获取当前HTTP请求HttpServletRequest httpRequest = ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest();// 2. 从请求头获取token并解析用户信息String token = httpRequest.getHeader("x-xxxx-token"); //前端命名User user = TokenUtil.recreateUserFromToken(token);// 3. 构建日志请求对象并设置基本信息SysLogModuleSaveRequest logRequest=new SysLogModuleSaveRequest();logRequest.setShopId(user .getShopId());logRequest.setResourceModule("xxxxxxxx");logRequest.setResourceName("XXXX系统");logRequest.setServerIp(httpRequest.getRemoteHost());logRequest.setServerPort(String.valueOf(httpRequest.getRemotePort()));logRequest.setClientIp(IpUtil.getIpAddr(httpRequest));logRequest.setOperTime(DateUtil.getToday());//操作人员工IDlogRequest.setOperUserId(user.getStaffId());//系统操作人员名称logRequest.setOperUser(user.getUserName());//创建时间logRequest.setCreateTime(DateUtil.getToday());// 4. 设置方法相关信息logRequest.setMethodName(getControllerMethodDescription(point));logRequest.setMethodUrl(httpRequest.getRequestURI());logRequest.setMethodParams(getParams(point,httpRequest));return logRequest;}/*** 获取方法参数* @param point 连接点* @param httpRequest HTTP请求对象* @return 参数字符串(JSON格式)*/private String getParams(JoinPoint point,HttpServletRequest httpRequest) {Map<String,Object> paramMap = new HashMap<>();// 1. 获取方法参数Object[] args = point.getArgs();MethodSignature signature=(MethodSignature)point.getSignature();Method method=signature.getMethod();// 2. 获取参数名称ParameterNameDiscoverer pnd =new DefaultParameterNameDiscoverer();String[] parameterNames = pnd.getParameterNames(method);// 3. 过滤特殊类型参数并构建参数Mapfor(int i=0;i<parameterNames.length;i++) {if(args[i] instanceof MultipartFile ||args[i] instanceof ServletRequest ||args[i] instanceof ServletResponse) {continue;// 跳过文件、请求和响应对象}paramMap.put(parameterNames[i],args[i]);}// 4. 添加请求参数Map<String,String[]> parameterMap=httpRequest.getParameterMap();if(ObjectUtils.isEmpty(parameterMap)) {paramMap.putAll(parameterMap);}return JSON.toJSONString(paramMap);}/*** 获取接口描述信息(从@SysLogModuleAnno注解中获取)* @param point 连接点* @return 方法描述*/private String getControllerMethodDescription(JoinPoint point) {String description="";try {// 获取连接点目标类名String targetName=point.getTarget().getClass().getName();// 获取连接点签名的方法名String methodName=point.getSignature().getName();// 获取连接点参数Object[] args=point.getArgs();// 根据连接点类的名字获取指定类Class targetClass=Class.forName(targetName);// 获取类里面的方法Method[] methods=targetClass.getMethods();for(Method method: methods) {if(method.getName().equals(methodName)) {Class[] clazzs=method.getParameterTypes();if(clazzs.length==args.length) {description=method.getAnnotation(SysLogModuleAnno.class).descrption();break;}}}}catch(Exception e) {log.error("SysLogModuleAop.getControllerMethodDescription error:{"+e.getMessage() +"}");}return description;}

4:返回结果集

@Data
public class SysLogModuleSaveRequest {private static final long serialVersionUID = xxxxxxxxxxxxxxxxxxL;private Long shopId;private String resourceModule;private String resourceName;private String serverIp;private String serverPort;private String clientIp;private String methodName;private String methodUrl;private String methodParams;private String operUser;private Date operTime;private String operResult;private String remark;//新增字段 系统操作人员IDprivate  String operUserId;//新增字段 系统更新时间private  Date createTime;//新增字段  请求0成功或者1失败private String operStatus;//分页参数public Integer page;public Integer size;//时间参数private Timestamp startTime;private Timestamp endTime;//员工IDprivate String staffId;
}

5:关于Token  还有  Ip 工具类,时间工具类等获取的方式可以在很多的地方有!或者自己可以写

http://www.xdnf.cn/news/2079.html

相关文章:

  • A. Ambitious Kid
  • MySQL 联合查询教程
  • 使用PyTorch实现简单图像识别(基于MNIST手写数字数据集)的完整代码示例,包含数据加载、模型定义、训练和预测全流程
  • 深度探索:DeepSeek赋能WPS图表绘制
  • Docker化HBase排错实录:从Master hflush启动失败到Snappy算法未支持解决
  • Oracle官宣 MySQL+APEX+AI三认证限时免费
  • 使用 AFL++ 对 IoT 二进制文件进行模糊测试 - 第二部分
  • 基于 Requests 与 Ollama 的本地大模型交互全栈实践指南
  • Trae 宝藏功能实测:从 Mcp 搭建天气系统,到 AI 重塑 Excel 数据处理
  • 精通线程池:业务场景中的实践、优化与监控
  • maven打包时配置多环境参数
  • 深入理解二叉树遍历:递归与栈的双重视角
  • php一些命名规范 和 css命名规范
  • 支付宝小程序组件与页面构造器使用指南:从页面到组件的正确迁移
  • 【Agent实战】从0到1开发一个Python 解释器 MCP SSE Server
  • RocketMQ 主题与队列的协同作用解析(既然队列存储在不同的集群中,那要主题有什么用呢?)---管理命令、配置安装(主题、消息、队列与 Broker 的关系解析)
  • 7年经验的Java程序员的技术知识概览(及分阶段学习计划、资源推荐、职业发展建议)
  • 基于Java(JSP)+MySQL实现深度学习的音乐推荐系统
  • Queue和Deque
  • #ifndef #else #endif条件编译
  • C语言基础语法详解:从入门到掌握
  • 【FreeRTOS】事件标志组
  • Linux文件操作命令
  • QPS说明
  • 提升变电站运维效率:安科瑞无线测温系统创新应用
  • oracle数据库物理结构
  • Python异常处理实战指南:从基础语法到设计哲学
  • windows一键测速DNS并切换
  • MQTT学习资源
  • 极域教师管理CMD命令操作