java web中Aspect、ControllerAdvice、Interceptor、Fliter示例以及的区别

1. Filter(过滤器)

filter是Servlet规范的内容,不属于Spring。通过filter,可以获取请求和响应信息,不能获取执行的类以及方法信息。

1.1 Filter类

package com.ruoyi.framework.filter;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import java.io.IOException;

/**
 * 
 */
public class TimerFilter implements Filter {

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        Filter.super.init(filterConfig);

        System.out.println("Time Filter init");
    }

    @Override
    public void destroy() {
        Filter.super.destroy();
        System.out.println("time filter destroy");
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {

        long start = System.currentTimeMillis();
        filterChain.doFilter(servletRequest,servletResponse);
        System.out.println("time filter:"+(System.currentTimeMillis()-start));
        System.out.println("time filter finish");

    }
}

通过示例代码,可以看到,可以获取请求servletRequest和响应ServletResponse,但是并不知道经过了那个controller的那个方法处理过。

1.2 配置filter

package com.ruoyi.framework.config;

import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.framework.filter.TimerFilter;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.servlet.DispatcherType;
import java.util.HashMap;
import java.util.Map;

/**
 * 
 */
@Configuration
public class TimeFilterConfig {

    private String urlPatterns = "/system/*";

    @Bean
    public FilterRegistrationBean timerFilterRegistration()
    {
        FilterRegistrationBean registration = new FilterRegistrationBean();
        registration.setDispatcherTypes(DispatcherType.REQUEST);
        registration.setFilter(new TimerFilter());

        registration.addUrlPatterns(StringUtils.split(urlPatterns, ","));
        registration.setName("timeFilter");
        registration.setOrder(FilterRegistrationBean.HIGHEST_PRECEDENCE);
        // Map<String, String> initParameters = new HashMap<String, String>();
        // initParameters.put("excludes", excludes);
        // registration.setInitParameters(initParameters);
        return registration;
    }

}

通过@Configuration和@Bean,可以实现Filter的注册。

此外,还可以在Filter类上添加注解来实现Filter注册。

@Component
@WebFilter(filterName ="TimeFilter",urlPatterns ="/*")
public class TimerFilter implements Filter {

......

}

2. Interceptor (拦截器)

可以获得Http原始的请求和响应信息,也拿得到执行请求的类信息和方法名(比如:com.ruoyi.web.controller.system.SysLoginController#login(HttpServletRequest, HttpServletResponse, ModelMap))。

2.1 Interceptor类实例

package com.ruoyi.framework.interceptor;

import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.resource.ResourceHttpRequestHandler;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 *
 */
@Component
public class TimeInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {

        if(handler instanceof  HandlerMethod)
        {
            HandlerMethod handlerMethod = (HandlerMethod)handler;

            System.out.println("method name:" + handlerMethod.getMethod().getName());
            System.out.println("class name:" +               handlerMethod.getBean().getClass().getName());
        }

        System.out.println("handler:" + handler);

        request.setAttribute("startTime",System.currentTimeMillis());
        boolean res = HandlerInterceptor.super.preHandle(request, response, handler);

        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {

        System.out.println("postHandle");
        Long start = (Long)request.getAttribute("startTime");
        System.out.println("time interceptor 耗时:"+(System.currentTimeMillis()-start));

    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("afterCompletion");
        Long start = (Long)request.getAttribute("startTime");
        System.out.println("time interceptor 耗时:"+(System.currentTimeMillis()-start));

    }
}

从实例代码中,可以看到,可以获取请求HttpServletRequest和响应HttpServletResponse信息,还有一个参数handler,通过该参数,可以获取执行的方法信息。

2.2 interceptor注册

package com.ruoyi.framework.config;

import com.ruoyi.framework.interceptor.TimeInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

/**
 * 
 */
@Configuration
public class TimeInterceptorWebConfig implements WebMvcConfigurer {

    @Autowired
    private TimeInterceptor timeInterceptor;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(timeInterceptor)
                .addPathPatterns("/system/*")
                .excludePathPatterns("/static/*")
                .excludePathPatterns("/template/*");
    }
}

通过@Configuration进行注册,并指定需要拦截的路径,以及不需要拦截的路径,一般静态资源路径不需要拦截。

3. ControllerAdvice(Controller增强)

ControllerAdvice常用的场景是作为统一的异常处理类。

3.1 ControllerAdvice实例代码

