1. 程式人生 > >【程式碼全】使用SpringAOP編寫日誌記錄(插入oracle資料庫中)

【程式碼全】使用SpringAOP編寫日誌記錄(插入oracle資料庫中)

程式碼較多,請耐心除錯


首先oracle資料庫表建立語句:

drop table cmu_system_log;

CREATE TABLE CMU_SYSTEM_LOG (
log_id INTEGER primary key ,
user_id INTEGER ,
username VARCHAR2(20)  ,
description VARCHAR2(50)  ,
methods VARCHAR2(500)  ,
log_type VARCHAR2(50) ,
request_ip INTEGER ,
exceptioncode VARCHAR2(255)  ,
exception_detail VARCHAR2(255)  ,
params VARCHAR2(255) ,
time DATE DEFAULT SYSDATE

);


需要在:Spring-mvc.xml中增加:

<!-- 最重要:如果放在spring-context.xml中,這裡的aop設定將不會生效,AOP日誌配置 -->
    <aop:aspectj-autoproxy proxy-target-class="true" />
    <bean id="systemLogAspect" class="com.security.annotation.SystemLogAspect"></bean>


pom.xml裡面需要匯入:

<dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjrt</artifactId>
            <version>1.8.10</version>
        </dependency>

<dependency>  
        <groupId>org.springframework</groupId>  
        <artifactId>spring-aop</artifactId>  
        <version>4.2.5.RELEASE</version>  
        </dependency>


編寫以下主要四個檔案:


SysLog.java

