【Java EE 学习 76 下】【数据采集系统第八天】【通过AOP实现日志管理】【日志管理功能分析和初步实现】
一、日志管理相关分析
1.日志管理是一种典型的系统级别的应用,非常适合使用spring AOP实现。
2.使用日志管理的目的:对系统修改的动作进行记录,比如对权限、角色、用户的写操作、修改操作、删除操作等
3.确定使用的通知方式:使用环绕通知。复习一下环绕通知,所谓环绕通知实际上就是AOP代理对接口中声明方法的执行进行拦截,在执行方法之前或者之后进行一些操作,在日志管理功能模块中,我们对Service接口中声明的方法进行拦截,如果是对系统进行的修改操作的方法,则将方法执行之后就需要将相关信息保存下来方便以后查看,比如是谁登陆的系统进行的修改(最重要),执行的是什么方法,方法的参数是什么,执行成功额还是失败了,方法的返回值是什么,执行方法的时间是什么等等。
4.日志管理功能在系统中的体现:单击导航菜单中的"日志管理"超链接,查看所有的系统的变更历史记录。
二、日志实体和相关类的书写
1.根据一种的分析,得到了以下的日志实体
public class Log {
private String logId; //日志消息标识ID
private String operator=""; //操作人
private Date operatorDate=new Date(); //操作日期
private String operatorName; //操作的名称(方法名)
private String operateParams; //操作参数
private String operateResult=""; //操作结果(success|failure)
private String resultMessage=""; //结果消息
}
2.DAO类的书写和Service的书写略。
3.创建日志切面
日志切面提供了保存保存日志的详细方法(通知),该方法将会拦截目标方法的执行并且记录该方法执行过程中的详细信息。
package com.kdyzm.aspect; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession; import org.apache.struts2.ServletActionContext;
import org.aspectj.lang.ProceedingJoinPoint; import com.kdyzm.domain.Log;
import com.kdyzm.domain.User;
import com.kdyzm.service.LogService;
import com.kdyzm.utils.StringUtils; public class Logger {
private LogService logService;
public LogService getLogService() {
return logService;
}
public void setLogService(LogService logService) {
this.logService = logService;
}
//通知方法
public Object record(ProceedingJoinPoint joinPoint) throws Throwable{
Log log=new Log();
try{
//获取操作人
HttpServletRequest request=ServletActionContext.getRequest();
if(request!=null){
HttpSession session=request.getSession();
User user=(User) session.getAttribute("user");
if(user!=null){
log.setOperator(user.getUserId()+"-"+user.getEmail());//设置操作人
}
} //设置方法名
String methodName=joinPoint.getSignature().getName();
log.setOperatorName(methodName); //获取参数列表
Object[] params=joinPoint.getArgs();
log.setOperateParams(StringUtils.arr2String(params)); //操作结果和结果消息的获取
Object obj=joinPoint.proceed();
log.setOperateResult("SUCCESS"); if(obj!=null){
log.setResultMessage(obj.toString());
}
return obj; //返回执行结果
}catch(Exception e){
log.setOperateResult("FAILURE");
log.setResultMessage(e.getMessage());
}finally{
logService.saveLog(log);
}
return null;
}
}
4.配置spring配置文件applicationConext.xml
(1)首先将切面注入到spring容器
<bean id="logger" class="com.kdyzm.aspect.Logger">
<property name="logService" ref="logService"></property>
</bean>
(2)在aop配置中声明切入点表达式,表示对那些方法进行日志记录
注意这些方法都在事务通知上有定义,但是不能直接使用事务通知中的声明,因为还有不同之处:必须刨除掉logService中的所有方法,否则最后肯定会抛出堆栈溢出的异常。
分析原因:logService中的记录方法本身也是写操作(默认加上了事务),如果是写操作按照规则是需要写入日志表的,但是写入的时候又被AOP日志代理拦截,每次想写的时候都被日志AOP代理拦截,最终这种无限递归方式就会导致堆栈溢出,注意以下的切入点表达式的写法已经将logService刨除掉了。
<aop:pointcut
expression="(execution(* *..*Service.save*(..))
or execution(* *..*Service.update*(..))
or execution(* *..*Service.delete*(..))
or execution(* *..*Service.batch*(..))
or execution(* *..*Service.create*(..))
or execution(* *..*Service.new*(..))) and !bean(logService)"
id="loggerPointcut" />
(3)切面配置,声明使用哪个切面中的哪些方法使用何种通知方式在指定的切入点上织入到目标对象
<aop:aspect id="loggerAspect" ref="logger" order="1">
<aop:around method="record" pointcut-ref="loggerPointcut" />
</aop:aspect>
这里的意思是使用logger切面,使用切面中的record方法以环绕通知的方式在loggerPointcut指定的切入点上织入到目标对象(Service对象)。
5.显示所有日志列表
基本显示是没有什么问题的,但是这里使用了静态调用的方法,可以直接在jsp页面调用某个类的静态方法,这里由于可能会出现参数名称过长的问题,必须在在这里对显示的长度进行限制。
(1)com.kdyzm.utils.StringUtils类中定义静态方法setTagContentLimitLength,默认长度为15,也就是说最多只是显示15个字符。
//通过jsp页面的静态调用可以直接调用某个类的某个方法
public static String setTagContentLimitLength(String string){
int length=15;
System.out.println("访问了setTagContentLimitLength方法!"+string);
if(string !=null){
if(string.length()>length){
return string.substring(0,length)+"......";
}else{
return string;
}
}
return "";
}
(2)在jsp页面中调用,调用新式:<s:property value="@类的全名@方法名(参数列表)"/>
<s:iterator value="%{#logList}" status="st">
<tr>
<td><s:property value="operator" /></td>
<td><s:property value="operatorName" /></td>
<td><s:property value="@com.kdyzm.utils.StringUtils@setTagContentLimitLength(operateParams)" /></td>
<td><s:property value="operateResult" /></td>
<td><s:property value="resultMessage" /></td>
<td><s:date name="operatorDate" format="yyyy/MM/dd HH:mm:ss" /></td>
</tr>
</s:iterator>
(3)如果只是以上两步肯定还会报错,因为strutrs2默认禁用静态调用,需要在配置文件中开启,这里为了方便起见,直接使用了struts.properties进行了配置
struts.i18n.encoding=UTF-8
struts.action.extension=action,,
struts.serve.static.browserCache=false
struts.i18n.reload=true
struts.configuration.xml.reload=true
struts.devMode=true
struts.ui.theme=simple
struts.enable.DynamicMethodInvocation=true
struts.multipart.maxSize=2097152
struts.ognl.allowStaticMethodAccess=true
三、测试日志
1.新建调查之后查看日志:
2.将新建的调查删除掉之后:
【Java EE 学习 76 下】【数据采集系统第八天】【通过AOP实现日志管理】【日志管理功能分析和初步实现】的更多相关文章
- 【Java EE 学习 69 下】【数据采集系统第一天】【实体类分析和Base类书写】
之前SSH框架已经搭建完毕,现在进行实体类的分析和Base类的书写.Base类是抽象类,专门用于继承. 一.实体类关系分析 既然是数据采集系统,首先调查实体(Survey)是一定要有的,一个调查有多个 ...
- 【Java EE 学习 74 下】【数据采集系统第六天】【使用Jfreechart的统计图实现】【将JFreechart整合到项目中】
之前说了JFreechart的基本使用方法,包括生成饼图.柱状统计图和折线统计图的方法.现在需要将其整合到数据采集系统中根据调查结果生成三种不同的统计图. 一.统计模型的分析和设计 实现统计图显示的流 ...
- 【Java EE 学习 67 下】【OA项目练习】【SSH整合JBPM工作流】【JBPM项目实战】
一.SSH整合JBPM JBPM基础见http://www.cnblogs.com/kuangdaoyizhimei/p/4981551.html 现在将要实现SSH和JBPM的整合. 1.添加jar ...
- 【Java EE 学习 79 下】【动态SQL】【mybatis和spring的整合】
一.动态SQL 什么是动态SQL,就是在不同的条件下,sql语句不相同的意思,曾经在“酒店会员管理系统”中写过大量的多条件查询,那是在SSH的环境中,所以只能在代码中进行判断,以下是其中一个多条件查询 ...
- 【Java EE 学习 76 上】【数据采集系统第八天】【角色授权】【用户授权】【权限的粗粒度控制】【权限的细粒度控制】
一.角色管理 单击导航栏上的"角色管理"超链接,跳转到角色管理界面,在该界面上显示所有角色,并提供角色的增加和删除.修改超链接. 1.增加新角色(角色授权) 流程:单击增加新角色超 ...
- 【Java EE 学习 77 下】【数据采集系统第九天】【使用spring实现答案水平分库】【未解决问题:分库查询问题】
之前说过,如果一个数据库中要存储的数据量整体比较小,但是其中一个表存储的数据比较多,比如日志表,这时候就要考虑分表存储了:但是如果一个数据库整体存储的容量就比较大,该怎么办呢?这时候就需要考虑分库了, ...
- 【Java EE 学习 75 下】【数据采集系统第七天】【二进制运算实现权限管理】【使用反射初始化权限表】【权限捕获拦截器动态添加权限】
一.使用反射动态添加权限 在该系统中,我使用struts2的时候非常规范,访问的Action的形式都是"ActionClassName_MethodName.action?参数列表" ...
- 【Java EE 学习 72 下】【数据采集系统第四天】【移动/复制页分析】【使用串行化技术实现深度复制】
一.移动.复制页的逻辑实现 移动.复制页的功能是在设计调查页面的时候需要实现的功能.规则是如果在同一个调查中的话就是移动,如果是在不同调查中的就是复制. 无论是移动还是复制,都需要注意一个问题,那就是 ...
- 【Java EE 学习 71 下】【数据采集系统第三天】【分析答案实体】【删除问题】【删除页面】【删除调查】【清除调查】【打开/关闭调查】
一.分析答案实体 分析答案实体主要涉及到的还是设计上的问题,技术点几乎是没有的.首先需要确定一下答案的格式才能最终确定答案实体中需要有哪些属性. 答案格式的设计是十分重要的,现设计格式如下: 在表单中 ...
随机推荐
- PHP根据array_map、array_reduce和array_column获取二维数组中某个key的集合
http://camnpr.com/php-python/1715.html 巧用array_map()和array_reduce()替代foreach循环
- redis 基础知识
1.安装 sudo apt-get install redis-server 检查Redis服务器程序,执行:ps -aux|grep redis 命令检查Redis服务器状态,执行:netstat ...
- c语言经典算法——查找一个整数数组中第二大数
题目: 实现一个函数,查找一个整数数组中第二大数. 算法思想: 设置两个变量max1和max2,用来保存最大数和第二大数,然后将数组剩余的数依次与这两个数比较,如果这个数a比max1大,则先将max1 ...
- Python 局部变量与全局变量
本来以为 局部变量就是在函数/def/class/lambda内部的变量,全局变量就是在之前这些之外的变量.但是,再一次学习Python atm 中应用时发现了一次特例(意外) 字典中 在函数内部改变 ...
- jquery on()
为多个元素绑定同一个事件: $(document).on('click', '#header .fixed-feedback-bn, #sb-sec .feedback-bn', function ( ...
- tftp服务器简单安装配置
tftp服务器最简单安装配置 1.安装tftp-server sudo apt-get install tftpd-hpa sudo apt-get install tftp-hpa(如果不需要客户端 ...
- 本地数据Store。Cookie,Session,Cache的理解。Timer类主要用于定时性、周期性任务 的触发。刷新Store,Panel
本地数据Store var monthStore = Ext.create('Ext.data.Store', { storeId : 'monthStore', autoLoad : false, ...
- php多线程操作同一文件-待续
同意文件操作同意文件的问题在于逻辑有些地方不合适,如果多个线程同时写入,在不加锁的情况下,可能导致得到结果不如意,为了安全,和脏读(数据库的词),应该使用排他锁,这就意味着每次只能被一个线程操作.其他 ...
- [BZOJ1861][Zjoi2006]Book 书架
[BZOJ1861][Zjoi2006]Book 书架 试题描述 小T有一个很大的书柜.这个书柜的构造有些独特,即书柜里的书是从上至下堆放成一列.她用1到n的正整数给每本书都编了号. 小T在看书的时候 ...
- 使用angular.bootstrap() 完成模块的手动加载
之前我们看到使用ng-app指令,可以实现模块的自动加载.现在我们看下,angular中如何手动加载模块.需要使用到angular.bootstrap这个函数. <html> <he ...