1. 程式人生 > >javaWEB SSM AOP+註解保存操作日誌

javaWEB SSM AOP+註解保存操作日誌

java aop aop保存日誌 aop異步保存日誌 javaweb

本篇文章的誕生離不開這篇文章的作者: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+註解保存操作日誌