package com.ruoyi.framework.web.exception;

import javax.servlet.http.HttpServletRequest;
import org.apache.shiro.authz.AuthorizationException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.validation.BindException;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.servlet.ModelAndView;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.exception.DemoModeException;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.ServletUtils;
import com.ruoyi.common.utils.security.PermissionUtils;

/**
 * 全局异常处理器
 * 
 * 
 */
@RestControllerAdvice
public class GlobalExceptionHandler
{
    private static final Logger log = LoggerFactory.getLogger(GlobalExceptionHandler.class);

    /**
     * 权限校验异常(ajax请求返回json,redirect请求跳转页面)
     */
    @ExceptionHandler(AuthorizationException.class)
    public Object handleAuthorizationException(AuthorizationException e, HttpServletRequest request)
    {
        String requestURI = request.getRequestURI();
        log.error("请求地址'{}',权限校验失败'{}'", requestURI, e.getMessage());
        if (ServletUtils.isAjaxRequest(request))
        {
            return AjaxResult.error(PermissionUtils.getMsg(e.getMessage()));
        }
        else
        {
            return new ModelAndView("error/unauth");
        }
    }

    /**
     * 请求方式不支持
     */
    @ExceptionHandler(HttpRequestMethodNotSupportedException.class)
    public AjaxResult handleHttpRequestMethodNotSupported(HttpRequestMethodNotSupportedException e,
            HttpServletRequest request)
    {
        String requestURI = request.getRequestURI();
        log.error("请求地址'{}',不支持'{}'请求", requestURI, e.getMethod());
        return AjaxResult.error(e.getMessage());
    }

    /**
     * 拦截未知的运行时异常
     */
    @ExceptionHandler(RuntimeException.class)
    public AjaxResult handleRuntimeException(RuntimeException e, HttpServletRequest request)
    {
        String requestURI = request.getRequestURI();
        log.error("请求地址'{}',发生未知异常.", requestURI, e);
        return AjaxResult.error(e.getMessage());
    }

    /**
     * 系统异常
     */
    @ExceptionHandler(Exception.class)
    public AjaxResult handleException(Exception e, HttpServletRequest request)
    {
        String requestURI = request.getRequestURI();
        log.error("请求地址'{}',发生系统异常.", requestURI, e);
        return AjaxResult.error(e.getMessage());
    }

    /**
     * 业务异常
     */
    @ExceptionHandler(ServiceException.class)
    public Object handleServiceException(ServiceException e, HttpServletRequest request)
    {
        log.error(e.getMessage(), e);
        if (ServletUtils.isAjaxRequest(request))
        {
            return AjaxResult.error(e.getMessage());
        }
        else
        {
            return new ModelAndView("error/service", "errorMessage", e.getMessage());
        }
    }

    /**
     * 自定义验证异常
     */
    @ExceptionHandler(BindException.class)
    public AjaxResult handleBindException(BindException e)
    {
        log.error(e.getMessage(), e);
        String message = e.getAllErrors().get(0).getDefaultMessage();
        return AjaxResult.error(message);
    }

    /**
     * 演示模式异常
     */
    @ExceptionHandler(DemoModeException.class)
    public AjaxResult handleDemoModeException(DemoModeException e)
    {
        return AjaxResult.error("演示模式,不允许操作");
    }
}

可以看到,在类上添加了@RestControllerAdvice,在方法上添加了@ExceptionHandler,并且通过参数的形式,指定了该方法处理的异常类型。

其中@RestControllerAdvice表示在方法出现异常后,返回信息采用@ResponseBody的方式将信息编码后输出到response对象的body属性,通常是json格式的数据。

3.2 自定义异常代码

package com.ruoyi.common.exception;

/**
 * 业务异常
 * 
 * 
 */
public final class ServiceException extends RuntimeException
{
    private static final long serialVersionUID = 1L;

    /**
     * 错误提示
     */
    private String message;

    /**
     * 错误明细,内部调试错误
     *
     * 和 {@link CommonResult#getDetailMessage()} 一致的设计
     */
    private String detailMessage;

    /**
     * 空构造方法,避免反序列化问题
     */
    public ServiceException()
    {
    }

    public ServiceException(String message)
    {
        this.message = message;
    }

    public String getDetailMessage()
    {
        return detailMessage;
    }

    public ServiceException setDetailMessage(String detailMessage)
    {
        this.detailMessage = detailMessage;
        return this;
    }

