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

数据库结果

原文地址:http://blog.51cto.com/13670038/2128210

时间: 2024-11-05 22:37:07

javaWEB SSM AOP+注解保存操作日志的相关文章

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

需求:系统中经常需要记录员工的操作日志和用户的活动日志,简单的做法在每个需要的方法中进行日志保存操作, 但这样对业务代码入侵性太大,下面就结合AOP和自定义日志注解实现更方便的日志记录 首先看下一个简单的操作日志表 action_log id subject(日志主题) content(日志内容) create_by create_time 日志主题可以用下面的枚举类来实现 package cn.bounter.common.model; /** * 应用日志主题枚举类 * @author si

spring-boot aop 增删改操作日志 实现

1.注解接口:import com.github.wxiaoqi.security.common.constant.Constants; import java.lang.annotation.*; /** * 日志注解 */@Target(ElementType.METHOD)@Retention(RetentionPolicy.RUNTIME)@Documentedpublic @interface SysLogOpt { String value(); String module() de

使用MVC过滤器保存操作日志

//定义过滤器 public class  LogAttribute : ActionFilterAttribute { /// <summary> /// 以逗号间隔 /// </summary> private readonly string _parameterNames; public BizActivityLogAttribute( string parameters) { _parameterNames = parameters; } public override v

OSharp3.0框架解说系列(6.2):操作日志与数据日志

前言 在<[开源]OSharp框架解说系列(6.1):日志系统设计>中,我们已经设计并实现了一个可扩展的日志系统,只要定义好输出端的Adapter,就可以以任意形式输出日志信息. 在日志开发中,有些日志记录需求是常规需要的,比如操作日志,数据变更日志,系统异常日志等,我们希望把这些常规需求都集成到OSharp框架当中.有了内置的支持,在做开发的时候,只需要很简单的配置,就可以实现相关需求. 关于三类日志,这里先简要描述一下: 操作日志:粗略描述系统用户(如管理员.业务人员.会员等)对系统的业务

spring AOP自定义注解方式实现日志管理

转:spring AOP自定义注解方式实现日志管理 今天继续实现AOP,到这里我个人认为是最灵活,可扩展的方式了,就拿日志管理来说,用Spring AOP 自定义注解形式实现日志管理.废话不多说,直接开始!!! 关于配置我还是的再说一遍. 在applicationContext-mvc.xml中要添加的 <mvc:annotation-driven />     <!-- 激活组件扫描功能,在包com.gcx及其子包下面自动扫描通过注解配置的组件 -->     <conte

Spring boot学习(六)Spring boot实现AOP记录操作日志

前言 在实际的项目中,特别是管理系统中,对于那些重要的操作我们通常都会记录操作日志.比如对数据库的CRUD操作,我们都会对每一次重要的操作进行记录,通常的做法是向数据库指定的日志表中插入一条记录.这里就产生了一个问题,难道要我们每次在 CRUD的时候都手动的插入日志记录吗?这肯定是不合适的,这样的操作无疑是加大了开发量,而且不易维护,所以实际项目中总是利用AOP(Aspect Oriented Programming)即面向切面编程这一技术来记录系统中的操作日志. 日志分类 这里我把日志按照面向

aop为系统添加操作日志,注入或配置声明的方式来实现

最近做项目实现操作记录添加日志,由于aop这两种实现方式各有优缺点,所以都实现了一下以后根据具体业务选择. 1实现方式一注入: 1.1首先在xml中开启aop注入,需要引入的包此处省略,可百度自己查找. <aop:aspectj-autoproxy /> 1.2添加链接点 package com.oasis.wyvern.res.service.base.logService; import java.lang.annotation.*; @Target({ElementType.PARAME

SSH基于Hibernate eventListener 事件侦听器的操作日志自动保存到数据库

在spring xml配置文件中添加配置,包含:model.listener 在model中增加需要写入数据库对应表的model 在auditLog.xml配置文件中配置自己项目中,需要进行日志记录的model类shortName,以及相关属性. 相关代码如下: 首先spring xml <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframew

Spring + Aop+注解 集成使用 Log4j,实现异常日志记录

A,首先说,如何配置: 1,在web.xml中添加代码: <!-- log4j的配置相关 --> <context-param> <param-name>log4jConfigLocation</param-name> <param-value>classpath:config/log4j/log4j.properties</param-value> </context-param> <context-param&g