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

 

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java中可以通过自定义注解实现AOP,其中Spring Boot框架提供了一种简单的方式来创建自定义注解实现AOP。 首先,我们需要定义一个注解注解可以使用在类、方法或者字段上。我们可以使用元注解`@Target`来指定注解的使用位置,比如在方法上使用。然后,我们可以使用元注解`@Retention`来指定注解的生命周期,比如运行时生命周期。接着,我们可以使用元注解`@Documented`来指定注解是否会保存在JavaDoc文档中。最后,我们还可以使用元注解`@Inherited`来指定注解是否具有可继承性。 在实现AOP时,我们可以通过自定义注解和切面来实现一些增强功能,比如日志打印、方法耗时统计、多数据源切换等。我们可以在自定义注解上添加一些切面逻辑,然后在需要应用这些增强功能的地方使用这个注解。 具体实现过程如下: 1. 定义一个自定义注解,使用`@Target`指定注解的使用位置,使用`@Retention`指定注解的生命周期,使用`@Documented`指定是否保存在JavaDoc文档中,使用`@Inherited`指定是否具有可继承性。 2. 创建一个切面类,使用`@Aspect`注解标识该类为切面类,并在该类中定义一些增强功能的逻辑,比如在方法执行前后打印日志。 3. 在需要应用增强功能的地方,使用自定义注解来标识,例如在方法上添加自定义注解。 4. 在Spring Boot配置类中,通过`@EnableAspectJAutoProxy`注解开启AOP功能。 通过以上步骤,我们就可以在Java中使用自定义注解实现AOP了。这样,我们可以通过在需要应用增强功能的地方使用自定义注解来触发切面逻辑,从而实现AOP的效果。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [Java AOP自定义注解](https://blog.csdn.net/baidu_28340727/article/details/128319277)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值