    public String getMessage()
    {
        return message;
    }

    public ServiceException setMessage(String message)
    {
        this.message = message;
        return this;
    }
}

可以根据业务的需要,定义各种各样的异常类。

4. Aspect(切面)

切面拦截的时候,可以指定拦截哪些方法,也可以获得方法的参数和返回值。

4.1 切面示例代码

package com.ruoyi.framework.aspectj;

import com.alibaba.fastjson.JSON;
import com.ruoyi.common.annotation.EventTrack;
import com.ruoyi.common.config.RuoYiConfig;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.ServletUtils;
import com.ruoyi.common.utils.ShiroUtils;
import com.ruoyi.system.domain.EventTrackLog;
import com.ruoyi.system.service.IEventTrackLogService;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
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.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.lang.reflect.Method;
import java.net.InetAddress;
import java.util.Arrays;
import java.util.Date;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicLong;

/**
 * 
 * 埋点切面
 */
@Aspect
@Component
public class EventTrackAspect {

    //日志工厂获取日志对象
    static Logger logger = LoggerFactory.getLogger(EventTrackAspect.class);

    /** 排除敏感属性字段 */
    public static final String[] EXCLUDE_PROPERTIES = { "password", "oldPassword", "newPassword", "confirmPassword" };

    @Autowired
    private IEventTrackLogService eventTrackLogService;

    //startTime存放开始时间
    private ThreadLocal<Map<String, Long >> startTime = new ThreadLocal<>();

    //eventTrackLog日志访问对象
    private ThreadLocal<EventTrackLog> eventTrackLog = new ThreadLocal<>();

    //Controller层切点
    @Pointcut("@annotation(com.ruoyi.common.annotation.EventTrack)")
    public void controllerAspectse() {
    }

    //前置通知  用于拦截Controller层记录用户的操作
    @Before("controllerAspectse()")
    public void before(JoinPoint pjp) {
        //方法调用之前初始化
        EventTrackLog eventTrackLog = this.eventTrackLog.get();
        eventTrackLog = new EventTrackLog();

        Map<String, Long> map = new HashMap<>();
        map.put("startTime",System.currentTimeMillis());
        this.startTime.set(map);

        logger.info("==============前置通知开始:记录用户的操作==============");
        String currentTime = DateUtils.getTime();

        logger.info("请求开始时间:" + currentTime);
        eventTrackLog.setStartTime(new Date());
        String resultString = "";

        // 是否打日志 默认打
        boolean isLog = true;
        try {
            MethodSignature signature = (MethodSignature) pjp.getSignature();
            EventTrack eventTrack = signature.getMethod().getAnnotation(EventTrack.class);
            //是否开启日志打印
            isLog = eventTrack.isLog();
            if(isLog){
                //开始打印日志
                HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
                HttpSession session = request.getSession();
                String api = pjp.getTarget().getClass().getName() + "." + pjp.getSignature().getName();
                logger.info("请求API:" + api);
                eventTrackLog.setMethod(api);

                String methodDescription = getControllerMethodDescription(pjp);
                logger.info("方法描述:" + methodDescription);
                eventTrackLog.setDescription(methodDescription);

                String ipAddress = InetAddress.getLocalHost().toString().substring(InetAddress.getLocalHost().toString().lastIndexOf("/") + 1);
                logger.info("请求ip:"+ ipAddress);
                eventTrackLog.setIpAddress(ipAddress);

                String hostName = InetAddress.getLocalHost().getHostName();
                logger.info("机器名:" + hostName);
                eventTrackLog.setHostName(hostName);

                Enumeration<?> enu = request.getParameterNames();
                String params = "{";
                while (enu.hasMoreElements()) {
                    String paraName = (String) enu.nextElement();
                    List<String> list = Arrays.asList(EXCLUDE_PROPERTIES);
                    if(list.contains(paraName)) {
                        continue;
                    }

                    params += "\"" + paraName + "\":\"" + request.getParameter(paraName) + "\",";
                }
                String methodParams = params + "}";
                String substring = methodParams.substring(0, methodParams.length() - 2);
                substring = substring + "}";
                logger.info("方法参数:" + substring);
                eventTrackLog.setReqParams(substring);

                StringBuffer url = request.getRequestURL();
                logger.info("URL:" + url);
                eventTrackLog.setUrl(String.valueOf(url));
            }
        } catch (Exception e) {
            StackTraceElement stackTraceElement2 = e.getStackTrace()[2];
            String reason = "异常:【"+
                    "类名:"+stackTraceElement2.getClassName()+";"+
                    "文件:"+stackTraceElement2.getFileName()+";"+"行:"+
                    stackTraceElement2.getLineNumber()+";"+"方法:"
                    +stackTraceElement2.getMethodName() + "】";
            //记录本地异常日志
            logger.error("==============前置通知异常:记录访问异常信息==============");
            String message = e.getMessage() + "|" + reason;
            logger.error("异常信息:",message);
            eventTrackLog.setErrorMsg(message);
            eventTrackLog.setResult("请求发生异常,异常信息:" + message);
        }finally {
            this.eventTrackLog.set(eventTrackLog);
        }
    }

