本章简介
- 基于Spring AOP对每次请求进行记录
数据库、表结构与实体类
日志表sysLog信息描述
创建表和插入数据的sql语句
CREATE TABLE sysLog(
id VARCHAR2(32) default SYS_GUID() PRIMARY KEY,
visitTime timestamp,
username VARCHAR2(50),
ip VARCHAR2(30),
url VARCHAR2(50),
executionTime int,
method VARCHAR2(200)
)
SysLog实体类
public class SysLog {
private String id;
private Date visitTime;
private String visitTimeStr;
private String username;
private String ip;
private String url;
private Long executionTime;
private String method;
}
基于AOP完成日志处理
创建LogAop切面类处理日志
在切面类中需要获取的内容包括:
- 访问用户的username
- 访问时间
- 访问的类
- 访问的方法
- 请求发出到返回数据的执行时间
- ip地址
- 资源URL
- 访问用户
LogAop类简介:
-
在com.cncs.controller中创建这个类
-
使用@Component标识它被Spring管理,使用@Aspect标识它是一个切面类
-
HttpServletRequest属性用于获取用户ip
-
在
doBefore()
中记录访问的类,方法和时间。 -
在
doAfter()
中记录执行时间,访问的ip,访问的用户,访问的资源URL。
@Component
@Aspect
public class LogAop {
@Autowired
private HttpServletRequest request;
@Autowired
private ISysLogService sysLogService;
private Date visitTime;//访问时间
private Class executionClass;//访问的类
private Method executionMethod;//访问的方法
@Pointcut("execution(* com.cncs.controller.*.*(..)) && !execution(* com.cncs.controller.SysLogController.*(..))")//自定义切入点,不处理sysLogController类
public void pt1(){};
//获取访问的类,访问的方法,访问的时间
@Before("pt1()")//记录所有controller访问过程
public void doBefore(JoinPoint jp) throws NoSuchMethodException {
visitTime = new Date();//访问时间
executionClass = jp.getTarget().getClass();//访问的类
//获取访问的方法
String methodName = jp.getSignature().getName();//访问的方法名
Object[] args = jp.getArgs();//访问的方法的参数
if (args == null || args.length == 0) {//无参数
executionMethod = executionClass.getMethod(methodName);
} else {
//有参数,将args中所有元素遍历,获取对应的class,装入到一个Class[]
Class[] classArgs = new Class[args.length];
for (int i = 0; i < args.length; i++) {
classArgs[i] = args[i].getClass();
}
executionMethod = executionClass.getMethod(methodName, classArgs);//获取有参数的方法
}
}
//获取执行的时间,访问的用户名称,用户ip,访问的url,
@After("pt1()")
public void doAfter() {
//执行的时间
long executionTime = new Date().getTime() - visitTime.getTime();
//用户访问的url
String url = "";
if (executionClass != LogAop.class) {
//获取controller上的@RequestMapping("/product")
RequestMapping classAnnotation = (RequestMapping) executionClass.getAnnotation(RequestMapping.class);
if (classAnnotation != null) {
//获取方法上的@RequestMapping("/findAll.do")
RequestMapping methodAnnotation = executionMethod.getAnnotation(RequestMapping.class);
if (methodAnnotation != null) {
String[] classValues = classAnnotation.value();//获取controller类参数数组
String[] methodValues = methodAnnotation.value();//获取方法参数数组
url = classValues[0] + methodValues[0];
}
}
}
//用户ip
String ip = request.getRemoteAddr();
//用户名称
SecurityContext securityContext = SecurityContextHolder.getContext();
String username = ((User) (securityContext.getAuthentication().getPrincipal())).getUsername();//也可以通过request.getSession().getAttribute("SPRING_SECURITY_CONTEXT")获取
//封装SysLog
SysLog sysLog = new SysLog();
sysLog.setVisitTime(visitTime);
sysLog.setExecutionTime(executionTime);
sysLog.setIp(ip);
sysLog.setMethod("[类名]"+executionClass.getName()+"[方法名]"+executionMethod.getName());
sysLog.setUsername(username);
sysLog.setUrl(url);
//存入数据库
sysLogService.save(sysLog);
}
}
要对SysAop完成HttpServletRequest的注入,需要在web.xml中添加配置:
<!-- 配置监听器,监听request域对象的创建和销毁的 -->
<listener>
<listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
</listener>
保存日志
- 在SysAop的
doAfter()
中保存日志时调用service层。
部分代码
SysLogService
@Override
public void save(SysLog sysLog) {
sysLogDao.save(sysLog);
}
SysLogDao
@Insert("insert into syslog(visitTime,username,ip,url,executionTime,method) values(#{visitTime},#{username},#{ip},#{url},#{executionTime},#{method})")
public void save(SysLog sysLog);
查看日志
部分代码
SysLogController
@RequestMapping("/findAll.do")
public ModelAndView findAll(@RequestParam(name = "page", required = true,defaultValue = "1") Integer page,@RequestParam(name = "size",required = true,defaultValue = "4") Integer size){
ModelAndView mv = new ModelAndView();
List<SysLog> sysLogs = sysLogService.findAll(page,size);
PageInfo pageInfo = new PageInfo(sysLogs,5);//页码数量为5
//pageInfo.setList(sysLogs);
mv.addObject("pageInfo",pageInfo);
mv.setViewName("syslog-list-page");
return mv;
}
SysLogService
@Override
public List<SysLog> findAll(int page, int size) {
PageHelper.startPage(page, size);
return sysLogDao.findAll();
}
SysLogDao
@Select("select * from sysLog")
List<SysLog> findAll();
syslog-list.jsp
<table id="dataList"
class="table table-bordered table-striped table-hover dataTable">
<thead>
<tr>
<th class="" style="padding-right: 0px"><input id="selall"
type="checkbox"
class="icheckbox_square-blue"></th>
<th class="sorting_asc">ID</th>
<th class="sorting">访问时间</th>
<th class="sorting">访问用户</th>
<th class="sorting">访问IP</th>
<th class="sorting">资源URL</th>
<th class="sorting">执行时间</th>
<th class="sorting">访问方法</th>
</tr>
</thead>
<tbody>
<c:forEach items="${pageInfo.list}" var="syslog">
<tr>
<td><input name="ids" type="checkbox"></td>
<td>${syslog.id}</td>
<td>${syslog.visitTimeStr }</td>
<td>${syslog.username }</td>
<td>${syslog.ip }</td>
<td>${syslog.url}</td>
<td>${syslog.executionTime}毫秒</td>
<td>${syslog.method}</td>
</tr>
</c:forEach>
</tbody>
</table>
<!--............-->
<div class="box-footer">
<div class="pull-left">
<div class="form-group form-inline">
总共${pageInfo.pages}页,共${pageInfo.total}条数据。 每页
<select class="form-control" id="choosePageSize" onchange="changePageSize()">
<option>5</option>
<option>6</option>
<option>7</option>
<option>8</option>
<option>9</option>
</select> 条
</div>
</div>
<div class="box-tools pull-right">
<ul class="pagination">
<li><a href="${pageContext.request.contextPath}/sysLog/findAll.do?page=${pageInfo.navigateFirstPage}&size=${pageInfo.pageSize}" aria-label="Previous">首页</a></li>
<li><a href="${pageContext.request.contextPath}/sysLog/findAll.do?page=${pageInfo.lastPage}&size=${pageInfo.pageSize}">上一页</a></li>
<c:forEach begin="1" end="${pageInfo.navigatePages}" varStatus="page">
<li>
<a href="${pageContext.request.contextPath}/sysLog/findAll.do?page=${page.index}&size=${pageInfo.pageSize}">
${page.index}
</a>
</li>
</c:forEach>
<li><a href="${pageContext.request.contextPath}/sysLog/findAll.do?page=${pageInfo.nextPage}&size=${pageInfo.pageSize}">下一页</a></li>
<li><a href="${pageContext.request.contextPath}/sysLog/findAll.do?page=${pageInfo.lastPage}&size=${pageInfo.pageSize}" aria-label="Next">尾页</a></li>
</ul>
</div>
</div>
// 改变每页显示条数
function changePageSize() {
var pageSize = $("#choosePageSize").val();
location.href = "${pageContext.request.contextPath}/sysLog/findAll.do?page=1&size=" + pageSize;
}
查看日志效果展示