javaWEB SSM AOP+注解保存操作日志

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了javaWEB SSM AOP+注解保存操作日志相关的知识,希望对你有一定的参考价值。

本篇文章的诞生离不开这篇文章的作者:http://blog.csdn.net/czmchen/article/details/42392985。

前言

操作日志在javaWeb的业务系统中是在是太常见的功能了,主要记录用户再什么时间,什么位置进行了什么操作。如果每新增一个功能都要写一个插入代码的话,是非常不容易维护的。加一个字段就要在每个插入语句上加入这个字段。所以AOP+注解的优势就显现了出来,不仅如此,当我们有了这套代码以后,可以通用在该系统的wap端或者其他的系统中,不必修改太多的代码。针对日志这种实时性不是很高的功能,这里用了异步的方式进行,这样日志系统独立出来,不会影响业务。下面是我整理的代码,欢迎留下宝贵意见。这里再次感谢原作者提供良好的思路。


代码

一、核心类

1.自定义注解 拦截Controller  

/**
 * 
 * 自定义注解 拦截Controller  
 * @see  [相关类/方法]
 * @since  [产品/模块版本]
 */
@Target({ElementType.PARAMETER, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface SystemControllerLog
{
    String description() default "";//描述
    
    String moduleType() default "";//模块代码
    
    String operateValue() default "";//操作类型
    
    boolean firstParamName() default false;
}

2.自定义注解 拦截service 

/**
 *  
 * 自定义注解 拦截service 
 * @see  [相关类/方法]
 * @since  [产品/模块版本]
 */
@Target({ElementType.PARAMETER, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface SystemServiceLog
{
    String description() default "";// 描述
    
    String moduleType() default "";// 模块代码
    
    String operateValue() default "";// 操作类型
}

3.AOP可以拦截到controller的配置

spring.xml中加入下面这句话

<aop:aspectj-autoproxy proxy-target-class="true" />

4.切点类

这里用的是返回通知,用来接收成功或失败。

/**
 * 
 * AOP记录操作&异常日志-切点类
 * @see [相关类/方法]
 * @since [产品/模块版本]
 */
@Aspect
@Component
public class SystemLogAspect
{
    
    private static final Logger logger = LoggerFactory.getLogger(SystemLogAspect.class);
    
    // 队列
    private static BlockingQueue<Log> queue = new LinkedBlockingQueue<Log>();
    
    // 缓存线程池
    private static ExecutorService threadPool = Executors.newFixedThreadPool(3);
    
    // 任务数
    private static int taskSize = 6;
    
    // 线程是否已启动
    boolean isStartThread = false;
    
    // 用来启动或停止线程
    static boolean run = true;
    
    @Autowired
    private LogService logService;
    
    @Autowired
    private UserService userService;
    
    // Service层切点
    @Pointcut("@annotation(com.rzzl.wap.log.annotation.SystemServiceLog)")
    public void serviceAspect()
    {
    }
    
    // Controller层切点
    @Pointcut("@annotation(com.rzzl.wap.log.annotation.SystemControllerLog)")
    public void controllerAspect()
    {
    }
    
    public static BlockingQueue<Log> getQueue()
    {
        return queue;
    }

    public static void setQueue(BlockingQueue<Log> queue)
    {
        SystemLogAspect.queue = queue;
    }

    public static boolean isRun()
    {
        return run;
    }

    public static void setRun(boolean run)
    {
        SystemLogAspect.run = run;
    }

    /**
     * 
     * 返回通知 用于拦截Controller层记录用户的操作
     * @param joinPoint 切点
     * @param result 返回值
     * @see [类、类#方法、类#成员]
     */
    @AfterReturning(value = "controllerAspect()", returning = "result")
    public void afterReturn(JoinPoint joinPoint, Object result)
    {
        // 请求的IP
        User user = WebUtils.getSessionValue(LoginContact.SESSION_USER);
        String params = "";
        WebResult webResult = new WebResult();
        webResult.setCode(FlagContact.BACK_SUCCESS);
        try
        {
            if (WebResult.class.isInstance(result))
            {
                webResult = (WebResult)result;
            }
            
            String loginName = "";
            InnnerBean innnerBean = getControllerMethodDescription(joinPoint);
            Object[] arguments = innnerBean.getArguments();
            String remark = innnerBean.getDescription();
            
            Log log = new Log.Builder().type(LogTypes.type.operate)
                .moduleType(innnerBean.getModuleType())
                .operateCode(joinPoint.getSignature().getName())
                .operateValue(innnerBean.getOperateValue())
                .remark(remark)
                .operateStatus(webResult.getCode().equals(FlagContact.BACK_SUCCESS) ? LogTypes.operateStatus.Y
                    : LogTypes.operateStatus.N)// 返回值1操作成功,否则失败
                .method((joinPoint.getTarget().getClass().getName() + "." + joinPoint.getSignature().getName() + "()"))
                .param(params)
                .loginName(user.getAccountNo())
                .fullName(user.getUserName())
                .build();
            // 放入队列
            queue.put(log);
            if (!isStartThread)
            {
                for (int i = 0; i < taskSize; i++)
                {
                    threadPool.execute(new saveLogThread());
                }
                isStartThread = true;
            }
        }
        catch (Exception e)
        {
            logger.error("异常信息:{}", e.toString());
        }
    }
    
    /**
     * 异常通知 用于拦截service层记录异常日志
     * @param joinPoint
     * @param e
     * @see [类、类#方法、类#成员]
     */
    @AfterThrowing(pointcut = "serviceAspect()", throwing = "e")
    public void doAfterThrowing(JoinPoint joinPoint, Throwable e)
    {
        // 读取session中的用户
        User user = WebUtils.getSessionValue(LoginContact.SESSION_USER);
        String params = "";
        
        try
        {
            if (joinPoint.getArgs() != null && joinPoint.getArgs().length > 0)
            {
                for (int i = 0; i < joinPoint.getArgs().length; i++)
                {
                    params += JSONUtils.valueToString(joinPoint.getArgs()[i].toString()) + ";";
                }
            }
            
            InnnerBean innnerBean = getServiceMthodDescription(joinPoint);
            String loginName = "";
            
            Log log =
                new Log.Builder().type(LogTypes.type.exception)
                    .moduleType(innnerBean.getModuleType())
                    .operateCode(joinPoint.getSignature().getName())
                    .operateValue(innnerBean.getOperateValue())
                    .remark(innnerBean.getDescription())
                    .operateStatus(LogTypes.operateStatus.N)
                    .method(
                        (joinPoint.getTarget().getClass().getName() + "." + joinPoint.getSignature().getName() + "()"))
                    .param(params)
                    .exceptionDetail(e.toString())
                    .build();
            // 放入队列
            queue.put(log);
            if (!isStartThread)
            {
                new Thread(new saveLogThread()).start();
                isStartThread = true;
            }
        }
        catch (Exception ex)
        {
            logger.error("异常信息:{}", ex.toString());
        }
        finally
        {
            logger.error("异常方法:{" + joinPoint.getTarget().getClass().getName() + "}异常代码:{"
                + joinPoint.getSignature().getName() + "}异常信息:{" + e.toString() + "}参数:{" + params + "}");
        }
        
    }
    
    /**
     * 获取注解中对方法的描述信息 用于service层注解
     * @param joinPoint 切点
     * @return 方法描述
     * @throws Exception
     * @see [类、类#方法、类#成员]
     */
    @SuppressWarnings("rawtypes")
    public static InnnerBean getServiceMthodDescription(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 moduleType = "";
        String operateValue = "";
        String description = "";
        InnnerBean innnerBean = new InnnerBean(moduleType, operateValue, description);
        for (Method method : methods)
        {
            if (method.getName().equals(methodName))
            {
                Class[] clazzs = method.getParameterTypes();
                if (clazzs.length == arguments.length)
                {
                    SystemServiceLog annotation = method.getAnnotation(SystemServiceLog.class);
                    moduleType = annotation.moduleType();
                    operateValue = annotation.operateValue();
                    description = annotation.description();
                    innnerBean = new InnnerBean(moduleType, operateValue, description);
                    break;
                }
            }
        }
        innnerBean.setArguments(arguments);
        return innnerBean;
    }
    
    /**
     * 获取注解中对方法的描述信息 用于Controller层注解
     * @param joinPoint 切点
     * @return 方法描述
     * @throws Exception
     * @see [类、类#方法、类#成员]
     */
    @SuppressWarnings("rawtypes")
    public static InnnerBean 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 moduleType = "";
        String operateValue = "";
        String description = "";
        boolean firstParamName = false;
        InnnerBean innnerBean = new InnnerBean(moduleType, operateValue, description);
        for (Method method : methods)
        {
            if (method.getName().equals(methodName))
            {
                Class[] clazzs = method.getParameterTypes();
                if (clazzs.length == arguments.length)
                {
                    SystemControllerLog annotation = method.getAnnotation(SystemControllerLog.class);
                    moduleType = annotation.moduleType();
                    operateValue = annotation.operateValue();
                    description = annotation.description();
                    firstParamName = annotation.firstParamName();
                    innnerBean = new InnnerBean(moduleType, operateValue, description);
                    innnerBean.setFirstParamName(firstParamName);
                    break;
                }
            }
        }
        innnerBean.setArguments(arguments);
        return innnerBean;
    }
    
    /**
     * 
     * 内部类封装注入信息
     * @see [相关类/方法]
     * @since [产品/模块版本]
     */
    static class InnnerBean
    {
        private String moduleType;// 模块代码
        
        private String description;// 描述
        
        private String operateValue;// 操作类型
        
        private boolean firstParamName;
        
        private Object[] arguments;
        
        public InnnerBean(String moduleType, String operateValue, String description)
        {
            super();
            this.moduleType = moduleType;
            this.description = description;
            this.operateValue = operateValue;
        }
        
        public String getOperateValue()
        {
            return operateValue;
        }
        
        public void setOperateValue(String operateValue)
        {
            this.operateValue = operateValue;
        }
        
        public String getModuleType()
        {
            return moduleType;
        }
        
        public void setModuleType(String moduleType)
        {
            this.moduleType = moduleType;
        }
        
        public String getDescription()
        {
            return description;
        }
        
        public void setDescription(String description)
        {
            this.description = description;
        }
        
        public Object[] getArguments()
        {
            return arguments;
        }
        
        public void setArguments(Object[] arguments)
        {
            this.arguments = arguments;
        }
        
        public boolean isFirstParamName()
        {
            return firstParamName;
        }
        
        public void setFirstParamName(boolean firstParamName)
        {
            this.firstParamName = firstParamName;
        }
    }
    
    /**
     * 
     * 异步保存日志
     * @see [相关类/方法]
     * @since [产品/模块版本]
     */
    class saveLogThread implements Runnable
    {
        Lock lock = new ReentrantLock();
        
        @Override
        public void run()
        {
            try
            {
                while (run)
                {
                    while (queue.size() != 0)
                    {
                        // 如果对插入顺序无要求,此处不需要同步可提升效率
                        lock.lock();
                        Log log = queue.take();
                        logService.insert(log);
                        lock.unlock();
                    }
                    Thread.sleep(3000);
                }
            }
            catch (InterruptedException e)
            {
                logger.error("saveLogThread被唤醒:" + e.toString());
            }
            catch (Exception e)
            {
                logger.error("saveLogThread异常:" + e.toString());
            }
        }
    }
}

二、定值类

日志系统中的定值

/**
 * 
 * 日志系统中的定值
 * 
 * @see [相关类/方法]
 * @since [产品/模块版本]
 */
public interface LogTypes
{
    
    /**
     * 
     * 操作状态(成功与否Y\N)
     * @see [相关类/方法]
     * @since [产品/模块版本]
     */
    static interface operateStatus
    {
        // 成功
        final String Y = "Y";
        
        // 失败
        final String N = "N";
    }
    
    /**
     * 
     * 日志类型
     * @see [相关类/方法]
     * @since [产品/模块版本]
     */
    static interface type
    {
        // 操作日志
        final String operate = "operate";
        
        // 异常日志
        final String exception = "exception";
    }
    
    /**
     * 
     * 模块类型
     * @see [相关类/方法]
     * @since [产品/模块版本]
     */
    static interface moduleType
    {
        // 登录模块
        final String LOGIN = "LOGIN";
        
        // 项目模块
        final String PROJECT = "PROJECT";
        
        // 客户模块
        final String CUSTOMER = "CUSTOMER";
        
        // 用户模块
        final String SYS_USER = "SYS_USER";
    }
    
    /**
     * 
     * 操作类型
     * @see [相关类/方法]
     * @since [产品/模块版本]
     */
    static interface operateValue
    {
        // 查询
        final String select = "select";
        
        // 登录
        final String login = "login";
        
        // 保存
        final String save = "save";
        
        // 新增
        final String add = "add";
        
        // 修改
        final String edit = "edit";
        
        // 删除
        final String delete = "delete";
        
        // 查看
        final String view = "view";
        
        // 修改密码
        final String editPassword = "editPassword";
        
        // 上传
        final String upload = "upload";
        
        // 下载
        final String down = "down";
        
        // 下载
        final String packagedown = "packagedown";
        
    }
    
    /**
     * 
     * 保存描述的前缀
     *          方便于批量修改该备注
     * @see [相关类/方法]
     * @since [产品/模块版本]
     */
    static interface Prefix
    {
        // 查询
        final String savePrefix = "新增/编辑";
        
    }
}

三、实体类

1、日志实体


应用了Builder设计模式

/**
 * 
 * 操作日志&异常日志
 * @see [相关类/方法]
 * @since [产品/模块版本]
 */
public class Log implements Serializable
{
    
    /**
     * serialVersionUID
     */
    private static final long serialVersionUID = 1L;
    
    private static final String reqSource;// 请求来源,pc:pc端,wap:wap端 默认来源为pc
    
    private static final String localAddr;// 服务器IP
    
    private String ip;// 操作电脑ip
    
    private String fullName;// 操作人员名字
    
    private String loginName;// 操作人员登录账号
    
    private Date operateDateTime;// 操作时间
    
    private Date createDateTime;// 创建时间
    
    private Long id;
    
    private String type;// 日志类型,‘operate’:操作日志,‘exception’:异常日志
    
    private String moduleType;// 模块代码
    
    private String operateCode;// 操作代码
    
    private String operateValue;// 操作类型
    
    private String remark;// 操作备注(记录参数)
    
    private String operateStatus;// 操作状态(成功与否Y\N)
    
    private String method;// 调用方法
    
    private String param;// 方法的请求参数
    
    private String exceptionDetail;// 异常信息
    
    static{
        reqSource = "wap";
        localAddr = WebUtils.getLocalAddr();
    }
    
    public void init()
    {
        User user = WebUtils.getSessionValue(LoginContact.SESSION_USER);
        ip = WebUtils.getRemoteIP();
        loginName = user != null ? user.getAccountNo() : getLoginName();
        fullName = user != null ? user.getUserName() : getFullName();
        operateDateTime = new Date();
        createDateTime = new Date();
    }
    
    public Log()
    {
        init();
    }
    
    public Log(Log origin)
    {
        init();
        this.id = origin.id;
        this.type = origin.type;
        this.moduleType = origin.moduleType;
        this.operateCode = origin.operateCode;
        this.operateValue = origin.operateValue;
        this.remark = origin.remark;
        this.operateStatus = origin.operateStatus;
        this.method = origin.method;
        this.param = origin.param;
        this.exceptionDetail = origin.exceptionDetail;
        this.fullName = origin.fullName;
        this.loginName = origin.loginName;
    }
    
    public String getIp()
    {
        return ip;
    }

    public void setIp(String ip)
    {
        this.ip = ip;
    }

    public String getFullName()
    {
        return fullName;
    }

    public void setFullName(String fullName)
    {
        this.fullName = fullName;
    }

    public String getLoginName()
    {
        return loginName;
    }

    public void setLoginName(String loginName)
    {
        this.loginName = loginName;
    }

    public Date getOperateDateTime()
    {
        return operateDateTime;
    }

    public void setOperateDateTime(Date operateDateTime)
    {
        this.operateDateTime = operateDateTime;
    }

    public Date getCreateDateTime()
    {
        return createDateTime;
    }

    public void setCreateDateTime(Date createDateTime)
    {
        this.createDateTime = createDateTime;
    }

    public Long getId()
    {
        return id;
    }

    public void setId(Long id)
    {
        this.id = id;
    }

    public String getType()
    {
        return type;
    }

    public void setType(String type)
    {
        this.type = type;
    }

    public String getModuleType()
    {
        return moduleType;
    }

    public void setModuleType(String moduleType)
    {
        this.moduleType = moduleType;
    }

    public String getOperateCode()
    {
        return operateCode;
    }

    public void setOperateCode(String operateCode)
    {
        this.operateCode = operateCode;
    }

    public String getOperateValue()
    {
        return operateValue;
    }

    public void setOperateValue(String operateValue)
    {
        this.operateValue = operateValue;
    }

    public String getRemark()
    {
        return remark;
    }

    public void setRemark(String remark)
    {
        this.remark = remark;
    }

    public String getOperateStatus()
    {
        return operateStatus;
    }

    public void setOperateStatus(String operateStatus)
    {
        this.operateStatus = operateStatus;
    }

    public String getMethod()
    {
        return method;
    }

    public void setMethod(String method)
    {
        this.method = method;
    }

    public String getParam()
    {
        return param;
    }

    public void setParam(String param)
    {
        this.param = param;
    }

    public String getExceptionDetail()
    {
        return exceptionDetail;
    }

    public void setExceptionDetail(String exceptionDetail)
    {
        this.exceptionDetail = exceptionDetail;
    }

    public String getLocalAddr()
    {
        return localAddr;
    }
    
    public static class Builder
    {
        
        private Log target;
        
        public Builder()
        {
            target = new Log();
        }
        
        public Builder id(Long id)
        {
            target.id = id;
            return this;
        }
        
        public Builder type(String type)
        {
            target.type = type;
            return this;
        }
        
        public Builder moduleType(String moduleType)
        {
            target.moduleType = moduleType;
            return this;
        }
        
        public Builder operateCode(String operateCode)
        {
            target.operateCode = operateCode;
            return this;
        }
        
        public Builder operateValue(String operateValue)
        {
            target.operateValue = operateValue;
            return this;
        }
        
        public Builder remark(String remark)
        {
            target.remark = remark;
            return this;
        }
        
        public Builder operateStatus(String operateStatus)
        {
            target.operateStatus = operateStatus;
            return this;
        }
        
        public Builder method(String method)
        {
            target.method = method;
            return this;
        }
        
        public Builder param(String param)
        {
            target.param = param;
            return this;
        }
        
        public Builder exceptionDetail(String exceptionDetail)
        {
            target.exceptionDetail = exceptionDetail;
            return this;
        }
        
        public Builder loginName(String loginName)
        {
            target.loginName = loginName;
            return this;
        }
        
        public Builder fullName(String fullName)
        {
            target.fullName = fullName;
            return this;
        }
        
        public Log build()
        {
            return new Log(target);
        }
        
    }
}

2.返回结果实体

/**
 * @ClassName: WebResult
 * @version 1.0
 * @Desc: WEB返回JSON结果
 * @history v1.0
 */
public class WebResult implements Serializable
{
    private static final long serialVersionUID = -4776437900752507269L;

    /**
     * 返回消息
     */
    private String msg;

    /**
     * 返回码
     */
    private String code;

    /**
     * 返回数据
     */
    private Object data;
    
    private Map<?,?> map;
    
    private List<Map<String, Object>> list;

    public WebResult()
    {
    }

    public WebResult(String msg, String code)
    {
        super();
        this.msg = msg;
        this.code = code;
    }

    public WebResult(String msg, String code, Object data)
    {
        super();
        this.msg = msg;
        this.code = code;
        this.data = data;
    }

    public String getMsg()
    {
        return msg;
    }

    public void setMsg(String msg)
    {
        this.msg = msg;
    }

    public String getCode()
    {
        return code;
    }

    public void setCode(String code)
    {
        this.code = code;
    }

    public Object getData()
    {
        return data;
    }

    public void setData(Object data)
    {
        this.data = data;
    }
    
    public Map<?, ?> getMap()
    {
        return map;
    }

    public void setMap(Map<?, ?> map)
    {
        this.map = map;
    }

    public List<Map<String, Object>> getList()
    {
        return list;
    }

    public void setList(List<Map<String, Object>> list)
    {
        this.list = list;
    }

    @Override
    public String toString()
    {
        return "WebResult [msg=" + msg + ", code=" + code + ", data=" + data + "]";
    }
    
    /**
     * 初始失败方法
     *
     * @author cc HSSD0473
     * @see [类、类#方法、类#成员]
     */
    public void invokeFail(){
    	this.data = null;
    	this.code = FlagContact.BACK_FAIL;
    	this.msg = "操作失败";
    }
    
    public void invokeFail(String msg){
    	this.data = null;
    	this.code = FlagContact.BACK_FAIL;
    	if(msg != null && !msg.equals(""))
    	{
    		this.msg = msg;
    	}
    }
    
    public void invokeSuccess()
    {
    	this.code = FlagContact.BACK_SUCCESS;
    	this.msg = "操作成功";
    }
    
    public void invokeSuccess(String msg)
    {
    	if(msg != null && !msg.equals(""))
    	{
    		this.msg = msg;
    	}
    	this.code = FlagContact.BACK_SUCCESS;
    }
}

三、工具类

获取登录用户,客户ip主机ip等方法

**
 * @ClassName: WebUtils
 * @version 1.0
 * @Desc: WebUtils
 * @history v1.0
 */
public class WebUtils
{
    /**
     * 描述:获取request对象
     * @return
     */
    public static HttpServletRequest getRequest()
    {
        return ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
    }

    /**
     * 描述:获取responce对象
     * @return
     */
    public static HttpServletResponse getResponse()
    {
        return ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getResponse();
    
    }

    /**
     * 描述:获取session
     * @return
     */
    public static HttpSession getSession()
    {
        return getRequest().getSession();
    }

    /**
     * 描述:设置session值
     * @param key
     * @param val
     */
    public static <T> void setSessionValue(String key, T val)
    {
        getSession().setAttribute(key, val);
    }

    /**
     * 描述:获取session值
     * @param key
     * @return
     */
    @SuppressWarnings("unchecked")
    public static <T> T getSessionValue(String key)
    {
        return (T) getSession().getAttribute(key);
    }

    /**
     * 描述:移除session
     * @param key
     * @return
     */
    @SuppressWarnings("unchecked")
    public static <T> T removeSessionValue(String key)
    {
        Object obj = getSession().getAttribute(key);
        getSession().removeAttribute(key);
        return (T) obj;
    }

    /**
     * 描述:获取客户端ip
     * @param request
     * @return
     */
    public static String getRemoteIP(HttpServletRequest request)
    {
        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.getRemoteAddr();
        }
        return ip.equals("0:0:0:0:0:0:0:1") ? "127.0.0.1" : ip;
    }
    
    /**
     * 
     * 获得本机IP
     * @return
     * @throws Exception
     * @see [类、类#方法、类#成员]
     */
    public final static String getLocalAddr()
    {
        String hostAddress = "";
        try
        {
            hostAddress = InetAddress.getLocalHost().getHostAddress();
        }
        catch (Exception e)
        {
        }
        return hostAddress;
    }

    /**
     * 描述:获取客户端ip
     * @return
     */
    public static String getRemoteIP()
    {
        HttpServletRequest request = getRequest();
        return getRemoteIP(request);
    }
}

四、清理工作

tomcat停止前,异步日志的清理动作

/**
 * 
 * tomcat停止前,异步日志的清理动作
 * @see  [相关类/方法]
 * @since  [产品/模块版本]
 */
@WebListener()
public class BeforeDestoryListener implements ServletContextListener
{
    
    @Override
    public void contextInitialized(ServletContextEvent sce)
    {
    }
    
    @Override
    public void contextDestroyed(ServletContextEvent sce)
    {
        while (SystemLogAspect.getQueue().size() == 0)
        {
            SystemLogAspect.setRun(false);
            break;
        }
    }

}


数据库

用的是mysql,其他数据库请自行更改语句

CREATE TABLE `t_log` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `reqSource` varchar(10) DEFAULT 'pc' COMMENT '请求来源,pc:pc端,wap:wap端 默认来源为pc',
  `type` varchar(10) DEFAULT NULL COMMENT '日志类型,‘operate’:操作日志,‘exception’:异常日志',
  `ip` varchar(20) NOT NULL COMMENT '操作电脑ip',
  `fullName` varchar(50) NOT NULL COMMENT '操作人员名字',
  `loginName` varchar(50) NOT NULL COMMENT '操作人员登录账号',
  `moduleType` varchar(50) NOT NULL COMMENT '模块代码',
  `operateCode` varchar(50) NOT NULL COMMENT '操作代码',
  `operateValue` varchar(50) DEFAULT NULL COMMENT '操作类型',
  `operateDateTime` datetime NOT NULL COMMENT '操作时间',
  `createDateTime` datetime NOT NULL COMMENT '创建时间',
  `remark` varchar(100) DEFAULT NULL COMMENT '操作备注(记录参数)',
  `operateStatus` varchar(20) DEFAULT NULL COMMENT '操作状态(成功与否Y\N)',
  `localAddr` varchar(20) DEFAULT NULL COMMENT '服务器IP',
  `method` varchar(100) DEFAULT NULL COMMENT '调用方法',
  `param` varchar(2000) DEFAULT NULL COMMENT '方法的请求参数',
  `exceptionDetail` varchar(1000) DEFAULT NULL COMMENT '异常信息',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3430 DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC;


测试及结果

控制层代码

/**
	 * 登录请求
	 *
	 * @param userName	用户名
	 * @param password	密码
	 * @return WebResult msg:系统反馈消息 code:登录标识码
	 * @see [类、类#方法、类#成员]
	 */
	@ResponseBody
	@RequestMapping("login")
	@SystemControllerLog(moduleType=LogTypes.moduleType.LOGIN,operateValue=LogTypes.operateValue.login,description = "登录动作")
	public WebResult userLogin(String accoutnNo, String password) {
		WebResult wt = new WebResult();
		try
		{
			// 登录逻辑
            
		}
		catch(Exception e)
		{
			log.error("登录异常:" + e.toString());
			wt.invokeFail();
		}
		
		return wt;
	}

数据库结果

技术分享图片







以上是关于javaWEB SSM AOP+注解保存操作日志的主要内容,如果未能解决你的问题,请参考以下文章

Sping Aop日志实现--使用Mybatis注解保存日志

JPOM - AOP+自定义注解实现操作日志记录

(面试总结)SSM 整合案例:AOP 日志

JPOM - AOP+自定义注解实现操作日志记录

ssm+redis整合(通过aop自定义注解方式)

javaweb基于ssm框架快递代拿管理系统设计与实现(项目源码)