    @Around("controllerAspectse()")
    public Object around(ProceedingJoinPoint pjp) throws Throwable {

        // 获取方法签名
        MethodSignature signature = (MethodSignature) pjp.getSignature();
        EventTrack eventTrack = signature.getMethod().getAnnotation(EventTrack.class);
        //是否开启日志打印
        Boolean isLog = eventTrack.isLog();

        EventTrackLog eventTrackLog = new EventTrackLog();

        Long startTime = System.currentTimeMillis();

        eventTrackLog.setStartTime(new Date());

        try {

            //开始打印日志
            HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
            HttpSession session = request.getSession();
            String api = pjp.getTarget().getClass().getName() + "." + pjp.getSignature().getName();
            logger.info("请求API:" + api);
            eventTrackLog.setMethod(api);

            String methodDescription = getControllerMethodDescription(pjp);
            logger.info("方法描述:" + methodDescription);
            eventTrackLog.setDescription(methodDescription);

            String ipAddress = InetAddress.getLocalHost().toString().substring(InetAddress.getLocalHost().toString().lastIndexOf("/") + 1);
            logger.info("请求ip:"+ ipAddress);
            eventTrackLog.setIpAddress(ipAddress);

            String hostName = InetAddress.getLocalHost().getHostName();
            logger.info("机器名:" + hostName);
            eventTrackLog.setHostName(hostName);

            Enumeration<?> enu = request.getParameterNames();
            String params = "{";
            while (enu.hasMoreElements()) {
                String paraName = (String) enu.nextElement();

                List<String> list = Arrays.asList(EXCLUDE_PROPERTIES);
                if(list.contains(paraName)) {
                    continue;
                }

                params += "\"" + paraName + "\":\"" + request.getParameter(paraName) + "\",";
            }
            String methodParams = params + "}";
            String substring = methodParams.substring(0, methodParams.length() - 2);
            substring = substring + "}";
            logger.info("方法参数:" + substring);
            eventTrackLog.setReqParams(substring);

            StringBuffer url = request.getRequestURL();
            logger.info("URL:" + url);
            eventTrackLog.setUrl(String.valueOf(url));

        }catch (Exception e) {

        }

        Object proceed = pjp.proceed();
        String result = JSON.toJSONString(proceed);
        logger.info("==============环切方法执行完成==============");
        logger.info("请求结果:" + result);

        try {

            Long endTime = System.currentTimeMillis();

            Long timeSpan = endTime - startTime;
            logger.info("timeSpan = " + timeSpan);

            eventTrackLog.setTimeSpend(timeSpan);

            eventTrackLog.setEndTime(new Date());

            // 获取当前的用户
            SysUser currentUser = ShiroUtils.getSysUser();

            if(currentUser != null)
            {
                eventTrackLog.setUserName(currentUser.getLoginName());
                eventTrackLog.setDeptName(currentUser.getDept().getDeptName());
            }

            eventTrackLog.setSystemName(RuoYiConfig.getName());

            eventTrackLog.setStatus(0l);
            eventTrackLog.setNumber(1L);

            eventTrackLog.setModuleTitle(eventTrack.title());
            eventTrackLog.setBusinessType(eventTrack.businessType().toString());

            if(ServletUtils.checkAgentIsMobile(ServletUtils.getRequest().getHeader("User-Agent")))
            {
                eventTrackLog.setChannel("Mobile");
            }
            else {
                eventTrackLog.setChannel("PC");
            }

            eventTrackLog.setCreateBy("around");
            eventTrackLog.setCreateTime(new Date());


        } catch (Exception e) {


        } finally {

            // 添加日志信息入库
            eventTrackLogService.insertEventTrackLog(eventTrackLog);
        }

        return proceed;
    }

