SpringBoot+Vue实现AOP系统日志功能

AOP扫盲:Spring AOP (面向切面编程)原理与代理模式—实例演示

logs表:

CREATE TABLE `logs` (`id` int(11) NOT NULL AUTO_INCREMENT,`operation` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '操作名称',`type` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '操作类型',`ip` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT 'ip地址',`user` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '操作人',`time` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '操作时间',PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='系统日志';

aop依赖:

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

获取IP地址工具类 IpUtils.java:

import javax.servlet.http.HttpServletRequest;public class IpUtils {public static String getIpAddr(HttpServletRequest request) {String ip = request.getHeader("x-forwarded-for");if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {ip = request.getHeader("Proxy-Client-IP");}if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {ip = request.getHeader("X-Forwarded-For");}if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {ip = request.getHeader("WL-Proxy-Client-IP");}if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {ip = request.getHeader("X-Real-IP");}if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {ip = request.getRemoteAddr();}return "0:0:0:0:0:0:0:1".equals(ip) ? "127.0.0.1" : ip;}}

自定义注解 @HoneyLogs:

import java.lang.annotation.*;@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface HoneyLogs {// 操作的模块String operation();// 操作类型String type();
}

切面 LogAspect.java:

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.thread.ThreadUtil;
import cn.hutool.core.util.ArrayUtil;
import com.example.springboot.common.HoneyLogs;
import com.example.springboot.entity.Logs;
import com.example.springboot.entity.User;
import com.example.springboot.service.LogsService;
import com.example.springboot.utils.IpUtils;
import com.example.springboot.utils.TokenUtils;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;@Component
@Aspect
@Slf4j
public class LogsAspect {@ResourceLogsService logsService;@AfterReturning(pointcut = "@annotation(honeyLogs)", returning = "jsonResult")public void recordLog(JoinPoint joinPoint, HoneyLogs honeyLogs, Object jsonResult) {// 获取当前登录的用户的信息User loginUser = TokenUtils.getCurrentUser();if (loginUser == null) { // 用户未登录的情况下  loginUser是null  是null的话我们就要从参数里面获取操作人信息// 登录、注册Object[] args = joinPoint.getArgs();if (ArrayUtil.isNotEmpty(args)) {if (args[0] instanceof User) {loginUser = (User) args[0];}}}if (loginUser == null) {log.error("记录日志信息报错,未获取到当前操作用户信息");return;}// 获取HttpServletRequest对象ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();HttpServletRequest request = servletRequestAttributes.getRequest();// 获取到请求的ipString ip = IpUtils.getIpAddr(request);Logs logs = Logs.builder().operation(honeyLogs.operation()).type(honeyLogs.type()).ip(ip).user(loginUser.getUsername()).time(DateUtil.now()).build();ThreadUtil.execAsync(() -> {// 异步记录日志信息logsService.save(logs);});}}

Logs.java

import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class Logs {@TableId(type = IdType.AUTO)private Integer id;private String operation;private String type;private String ip;private String user;private String time;
}

LogsController.java

import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.example.springboot.common.Result;
import com.example.springboot.entity.Logs;
import com.example.springboot.service.LogsService;
import com.example.springboot.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;import java.util.List;/*** 系统日志相关接口*/
@RestController
@RequestMapping("/logs")
public class LogsController {@AutowiredLogsService logsService;@AutowiredUserService userService;/*** 删除信息*/@DeleteMapping("/delete/{id}")public Result delete(@PathVariable Integer id) {logsService.removeById(id);return Result.success();}/*** 批量删除信息*/@DeleteMapping("/delete/batch")public Result batchDelete(@RequestBody List<Integer> ids) {logsService.removeBatchByIds(ids);return Result.success();}/*** 多条件模糊查询信息* pageNum 当前的页码* pageSize 每页查询的个数*/@GetMapping("/selectByPage")public Result selectByPage(@RequestParam Integer pageNum,@RequestParam Integer pageSize,@RequestParam String operation) {QueryWrapper<Logs> queryWrapper = new QueryWrapper<Logs>().orderByDesc("id");  // 默认倒序,让最新的数据在最上面queryWrapper.like(StrUtil.isNotBlank(operation), "operation", operation);Page<Logs> page = logsService.page(new Page<>(pageNum, pageSize), queryWrapper);return Result.success(page);}}

前端:

Logs.vue:

<template><div><div><el-input style="width: 200px" placeholder="查询模块" v-model="operation"></el-input><el-select style="margin: 0 5px" v-model="type"><el-option v-for="item in ['新增', '修改', '删除']" :key="item" :value="item" :label="item"></el-option></el-select><el-input style="width: 200px" placeholder="查询操作人" v-model="optUser"></el-input><el-button type="primary" style="margin-left: 10px" @click="load(1)">查询</el-button><el-button type="info" @click="reset">重置</el-button></div><div style="margin: 10px 0"><el-button type="danger" plain @click="delBatch">批量删除</el-button></div><el-table :data="tableData" stripe :header-cell-style="{ backgroundColor: 'aliceblue', color: '#666' }"@selection-change="handleSelectionChange"><el-table-column type="selection" width="55" align="center"></el-table-column><el-table-column prop="id" label="序号" width="70" align="center"></el-table-column><el-table-column prop="operation" label="操作模块"></el-table-column><el-table-column prop="type" label="操作类型"><template v-slot="scope"><el-tag type="primary" v-if="scope.row.type === '新增'">{{ scope.row.type }}</el-tag><el-tag type="info" v-if="scope.row.type === '修改'">{{ scope.row.type }}</el-tag><el-tag type="danger" v-if="scope.row.type === '删除'">{{ scope.row.type }}</el-tag><el-tag type="danger" v-if="scope.row.type === '批量删除'">{{ scope.row.type }}</el-tag><el-tag type="success" v-if="scope.row.type === '登录'">{{ scope.row.type }}</el-tag><el-tag type="success" v-if="scope.row.type === '注册'">{{ scope.row.type }}</el-tag></template></el-table-column><el-table-column prop="ip" label="操作人IP"></el-table-column><el-table-column prop="user" label="操作人"></el-table-column><el-table-column prop="time" label="操作时间"></el-table-column><el-table-column label="操作" align="center" width="180"><template v-slot="scope"><el-button size="mini" type="danger" plain @click="del(scope.row.id)">删除</el-button></template></el-table-column></el-table><div style="margin: 10px 0"><el-pagination@current-change="handleCurrentChange":current-page="pageNum":page-size="pageSize"layout="total, prev, pager, next":total="total"></el-pagination></div></div>
</template><script>export default {name: "Logs",data() {return {tableData: [],  // 所有的数据pageNum: 1,   // 当前的页码pageSize: 5,  // 每页显示的个数operation: '',total: 0,form: {},user: JSON.parse(localStorage.getItem('honey-user') || '{}'),ids: [],type: '',optUser: ''}},created() {this.load()},methods: {delBatch() {if (!this.ids.length) {this.$message.warning('请选择数据')return}this.$confirm('您确认批量删除这些数据吗?', '确认删除', {type: "warning"}).then(response => {this.$request.delete('/logs/delete/batch', {data: this.ids}).then(res => {if (res.code === '200') {   // 表示操作成功this.$message.success('操作成功')this.load(1)} else {this.$message.error(res.msg)  // 弹出错误的信息}})}).catch(() => {})},handleSelectionChange(rows) {   // 当前选中的所有的行数据this.ids = rows.map(v => v.id)},del(id) {this.$confirm('您确认删除吗?', '确认删除', {type: "warning"}).then(response => {this.$request.delete('/logs/delete/' + id).then(res => {if (res.code === '200') {   // 表示操作成功this.$message.success('操作成功')this.load(1)} else {this.$message.error(res.msg)  // 弹出错误的信息}})}).catch(() => {})},reset() {this.operation = ''this.type = ''this.optUser = ''this.load()},load(pageNum) {  // 分页查询if (pageNum) this.pageNum = pageNumthis.$request.get('/logs/selectByPage', {params: {pageNum: this.pageNum,pageSize: this.pageSize,operation: this.operation,type: this.type,user: this.optUser,}}).then(res => {this.tableData = res.data.recordsthis.total = res.data.total})},handleCurrentChange(pageNum) {this.load(pageNum)},}
}
</script><style>
.el-tooltip__popper {max-width: 300px !important;
}
</style>

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

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

相关文章

Anthropic全球上线AI语言模型Claude 2;多模态系统:融合文本和图像的新前沿

&#x1f989; AI新闻 &#x1f680; Anthropic全球上线AI语言模型Claude 2&#xff0c;编程、数学、推理能力大幅提升 摘要&#xff1a;Anthropic在全球正式上线了AI语言模型Claude 2。相比前代版本&#xff0c;Claude 2在编程、数学、推理等方面都有大幅提升&#xff0c;支…

Centos磁盘爆满_openEuler系统磁盘爆满清理方法---Linux工作笔记060

磁盘爆满,监控部门就会报警,报警就要处理,但是程序员并不擅长做运维的工作,记录一下把...以后用到会方便: 使用df -h命令可以看到,对应的磁盘占用情况,这里我的/dev/mapper/openeuler-root这个目录 占用的磁盘比较多,到了百分之95了.. 往往就是这个跟目录,我这里/data目录是自…

laravel队列

laravel redis队列 1、创建job队列任务 php artisan make:job StoreUser执行上述命令后&#xff0c;会生成app/Jobs/StoreUser.php文件&#xff0c;编辑文件内容如下&#xff1a; <?phpnamespace App\Jobs;use Illuminate\Bus\Queueable; use Illuminate\Contracts\Queu…

R语言的计量经济学技术

量经济学通常使用较小样本&#xff0c;但这种区别日渐模糊&#xff0c;机器学习在经济学领域、特别是经济学与其它学科的交叉领域表现日益突出&#xff0c;R语言是用于统计建模的主流计算机语言&#xff0c;在本次培训中&#xff0c;我们将从实际应用出发&#xff0c;重点从数据…

VUE:可收缩工具栏

作者:CSDN @ _乐多_ 本文记录了一个vue可伸缩工具栏组件,代码即插即用。 只需要新增函数名并且填函数体就可以。 效果如下图所示, 文章目录 一、Vue代码一、Vue代码 <template><div class="ToolBar"><div class=

机器人SLAM与自主导航

机器人技术的迅猛发展&#xff0c;促使机器人逐渐走进了人们的生活&#xff0c;服务型室内移动机器人更是获得了广泛的关注。但室内机器人的普及还存在许多亟待解决的问题&#xff0c;定位与导航就是其中的关键问题之一。在这类问题的研究中&#xff0c;需要把握三个重点&#…

如何破解压缩包密码,CTF压缩包处理

I. 引言 压缩包我们经常接触&#xff0c;用于对文件进行压缩存储/传输。压缩包处理在CTF比赛中是非常重要的一块&#xff0c;因为压缩包中可能包含重要信息&#xff1a;许多CTF题目会将关键信息隐藏在压缩包中&#xff0c;参赛者需要解压并查看其中的内容才能获取有用的线索。…

Oracle数据中如何在 where in() 条件传参

一、问题场景描述 在sql 条件中&#xff0c;如何在 where in()中想传入参数&#xff0c;如果直接 where in(:seqList)&#xff0c;当传入单个值&#xff0c;seqList: ‘80’ 是没问题的&#xff0c;但是初入多个值时&#xff0c;seqList: ‘80,90’ &#xff0c;因缺少单引号&…

CASAIM自动激光3D测量系统助力海外家电组装企业IQC来料检测装配尺寸测量

随着家电产品的不断创新发展&#xff0c;海外家电组装企业也面临着越来越高的质量标准&#xff0c;几何尺寸测量与控制是保证产品交付质量的基础。零部件、外壳壳体经过国内或东南亚其他地区生产好后&#xff0c;为了确保产品质量和一致性&#xff0c;外协件物料需要送往组装厂…

QT学习day5(QT实现TCP协议)

作业&#xff1a;利用TCP客户端和服务器实现网络聊天室&#xff08;简单版QQ&#xff09; 1.服务器代码 widget.h #ifndef WIDGET_H #define WIDGET_H#include <QWidget> #include<QTcpServer> //服务器头文件 #include<QTcpSocket> …

用 HarmonyOS 做一个可以手势控制的电子相册应用(ArkTS)

介绍 本篇 Codelab 介绍了如何实现一个简单的电子相册应用&#xff0c;主要功能包括&#xff1a; 1. 实现首页顶部的轮播效果。 2. 实现页面多种布局方式。 3. 实现通过手势控制图片的放大、缩小、左右滑动查看细节等效果。 相关概念 ● Swiper&#xff1a;滑块视图容…

2023年全球及中国半导体石英坩埚市场发展概况分析:未来需求量迅速增长[图]

2018年至2022年&#xff0c;全球半导体石英坩埚市场规模由10.4亿元增至18.2亿元&#xff0c;期间年复合增长率为15.1%。未来&#xff0c;随着集成电路行业的发展&#xff0c;下游芯片行业的需求将推动8吋及12吋半导体硅片出货量在未来将持续增长&#xff0c;同时半导体硅片厂的…