java custom annotation + AOP achieve logging

java custom annotation + AOP achieve logging

1, custom annotation

 Note: My reference this blog: 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, reflected by AOP +

  

AOP: using called "cross" technique, the internal cross-sectional decapsulates the object, and those that affect the behavior of the public classes encapsulated into a plurality of reusable modules, and named it "Aspect", i.e., section. The so-called "cut", it simply is that nothing to do with business, but it is the responsibility of the business logic or common module called encapsulated, easy to duplicate code to reduce system and reduce the degree of coupling between modules, and facilitate future operability and maintainability.


AOP concepts
section (Aspect): a modular point of interest, this concerns the implementation might otherwise cut across multiple objects. J2EE application transaction management is a good example of cross-cutting concerns. Achieving Spring-Advisor or interceptors.

Connection point (Joinpoint): during program execution definite point, such as calling or particular exception being thrown.

Notification (Advice): In a particular connection point, an operation performed AOP framework. Various types of notification includes "around", "before" and "throws" notification. The type of notification will be discussed below. Many AOP frameworks, including Spring, model an advice as an interceptor, maintaining a "around" the interceptor chain connection points. Spring defines four advice: BeforeAdvice, AfterAdvice, ThrowAdvice and DynamicIntroductionAdvice

Entry point (Pointcut): Specifies a notification of a collection of point of attachment will be initiated. AOP framework must allow developers to specify the starting point: for example, using regular expressions. Spring Pointcut defined interfaces, and for combining MethodMatcher ClassFilter, can be clearly understood by name, MethodMatcher method is used to check whether the target class may be applied to this notice, and is used to check whether ClassFilter should be applied to the target class Pointcut on.


Notification (advice)

The so-called after the notification means refers to the code to intercept the connection point to be performed, a notification is divided into front, rear, abnormal end, surrounded by five notifications:

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 class


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);
    }
}  

 Examples of Use

/**
     * @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);
    }

Reference blog: 1, https://blog.csdn.net/u011781521/article/details/80528049

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

PS: custom annotation + AOP also be used to achieve access control, can add custom annotations in the permission request method, and then add the business logic class section. Refer to: https://blog.csdn.net/qq_24689877/article/details/85143929

 

Guess you like

Origin blog.csdn.net/xiaoao20080/article/details/92061076