aop+自定义注解实现操作日志记录
来源:互联网 发布:微信js接口安全域名 编辑:程序博客网 时间:2024/05/28 01:35
记录日志的自定义注解
- package com.apabi.leopard.annotation;
- import java.lang.annotation.Retention;
- import java.lang.annotation.Target;
- import java.lang.annotation.RetentionPolicy;
- import java.lang.annotation.ElementType;
- /**
- * @author pengjin
- * @version 2.1
- * @since 2.1
- */
- @Retention(RetentionPolicy.RUNTIME)
- @Target(ElementType.METHOD)
- public @interface LogAnnotation {
- String operateModelNm();
- String operateFuncNm();
- String operateDescribe();
- }
aop切面处理方法:
- package com.apabi.leopard.annotation;
- import java.lang.reflect.Array;
- import java.lang.reflect.Method;
- import java.util.ArrayList;
- import java.util.Arrays;
- import java.util.Date;
- import java.util.List;
- import javax.servlet.http.HttpServletRequest;
- import javacommon.base.BaseSpringController;
- import javacommon.security.springsecurity.SpringSecurityUtils;
- import org.aspectj.lang.JoinPoint;
- import org.springframework.beans.factory.annotation.Autowired;
- import com.apabi.leopard.model.Admin;
- import com.apabi.leopard.model.OperateLog;
- import com.apabi.leopard.service.OperateLogManager;
- import com.apabi.leopard.sso.SsoService;
- import com.apabi.leopard.sso.User;
- /**
- * @author pengjin
- * @version 2.1
- * @since 2.1
- */
- public class WriteOperateLog {
- @Autowired
- private OperateLogManager operateLogManager;
- public void writeLogInfo(JoinPoint joinPoint) throws Exception,
- IllegalAccessException {
- String temp = joinPoint.getStaticPart().toShortString();
- String longTemp = joinPoint.getStaticPart().toLongString();
- joinPoint.getStaticPart().toString();
- String classType = joinPoint.getTarget().getClass().getName();
- String methodName = temp.substring(10, temp.length() - 1);
- Class<?> className = Class.forName(classType);
- // 日志动作
- @SuppressWarnings("rawtypes")
- Class[] args = new Class[joinPoint.getArgs().length];
- String[] sArgs = (longTemp.substring(longTemp.lastIndexOf("(") + 1,
- longTemp.length() - 2)).split(",");
- for (int i = 0; i < args.length; i++) {
- if (sArgs[i].endsWith("String[]")) {
- args[i] = Array.newInstance(Class.forName("java.lang.String"),
- 1).getClass();
- } else if (sArgs[i].endsWith("Long[]")) {
- args[i] = Array.newInstance(Class.forName("java.lang.Long"), 1)
- .getClass();
- } else if (sArgs[i].indexOf(".") == -1) {
- if (sArgs[i].equals("int")) {
- args[i] = int.class;
- } else if (sArgs[i].equals("char")) {
- args[i] = char.class;
- } else if (sArgs[i].equals("float")) {
- args[i] = float.class;
- } else if (sArgs[i].equals("long")) {
- args[i] = long.class;
- }
- } else {
- args[i] = Class.forName(sArgs[i]);
- }
- }
- Method method = className.getMethod(
- methodName.substring(methodName.indexOf(".") + 1,
- methodName.indexOf("(")), args);
- BaseSpringController thisController = (BaseSpringController) joinPoint
- .getTarget();
- // 如果该方法写了注解才做操作
- if (method.isAnnotationPresent(LogAnnotation.class)) {
- LogAnnotation logAnnotation = method
- .getAnnotation(LogAnnotation.class);
- String operateModelNm = logAnnotation.operateModelNm();
- String operateFuncNm = logAnnotation.operateFuncNm();
- String operateDescribe = logAnnotation.operateDescribe();
- List<String> logArgs = null;
- if (operateDescribe.indexOf("#") != -1) {
- logArgs = new ArrayList<String>();
- int startIndex = operateDescribe.indexOf("#", 0);
- int endIndex = operateDescribe.indexOf("#", startIndex + 1);
- while (startIndex != -1) {
- String tempArg = operateDescribe.substring(startIndex + 1,
- endIndex);
- startIndex = operateDescribe.indexOf("#", endIndex + 1);
- endIndex = operateDescribe.indexOf("#", startIndex + 1);
- logArgs.add(tempArg);
- }
- }
- // 获取被注解方法的参数,实现动态注解
- String logArg = null;
- // 被注解方法只有一个参数的情况可用%替代要传入的参数
- if (args.length == 1) {
- if (args[0].getName().equals("java.lang.Long")
- || args[0].getName().equals("java.lang.Integer")
- || args[0].getName().equals("java.lang.String")) {
- logArg = String.valueOf((joinPoint.getArgs())[0]);
- } else if (args[0] == String[].class) {
- String[] arrayArg = (String[]) (joinPoint.getArgs())[0];
- logArg = Arrays.toString(arrayArg);
- } else if (args[0].getName().startsWith(
- "com.apabi.leopard.model")) {
- Method m = args[0].getMethod("getId");
- logArg = String.valueOf(m.invoke(joinPoint.getArgs()[0]));
- // 包含了两个操作的日志内容如save方法中包含了增加和修改操作,根据是否存在参数来判断是什么操作
- if (operateDescribe.indexOf("|") != -1) {
- if (!logArg.equals("null")) {
- operateDescribe = operateDescribe
- .substring(operateDescribe.indexOf("|") + 1);
- } else {
- operateDescribe = operateDescribe.substring(0,
- operateDescribe.indexOf("|"));
- }
- }
- }
- // 将注解中%转换为被拦截方法参数中的id
- if (!logArg.equals("null")) {
- operateDescribe = operateDescribe.indexOf("%") != -1 ? operateDescribe
- .replace("%", logArg) : operateDescribe;
- }
- } else {
- Object obj[] = joinPoint.getArgs();
- for (int k = 0; k < logArgs.size(); k++) {
- for (int j = k; j < obj.length; j++) {
- // 如果是实体
- if (logArgs.get(k).startsWith("@")) {
- if (args[j].getName().startsWith(
- "com.apabi.leopard.model")) {
- Method m = args[j].getMethod("getId");
- logArg = String.valueOf(m.invoke(joinPoint
- .getArgs()[j]));
- // 包含了两个操作的日志内容如save方法中包含了增加和修改操作,根据是否存在参数来判断是什么操作
- if (!logArg.equals("null")) {
- operateDescribe = operateDescribe
- .substring(operateDescribe
- .indexOf("|") + 1);
- } else {
- operateDescribe = operateDescribe
- .substring(0, operateDescribe
- .indexOf("|"));
- }
- } else {
- continue;
- }
- // 数组
- } else if (logArgs.get(k).startsWith("{1}quot;)) {
- String[] arrayArg = thisController.request
- .getParameterValues(logArgs.get(k)
- .substring(1));
- logArg = Arrays.toString(arrayArg);
- // String
- } else {
- logArg = thisController.request
- .getParameter(logArgs.get(k));
- if (logArgs.get(k).equals("bsId") && logArg == null) {
- logArg = SpringSecurityUtils.getCurrentAdmin()
- .getNwOfficeId().toString();
- }
- if (operateDescribe.indexOf("|") != -1) {
- if (!logArg.equals("null")) {
- operateDescribe = operateDescribe
- .substring(operateDescribe
- .indexOf("|") + 1);
- } else {
- operateDescribe = operateDescribe
- .substring(0, operateDescribe
- .indexOf("|"));
- }
- }
- }
- if (logArg == null || logArg.equals("null")) {
- logArg = "";
- }
- operateDescribe = operateDescribe.replace(
- "#" + logArgs.get(k) + "#", logArg);
- break;
- }
- }
- }
- OperateLog log = null;
- Admin admin = SpringSecurityUtils.getCurrentAdmin();
- if (admin != null) {
- log = new OperateLog(admin.getNwOfficeId(),
- admin.getLoginName(), operateModelNm, operateFuncNm,
- operateDescribe, new Date(),
- getIpAddr(thisController.request));
- } else {
- final User user = (User) thisController.request.getSession()
- .getAttribute(SsoService.SESSION_USER);
- log = new OperateLog(user.getNwOfficeId(), user.getUsername(),
- operateModelNm, operateFuncNm, operateDescribe,
- new Date(), user.getIpAddress());
- }
- operateLogManager.saveOrUpdate(log);
- }
- }
- public static String getIpAddr(HttpServletRequest request) {
- String ip = request.getHeader("x-forwarded-for");
- if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
- ip = request.getHeader("Proxy-Client-IP");
- }
- if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
- ip = request.getHeader("WL-Proxy-Client-IP");
- }
- if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
- ip = request.getRemoteAddr();
- }
- return ip;
- }
- }
配置文件springmvc-servlet.xml增加
<aop:config proxy-target-class="true">
<aop:aspect id="goLogAspect" ref="AfterReturningAdvice">
<aop:pointcut id="actionPointcut" expression="execution(* com.*..*.web.*Controller.*(..))" />
<aop:before pointcut-ref="actionPointcut"
method="writeLogInfo" />
</aop:aspect>
</aop:config>
<bean id="AfterReturningAdvice" class="com.xxx.leopard.annotation.AfterReturningAdvice"></bean>
例:
/**
* 保存对象.
**/
@RequestMapping
@LogAnnotation(operateDescribe="公开策略")
public String save(final IssuePolicy issuePolicy, final String limitIpRange) throws Exception {
//
}
/**
* 开放公开策略.
*/
@RequestMapping
@LogAnnotation(operateDescribe="开放了id为%的公开策略")
public void open(final String[] ids) {
}
添加日志的方法:在需要添加日志的controller方法上面添加
传一个参数的情况用%
@LogAnnotation(operateModelNm = "模块名",operateFuncNm = "功能名",operateDescribe = "修好了id=%的套餐")
传多个参数的情况用#参数名#,实体类型前面加@ 数组类型前面加$,其他类型不加 例如#$参数名#
@LogAnnotation(operateModelNm = "模块名",operateFuncNm = "功能名",operateDescribe = "修好了id=#@role#,nwOfficeId=#nwOfficeId#的角色")
由于以上代码不能适应所有的情况,所以实际使用时还需要根据情况进行修改
利用spring实现AOP有两种方式:注解和xml文件定义。前者比较灵活,利于维护。一个小例子:
一、接口PersonService
package com.aoptest.service;
public interface PersonService
{
public void save(String name);
public void update(String name,Integer id);
public String getPersonName();
}
二、接口的实现类PersonServiceBeanpackage com.aoptest.service.impl;
import com.aoptest.service.PersonService;
public class PersonServiceBean implements PersonService
{
@Override
public String getPersonName()
{
System.out.println("我是getPersonName()方法。。。");
return "返回结果";
}
@Override
public void save(String name)
{
System.out.println("我是save()方法。。。");
throw new RuntimeException("异常了。。");
}
@Override
public void update(String name, Integer id)
{
System.out.println("我是update()方法。。。");
}
}
三、spring配置文件applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans
xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-2.5.xsd">
<aop:aspectj-autoproxy />
<bean id="myInterceptor" class="com.aoptest.service.MyInterceptor" />
<bean id="personService" class="com.aoptest.service.impl.PersonServiceBean"></bean>
</beans>
ps:
1、红色部分是引入springAOP的命名空间
2、绿色部分必须要有,声明需要AOP操作
3、蓝色部分是做测试时用
四、切面部分MyInterceptor
/**
* 切面
*/
@Aspect //声明此类为一个切面
public class MyInterceptor
{
@Pointcut("execution(* com.aoptest.service..*.*(..))")//声明一个切入点,可以拦截具体到某个方法,即在执行此方法之前、之后、最终、异常……时可以执行的其他业务方法(通知advice);括号内的意思是:拦截某个方法,返回值是所有类型(第一个*),com.aoptest.service包及其子包下的所有类(..*),类下所有的方法(第三个.*),返回值任意(内部嵌套括号(..))
//@Pointcut("execution(* com.aoptest.service.impl.PersonServiceBean.*(..))")//同上,两种都可以
private void anyMethod(){}//声明一个切入点
@Before("anyMethod() && args(name)")//声明前置通知
public void doBefore(String name){
System.out.println("前置通知");
System.out.println("---"+name+"---");//可以得到参数值,此时args(name)限制条件限定了"execution(* com.aoptest.service..*.*(..))"中只拦截参数个数只有1个且类型为String的方法,而不是所有方法(该属性在当前拦截中适用,即前置通知适用)
}
@AfterReturning(pointcut="anyMethod()",returning="result")//声明后置通知
public void doAfterReturning(String result){
System.out.println("后置通知");
System.out.println("---"+result+"---");//返回结果,同上
}
@AfterThrowing(pointcut="anyMethod()",throwing="e")//声明例外通知
public void doAfterThrowing(Exception e){
System.out.println("例外通知");
System.out.println(e.getMessage());//获取异常信息,同上
}
@After("anyMethod()")//声明最终通知
public void doAfter(){
System.out.println("最终通知");
}
@Around("anyMethod()")//声明环绕通知
public Object doAround(ProceedingJoinPoint pjp)throws Throwable
{
System.out.println("进入方法---环绕通知");
Object o = pjp.proceed();
System.out.println("退出方法---环绕通知");
return o;
}
}
五、测试部分
public class SpringAopTest
{
@Test public void interceptorTest()
{
ApplicationContext cxt = new ClassPathXmlApplicationContext("applicationContext.xml");
PersonService personService = (PersonService)cxt.getBean("personService");
personService.save("xx");
String result=personService.getPersonName();
System.out.println(result);
}
}
http://xiaojinge-ok-163-com.iteye.com/blog/908190
最近项目组长分配给我一个任务,让我完成一个操作日志的管理功能。需求是这样的:项目很大,有好几个子系统,而且这些子系统已经都在开发过程中了,都进行了大半了。现在要实现的操作日志管理是要将用户在登录系统后所做的重要操作记录下来并查询。记录的内容包括操作人的相关信息(比如:用户ID,用户名,用户IP地址,所属机构等)和所执行的操作的相关信息(比如:所属模块名称、类名、方法名、参数、是否操作成功、描述信息和错误信息)。操作日志查询功能没有什么可说的,难点是在于操作日志的记录,首先要考虑到的是日志的记录不能或要尽量少地让其他人改动自己的代码;其次要考虑到日志记录的灵活性。因此我采用了注解的方式来实现,只要将注解添加到想要记录日志的方法体上就可以实现操作日志的记录。
实现步骤如下:
第一步:启用@AspectJ支持。
在你的工程lib目录下添加aspectjweaver.jar和aspectjrt.jar并在spring 的配置文件中添加如下代码:
- <aop:aspectj-autoproxy/>
这一步就完成了@AspectJ的支持,从而可以实现通过注解方式将通知编织到非公共方法中。
第二步:编写自定义注解。实现对方法所实现的功能进行描述,以便在通知中获取描述信息,代码非常简单,如下:
- 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.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;
- }
- }
大家看上面的代码会发现这两个方法体:
- @AfterReturning("within(com.abchina.irms..*) && @annotation(rl)")
- public void addLogSuccess(JoinPoint jp, rmpfLog rl){…}
- @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对象。
- <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=”描述信息”)即可。代码如下:
- @rmpfLog(desc="创建关联交易合同")
- @Transactional
- public void insertRtcont(RtcontVO rtcontVO) throws BusinessException {
- rtcontAL.insertRtcont(toRtcontDomain(rtcontVO));
- }
- aop+自定义注解实现操作日志记录
- aop+自定义注解实现操作日志记录
- Spring AOP 自定义注解记录操作日志
- spring aop自定义注解实现日志记录
- springboot 自定义注解+AOP 实现日志记录
- Spring自定义注解+Aop记录用户操作日志
- SpringMVC利用AOP实现自定义注解记录日志
- SpringMVC利用AOP实现自定义注解记录日志
- SpringMVC利用AOP实现自定义注解记录日志
- Spring AOP实现复杂的日志记录(自定义注解)
- SpringMVC利用AOP实现自定义注解记录日志
- springMVC自定义注解,用AOP来实现日志记录
- SpringMVC利用AOP实现自定义注解记录日志
- Spring AOP自定义注解实现系统日志记录管理
- 自定义注解 Aspect 实现aop 日志记录切面编程
- SpringMVC利用AOP实现自定义注解记录日志
- SpringMVC利用AOP实现自定义注解记录日志
- SpringMVC利用AOP实现自定义注解记录日志
- android4.0activity的onConfigurationChanged方法不执行
- 注册窗口类 registerclass
- PHP 多进程实践(一)
- 逻辑电平
- 线程同步与互斥的总结
- aop+自定义注解实现操作日志记录
- Win7下安装JDK和配置环境
- hello world!
- C++中const的作用
- PHP 多进程实践(二)
- hdu1008
- epoll原理与应用详解
- Ogre环境的配置
- 数据结构读书笔记(一)(C语言)