    /**
     * 拦截异常操作
     *
     * @param joinPoint 切点
     * @param ex 异常
     */
    @AfterThrowing(value = "@annotation(eventTrack)", throwing = "ex")
    public void doAfterThrowing(JoinPoint joinPoint, EventTrack eventTrack, Exception ex)
    {
        logger.info("==============异常方法执行==============");
        EventTrackLog eventTrackLog = this.eventTrackLog.get();

        try {
            //获取方法名
            String methodName = joinPoint.getSignature().getName();

            Long end = System.currentTimeMillis();
            Long total =  end - startTime.get().get("startTime");
            logger.info("执行总耗时为:" +total);

            eventTrackLog = this.eventTrackLog.get();
            eventTrackLog.setTimeSpend(total);
            String endTime = DateUtils.getTime();
            logger.info("请求结束时间:" + endTime);
            eventTrackLog.setEndTime(new Date());

            // 获取当前的用户
            SysUser currentUser = ShiroUtils.getSysUser();

            if(currentUser != null)
            {
                eventTrackLog.setUserName(currentUser.getLoginName());
                eventTrackLog.setDeptName(currentUser.getDept().getDeptName());
            }

            // eventTrackLog.setSystemName("平台管理系统");
            eventTrackLog.setSystemName(RuoYiConfig.getName());

            // eventTrackLog.setModuleTitle("后台管理");

            eventTrackLog.setStatus(2l);
            eventTrackLog.setNumber(1L);

            eventTrackLog.setExceptMsg(ex.getMessage());

            eventTrackLog.setModuleTitle(eventTrack.title());
            eventTrackLog.setBusinessType(eventTrack.businessType().toString());

            if(ServletUtils.checkAgentIsMobile(ServletUtils.getRequest().getHeader("User-Agent")))
            {
                eventTrackLog.setChannel("Mobile");
            }
            else {
                eventTrackLog.setChannel("PC");
            }

            eventTrackLog.setCreateBy("except");
            eventTrackLog.setCreateTime(new Date());

        } catch (Exception e) {
            StackTraceElement stackTraceElement2 = e.getStackTrace()[2];
            String reason = "异常:【"+
                    "类名:"+stackTraceElement2.getClassName()+";"+
                    "文件:"+stackTraceElement2.getFileName()+";"+"行:"+
                    stackTraceElement2.getLineNumber()+";"+"方法:"
                    +stackTraceElement2.getMethodName() + "】";
            //记录本地异常日志
            logger.error("==============通知异常:记录访问异常信息==============");
            String message = e.getMessage() + "|" + reason;
            logger.error("异常信息:",message);
            eventTrackLog.setExceptMsg(message);
            eventTrackLog.setResult("请求发生异常!!!");
        } finally {
            // 添加日志信息入库
            eventTrackLogService.insertEventTrackLog(eventTrackLog);

            // 处理使用结束,清理变量
            this.eventTrackLog.remove();
        }

    }


    /**
     *
     * @param jp
     */

