- 浏览: 155537 次
- 性别:
- 来自: 北京
文章分类
最新评论
-
bkk854762363:
好文章,赞
Spring3.0 + 自定义注解实现操作日志记录功能 -
怪黍叔:
学习了
Spring3.0 + 自定义注解实现操作日志记录功能 -
wellway:
请问jfreechart-1.0.11-demo.jar怎么反 ...
关于JFreeChart Demo
Xml代码
<aop:aspectj-autoproxy/>
<aop:aspectj-autoproxy/> 这一步就完成了@AspectJ的支持,从而可以实现通过注解方式将通知编织到非公共方法中。
第二步:编写自定义注解。实现对方法所实现的功能进行描述,以便在通知中获取描述信息,代码非常简单,如下:
Java代码
package com.abchina.rmpf.logmng.ann;
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.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface rmpfLog {
String desc() default "无描述信息";
}
package com.abchina.rmpf.logmng.ann;
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.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface rmpfLog {
String desc() default "无描述信息";
}
第三步:编写操作日志切面通知实现类。
在编写切面通知实现类之前,我们需要搞清楚我们需要哪些通知类型,是前置通知、后置通知、环绕通知或异常通知?根据我的需求,我们知道我们记录的操作日志
有两种情况,一种是操作成功,一种是操作失败。操作成功时则方法肯定已经执行完成,顾我们需要实现一个后置通知;操作失败时则说明方法出现异常无法正常执
行完成,顾还需要一个异常通知。因此我们就需要实现这两个通知即可。代码如下:
Java代码
package com.abchina.rmpf.logmng.aop;
import java.io.File;
import java.lang.reflect.Array;
import java.util.Collection;
import java.util.Iterator;
import net.sf.json.JSONArray;
import net.sf.json.JSONObject;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.springframework.util.ResourceUtils;
import plantix.core.business.exception.BusinessException;
import plantix.core.context.ThreadContext;
import com.abchina.rmpf.privmng.web.vo.ActorVO;
import com.abchina.rmpf.common.Constant;
import com.abchina.rmpf.common.DateTool;
import com.abchina.rmpf.logmng.ann.rmpfLog;
import com.abchina.rmpf.logmng.service.ILogService;
import com.abchina.rmpf.logmng.web.vo.LogVO;
import com.opensymphony.xwork2.ActionContext;
@Aspect //该注解标示该类为切面类
public class LogAspect {
/**
* LogService
* @generated
*/
private ILogService logService;
//标注该方法体为后置通知,当目标方法执行成功后执行该方法体
@AfterReturning("within(com.abchina.irms..*) && @annotation(rl)")
public void addLogSuccess(JoinPoint jp, rmpfLog rl){
Object[] parames = jp.getArgs();//获取目标方法体参数
String params = parseParames(parames); //解析
目标方法体的参数
String className = jp.getTarget().getClass().toString();//获取目标类名
className = className.substring(className.indexOf("com"));
String signature = jp.getSignature().toString();//获取目标方法签名
String methodName = signature.substring(signature.lastIndexOf(".")+1, signature.indexOf("("));
String modelName = getModelName(className); //根据类名获取所属的模块
String ip = (String)ActionContext.getContext().getSession().get(Constant.THREAD_APP_IP_KEY); //用户IP
ActorVO actor = ((ActorVO)ActionContext.getContext().getSession().get(Constant.SESSION_ACTOR_KEY));
LogVO logvo = new LogVO();
logvo.setId(java.util.UUID.randomUUID().toString());
logvo.setClassname(className);
logvo.setMethodname(methodName);
logvo.setArgument(params);
logvo.setMemo(rl.desc());
logvo.setModelname(modelName);
logvo.setIp(ip);
logvo.setOperationtime(DateTool.getDateTime4());
// logvo.setErr("");
logvo.setFlag("1");
if(actor!=null){
logvo.setOrgid(actor.getOrgcode());
logvo.setUserid(actor.getUserid());
logvo.setUsername(actor.getUsername());
}
logService.insertLog(logvo);
}
//标注该方法体为异常通知,当目标方法出现异常时,执行该方法体
@AfterThrowing(pointcut="within(com.abchina.irms..*) && @annotation(rl)", throwing="ex")
public void addLog(JoinPoint jp, rmpfLog rl, BusinessException ex){
Object[] parames = jp.getArgs();
String params = parseParames(parames);
String className = jp.getTarget().getClass().toString();
className = className.substring(className.indexOf("com"));
String signature = jp.getSignature().toString();
String methodName = signature.substring(signature.lastIndexOf(".")+1, signature.indexOf("("));
String modelName = getModelName(className);
String ip = (String)ActionContext.getContext().getSession().get(Constant.THREAD_APP_IP_KEY);
ActorVO actor = ((ActorVO)ActionContext.getContext().getSession().get(Constant.SESSION_ACTOR_KEY));
LogVO logvo = new LogVO();
logvo.setId(java.util.UUID.randomUUID().toString());
logvo.setClassname(className);
logvo.setMethodname(methodName);
logvo.setArgument(params);
logvo.setMemo(rl.desc());
logvo.setModelname(modelName);
logvo.setIp(ip);
logvo.setOperationtime(DateTool.getDateTime4());
logvo.setErr(ex.toString());//记录异常信息
logvo.setFlag("0");
if(actor!=null){
logvo.setOrgid(actor.getOrgcode());
logvo.setUserid(actor.getUserid());
logvo.setUsername(actor.getUsername());
}
logService.insertLog(logvo);
}
/**
* 根据包名查询检索其所属的模块
* @param packageName 包名
* @return 模块名称
*/
private String getModelName(String packageName){
String modelName = "";
SAXReader reader = new SAXReader();
try {
//读取project.xml
模块信息描述xml文档
File proj = ResourceUtils.getFile("classpath:project.xml");
Document doc = reader.read(proj);
//获取文档根节点
Element root = doc.getRootElement();
//查询模块名称
modelName = searchModelName(root, packageName);
} catch (Exception e) {
e.printStackTrace();
}
return modelName;
}
/**
* 采用递归方式根据包名逐级检索所属模块
* @param element 元素节点
* @param packageName 包名
* @return 模块名称
*/
private String searchModelName(Element element, String packageName){
String modelName = searchModelNodes(element, packageName);
//若将包名解析到最后的根目录后仍未检索到模块名称,则返回空
if(packageName.lastIndexOf(".")==-1){
return modelName;
}
//逐级检索模块名称
if(modelName.equals("")){
packageName = packageName.substring(0, packageName.lastIndexOf("."));
modelName = searchModelName(element, packageName);
}
return modelName;
}
/**
* 根据xml文档逐个节点检索模块名称
* @param element 节点元素
* @param packageName 包名
* @return 模块名称
*/
@SuppressWarnings("unchecked")
private String searchModelNodes(Element element, String packageName){
String modelName = "";
Element modules = element.element("modules");
Iterator it = modules.elementIterator();
if(!it.hasNext()){
return modelName;
}
while (it.hasNext()) {
Element model = (Element) it.next();
String pack = model.attributeValue("packageName");
String name = model.elementText("moduleCHPath");
if(packageName.equals(pack)){
modelName = name;
return modelName;
}
if(modelName!=null && !modelName.equals("")){
break;
}
modelName = searchModelNodes(model, packageName);
}
return modelName;
}
/**
* 解析方法参数
* @param parames 方法参数
* @return 解析后的方法参数
*/
private String parseParames(Object[] parames) {
StringBuffer sb = new StringBuffer();
for(int i=0; i<parames.length; i++){
if(parames[i] instanceof Object[] || parames[i] instanceof Collection){
JSONArray json = JSONArray.fromObject(parames[i]);
if(i==parames.length-1){
sb.append(json.toString());
}else{
sb.append(json.toString() + ",");
}
}else{
JSONObject json = JSONObject.fromObject(parames[i]);
if(i==parames.length-1){
sb.append(json.toString());
}else{
sb.append(json.toString() + ",");
}
}
}
String params = sb.toString();
params = params.replaceAll("(\"\\w+\":\"\",)", "");
params = params.replaceAll("(,\"\\w+\":\"\")", "");
return params;
}
public ILogService getLogService() {
return logService;
}
public void setLogService(ILogService logService) {
this.logService = logService;
}
}
package com.abchina.rmpf.logmng.aop;
import java.io.File;
import java.lang.reflect.Array;
import java.util.Collection;
import java.util.Iterator;
import net.sf.json.JSONArray;
import net.sf.json.JSONObject;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.springframework.util.ResourceUtils;
import plantix.core.business.exception.BusinessException;
import plantix.core.context.ThreadContext;
import com.abchina.rmpf.privmng.web.vo.ActorVO;
import com.abchina.rmpf.common.Constant;
import com.abchina.rmpf.common.DateTool;
import com.abchina.rmpf.logmng.ann.rmpfLog;
import com.abchina.rmpf.logmng.service.ILogService;
import com.abchina.rmpf.logmng.web.vo.LogVO;
import com.opensymphony.xwork2.ActionContext;
@Aspect //该注解标示该类为切面类
public class LogAspect {
/**
* LogService
* @generated
*/
private ILogService logService;
//标注该方法体为后置通知,当目标方法执行成功后执行该方法体
@AfterReturning("within(com.abchina.irms..*) && @annotation(rl)")
public void addLogSuccess(JoinPoint jp, rmpfLog rl){
Object[] parames = jp.getArgs();//获取目标方法体参数
String params = parseParames(parames); //解析目标方法体的参数
String className = jp.getTarget().getClass().toString();//获取目标类名
className = className.substring(className.indexOf("com"));
String signature = jp.getSignature().toString();//获取目标方法签名
String methodName = signature.substring(signature.lastIndexOf(".")+1, signature.indexOf("("));
String modelName = getModelName(className); //根据类名获取所属的模块
String ip = (String)ActionContext.getContext().getSession().get(Constant.THREAD_APP_IP_KEY); //用户IP
ActorVO actor = ((ActorVO)ActionContext.getContext().getSession().get(Constant.SESSION_ACTOR_KEY));
LogVO logvo = new LogVO();
logvo.setId(java.util.UUID.randomUUID().toString());
logvo.setClassname(className);
logvo.setMethodname(methodName);
logvo.setArgument(params);
logvo.setMemo(rl.desc());
logvo.setModelname(modelName);
logvo.setIp(ip);
logvo.setOperationtime(DateTool.getDateTime4());
// logvo.setErr("");
logvo.setFlag("1");
if(actor!=null){
logvo.setOrgid(actor.getOrgcode());
logvo.setUserid(actor.getUserid());
logvo.setUsername(actor.getUsername());
}
logService.insertLog(logvo);
}
//标注该方法体为异常通知,当目标方法出现异常时,执行该方法体
@AfterThrowing(pointcut="within(com.abchina.irms..*) && @annotation(rl)", throwing="ex")
public void addLog(JoinPoint jp, rmpfLog rl, BusinessException ex){
Object[] parames = jp.getArgs();
String params = parseParames(parames);
String className = jp.getTarget().getClass().toString();
className = className.substring(className.indexOf("com"));
String signature = jp.getSignature().toString();
String methodName = signature.substring(signature.lastIndexOf(".")+1, signature.indexOf("("));
String modelName = getModelName(className);
String ip = (String)ActionContext.getContext().getSession().get(Constant.THREAD_APP_IP_KEY);
ActorVO actor = ((ActorVO)ActionContext.getContext().getSession().get(Constant.SESSION_ACTOR_KEY));
LogVO logvo = new LogVO();
logvo.setId(java.util.UUID.randomUUID().toString());
logvo.setClassname(className);
logvo.setMethodname(methodName);
logvo.setArgument(params);
logvo.setMemo(rl.desc());
logvo.setModelname(modelName);
logvo.setIp(ip);
logvo.setOperationtime(DateTool.getDateTime4());
logvo.setErr(ex.toString());//记录异常信息
logvo.setFlag("0");
if(actor!=null){
logvo.setOrgid(actor.getOrgcode());
logvo.setUserid(actor.getUserid());
logvo.setUsername(actor.getUsername());
}
logService.insertLog(logvo);
}
/**
* 根据包名查询检索其所属的模块
* @param packageName 包名
* @return 模块名称
*/
private String getModelName(String packageName){
String modelName = "";
SAXReader reader = new SAXReader();
try {
//读取project.xml模块信息描述xml文档
File proj = ResourceUtils.getFile("classpath:project.xml");
Document doc = reader.read(proj);
//获取文档根节点
Element root = doc.getRootElement();
//查询模块名称
modelName = searchModelName(root, packageName);
} catch (Exception e) {
e.printStackTrace();
}
return modelName;
}
/**
* 采用递归方式根据包名逐级检索所属模块
* @param element 元素节点
* @param packageName 包名
* @return 模块名称
*/
private String searchModelName(Element element, String packageName){
String modelName = searchModelNodes(element, packageName);
//若将包名解析到最后的根目录后仍未检索到模块名称,则返回空
if(packageName.lastIndexOf(".")==-1){
return modelName;
}
//逐级检索模块名称
if(modelName.equals("")){
packageName = packageName.substring(0, packageName.lastIndexOf("."));
modelName = searchModelName(element, packageName);
}
return modelName;
}
/**
* 根据xml文档逐个节点检索模块名称
* @param element 节点元素
* @param packageName 包名
* @return 模块名称
*/
@SuppressWarnings("unchecked")
private String searchModelNodes(Element element, String packageName){
String modelName = "";
Element modules = element.element("modules");
Iterator it = modules.elementIterator();
if(!it.hasNext()){
return modelName;
}
while (it.hasNext()) {
Element model = (Element) it.next();
String pack = model.attributeValue("packageName");
String name = model.elementText("moduleCHPath");
if(packageName.equals(pack)){
modelName = name;
return modelName;
}
if(modelName!=null && !modelName.equals("")){
break;
}
modelName = searchModelNodes(model, packageName);
}
return modelName;
}
/**
* 解析方法参数
* @param parames 方法参数
* @return 解析后的方法参数
*/
private String parseParames(Object[] parames) {
StringBuffer sb = new StringBuffer();
for(int i=0; i<parames.length; i++){
if(parames[i] instanceof Object[] || parames[i] instanceof Collection){
JSONArray json = JSONArray.fromObject(parames[i]);
if(i==parames.length-1){
sb.append(json.toString());
}else{
sb.append(json.toString() + ",");
}
}else{
JSONObject json = JSONObject.fromObject(parames[i]);
if(i==parames.length-1){
sb.append(json.toString());
}else{
sb.append(json.toString() + ",");
}
}
}
String params = sb.toString();
params = params.replaceAll("(\"\\w+\":\"\",)", "");
params = params.replaceAll("(,\"\\w+\":\"\")", "");
return params;
}
public ILogService getLogService() {
return logService;
}
public void setLogService(ILogService logService) {
this.logService = logService;
}
}
大家看上面的代码会发现这两个方法体:
Java代码
@AfterReturning("within(com.abchina.irms..*) && @annotation(rl)")
public void addLogSuccess(JoinPoint jp, rmpfLog rl){…}
@AfterReturning("within(com.abchina.irms..*) && @annotation(rl)")
public void addLogSuccess(JoinPoint jp, rmpfLog rl){…}
Java代码
@AfterThrowing(pointcut="within(com.abchina.irms..*) && @annotation(rl)", throwing="ex")
public void addLog(JoinPoint jp, rmpfLog rl, BusinessException ex){…}
@AfterThrowing(pointcut="within(com.abchina.irms..*) && @annotation(rl)", throwing="ex")
public void addLog(JoinPoint jp, rmpfLog rl, BusinessException ex){…}
这两个方法体分别是后置通知和异常通知的实现。它们有两个相同的参数jp和rl,jp是切点对象,通过该对象可以获取切点所切入方法所在的类,方法名、参
数等信息,具体方法可以看方法体的实现;rl则是我们的自定义注解的对象,通过该对象我们可以获取注解中参数值,从而获取方法的描述信息。在异常通知中多
出了一个ex参数,该参数是方法执行时所抛出的异常,从而可以获取相应的异常信息。此处为我写的自定义异常。注意:如果指定异常参数,则异常对象必须与通
知所切入的方法体抛出的异常保持一致,否则该通知不会执行。
addLogSuccess方法签名上的@AfterReturning("within(com.abchina.irms..*)
&&
@annotation(rl)")注解,是指定该方法体为后置通知,其有一个表达式参数,用来检索符合条件的切点。该表达式指定com/abchina
/irms目录下及其所有子目录下的所有带有@rmpfLog注解的方法体为切点。
addLog方法签名上的@AfterThrowing(pointcut="within(com.abchina.irms..*)
&& @annotation(rl)",
throwing="ex")注解,是指定方法体为异常通知,其有一个表达式参数和一个抛出异常参数。表达式参数与后置通知的表达式参数含义相同,而抛出
异常参数,则表示如果com/abchina/irms目录下及其所有子目录下的所有带有@rmpfLog注解的方法体在执行时抛出
BusinessException异常时该通知便会执行。
注意:切面通知实现类是一个普通的pojo对象,如果要想指定其为通知对象,则需在其类名上添加@Aspect注解
第四步:在spring配置文件中创建通知bean对象。
Xml代码
<bean id="logAspect" class="com.abchina.rmpf.logmng.aop.LogAspect">
<property name="logService">
<ref local="com.abchina.rmpf.logmng.service.impl.LogServiceImpl"/>
</property>
</bean>
<bean id="logAspect" class="com.abchina.rmpf.logmng.aop.LogAspect">
<property name="logService">
<ref local="com.abchina.rmpf.logmng.service.impl.LogServiceImpl"/>
</property>
</bean>
第五步:使用操作日志记录注解。
通过以上四步操作后,操作日志的记录功能就算完成了,那我们该如何使用呢?很简单!在com/abchina/irms目录下及其所有子目录下任意找到一个service层的某个类的方法,在其方法体上添加@rmpfLog(desc=”描述信息”)即可。代码如下:
Java代码
@rmpfLog(desc="创建关联交易合同")
@Transactional
public void insertRtcont(RtcontVO rtcontVO) throws BusinessException {
rtcontAL.insertRtcont(toRtcontDomain(rtcontVO));
}
发表评论
-
子类可以继承到父类上的注解吗?
2012-11-12 17:07 7978不了解注解基础知识的请先看《JDK 5 Annotation\ ... -
JDK 5 Annotation\注解\注释\自定义注解
2012-11-12 17:06 1472自定义注解示例 ------ ... -
Java基础知识点梳理
2012-10-16 10:50 1126... -
String考点
2012-10-08 10:37 8471.String StringBuffer StringBui ... -
抽取网页数据的不同思路
2012-09-27 18:52 0客户要求从Internet上的网页上抽取一定的数据,用来显示或 ... -
使用TransactionTemplate 编程式控制事务
2012-09-27 17:10 27900使用 TransactionTempla ... -
Java编程中的性能优化手段
2012-09-26 15:35 10111.尽量使用final修饰符。 带有final修饰符的类是不 ... -
java 异常处理
2012-09-26 15:32 9051.异常处理的流程: ① 遇到错误,方法立即结束,并不返回一个 ... -
灵活自定义缩略图片尺寸大小方案分享(nginx,lua_nginx,GraphicsMagick)
2012-07-11 12:27 3109melin 写道 在开发电子商务网站时,同一个图片需要不 ... -
jmagic 的安装与使用
2012-03-25 08:59 1646平台:winXP 1. 安装Imag ... -
单例模式
2012-03-25 08:45 1160饿汉式: package com.design.pat ... -
判断滚动条已经滚动到底部 方法收集
2011-10-17 14:17 32721.window.onscroll=function() { ... -
如何在HttpServletRequest上下文环境中判断请求是同步请求还是异步请求
2011-05-05 15:01 1976在Java后台,有时候我们需要根据同步请求和异步请求做个性 ... -
跨应用程序的session共享
2010-09-30 12:36 1850常常有这样的情况,一个大项目被分割成若干小项目开发,为了能够互 ... -
Java的垃圾回收机制详解和调优
2010-09-30 11:21 9561.JVM的gc概述 gc即 ... -
sso单点登陆学习
2010-09-30 10:43 1729我对于一个新的内容学习.一般先知道其作用和特点是什么.然后从网 ... -
单点登录系统的设计与实现方案
2010-09-30 09:26 1580目的: 对目前已有的 Web 应用系统,和将来待开发的 Web ...
相关推荐
Myeclipse8.5下搭建SSH框架(图解)Struts2.1+Spring3.0+Hibernate3.3
Struts2.1+Spring3.0+JPA1.0 .pdfStruts2.1+Spring3.0+JPA1.0 .pdfStruts2.1+Spring3.0+JPA1.0 .pdfStruts2.1+Spring3.0+JPA1.0 .pdfStruts2.1+Spring3.0+JPA1.0 .pdfStruts2.1+Spring3.0+JPA1.0 .pdf
spring3.0+spring mvc3.0+mybaits3.0
一个简单的采用自定义注解结合SpringAop实现方法执行的权限管理,这个demo中并没有涉及到与数据库的交互和业务代码,用户权限在登陆时采用简单的手动初始化。该demo用的jdk1.7编译,Spring4.0版本,只想通过这个demo...
spring3.0+hibernate3.0+struts2整合实现,直接导入就可以用。
spring3.0+,经典版本,完整架包,包含spring+json+gson+mysql,整理不易,请大家下载后好好使用,有什么欠缺,大家可以回复我。
本来刚开始学Spring mvc 3.0+ Ibtais 基于Eclipse开发集成Spring mvc 3.0+ Ibtais 注解 求高手指导QQ286596209
spring3.0+hibernate3.3+struts2整合jar包
搭建Struts2.1+Spring3.0+Hibernate3.3框架
4、想看spring aop 注解实现记录系统日志并入库等 二、能学到什么 1、收获可用源码 2、能够清楚的知道如何用spring aop实现自定义注解以及注解的逻辑实现 (需要知道原理的请看spring aop源码,此处不做赘述) 3、...
spring3.0 + jpa 需要的jar包 spring3.0 + jpa 需要的jar包 spring3.0 + jpa 需要的jar包
公文管理、申请审批、公告管理、会议管理、权限管理、个人办公、客户管理、人事等等。项目技术:Struts1.2 + Hibernate3.0 + Spring2 +DWR。java毕业设计 jsp毕业设计 ssh毕业设计
整合Spring3.0+quartz-2.1.6 ..............................................................................
spring3.0+hibernate3.0+struts2
Spring3.0+myBatis3.0
该文件是一个完整的Spring3.0+Ibatis+Oracle全注解式开发项目,里面详细的介绍了注解的使用,注解描述很全,下载就可以导入到您的myeclipse中运行,很好的Spring注解开发小项目
Struts2+spring3.0+JPA(注解方式集成) 步骤详细 推荐下载
java 技术分享:Spring3.0+Ibatis+Oracle全注解开发详细过程
Myeclipse10下搭建SSH框架(图解)Struts2.1+Spring3.0+Hibernate3.3 该文件的内容来自网络,我搜集并整理供大家参考学习。
spring3.0+hibernate3.0+struts2,此Demo有,增,删,查,改