一、AOP介绍
Spring Boot AOP可以用来拦截Controller中的方法,实现对请求的统一处理。通过定义切面和切点,可以在请求前、后、异常等不同的阶段进行处理,比如记录日志、权限校验、参数校验等。在Spring Boot中,可以使用@Aspect注解定义切面,使用@Pointcut注解定义切点,使用@Before、@After、@Around等注解定义不同类型的通知。同时,还可以使用@Order注解指定切面的执行顺序
二、代码
数据表对应的实体类
package com.ruoyi.car.aop;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
/**
* 操作日志表
* */
@Data
@AllArgsConstructor
@NoArgsConstructor
public class AdminLog implements Serializable {
private static final long serialVersionUID = 7925874058046995566L;
private Long carRecordId;//用车记录id
private Long operationBy;//用户id 操作人ID
private Long carinfoId;//车辆信息id
private Long useinfoId;//车辆申请id
private String userName;//用户名称
private String operationName;//操作内容
private String operationTime;//操作时间
private String carName;
private String color;
private String carNumber;
}
自定义注解类
package com.ruoyi.car.aop;
import java.lang.annotation.*;
/**
* 配置自定义log注解类
*/
@Target(ElementType.METHOD) //注解放置的目标位置,METHOD是可注解在方法级别上
@Retention(RetentionPolicy.RUNTIME) //注解在哪个阶段执行
@Documented
public @interface MyLog {
String operation () default "";
}
aspect切面类
package com.ruoyi.car.aop;
import com.ruoyi.car.domain.CarInfo;
import com.ruoyi.car.domain.CarUseInfo;
import com.ruoyi.car.mapper.CarInfoMapper;
import com.ruoyi.car.mapper.MyLogMapper;
import com.ruoyi.car.service.ICarUseRecordService;
import com.ruoyi.car.vo.CarInfoAndUser;
import com.ruoyi.common.core.domain.entity.SysUser;
import org.apache.shiro.SecurityUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.lang.reflect.Method;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
/** 系统日志:切面处理类 */
@Aspect
@Component
public class SysLogAspect {
/**操作数据库 */
@Autowired
private MyLogMapper myLogMapper;
@Autowired
private CarInfoMapper carInfoMapper;
@Autowired
private ICarUseRecordService carUseRecordService;
//定义切点 @Pointcut
//在注解的位置切入代码
@Pointcut("@annotation(com.ruoyi.car.aop.MyLog)")
public void logPoinCut() {
}
//切面 配置通知
@Before("logPoinCut()")
public void saveOperation(JoinPoint joinPoint) {
}
@After("logPoinCut()")
public void saveOperationAfter(JoinPoint joinPoint) {
//用于保存操作日志
AdminLog adminLog = new AdminLog();
//存放所有记录的集合
List<AdminLog> adminLogs = new ArrayList<>();
//从切面织入点处通过反射机制获取织入点处的方法
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
//获取切入点所在的方法
Method method = signature.getMethod();
// 请求的方法参数值
Object[] obj = joinPoint.getArgs();
for (Object eve : obj) {
//车辆列表操作
if (eve instanceof CarInfo) {
adminLog.setCarinfoId(((CarInfo) eve).getCarinfoId());
adminLog.setCarName(((CarInfo) eve).getCarName());
adminLog.setColor(((CarInfo) eve).getColor());
adminLog.setCarNumber(((CarInfo) eve).getCarNumber());
adminLogs.add(adminLog);
}
//用车信息列表操作
if (eve instanceof CarUseInfo) {
CarInfoAndUser carInfoAndUser = carInfoMapper.selectCarInfoByCarinfoId(((CarUseInfo) eve).getCarinfoId());
adminLog.setUseinfoId(((CarUseInfo) eve).getUseinfoId());
adminLog.setCarinfoId(((CarUseInfo) eve).getCarinfoId());
adminLog.setCarName(carInfoAndUser.getCarName());
adminLog.setColor(carInfoAndUser.getColor());
adminLog.setCarNumber(carInfoAndUser.getCarNumber());
adminLogs.add(adminLog);
}
//针对删除操作
if (eve instanceof String) {
String[] split = ((String) eve).split(",");
for (String item : split) {
AdminLog batchdel = new AdminLog();
Long id = Long.parseLong(item);
CarInfoAndUser carInfoAndUser = carInfoMapper.selectCarInfoByCarinfoId(id);
batchdel.setCarinfoId(id);
batchdel.setCarName(carInfoAndUser.getCarName());
batchdel.setColor(carInfoAndUser.getColor());
batchdel.setCarNumber(carInfoAndUser.getCarNumber());
adminLogs.add(batchdel);
//获取操作--方法上的Log的值
MyLog myLog = method.getAnnotation(MyLog.class);
if (myLog != null) {
//保存操作事件
String operation = myLog.operation();
batchdel.setOperationName(operation);
}
// 操作人账号、姓名(需要提前将用户信息存到session)
SysUser sysUser = (SysUser) SecurityUtils.getSubject().getPrincipal();
if (sysUser != null) {
Long userId = sysUser.getUserId();
String userName = sysUser.getUserName();
batchdel.setOperationBy(userId);
batchdel.setUserName(userName);
}
//存入操作时间
Date date = new Date();
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String format = simpleDateFormat.format(date);
batchdel.setOperationTime(format);
}
}
}
//获取操作--方法上的Log的值
MyLog myLog = method.getAnnotation(MyLog.class);
if (myLog != null) {
//保存操作事件
String operation = myLog.operation();
adminLog.setOperationName(operation);
}
// 操作人账号、姓名(需要提前将用户信息存到session)
SysUser sysUser = (SysUser) SecurityUtils.getSubject().getPrincipal();
if (sysUser != null) {
Long userId = sysUser.getUserId();
String userName = sysUser.getUserName();
adminLog.setOperationBy(userId);
adminLog.setUserName(userName);
}
//存入操作时间
Date date = new Date();
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String format = simpleDateFormat.format(date);
adminLog.setOperationTime(format);
//调用service保存Operation实体类到数据库
carUseRecordService.insertCarUseRecord(adminLogs);
}
}
controller
/**
* 新增保存车辆信息
*/
@MyLog(operation = "新增车辆")
@RequiresPermissions("system:carInfo:add")
@Log(title = "车辆信息", businessType = BusinessType.INSERT)
@PostMapping("/add")
@ResponseBody
public AjaxResult addSave(CarInfo carInfo)
{
return toAjax(carInfoService.insertCarInfo(carInfo));
}
/**
* 修改保存车辆信息
*/
@MyLog(operation = "修改车辆")
@RequiresPermissions("system:carInfo:edit")
@Log(title = "车辆信息", businessType = BusinessType.UPDATE)
@PostMapping("/edit")
@ResponseBody
public AjaxResult editSave(CarInfo carInfo)
{
return toAjax(carInfoService.updateCarInfo(carInfo));
}
在controller的方法上加上我们的自定义注解,并写上相应的操作名称
然后切面类中
@Pointcut("@annotation(com.ruoyi.car.aop.MyLog)")
只要访问添加MyLog注解的方法都会被AOP给拦截,然后我们可以获得方法中的传参,将信息存入数据库中。
流!