package com.security.annotation;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target({ ElementType.PARAMETER, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface SysLog {
    /** 要執行的操作型別比如:add操作 **/
    public String operationType() default "";

    /** 要執行的具體操作比如:新增使用者 **/
    public String operationName() default "";
}



SystemControllerLog.java

package com.security.annotation;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target({ ElementType.PARAMETER, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface SystemControllerLog {
    String description() default "";
}

最重要的檔案:SystemLogAspect.java

package com.security.annotation;

import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Date;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.subject.Subject;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import com.community.service.SystemLogService;
import com.community.util.IpUtil;
import com.oracle.pojo.SystemLog;
import com.oracle.pojo.Users;

@Aspect
@Component
public class SystemLogAspect {
    // 使用service注入功能把日誌寫進資料庫中
    @Resource
    private SystemLogService systemLogService;

    private static final Logger logger = LoggerFactory
            .getLogger(SystemLogAspect.class);

    // Conntroller層的切點
    @Pointcut("@annotation(com.security.annotation.SysLog)")
    public void controllerAspect() {
    }

    /**
     * 編寫後置通知,用於攔截Controller 層記錄使用者的操作
     *
     * joinPoint 切點
     */
    @After("controllerAspect()")
    public void after(JoinPoint joinPoint) {
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder
                .getRequestAttributes()).getRequest();
        Users user = (Users) SecurityUtils.getSubject().getPrincipal();
        String userName = null;
        String userId = null;
        if (user != null) {
            Subject currentUser = SecurityUtils.getSubject();
            userId = currentUser.getSession().getAttribute("_USER_ID")
                    .toString();
            userName = (String) user.getUsername();
        }
        // 請求的IP
        String ip = request.getRemoteAddr();
        try {
            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 operationType = "";
            String operationName = "";
            for (Method method : methods) {
                if (method.getName().equals(methodName)) {
                    Class[] clazzs = method.getParameterTypes();
                    if (clazzs.length == arguments.length) {
                        operationType = method.getAnnotation(SysLog.class)
                                .operationType();
                        operationName = method.getAnnotation(SysLog.class)
                                .operationName();
                        break;
                    }
                }
            }
            // 資料庫日誌
            SystemLog log = new SystemLog();
            log.setUserId(new Integer(userId));// 登入的使用者id
            log.setUsername(userName);// 這裡需要獲取使用者名稱
            log.setDescription(operationName);
            log.setMethods((joinPoint.getTarget().getClass().getName() + "."
                    + joinPoint.getSignature().getName() + "()"));
            log.setLogType(operationType);
            log.setRequestIp(IpUtil.ipToInt(ip));
            log.setExceptioncode(null);
            log.setExceptionDetail(null);
            log.setParams(null);
            log.setTime(new Date());
            // 儲存資料庫
            systemLogService.insertSelective(log);
            System.out.println("=====controller後置通知成功結束=====");
        } catch (Exception e) {
            // 記錄本地異常日誌
            logger.error("===後置通知異常===");
            logger.error("異常資訊:{}", e.getMessage());
        }
    }

    /**
     * 異常通知 用於攔截記錄異常日誌
     */
    @AfterThrowing(pointcut = "controllerAspect()", throwing = "e")
    public void doAfterThrowing(JoinPoint joinPoint, Throwable e) {
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder
                .getRequestAttributes()).getRequest();
        Users user = (Users) SecurityUtils.getSubject().getPrincipal();
        String userName = null;
        String userId = null;
        if (user != null) {
            Subject currentUser = SecurityUtils.getSubject();
            userId = currentUser.getSession().getAttribute("_USER_ID")
                    .toString();
            userName = (String) user.getUsername();
        }
        // 請求的IP
        String ip = request.getRemoteAddr();
        String params = "";
        if (joinPoint.getArgs() != null && joinPoint.getArgs().length > 0) {

            params = Arrays.toString(joinPoint.getArgs());
        }
        try {
            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 operationType = "error";
            String operationName = "";
            for (Method method : methods) {
                if (method.getName().equals(methodName)) {
                    Class[] clazzs = method.getParameterTypes();
                    if (clazzs.length == arguments.length) {
                        operationType = method.getAnnotation(SysLog.class)
                                .operationType();
                        operationName = method.getAnnotation(SysLog.class)
                                .operationName();
                        break;
                    }
                }
            }
            // ====資料庫日誌=====
            SystemLog log = new SystemLog();
            log.setUserId(new Integer(userId));// 登入的使用者id
            log.setUsername(userName);// 這裡需要獲取使用者名稱
            log.setDescription(operationName);
            log.setMethods((joinPoint.getTarget().getClass().getName() + "."
                    + joinPoint.getSignature().getName() + "()")
                    + "." + operationType);
            log.setLogType(operationType);
            log.setRequestIp(IpUtil.ipToInt(ip));
            log.setExceptioncode(null);
            log.setExceptionDetail(null);
            log.setParams(null);
            log.setTime(new Date());
            // 儲存資料庫
            systemLogService.insertSelective(log);
            System.out.println("=====異常通知結束=====");
        } catch (Exception ex) {
            // 記錄本地異常日誌
            logger.error("==異常通知異常==");
            logger.error("異常資訊:{}", ex.getMessage());
        }
        // 記錄本地異常日誌
        logger.error("異常方法:{}異常程式碼:{}異常資訊:{}引數:{}", joinPoint.getTarget()
                .getClass().getName()
                + joinPoint.getSignature().getName(), e.getClass().getName(),
                e.getMessage(), params);
    }
}


SystemServiceLog.java


package com.security.annotation;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target({ ElementType.PARAMETER, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface SystemServiceLog {
    String description() default "";
}


SytemLogcontroller.java  負責與前端互動


package com.community.controller;

import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;

import com.community.pager.PageInfo;
import com.community.service.SystemLogService;

@Controller
@Scope(value = "prototype")
@RequestMapping(value = "systemlog")
public class SystemLogController extends BaseController {
    @Autowired
    SystemLogService systemLogService;

    /**
     * 跳轉到日誌展示介面 許可權控制判斷 目前沒有增加判斷,僅跳轉使用
     */
    @RequestMapping(value = "tolist")
    public ModelAndView tolist(ModelMap map) {
        return new ModelAndView("/security/logs/logs");
    }

    /**
     * @param page 頁數
     * @param rows 每頁的資料量
     * @param searchvalue  搜尋關鍵字
     * @param order  排序
     * @param sort  按。。順序排 ,desc、asc
     * @param starttime 開始時間
     * @param endtime  結束時間
     * @param response 相應資訊
     * @return
     */
    @RequestMapping(value = "list")
    @ResponseBody
    public Object list(Integer page, Integer rows, String searchvalue,
            String order, String sort, String starttime, String endtime,
            HttpServletResponse response) {
        String value = null;
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        // ----非空判斷----
        if (StringUtils.isNotEmpty(searchvalue)) {
            try {
                value = URLDecoder.decode(searchvalue, "UTF-8");
            } catch (UnsupportedEncodingException e1) {
                e1.printStackTrace();
            }
        }
        Date st = null;
        Date et = null;
        if (StringUtils.isNotEmpty(starttime)) {
            try {
                st = sdf.parse(starttime);
            } catch (ParseException e) {
                e.printStackTrace();
            }
        }
        if (StringUtils.isNoneEmpty(endtime)) {
            try {
                et = sdf.parse(endtime);
            } catch (ParseException e) {
                e.printStackTrace();
            }
        }
        // ---獲取到登入賬戶的ID值
        Subject currentUser = SecurityUtils.getSubject();
        String userId = currentUser.getSession().getAttribute("_USER_ID")
                .toString();
        PageInfo pageInfo = new PageInfo(page, rows);
        Map<String, Object> condition = new HashMap<String, Object>();
        int start = (page - 1) * rows;
        int end = start + rows;
        condition.put("st", st);// 開始時間
        condition.put("et", et);// 結束時間
        condition.put("start", start);
        condition.put("end", end);
        condition.put("order", order);// 為空沒有使用
        condition.put("sort", sort);// 為空沒有使用
        condition.put("value", value);// 獲取到搜尋框的值(字元)
        condition.put("userId", userId);
        condition.put("searchvalue", searchvalue);
        pageInfo.setCondition(condition);
        systemLogService.findLogs(pageInfo);
        return pageInfo;
    }

}

systemLogMapper.xml

三個方法:

//插入到資料庫

 <insert id="insertSelective" parameterType="com.oracle.pojo.SystemLog">
    <!--
      WARNING - @mbggenerated
      This element is automatically generated by MyBatis Generator, do not modify.
    -->
    insert into CMU_SYSTEM_LOG
    <trim prefix="(" suffix=")" suffixOverrides=",">
      <if test="logId != null">
        LOG_ID,
      </if>
      <if test="userId != null">
        USER_ID,
      </if>
      <if test="username != null">
        USERNAME,
      </if>
      <if test="description != null">
        DESCRIPTION,
      </if>
      <if test="methods != null">
        METHODS,
      </if>
      <if test="logType != null">
        LOG_TYPE,
      </if>
      <if test="requestIp != null">
        REQUEST_IP,
      </if>
      <if test="exceptioncode != null">
        EXCEPTIONCODE,
      </if>
      <if test="exceptionDetail != null">
        EXCEPTION_DETAIL,
      </if>
      <if test="params != null">
        PARAMS,
      </if>
      <if test="time != null">
        TIME,
      </if>
    </trim>
    <trim prefix="values (" suffix=")" suffixOverrides=",">
      <if test="logId != null">
        #{logId,jdbcType=DECIMAL},
      </if>
      <if test="userId != null">
        #{userId,jdbcType=DECIMAL},
      </if>
      <if test="username != null">
        #{username,jdbcType=VARCHAR},
      </if>
      <if test="description != null">
        #{description,jdbcType=VARCHAR},
      </if>
      <if test="methods != null">
        #{methods,jdbcType=VARCHAR},
      </if>
      <if test="logType != null">
        #{logType,jdbcType=VARCHAR},
      </if>
      <if test="requestIp != null">
        #{requestIp,jdbcType=DECIMAL},
      </if>
      <if test="exceptioncode != null">
        #{exceptioncode,jdbcType=VARCHAR},
      </if>
      <if test="exceptionDetail != null">
        #{exceptionDetail,jdbcType=VARCHAR},
      </if>
      <if test="params != null">
        #{params,jdbcType=VARCHAR},
      </if>
      <if test="time != null">
        #{time,jdbcType=TIMESTAMP},
      </if>
    </trim>
  </insert>

//查詢拉取資料(並且有模糊查詢和時間判斷)

  <select id="findLogsList" parameterType="com.community.pager.PageInfo" resultMap="BaseResultMap">
    SELECT * FROM (SELECT tt.*, ROWNUM AS rowno FROM(
    SELECT
    CSL.LOG_ID,
    CSL.USER_ID,
    CSL.USERNAME,
    CSL.DESCRIPTION,
    CSL.METHODS,
    CSL.LOG_TYPE,
    CSL.REQUEST_IP,
    CSL.EXCEPTIONCODE,
    CSL.EXCEPTION_DETAIL,
    CSL.PARAMS,
    CSL.TIME
    FROM(SELECT * FROM CMU_USERS START WITH USER_ID = #{condition.userId} CONNECT BY PRIOR USER_ID = PID) U
    LEFT OUTER JOIN CMU_SYSTEM_LOG CSL ON U.USER_ID = CSL.USER_ID
    where CSL.USER_ID is NOT NULL
      <if test="condition.searchvalue !=null and condition.searchvalue !='' ">
          and(CSL.USERNAME LIKE '%'||#{condition.searchvalue}||'%'
           or CSL.DESCRIPTION LIKE '%'||#{condition.value}||'%'
           or CSL.LOG_TYPE LIKE '%'||#{condition.searchvalue}||'%')
      </if>
      <if test="condition.st != null">
        and CSL.TIME >= #{condition.st}
    </if>
    <if test="condition.et != null">
        AND #{condition.et} >= CSL.TIME
    </if>
    order by TIME desc) tt
      WHERE ROWNUM &lt;= #{condition.end}) table_alias WHERE table_alias.rowno > #{condition.start}
  </select>

//計算資料的條數

  <select id="findLogsListCount" parameterType="com.community.pager.PageInfo" resultType="int">
      select count(*) FROM(SELECT * FROM CMU_USERS START WITH USER_ID = #{condition.userId} CONNECT BY PRIOR USER_ID = PID) U
    LEFT OUTER JOIN CMU_SYSTEM_LOG CSL ON U.USER_ID = CSL.USER_ID
    where CSL.USER_ID is NOT NULL
      <if test="condition.searchvalue !=null and condition.searchvalue !='' ">
          and(CSL.USERNAME LIKE '%'||#{condition.searchvalue}||'%'
           or CSL.DESCRIPTION LIKE '%'||#{condition.value}||'%'
           or CSL.LOG_TYPE LIKE '%'||#{condition.searchvalue}||'%')
      </if>
      <if test="condition.st != null">
        and CSL.TIME >= #{condition.st}
    </if>
    <if test="condition.et != null">
        AND #{condition.et} >= CSL.TIME
    </if>
  </select>

最後  最重要的是給你需要插入資料庫的介面增加:@SysLog(operationType="submitLogin",operationName="代理商登入")   //舉例


前端jsp使用的是easyUI框架:

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<c:set var="ctx" value="${pageContext.request.contextPath}" />
<%@ taglib prefix="shiro" uri="http://shiro.apache.org/tags"%>
<style type="text/css">
#treeGrid tr td {
    white-space: nowrap;
    text-overflow: ellipsis;
    -o-text-overflow: ellipsis;
    overflow: hidden;
}
</style>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="X-UA-Compatible" content="edge" />
<title>日誌列表</title>
<link rel="stylesheet" type="text/css"
    href="${ctx}/resources/easyui/themes/default/easyui.css">
<link rel="stylesheet" type="text/css"
    href="${ctx}/resources/easyui/themes/icon.css">
<script type="text/javascript"
    src="${ctx}/resources/easyui/jquery.min.js"></script>
<script type="text/javascript"
    src="${ctx}/resources/easyui/jquery.easyui.min.js"></script>
<script type="text/javascript"
    src="${ctx}/resources/easyui/locale/easyui-lang-zh_CN.js"></script>
<script type="text/javascript" src="${ctx}/resources/js/extJs.js"></script>
<script type="text/javascript">
    var gUrl;
    $(document).ready(function() {
        gUrl = '${ctx}/systemlog/list';
        loadDatagrid(gUrl);
    });
    function loadDatagrid(gUrl) {
        $('#treeGrid').datagrid({
            method : 'post',
            url : gUrl,
            title : "日誌列表",
            loadMsg : '正在載入資訊...',
            pagination : true, // 分頁
            fit : true,
            fitColumns : true,
            striped : true, // 是否顯示行間隔色
            queryParams : queryParams,
            pageList : [ 15, 20, 30, 50 ],
            pageSize : 20,
            rownumbers : true,//行號
            sidePagination : "server", // 服務端處理分頁  
            columns : [ [ {
                title : '登入名',
                field : 'username', // 欄位  
                width : '10%'
            }, {
                field : 'description',
                title : '描述',
                width : '10%'
            }, {
                title : '日誌型別',
                field : 'logType',
                width : '10%'
            }, {
                title : '呼叫方法',
                field : 'methods',
                width : '40%'
            }, {
                title : 'IP地址',
                field : 'requestIp',
                width : '10%',
                formatter : function(value, row, index) {
                    return _int2iP(value);
                }
            }, {
                title : '建立時間',
                field : 'time',
                align : 'center',
                valign : 'middle',
                width : 80,
                formatter : function(value, row, index) {
                    if (value) {
                        return dataformatter(value);
                    }
                }
            }, ] ],
        });
    }
    function doSearch(value) {
        var starttime = $("#starttime").datebox('getValue');
        var endtime = $("#endtime").datebox('getValue');
        gUrl = "${ctx}/systemlog/list?searchvalue="+encodeURI(encodeURI(value))+"&starttime="+ starttime + "&endtime="+endtime;
        loadDatagrid(gUrl);
    }
    function searchByTime(){
        var starttime = $("#starttime").datebox('getValue');
        var endtime = $("#endtime").datebox('getValue');
        var gUrl = "${ctx}/systemlog/list?starttime="+ starttime + "&endtime="+endtime;
        loadDatagrid(gUrl);
    }
    function dataformatter(value) {
        var date = new Date(value);
        var year = date.getFullYear().toString();
        var month = (date.getMonth() + 1);
        var day = date.getDate().toString();
        var hour = date.getHours().toString();
        var minutes = date.getMinutes().toString();
        var seconds = date.getSeconds().toString();
        if (month < 10) {
            month = "0" + month;
        }
        if (day < 10) {
            day = "0" + day;
        }
        if (hour < 10) {
            hour = "0" + hour;
        }
        if (minutes < 10) {
            minutes = "0" + minutes;
        }
        if (seconds < 10) {
            seconds = "0" + seconds;
        }
        return year + "-" + month + "-" + day + " " + hour + ":" + minutes
                + ":" + seconds;
    }

     /** 重新整理頁面 */
    function refresh() {
        $('#treeGrid').bootstrapTable('refresh');
    }

    function _int2iP(num) {
        var str;
        var tt = new Array();
        tt[0] = (num >>> 24) >>> 0;
        tt[1] = ((num << 8) >>> 24) >>> 0;
        tt[2] = (num << 16) >>> 24;
        tt[3] = (num << 24) >>> 24;
        str = String(tt[0]) + "." + String(tt[1]) + "." + String(tt[2]) + "."
                + String(tt[3]);
        return str;
    }
    /**查詢條件與分頁資料 */
    function queryParams(pageReqeust) {
        pageReqeust.enabled = $("#enabled").val();
        pageReqeust.querys = $("#querys").val();
        pageReqeust.pageNo = this.pageNumber;
        return pageReqeust;
    }
    $.extend($.fn.validatebox.defaults.rules, {
        TimesCheck: {
            validator: function (value, param) {
                var s = $('#starttime').datebox('getValue');
                //因為日期是統一格式的所以可以直接比較字串 否則需要Date.parse(_date)轉換
                return value >= s;
            },
            message: '結束時間必須大於開始時間!!!'
        }
    });
</script>
</head>
<body>
    <div class="easyui-layout" data-options="fit:true">
        <div data-options="region:'center',border:false"
            style="overflow: hidden;">
            <table id="treeGrid" toolbar="#toolbar"></table>
            <div id="toolbar">
            <div style="float: right;">
                <input id="ss" class="easyui-searchbox" searcher="doSearch" prompt="請輸入要查詢的條件(登入名、描述或日誌型別,選擇時間後也可點選此處)..." style="width: 450px; vertical-align: middle;"></input>
            </div>&nbsp;&nbsp;&nbsp;
            開始時間:&nbsp;&nbsp;<input type="text" class="easyui-datebox" name="starttime" id="starttime" editable="false" style="width:110px;" data-options="buttons:buttons,prompt:'請輸入開始時間'">&nbsp;&nbsp;&nbsp;
            結束時間:&nbsp;&nbsp;<input type="text" class="easyui-datebox" name="endtime" id="endtime" editable="false" style="width:110px;" data-options="buttons:buttons,prompt:'請輸入結束時間'" validType="TimesCheck['starttime']" invalidMessage="結束時間必須大於開始時間!">&nbsp;&nbsp;
            <a href="#" onclick="javascript:searchByTime();return false;"class="easyui-linkbutton" iconCls="icon-search">查詢</a>
            </div>
        </div>
</body>
</html>



最終顯示:


本文編輯為:美推網www.zdflshop.com  (站長編輯)