使用aop切面实现系统操作日志管理

使用aop切面实现系统操作日志管理

    一、思路:
        新增表SYS_OPERATE_LOG(表结构在下面),在需要的地方加上@MyLog(value = "**"),value为表字段OPERATION的值.
        表示发生了什么操作.比如:加@MyLog(value = "**")注解的地方就会进入切面SysLogAspect(代码如下),而这些操作具体的参数和时间,操作者,IP,都会被记录下来
        
        步骤如下:
            用到两个工具类:
                1.IpUtils  获取IP地址
                2.HttpContextUtils  获取HttpServletRequest对象

        1.SYS_OPERATE_LOG建表语句:
            -- sys日志操作表 
            CREATE TABLE SYS_OPERATE_LOG
            (
              KID       VARCHAR2(32) NOT NULL,
              USER_NAME VARCHAR2(32),
              OPERATION VARCHAR2(32),
              METHOD    VARCHAR2(1024),
              PARAMS    VARCHAR2(1024),
              IP        VARCHAR2(32),
              CREATE_TIME           TIMESTAMP   
            );
            alter table SYS_OPERATE_LOG
            add constraint PK_SYS_OPERATE_LOG primary key (KID);

            comment on table SYS_OPERATE_LOG
              is 'sys日志操作表';
            comment on column SYS_OPERATE_LOG.KID
              is '主键';
            comment on column SYS_OPERATE_LOG.USER_NAME
              is '操作员姓名';
            comment on column SYS_OPERATE_LOG.OPERATION
              is '操作如( 新增操作员)';
            comment on column SYS_OPERATE_LOG.METHOD
              is '操作的方法com.test.****';
            comment on column SYS_OPERATE_LOG.PARAMS
              is '操作的参数';
            comment on column SYS_OPERATE_LOG.IP
              is 'ip地址';
            comment on column SYS_OPERATE_LOG.CREATE_TIME   
              is '操作时间';

        
        2.自定义注解@MyLog

            

            import java.lang.annotation.*;

            /**
             * 自定义注解类
             */
            @Target(ElementType.METHOD) //注解放置的目标位置,METHOD是可注解在方法级别上
            @Retention(RetentionPolicy.RUNTIME) //注解在哪个阶段执行
            @Documented //生成文档
            public @interface MyLog {

                String value() default "";
            }

        3.SysLogAspect切面
            package ****.common.base;

            import com.alibaba.fastjson.JSON;
            import ****.common.util.HttpContextUtils;
            import ****.common.util.IpUtils;
            import ****.constant.UUIDGenerator;
            import ****.dao.pojo.SysLog;
            import ****.service.operate.ISysLogService;
            import org.aspectj.lang.JoinPoint;
            import org.aspectj.lang.annotation.AfterReturning;
            import org.aspectj.lang.annotation.Aspect;
            import org.aspectj.lang.annotation.Pointcut;
            import org.aspectj.lang.reflect.MethodSignature;
            import org.springframework.beans.factory.annotation.Autowired;
            import org.springframework.security.core.context.SecurityContext;
            import org.springframework.security.core.userdetails.UserDetails;
            import org.springframework.stereotype.Component;

            import javax.servlet.http.HttpServletRequest;
            import java.lang.reflect.Method;
            import java.util.ArrayList;
            import java.util.Arrays;
            import java.util.List;

            /**
             * 系统日志:切面处理类
             *
             */
            @Aspect
            @Component
            public class SysLogAspect {

                @Autowired
                private ISysLogService sysLogService;

                //定义切点 @Pointcut
                //在注解的位置切入代码
                @Pointcut("@annotation( ****.common.base.MyLog)")
                public void logPoinCut() {
                }

                //切面 配置通知
                @AfterReturning("logPoinCut()")
                public void saveSysLog(JoinPoint joinPoint) {
                    //保存日志
                    SysLog sysLog = new SysLog();
                    //从切面织入点处通过反射机制获取织入点处的方法
                    MethodSignature signature = (MethodSignature) joinPoint.getSignature();
                    //获取切入点所在的方法
                    Method method = signature.getMethod();
                    sysLog.setKid(UUIDGenerator.idGenerator());
                    //获取操作
                    MyLog myLog = method.getAnnotation(MyLog.class);
                    if (myLog != null) {
                        String value = myLog.value();
                        sysLog.setOperation(value);//保存获取的操作
                    }

                    //获取请求的类名
                    String className = joinPoint.getTarget().getClass().getName();
                    //获取请求的方法名
                    String methodName = method.getName();
                    sysLog.setMethod(className + "." + methodName);

                    //请求的参数
                    Object[] args = joinPoint.getArgs();
                    List argsList = Arrays.asList(args);
                    List argsList2 = new ArrayList<>();

                    //去除Authentication对象,或者不需要的参数,比如HttpServletRequest,这些对象的太大,存下来没什么卵用
                    //注意:要注意的是Authentication这个对象是单例的,因此在操作这个对象时会报反射错误.通过joinPoint拿到的对象实际上是克隆出来的
                    //并不是在上下文中的那个Authentication,所以无法转换.
                    //解决方法:新建一个argsList2将不要的对象排除掉
                    for (Object param:argsList) {
                       if(!param.getClass().getName().contains("Authentication")){
                           argsList2.add(param);
                       }
                    }
                    //将参数所在的数组转换成json
                    String params = JSON.toJSONString(argsList2);
                    sysLog.setParams(params);

                    //获取用户ip地址
                    HttpServletRequest request = HttpContextUtils.getHttpServletRequest();

                    //通过request获取用户名
                    SecurityContext securityContext = (SecurityContext) request.getSession().getAttribute("SPRING_SECURITY_CONTEXT");
                    UserDetails userDetails = (UserDetails) securityContext.getAuthentication().getPrincipal();
                    sysLog.setUserName(userDetails.getUsername());

                    sysLog.setIp(IpUtils.getIpAddr(request));

                    //调用service保存SysLog实体类到数据库
                    sysLogService.save(sysLog);
                }
            }

        4. IpUtils和HttpContextUtils
            (1).IpUtils
                package ****.common.util;

                import javax.servlet.http.HttpServletRequest;
                import java.io.IOException;
                import java.io.InputStreamReader;
                import java.io.LineNumberReader;
                import java.net.InetAddress;
                import java.net.UnknownHostException;

                public class IpUtils {
                    private IpUtils() {
                    }

                    /**
                     * 获取当前网络ip
                     * @param request
                     * @return
                     */
                    public static String getIpAddr(HttpServletRequest request){
                        String ipAddress = request.getHeader("x-forwarded-for");
                        if(ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
                            ipAddress = request.getHeader("Proxy-Client-IP");
                        }
                        if(ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
                            ipAddress = request.getHeader("WL-Proxy-Client-IP");
                        }
                        if(ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
                            ipAddress = request.getRemoteAddr();
                            if(ipAddress.equals("127.0.0.1") || ipAddress.equals("0:0:0:0:0:0:0:1")){
                                //根据网卡取本机配置的IP
                                InetAddress inet=null;
                                try {
                                    inet = InetAddress.getLocalHost();
                                } catch (UnknownHostException e) {
                                    e.printStackTrace();
                                }
                                ipAddress= inet.getHostAddress();
                            }
                        }
                        //对于通过多个代理的情况,第一个IP为客户端真实IP,多个IP按照','分割
                        if(ipAddress!=null && ipAddress.length()>15){ //"***.***.***.***".length() = 15
                            if(ipAddress.indexOf(",")>0){
                                ipAddress = ipAddress.substring(0,ipAddress.indexOf(","));
                            }
                        }
                        return ipAddress;
                    }

                    /**
                     * 获得MAC地址
                     * @param ip
                     * @return
                     */
                    public static String getMACAddress(String ip){
                        String str = "";
                        String macAddress = "";
                        try {
                            Process p = Runtime.getRuntime().exec("nbtstat -A " + ip);
                            InputStreamReader ir = new InputStreamReader(p.getInputStream());
                            LineNumberReader input = new LineNumberReader(ir);
                            for (int i = 1; i < 100; i++) {
                                str = input.readLine();
                                if (str != null) {
                                    if (str.indexOf("MAC Address") > 1) {
                                        macAddress = str.substring(str.indexOf("MAC Address") + 14, str.length());
                                        break;
                                    }
                                }
                            }
                        } catch (IOException e) {
                            e.printStackTrace(System.out);
                        }
                        return macAddress;
                    }
                }
            (2).HttpContextUtils
                package ****.common.util;

                import org.springframework.web.context.request.RequestContextHolder;
                import org.springframework.web.context.request.ServletRequestAttributes;

                import javax.servlet.http.HttpServletRequest;

                public class HttpContextUtils {
                    public static HttpServletRequest getHttpServletRequest() {
                        return ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
                    }
                }

你可能感兴趣的:(aop,系统操作日志)