SpringBoot自定义AOP 升级版本

基础版见这个

SpringBoot AOP 实现请求日志记录_Teln_小凯的博客-CSDN博客_springboot请求日志记录引入依赖<dependency> <groupId>aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.5.4</version> </dependency>监控类代码,目前只做了控制台输出,后续自己切换到文本或者数据库中pachttps://blog.csdn.net/qq873113580/article/details/123933646下面是升级版

依赖

<dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.8.8</version>
        </dependency>

自定义监控日志类

package com.java.core.com.annotation;

import com.java.core.com.enums.BusinessType;

import java.lang.annotation.*;

@Target({ ElementType.PARAMETER, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Log
{
    /**
     * 模块
     */
    public String title() default "";

    /**
     * 功能
     */
    public BusinessType businessType() default BusinessType.OTHER;

    /**
     * 是否保存请求的参数
     */
    public boolean isSaveRequestData() default true;

    /**
     * 是否保存响应的参数
     */
    public boolean isSaveResponseData() default true;
}

枚举

package com.java.core.com.enums;

public enum BusinessType
{
    /**
     * 其它
     */
    OTHER,
    /**
     * 获取
     */
    GET,
    /**
     * 新增
     */
    INSERT,

    /**
     * 修改
     */
    UPDATE,

    /**
     * 删除
     */
    DELETE,

    /**
     * 授权
     */
    GRANT,

    /**
     * 导出
     */
    EXPORT,

    /**
     * 导入
     */
    IMPORT,

    /**
     * 强退
     */
    FORCE,

    /**
     * 生成代码
     */
    GENCODE,

    /**
     * 清空
     */
    CLEAN,
}

controller用法

@ApiOperation(value = "刷新登录状态")
    @Log(title = "在线用户", businessType = BusinessType.UPDATE)
    @PreAuthorize("hasAuthority('sys:userOnline:insert') || hasAuthority('sys:userOnline:edit')")
    @PostMapping(value = "/refreshToken")
    public HttpResult refreshToken(HttpServletRequest request){
        //在线用户
        SysUserOnline onlineUser= WebApp.getOnlineUser(request,"","");
        //保存到数据库
        return HttpResult.ok(sysUserOnlineService.saveOnline(onlineUser));
    }

请求后的监控,和报错的监控

package com.java.core.web.config;

import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.support.spring.PropertyPreFilters;
import com.java.core.com.annotation.Log;
import com.java.core.com.enums.BusinessStatus;
import com.java.core.com.utils.StringUtils;
import com.java.core.com.utils.http.AddressUtils;
import com.java.core.com.utils.http.IpUtils;
import com.java.core.com.utils.spring.SpringUtils;
import com.java.core.com.vo.HttpResult;
import com.java.core.core.security.JwtTokenUtils;
import com.java.core.entity.master.SysOperLog;
import com.java.core.service.system.SysOperLogService;
import com.java.core.service.system.SysUserOnlineService;
import eu.bitwalker.useragentutils.UserAgent;
import io.jsonwebtoken.Claims;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import org.springframework.validation.BindingResult;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Collection;
import java.util.Date;
import java.util.Map;

//处理AOP切面请求日志
@Slf4j
@Component
@Aspect
public class OperLogConfig {
    /** 排除敏感属性字段 */
    public static final String[] EXCLUDE_PROPERTIES = { "salt","sessionId","password", "oldPassword", "newPassword", "confirmPassword" };

    // 配置织入点
    @Pointcut("@annotation(com.java.core.com.annotation.Log)")
    public void pointcut()
    {
    }
    /**
     * 处理完请求后执行
     *
     * @param joinPoint 切点
     */
    @AfterReturning(pointcut = "@annotation(controllerLog)", returning = "result")
    public void requestAfter(JoinPoint joinPoint, Log controllerLog, Object result) throws Exception {
        handleLog(joinPoint, controllerLog, null, result);
    }

    /**
     * 拦截异常操作
     *
     * @param joinPoint 切点
     * @param e 异常
     */
    @AfterThrowing(value = "@annotation(controllerLog)", throwing = "e")
    public void doAfterThrowing(JoinPoint joinPoint, Log controllerLog, Exception e) throws Exception {
        handleLog(joinPoint, controllerLog, e, null);
    }

    private void handleLog(final JoinPoint joinPoint, Log controllerLog, final Exception e, Object result) throws Exception {
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
        //浏览器信息
        UserAgent userAgent = UserAgent.parseUserAgentString(request.getHeader("User-Agent"));

        String token = request.getHeader(JwtTokenUtils.AUTHORITIES);

        Claims claims =JwtTokenUtils.getClaimsFromToken(token);
        String userId=claims.getSubject();
        String userName = claims.getAudience();


        SysOperLog dbLog=new SysOperLog();
        // 设置标题
        dbLog.setTitle(controllerLog.title());
        // 设置action动作
        dbLog.setBusiness_type(controllerLog.businessType().ordinal());
        // 设置方法名称
        String className = joinPoint.getTarget().getClass().getName();
        String methodName = joinPoint.getSignature().getName();
        dbLog.setMethod(className + "." + methodName + "()");
        dbLog.setRequest_method(request.getMethod());
        dbLog.setBrowser(userAgent.getBrowser().getName());
        dbLog.setOs(userAgent.getOperatingSystem().getName());
        dbLog.setOper_user_id(userId);
        dbLog.setOper_user_name(userName);
        dbLog.setOper_url(request.getRequestURI());
        dbLog.setOper_ip(IpUtils.getIpAddr(request));
        dbLog.setOper_location(AddressUtils.getRealAddressByIP(dbLog.getOper_ip()));
        dbLog.setJson_result(StringUtils.substring(JSONObject.toJSONString(result),0,2000));
        if (e != null)
        {
            dbLog.setStatus(BusinessStatus.FAIL.ordinal());
            dbLog.setError_msg(StringUtils.substring(e.getMessage(), 0, 2000));
        }else {
            dbLog.setStatus(BusinessStatus.SUCCESS.ordinal());
            dbLog.setError_msg("");
        }
        dbLog.setOper_time(new Date());
        if(result!=null){
            //设置参数
            setRequestValue(joinPoint,request,dbLog);
        }
        //保存参数
        SpringUtils.getBean(SysOperLogService.class).insertOperlog(dbLog);
    }
    /**
     * 获取请求的参数,放到log中
     *
     * @param operLog 操作日志
     * @throws Exception 异常
     */
    private void setRequestValue(JoinPoint joinPoint, HttpServletRequest request, SysOperLog operLog) throws Exception
    {
        Map<String, String[]> map = request.getParameterMap();
        if (StringUtils.isNotEmpty(map))
        {
            String params = JSONObject.toJSONString(map, excludePropertyPreFilter());
            operLog.setOper_param(StringUtils.substring(params, 0, 2000));
        }
        else
        {
            Object args = joinPoint.getArgs();
            if (StringUtils.isNotNull(args))
            {
                String params = argsArrayToString(joinPoint.getArgs());
                operLog.setOper_param(StringUtils.substring(params, 0, 2000));
            }
        }
    }
    /**
     * 忽略敏感属性
     */
    public PropertyPreFilters.MySimplePropertyPreFilter excludePropertyPreFilter()
    {
        return new PropertyPreFilters().addFilter().addExcludes(EXCLUDE_PROPERTIES);
    }
    /**
     * 参数拼装
     */
    private String argsArrayToString(Object[] paramsArray)
    {
        String params = "";
        if (paramsArray != null && paramsArray.length > 0)
        {
            for (Object o : paramsArray)
            {
                if (StringUtils.isNotNull(o) && !isFilterObject(o))
                {
                    try
                    {
                        Object jsonObj = JSONObject.toJSONString(o, excludePropertyPreFilter());
                        params += jsonObj.toString() + " ";
                    }
                    catch (Exception e)
                    {
                    }
                }
            }
        }
        return params.trim();
    }
    /**
     * 判断是否需要过滤的对象。
     *
     * @param o 对象信息。
     * @return 如果是需要过滤的对象,则返回true;否则返回false。
     */
    @SuppressWarnings("rawtypes")
    public boolean isFilterObject(final Object o)
    {
        Class<?> clazz = o.getClass();
        if (clazz.isArray())
        {
            return clazz.getComponentType().isAssignableFrom(MultipartFile.class);
        }
        else if (Collection.class.isAssignableFrom(clazz))
        {
            Collection collection = (Collection) o;
            for (Object value : collection)
            {
                return value instanceof MultipartFile;
            }
        }
        else if (Map.class.isAssignableFrom(clazz))
        {
            Map map = (Map) o;
            for (Object value : map.entrySet())
            {
                Map.Entry entry = (Map.Entry) value;
                return entry.getValue() instanceof MultipartFile;
            }
        }
        return o instanceof MultipartFile || o instanceof HttpServletRequest || o instanceof HttpServletResponse
                || o instanceof BindingResult;
    }
}

实现效果

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Spring Boot允许我们使用自定义AOP来定制业务逻辑。AOP(面向切面编程)是一种编程范式,可以在不改变原有代码的情况下,对现有代码进行增强。 下面是自定义AOP的步骤: 1. 创建一个切面类,使用@Aspect注解标注该类。该类中需要定义一个或多个切点和通知方法。 ```java @Aspect @Component public class MyAspect { @Pointcut("execution(* com.example.demo.service.*.*(..))") public void pointcut() { } @Around("pointcut()") public Object around(ProceedingJoinPoint pjp) throws Throwable { // 前置通知 System.out.println("Before method execute..."); // 执行目标方法 Object result = pjp.proceed(); // 后置通知 System.out.println("After method execute..."); return result; } } ``` 上述代码中,@Pointcut注解定义了一个切点,切点表达式指定了需要增强的方法,这里指定为com.example.demo.service包下的所有方法。@Around注解定义了一个环绕通知方法,该方法在目标方法执行前后分别执行前置通知和后置通知。 2. 在应用程序入口类上添加@EnableAspectJAutoProxy注解,启用Spring的AOP功能。 ```java @SpringBootApplication @EnableAspectJAutoProxy public class DemoApplication { public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); } } ``` 3. 在需要增强的方法上添加自定义注解,并在切面类中定义一个针对该注解的切点。 ```java @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface MyAnnotation { } ``` ```java @Aspect @Component public class MyAspect { @Pointcut("@annotation(com.example.demo.annotation.MyAnnotation)") public void pointcut() { } @Around("pointcut()") public Object around(ProceedingJoinPoint pjp) throws Throwable { // 前置通知 System.out.println("Before method execute..."); // 执行目标方法 Object result = pjp.proceed(); // 后置通知 System.out.println("After method execute..."); return result; } } ``` 上述代码中,@MyAnnotation注解用于标注需要增强的方法,@Pointcut注解定义一个针对@MyAnnotation注解的切点,@Around注解定义一个环绕通知方法,该方法在目标方法执行前后分别执行前置通知和后置通知。 4. 在需要增强的方法上添加@MyAnnotation注解。 ```java @Service public class UserServiceImpl implements UserService { @Override @MyAnnotation public void addUser(User user) { System.out.println("Add user: " + user.getName()); } } ``` 上述代码中,addUser方法上添加了@MyAnnotation注解,表示该方法需要增强。 5. 运行应用程序,观察控制台输出。 ```java Before method execute... Add user: Alice After method execute... ``` 上述输出结果表明,自定义AOP已经生效,增强逻辑被成功执行。 总结:Spring Boot允许我们使用自定义AOP来定制业务逻辑,可以通过定义切面类、切点、通知方法等方式来实现增强逻辑。在实际应用中,我们可以根据具体需求来制定相应的AOP策略,从而提高应用程序的可扩展性和可维护性。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值