Spring AOP 实现写事件日志功能
来源:互联网 发布:虚拟充值软件 编辑:程序博客网 时间:2024/05/21 18:33
什么是AOP?AOP使用场景?AOP相关概念?Spring AOP组件?如何使用Spring AOP?等等这些问题请参考博文:Spring AOP 实现原理
下面重点介绍如何写事件日志功能,把日志保存到数据库中。
事件日志是与主业务功能无关的逻辑,用AOP实现是再好不过了,其中因为有些数据库日志表中的字段参数需要传递,所以会用到自定义注解,将这些参数用自定义注解传递过来。
1.自定义注解Operation
package com.jykj.demo.filter;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;/** * @Descrption该注解描述方法的操作类型和方法的参数意义 */@Target(value = ElementType.METHOD)@Retention(value = RetentionPolicy.RUNTIME)@Documentedpublic @interface Operation { /** * @Description描述操作类型 为必填项,1:登录日志2:操作日志 */ int type(); /** * @Description描述操作意义 比如申报通过或者不通过等 */ String desc() default ""; /** * @Description描述操作方法的参数意义 数组长度需与参数长度一致,否则会参数与描述不一致的情况 */ String[] arguDesc() default {};}
2.切面类EventLogAspect
package com.jykj.demo.filter;import java.lang.reflect.Method;import org.aspectj.lang.JoinPoint;import org.aspectj.lang.reflect.MethodSignature;import org.springframework.beans.factory.annotation.Autowired;import com.jykj.demo.service.SysEventService;//事件日志 切面,凡是带有 @Operation 注解的service方法都将会写日志public class EventLogAspect { @Autowired SysEventService sysEventService; public void doAfterReturning(JoinPoint jp) { System.out.println( "log Ending method: " + jp.getTarget().getClass().getName() + "." + jp.getSignature().getName()); Method proxyMethod = ((MethodSignature) jp.getSignature()).getMethod(); Method soruceMethod; try { soruceMethod = jp.getTarget().getClass().getMethod(proxyMethod.getName(), proxyMethod.getParameterTypes()); Operation oper = soruceMethod.getAnnotation(Operation.class); if (oper != null) { System.out.println(oper.desc()); // 解析参数 sysEventService.insertEventLog(oper.type(),oper.desc()+"("+extractParam(jp.getArgs(),oper.arguDesc())+") 成功"); } } catch (NoSuchMethodException e) { e.printStackTrace(); } catch (SecurityException e) { e.printStackTrace(); }catch (Exception e) { e.printStackTrace(); } } public void doAfterThrowing(JoinPoint jp, Throwable ex) { Method proxyMethod = ((MethodSignature) jp.getSignature()).getMethod(); Method soruceMethod; try { soruceMethod = jp.getTarget().getClass().getMethod(proxyMethod.getName(), proxyMethod.getParameterTypes()); Operation oper = soruceMethod.getAnnotation(Operation.class); if (oper != null) { System.out.println(oper.desc()); sysEventService.insertEventLog(oper.type(),oper.desc()+ "("+extractParam(jp.getArgs(),oper.arguDesc())+" 出现异常:"+ex.getMessage()); } } catch (NoSuchMethodException e) { e.printStackTrace(); } catch (SecurityException e) { e.printStackTrace(); } } private String extractParam(Object[] objParam, String[] arguDesc) { StringBuilder sb = new StringBuilder(); int len = objParam.length<arguDesc.length?objParam.length:arguDesc.length;//取最小值 for (int i = 0; i < len; i++) { //空字符串将不解析 if(arguDesc[i]!=null && !arguDesc[i].isEmpty()){ sb.append(arguDesc[i]+":"+objParam[i]+","); } } String rs = sb.toString(); return rs.substring(0,rs.length()-1); }}
3.切入点 主业务逻辑类FrmAppsService
package com.jykj.demo.service;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Service;import com.jykj.demo.dao.FrmAppsMapper;import com.jykj.demo.entity.FrmApps;import com.jykj.demo.filter.Operation;import com.jykj.demo.mapper.AbstractService;@Servicepublic class FrmAppsService { @Autowired FrmAppsMapper mapper; @Operation(type=1,desc="更新框架应用",arguDesc={"","操作类型"}) public int access(FrmApps app,String action){ return mapper.access(app,action); }}
4.Spring xml对AOP的配置
<bean id="aspectEventLog" class="com.jykj.demo.filter.EventLogAspect" /> <!-- <aop:aspectj-autoproxy /> --> <!--配置service包下所有类或接口的所有方法--> <aop:config proxy-target-class="true"> <aop:aspect id="EventLogAspect" ref="aspectEventLog"> <aop:pointcut id="myService" expression="execution(* com.jykj.demo.service.*.*(..)) " /> <aop:after-returning pointcut-ref="myService" method="doAfterReturning"/> <aop:after-throwing pointcut-ref="myService" method="doAfterThrowing" throwing="ex"/> </aop:aspect> </aop:config> <!-- 控制器 --> <context:component-scan base-package="com.jykj.demo.controller" /> <!-- service --> <context:component-scan base-package="com.jykj.demo.service" /> <context:component-scan base-package="com.jykj.demo.filter" />
需要注意的是 proxy-target-class=”true” ,如果没有这个,目标类若是实现了接口,将会以JDK代理的方式,否则采用的是CGLib代理的方式,如果启动项目报错了,会报代理类无法转换的问题,这时候把这个配置写上就可以了。
这样就实现了写日志的功能,只要在需要写日志的service类的方法上用自定义注解Operation注解即可
5.输出 (编辑一个记录时)
log Ending method: com.jykj.demo.service.FrmAppsService.access更新框架应用log Ending method: com.jykj.demo.service.SysEventService.insertEventLog
另外再附加 在未登录时禁止访问页面的功能 采用拦截器
SecurityInterceptor类
package com.jykj.demo.filter;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import javax.servlet.http.HttpSession;import org.springframework.web.servlet.HandlerInterceptor;import org.springframework.web.servlet.ModelAndView;import com.jykj.demo.util.Helper;public class SecurityInterceptor implements HandlerInterceptor{ @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { HttpSession session = request.getSession(); if (session.getAttribute(Helper.SESSION_USER) == null) { throw new AuthorizationException(); } else { return true; } } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { // TODO Auto-generated method stub } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { // TODO Auto-generated method stub }}
对应的拦截器的配置 spring-mvc.xml
<mvc:interceptors> <mvc:interceptor> <mvc:mapping path="/*"/> <mvc:exclude-mapping path="/login"/> <mvc:exclude-mapping path="/signIn"/> <mvc:exclude-mapping path="/register"/> <bean class="com.jykj.demo.filter.SecurityInterceptor"> </bean> </mvc:interceptor> </mvc:interceptors> <!-- bean 处理未登录重定向到登录界面 --> <bean id="handlerExceptionResolver" class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver"> <property name="exceptionMappings"> <props> <prop key="com.jykj.demo.filter.AuthorizationException">redirect:login</prop> </props> </property> </bean>
异常类AuthorizationException
package com.jykj.demo.filter;public class AuthorizationException extends Exception{ private static final long serialVersionUID = 1L;}
参考博文:Spring Aop 日志拦截应用
参考博文:基于配置的Spring AOP
参考博文:Spring AOP 详解
0 0
- Spring AOP 实现写事件日志功能
- spring aop实现日志功能
- spring aop写日志
- 不使用spring的aop功能实现日志输出
- spring aop 实现用户操作日志记录功能
- 关于Spring Aop,日志功能简单的实现
- 在Spring中使用AOP实现日志功能
- Spring 实现AOP功能
- Spring AOP实现日志记录
- Spring -aop 实现系统日志
- Spring AOP实现日志记录
- Spring AOP实现日志管理
- spring aop实现日志管理
- spring AOP的 操作日志记录功能
- 利用spring AOP功能进行日志管理
- 采用Spring实现AOP功能
- Spring AOP 实现功能权限校验功能
- Spring AOP 实现功能权限校验功能
- SparkR环境搭建
- scala隐式参数(implicit)
- 7-1什么是对象 Date
- How to Interactively Create a Docker Container
- LibUSB-Win32
- Spring AOP 实现写事件日志功能
- iOS 基础篇12- 定时器的使用
- linux脚本 运行java程序引入jar
- spark内核揭秘-spark任务调度系统
- 创建一个上线web需要的思考问题(一)
- libusb的使用教程和例子
- 液压阀工作原理及动画
- 出现( linker command failed with exit code 1)错误总结
- java程序命令行运行——札记