java 自定义注解+AOP实现日志记录

java  自定义注解+AOP实现日志记录

1、自定义注解

 注解:参考我的这篇博客:https://blog.csdn.net/xiaoao20080/article/details/89632015

package com.xxx.controller.framework.auth;

import java.lang.annotation.*;

@Target({ ElementType.PARAMETER, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ControllerAop {
    String url() default "";

    /** 动作的名称 */
    String action() default "";
}

2、通过AOP+反射

  

AOP:利用一种称为"横切"的技术,剖解开封装的对象内部,并将那些影响了多个类的公共行为封装到一个可重用模块,并将其命名为"Aspect",即切面。所谓"切面",简单说就是那些与业务无关,却为业务模块所共同调用的逻辑或责任封装起来,便于减少系统的重复代码,降低模块之间的耦合度,并有利于未来的可操作性和可维护性。


AOP相关概念
切面(Aspect):一个关注点的模块化,这个关注点实现可能另外横切多个对象。事务管理是J2EE应用中一个很好的横切关注点例子。方面用Spring的 Advisor或拦截器实现。

连接点(Joinpoint): 程序执行过程中明确的点,如方法的调用或特定的异常被抛出。

通知(Advice): 在特定的连接点,AOP框架执行的动作。各种类型的通知包括“around”、“before”和“throws”通知。通知类型将在下面讨论。许多AOP框架包括Spring都是以拦截器做通知模型,维护一个“围绕”连接点的拦截器链。Spring中定义了四个advice: BeforeAdvice, AfterAdvice, ThrowAdvice和DynamicIntroductionAdvice

切入点(Pointcut): 指定一个通知将被引发的一系列连接点的集合。AOP框架必须允许开发者指定切入点:例如,使用正则表达式。 Spring定义了Pointcut接口,用来组合MethodMatcher和ClassFilter,可以通过名字很清楚的理解, MethodMatcher是用来检查目标类的方法是否可以被应用此通知,而ClassFilter是用来检查Pointcut是否应该应用到目标类上。


通知(advice)

所谓通知指的就是指拦截到连接点之后要执行的代码,通知分为前置、后置、异常、最终、环绕通知五类:

Before(前) org.apringframework.aop.MethodBeforeAdvice 

After-returning(返回后) org.springframework.aop.AfterReturningAdvice 

After-throwing(抛出后) org.springframework.aop.ThrowsAdvice 

Introduction(引入) org.springframework.aop.IntroductionInterceptor 

Arround(环绕) org.aopaliance.intercept.MethodInterceptor 
 

package com.xxx.controller.framework.auth;

import java.lang.reflect.Method;
import java.util.Date;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.xxx.controller.base.controller.BaseController;
import com.xxx.model.common.system.user.MipUser;
import com.xxx.model.common.system.userlog.SysUserlog;
import com.xxx.service.SysUserlogService;
import com.xxx.service.UserService;
import com.xxx.utils.OrgUtil;
import com.xxx.utils.Tools;
import com.xxx.utils.common.IdUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
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;

/**
 * 操作日志记录处理
 *
 * @author xiaoao
 */

@Aspect
@Component
public class ControllerAopOperator extends BaseController{


    @Autowired
    private SysUserlogService sysUserlogService;


	HttpServletRequest request = null;
	
	//声明AOP切入点,凡是使用了XXXOperateLog的方法均被拦截
    @Pointcut("@annotation(com.xxx.controller.framework.auth.ControllerAop)")
    public void log() {
//        System.out.println("我是一个切入点");
    }


    /**
     * 前置通知 用于拦截Controller层记录用户的操作
     *
     * @param joinPoint 切点
     */
    @AfterReturning(pointcut = "log()")
    public void doBefore(JoinPoint joinPoint)
        {
            handleLog(joinPoint, null);
    }

    @AfterThrowing(value = "log()", throwing = "e")
    public void doAfter(JoinPoint joinPoint, Exception e)
    {
        handleLog(joinPoint, e);
    }


    private void handleLog(JoinPoint joinPoint, Exception e)
    {
        try
        {
            // 获得注解
            ControllerAop controllerAop = giveController(joinPoint);
            if (controllerAop== null)
            {
                return;
            }
            System.out.println(controllerAop.action()+">>>>>>>>>>>>>>>>>>>>>>>");
            HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes())
                    .getRequest();

            // *========数据库日志=========*//
            SysUserlog sysUserlog = new SysUserlog();
            // 请求的IP
            sysUserlog.setUserName(Tools.getUserName());
//            sysUserlog.setUserName("sysadmin");
            sysUserlog.setLoginTime(new Date());
            String clientIp = getIpAddr(request);
            sysUserlog.setLoginIp(clientIp);
            sysUserlog.setUrl(request.getRequestURI());
            sysUserlog.setRequestParam(JSON.toJSONString(request.getParameterMap()));



            // 处理设置注解上的参数
            getControllerMethodDescription(controllerAop,sysUserlog,request);
            // 保存数据库
            sysUserlogService.insertUserlog(sysUserlog);
        }
        catch (Exception ex)
        {
            // 记录本地异常日志
            ex.printStackTrace();
        }
    }


    /**
     * 是否存在注解,如果存在就记录日志
     *
     * @param joinPoint
     * @param  //controllerAop
     * @return
     * @throws Exception
     */
    private static ControllerAop giveController(JoinPoint joinPoint) throws Exception
    {
        Signature signature = joinPoint.getSignature();
        MethodSignature methodSignature = (MethodSignature) signature;
        Method method = methodSignature.getMethod();

        if (method != null)
        {
            return method.getAnnotation(ControllerAop.class);
        }
        return null;
    }




    /**
     * 获取注解中对方法的描述信息 用于Controller层注解
     *
     * @param  /joinPoint 切点
     * @return 方法描述
     * @throws Exception
     */
    public static void getControllerMethodDescription(ControllerAop  controllerAop, SysUserlog sysUserlog,
                                                      HttpServletRequest request) throws Exception
    {
        // 设置action动作
        sysUserlog.setAction(controllerAop.action());

    }



    /**
     * 获取请求的参数,放到log中
     *
     * @param sysUserlog
     * @param request
     */
    @SuppressWarnings("all")
    private static void setRequestValue(SysUserlog sysUserlog, HttpServletRequest request)
    {
        if (sysUserlog == null){
            sysUserlog = new SysUserlog();
            Map map = request.getParameterMap();
            String params = JSONObject.toJSONString(map);
            sysUserlog.setRequestParam(params);
        }

    }

}

IpUtils类


package com.xxxx.utils.logs.utils;
 
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import javax.servlet.http.HttpServletRequest; 
/**
 * @version: V1.0
 * @author: fendo
 * @className: IpUtils
 * @packageName: com.xxxx.logs.utils
 * @description: IP工具类
 * @data: 2018-05-31 10:48  
 **/
public class IpUtils {
    /**
     * 获取客户端IP地址
     * @param request
     * @return
     */
    public static String getRemoteAddr(HttpServletRequest request) {
        if (request == null) {
            return "unknown";
        }
        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("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 StringUtils.split(ObjectUtils.toString(ip), ",")[0];
    }
 
}  

UserAgentUtils类


package com.xxxx.utils.logs.utils;
 
import eu.bitwalker.useragentutils.Browser;
import eu.bitwalker.useragentutils.DeviceType;
import eu.bitwalker.useragentutils.UserAgent;
import javax.servlet.http.HttpServletRequest;
/**
 * @version: V1.0
 * @author: fendo
 * @className: UserAgentUtils
 * @packageName: com.xxxx.logs.utils
 * @description: 用户代理
 * @data: 2018-05-31 10:49  
 **/
public class UserAgentUtils {
    /**
     * 获取用户代理对象
     * @param request
     * @return
     */
    public static UserAgent getUserAgent(HttpServletRequest request){
        return UserAgent.parseUserAgentString(request.getHeader("User-Agent"));
    }
 
    /**
     * 获取设备类型
     * @param request
     * @return
     */
    public static DeviceType getDeviceType(HttpServletRequest request){
        return getUserAgent(request).getOperatingSystem().getDeviceType();
    }
 
    /**
     * 是否是PC
     * @param request
     * @return
     */
    public static boolean isComputer(HttpServletRequest request){
        return DeviceType.COMPUTER.equals(getDeviceType(request));
    }
 
    /**
     * 是否是手机
     * @param request
     * @return
     */
    public static boolean isMobile(HttpServletRequest request){
        return DeviceType.MOBILE.equals(getDeviceType(request));
    }
 
    /**
     * 是否是平板
     * @param request
     * @return
     */
    public static boolean isTablet(HttpServletRequest request){
        return DeviceType.TABLET.equals(getDeviceType(request));
    }
 
    /**
     * 是否是手机和平板
     * @param request
     * @return
     */
    public static boolean isMobileOrTablet(HttpServletRequest request){
        DeviceType deviceType = getDeviceType(request);
        return DeviceType.MOBILE.equals(deviceType) || DeviceType.TABLET.equals(deviceType);
    }
 
    /**
     * 获取浏览类型
     * @param request
     * @return
     */
    public static Browser getBrowser(HttpServletRequest request){
        return getUserAgent(request).getBrowser();
    }
 
    /**
     * 是否IE版本是否小于等于IE8
     * @param request
     * @return
     */
    public static boolean isLteIE8(HttpServletRequest request){
        Browser browser = getBrowser(request);
        return Browser.IE5.equals(browser) || Browser.IE6.equals(browser)
                || Browser.IE7.equals(browser) || Browser.IE8.equals(browser);
    }
}  

 使用示例

/**
     * @Description 查询日志列表
     * @param   //分页参数
     * @return
     */
    @ControllerAop(action="查询日志列表")
    @RequestMapping("/getSyslogList")
    @ResponseBody
    public JSONObject getDepartList(String username,String logintime,String endTime,@RequestParam(defaultValue = "1") Integer
            currentPage, @RequestParam(defaultValue =
            "10") Integer size) throws Exception{
        return  sysUserlogService.userlogList(username,logintime,endTime,currentPage,size);
    }

参考博客:1、https://blog.csdn.net/u011781521/article/details/80528049

 2、https://blog.csdn.net/sinat_27143551/article/details/79794241

PS:自定义注解+AOP还可以用来实现权限控制,可以在请求方法上加上自定义权限注解,然后在切面类里添加业务逻辑。可参考:https://blog.csdn.net/qq_24689877/article/details/85143929

猜你喜欢

转载自blog.csdn.net/xiaoao20080/article/details/92061076