springboot AOP拦截用户操作,并将操作信息存入数据库

一、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给拦截,然后我们可以获得方法中的传参,将信息存入数据库中。

可能代码讲的不是很详细,有疑问可以留言交流!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
### 回答1: Spring Boot AOP可以用来拦截Controller中的方法,实现对请求的统一处理。通过定义切面和切点,可以在请求前、后、异常等不同的阶段进行处理,比如记录日志、权限校验、参数校验等。在Spring Boot中,可以使用@Aspect注解定义切面,使用@Pointcut注解定义切点,使用@Before、@After、@Around等注解定义不同类型的通知。同时,还可以使用@Order注解指定切面的执行顺序。 ### 回答2: 在Web应用中,Controller是连接前端和后端的重要部分,用于处理请求和响应返回数据。在某些情况下,我们需要对Controller进一步处理,例如记录请求日志、验证权限、异常处理等。这就需要用到SpringBoot AOP进行拦截SpringBoot AOP是一种面向切面的编程方式,通过拦截目标方法,插入特定的处理逻辑来增强系统功能。在Controller上使用AOP进行拦截可以帮助我们方便的实现业务逻辑,避免重复代码。 实现步骤如下: 1. 创建一个自定义注解,用于标记要拦截的Controller方法。 ``` @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface LogRecord { String value() default ""; } ``` 2. 在拦截器中定义具体的切面逻辑,例如记录请求日志、验证权限等。 ``` @Component @Aspect public class ControllerInterceptor { @Autowired private HttpServletRequest request; private static final Logger logger = LoggerFactory.getLogger(ControllerInterceptor.class); @Around("@annotation(com.example.demo.annotations.LogRecord)") public Object recordLog(ProceedingJoinPoint joinPoint) throws Throwable { ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); HttpServletRequest request = attributes.getRequest(); String methodName = joinPoint.getSignature().getName(); String className = joinPoint.getTarget().getClass().getSimpleName(); logger.info("请求路径:{},请求参数:{},请求方法:{}.{}", request.getRequestURI(), JsonUtil.toJSONString(request.getParameterMap()), className, methodName); Object result = joinPoint.proceed(); return result; } } ``` 3. 在Controller方法上标注自定义注解,使其成为切面的切点。 ``` @RestController @RequestMapping("/demo") public class DemoController { @Autowired private UserService userService; @RequestMapping(value = "/getUserById", method = RequestMethod.GET) @LogRecord public ResponseEntity<?> getUserById(@RequestParam("id") String id) { User user = userService.getUserById(id); return ResponseEntity.ok(user); } } ``` 4. 在SpringBoot主类上使用@EnableAspectJAutoProxy注解开启代理自动配置。 ``` @SpringBootApplication @EnableAspectJAutoProxy public class MyApplication { public static void main(String[] args) { SpringApplication.run(MyApplication.class, args); } } ``` 以上就是使用SpringBoot AOP进行Controller拦截的步骤,通过自定义注解和拦截器的方式,我们可以方便的实现各种Controller拦截逻辑,提升Web应用的可维护性和可扩展性。 ### 回答3: Spring Boot AOP(面向切面编程)是Spring Framework的一个重要部分,它允许我们在程序中实现横切关注点的模块化。横切关注点是一个横跨不同模块和层的功能,如日志、安全性、事务管理等,这些功能在整个程序中多次出现,从而导致代码不需要重复编写。在Spring Boot中,我们可以使用AOP来实现一些特定的横切关注点,例如:拦截Controller请求。 在Spring Boot中,拦截Controller请求是很常见的需求,这是因为我们需要对请求进行验证、权限控制和日志记录等。使用AOP拦截Controller请求的过程中,我们需要定义一个Aspect切面,切入到Controller的请求中执行某些操作。 下面是实现在Spring Boot中使用AOP拦截Controller请求的步骤: 1. 定义一个Aspect切面: @Component @Aspect public class MyAspect { @Pointcut("execution(public * com.example.controller.*.*(..))") public void controllerPointcut() {} @Before("controllerPointcut()") public void beforeControllerMethod(JoinPoint jp) { //执行请求前的逻辑 } @AfterReturning(pointcut="controllerPointcut()", returning="result") public void afterControllerMethod(JoinPoint jp, Object result) { //执行请求后的逻辑 } } 2. 在切面中定义一个Pointcut,用来指定需要拦截的请求。上面的例子中,我们使用execution表达式指定了com.example.controller包下所有public方法为切入点。 3. 在切面中定义拦截Controller请求时需要执行的操作。我们可以在@Before注解中定义请求进入前的逻辑,在@AfterReturning注解中定义请求结束后的逻辑。 4. 在Controller类中注入我们定义的切面,即可使用AOP拦截Controller请求。 @Controller public class MyController { @Autowired private MyAspect myAspect; @GetMapping("/test") public String test() { //请求逻辑 return "test"; } } 通过以上步骤,我们就可以在Spring Boot中使用AOP拦截Controller请求了。需要注意的是,在AOP中定义的逻辑需要足够简洁,并且避免阻塞请求。此外,对于业务逻辑中存在事务的Controller方法不建议使用AOP拦截,因为AOP会改变事务管理的行为。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值