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依赖:
- <dependency>
- <groupId>org.springframework.bootgroupId>
- <artifactId>spring-boot-starter-aopartifactId>
- 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 {
-
- @Resource
- LogsService 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();
-
- // 获取到请求的ip
- String 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 {
-
- @Autowired
- LogsService logsService;
-
- @Autowired
- UserService userService;
-
-
- /**
- * 删除信息
- */
- @DeleteMapping("/delete/{id}")
- public Result delete(@PathVariable Integer id) {
- logsService.removeById(id);
- return Result.success();
- }
-
-
- /**
- * 批量删除信息
- */
- @DeleteMapping("/delete/batch")
- public Result batchDelete(@RequestBody List
ids) { - logsService.removeBatchByIds(ids);
- return Result.success();
- }
-
- /**
- * 多条件模糊查询信息
- * pageNum 当前的页码
- * pageSize 每页查询的个数
- */
- @GetMapping("/selectByPage")
- public Result selectByPage(@RequestParam Integer pageNum,
- @RequestParam Integer pageSize,
- @RequestParam String operation) {
- QueryWrapper
queryWrapper = new QueryWrapper().orderByDesc("id"); // 默认倒序,让最新的数据在最上面 - queryWrapper.like(StrUtil.isNotBlank(operation), "operation", operation);
- Page
page = logsService.page(new Page<>(pageNum, pageSize), queryWrapper); - return Result.success(page);
- }
-
- }
前端:
Logs.vue:
-
-
-
"width: 200px" placeholder="查询模块" v-model="operation"> -
"margin: 0 5px" v-model="type"> -
for="item in ['新增', '修改', '删除']" :key="item" :value="item" :label="item"> -
-
"width: 200px" placeholder="查询操作人" v-model="optUser"> -
"primary" style="margin-left: 10px" @click="load(1)">查询 -
"info" @click="reset">重置 -
- "margin: 10px 0">
-
"danger" plain @click="delBatch">批量删除 -
-
"tableData" stripe :header-cell-style="{ backgroundColor: 'aliceblue', color: '#666' }" - @selection-change="handleSelectionChange">
-
"selection" width="55" align="center"> -
"id" label="序号" width="70" align="center"> -
"operation" label="操作模块"> -
"type" label="操作类型"> - "scope">
-
"primary" v-if="scope.row.type === '新增'">{{ scope.row.type }} -
"info" v-if="scope.row.type === '修改'">{{ scope.row.type }} -
"danger" v-if="scope.row.type === '删除'">{{ scope.row.type }} -
"danger" v-if="scope.row.type === '批量删除'">{{ scope.row.type }} -
"success" v-if="scope.row.type === '登录'">{{ scope.row.type }} -
"success" v-if="scope.row.type === '注册'">{{ scope.row.type }} -
-
-
"ip" label="操作人IP"> -
"user" label="操作人"> -
"time" label="操作时间"> -
"操作" align="center" width="180"> - "scope">
-
"mini" type="danger" plain @click="del(scope.row.id)">删除 -
-
-
-
- "margin: 10px 0">
-
- @current-change="handleCurrentChange"
- :current-page="pageNum"
- :page-size="pageSize"
- layout="total, prev, pager, next"
- :total="total">
-
-
-
-
-
-
- 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 = pageNum
- this.$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.records
- this.total = res.data.total
- })
- },
- handleCurrentChange(pageNum) {
- this.load(pageNum)
- },
- }
- }
-
- .el-tooltip__popper {
- max-width: 300px !important;
- }