    @AfterReturning(pointcut = "@annotation(eventTrack)", returning = "jsonResult")
    public void afterMethod(JoinPoint jp, EventTrack eventTrack, Object jsonResult) {
        logger.info("==============方法执行完成==============");
        EventTrackLog eventTrackLog = this.eventTrackLog.get();
        try {
            //获取方法名
            String methodName = jp.getSignature().getName();

            Long end = System.currentTimeMillis();
            Long total =  end - startTime.get().get("startTime");
            logger.info("执行总耗时为:" +total);

            eventTrackLog = this.eventTrackLog.get();
            eventTrackLog.setTimeSpend(total);
            String endTime = DateUtils.getTime();
            logger.info("请求结束时间:" + endTime);
            eventTrackLog.setEndTime(new Date());

            // 获取当前的用户
            SysUser currentUser = ShiroUtils.getSysUser();

            if(currentUser != null)
            {
                eventTrackLog.setUserName(currentUser.getLoginName());
                eventTrackLog.setDeptName(currentUser.getDept().getDeptName());
            }

            // eventTrackLog.setSystemName("平台管理系统");
            eventTrackLog.setSystemName(RuoYiConfig.getName());
            // eventTrackLog.setModuleTitle("后台管理");

            eventTrackLog.setStatus(0l);
            eventTrackLog.setNumber(1L);

            eventTrackLog.setModuleTitle(eventTrack.title());
            eventTrackLog.setBusinessType(eventTrack.businessType().toString());

            if(ServletUtils.checkAgentIsMobile(ServletUtils.getRequest().getHeader("User-Agent")))
            {
                eventTrackLog.setChannel("Mobile");
            }
            else {
                eventTrackLog.setChannel("PC");
            }

            eventTrackLog.setCreateBy("return");
            eventTrackLog.setCreateTime(new Date());

        } catch (Exception e) {
            StackTraceElement stackTraceElement2 = e.getStackTrace()[2];
            String reason = "异常:【"+
                    "类名:"+stackTraceElement2.getClassName()+";"+
                    "文件:"+stackTraceElement2.getFileName()+";"+"行:"+
                    stackTraceElement2.getLineNumber()+";"+"方法:"
                    +stackTraceElement2.getMethodName() + "】";
            //记录本地异常日志
            logger.error("==============通知异常:记录访问异常信息==============");
            String message = e.getMessage() + "|" + reason;
            logger.error("异常信息:",message);
            eventTrackLog.setExceptMsg(message);
            eventTrackLog.setResult("请求发生异常!!!");

        } finally {
            // this.eventTrackLog.set(eventTrackLog);
            // 添加日志信息入库
            eventTrackLogService.insertEventTrackLog(eventTrackLog);

            // 处理使用结束,清理变量
            this.eventTrackLog.remove();
        }
    }

    /**
     * 获取注解中对方法的描述信息 用于Controller层注解
     */
    public static String getControllerMethodDescription(JoinPoint joinPoint) throws Exception {
        String targetName = joinPoint.getTarget().getClass().getName();
        String methodName = joinPoint.getSignature().getName();//目标方法名
        Object[] arguments = joinPoint.getArgs();
        Class targetClass = Class.forName(targetName);
        Method[] methods = targetClass.getMethods();
        String description = "";
        for (Method method:methods) {
            if (method.getName().equals(methodName)){
                Class[] clazzs = method.getParameterTypes();
                if (clazzs.length==arguments.length){
                    description = method.getAnnotation(EventTrack.class).description();
                    break;
                }
            }
        }
        return description;
    }

}

这里以一个记录日志的切面为例进行说明。切面包括前置通知,后置通知和环绕通知。这里以指定的注解来判断是否需要拦截。

这里虽然同时使用了前置通知,后置通知以及环绕通知,在实际的使用场景中,可以根据需要进行有选择的使用。

4.2 自定义注解代码

package com.ruoyi.common.annotation;

/**
 * 
 */

import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.common.enums.OperatorType;
import org.springframework.web.bind.annotation.ResponseBody;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

// 事件埋点
@Target({ElementType.PARAMETER, ElementType.METHOD})//作用在参数和方法上
@Retention(RetentionPolicy.RUNTIME)//运行时注解
@Documented//表明这个注解应该被 javadoc工具记录
// @ResponseBody//响应时转JSON格式
public @interface EventTrack {

    /**
     * 模块
     */
    public String title() default "";

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

    /**
     * 操作人类别
     */
    public OperatorType operatorType() default OperatorType.MANAGE;

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

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

    /**
     * 业务描述
     * @return
     */
    String description() default "";

    /**
     * 是否打日志 默认打
     */
    boolean isLog() default true;

}

以上是对Aspect、ControllerAdvice、Interceptor、Fliter的举例说明,通过这些示例,可以更具体的理解他们的差异。

1.过滤器:Filter :可以获得Http原始的请求和响应信息,但是拿不到处理该请求的方法信息(比如类名称,方法名称等);

2.拦截器:Interceptor:可以获得Http原始的请求和响应信息,也可以拿得到相应方法的信息,根据httpServeltRquest也能拿到请求参数;

3.ControllerAdvice(Controller增强):主要是用于全局的异常拦截和处理,这里的异常可以使自定义异常,也可以是JDK里面的异常;

4.切片:Aspect:主要是进行公共方法的拦截,可以拿得到方法参数的值,也可以获得方法处理后的返回值。

从技术层次来看,可以参考下图:

外层技术主要是原始的请求和响应,内层可以具体到某个具体的Controller的方法,获取的信息可以更具体和准确。

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值