代码较多,请耐心调试
首先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 <= #{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>
开始时间: <input type="text" class="easyui-datebox" name="starttime" id="starttime" editable="false" style="width:110px;" data-options="buttons:buttons,prompt:'请输入开始时间'">
结束时间: <input type="text" class="easyui-datebox" name="endtime" id="endtime" editable="false" style="width:110px;" data-options="buttons:buttons,prompt:'请输入结束时间'" validType="TimesCheck['starttime']" invalidMessage="结束时间必须大于开始时间!">
<a href="#" οnclick="javascript:searchByTime();return false;"class="easyui-linkbutton" iconCls="icon-search">查询</a>
</div>
</div>
</body>
</html>
最终显示:
本文编辑为:美推网www.zdflshop.com (站长编辑)