Spring AOP 实现写事件日志功能
什么是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)
@Documented
public @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;
@Service
public 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 详解
Spring AOP 实现写事件日志功能的更多相关文章
- Spring Boot 2.X(八):Spring AOP 实现简单的日志切面
AOP 1.什么是 AOP ? AOP 的全称为 Aspect Oriented Programming,译为面向切面编程,是通过预编译方式和运行期动态代理实现核心业务逻辑之外的横切行为的统一维护的一 ...
- 利用Spring AOP自定义注解解决日志和签名校验
转载:http://www.cnblogs.com/shipengzhi/articles/2716004.html 一.需解决的问题 部分API有签名参数(signature),Passport首先 ...
- spring AOP自定义注解 实现日志管理
今天继续实现AOP,到这里我个人认为是最灵活,可扩展的方式了,就拿日志管理来说,用Spring AOP 自定义注解形式实现日志管理.废话不多说,直接开始!!! 关于配置我还是的再说一遍. 在appli ...
- (转)利用Spring AOP自定义注解解决日志和签名校验
一.需解决的问题 部分API有签名参数(signature),Passport首先对签名进行校验,校验通过才会执行实现方法. 第一种实现方式(Origin):在需要签名校验的接口里写校验的代码,例如: ...
- spring aop通过注解实现日志记录
首先是几个概念:连接点(Joinpoint).切点(Pointcut).增强(Advice).切面(Aspect) 另外也要使用到注解. 需求:通过注解定义LogEnable.然后程序运行能够识别定义 ...
- springboot—spring aop 实现系统操作日志记录存储到数据库
原文:https://www.jianshu.com/p/d0bbdf1974bd 采用方案: 使用spring 的 aop 技术切到自定义注解上,针对不同注解标志进行参数解析,记录日志 缺点是要针对 ...
- Spring AOP 切面实现操作日志
创建接口注解日志类 package com.fh.service.logAop; /** * Created by caozengling on 2018/7/21. */ import java.l ...
- spring AOP知识点总结以及日志的输出
AOP的作用就是在基于OCP在不改变原有系统核心业务代码的基础上动态添加一些扩展功能.通常应用于日志的处理,事务处理,权限处理,缓存处理等等 首先,使用AOP需要添加的依赖有:spring-conte ...
- 采用Spring AOP+Log4j记录项目日志
转载请注明出处:http://www.cnblogs.com/Joanna-Yan/p/6567672.html 项目日志记录是项目开发.运营必不可少的内容,有了它可以对系统有整体的把控,出现任何问题 ...
随机推荐
- C# JavaScriptSerializer 解析Json数据(多方法解析Json 三)
准备工作: 1.添加引用System.Web.Extensions, 2..net3.5+版本都有,如果VS2010找不到,在这个文件夹找:C:\Program Files\Reference Ass ...
- ARM2440换lcd
将原来的3.5寸分辨率为240x320换为480x272所需要修改的地方 时序设置: CLKVAL=4 (VCLK =10) 5< VCLK <12 每个点扫描周期 ...
- HDU 3377 插头dp
题目大意: 从左上角走到右下角,每个点之多经过一次,取到所有路径上经过点的权值,求最大的权值之和,这里走到右下角就算停止了 这里有个思路是转化成熟悉的回路问题 在上方和右方最外围定义一圈权值为0 , ...
- Mac运行exe的几种方法,欢迎补充!
1. 用wine直接运行exe.安装wine后有个放exe的文件夹,双击后会自动包装运行.看起来挺方便的,就怕暂用资源比较大: http://www.youtube.com/watch?v=eYISV ...
- cf--1C
//Accepted 0 KB 60 ms //给出正多变形上的三个点,求正多形的最小面积 //记三个点之间的距离a,b,c; //由余弦定理得cosA //从而可求出sinA,和正多边形所在外接圆的 ...
- Ogre 1.8 terrain 和 paging 组件
以下转自:http://hi.baidu.com/xocoder/item/e8d87cf53d87612b753c4cfd OGRE地形生成 OGRE可以通过两个接口来生成地形,分别是void Te ...
- android unique identifier
android get device mac address programmatically http://android-developers.blogspot.jp/2011/03/identi ...
- Chapter 3: Connector(连接器)
一.概述 Tomcat或者称之为Catalina(开发名称),可以简化为两个主要的模块,如下图: 多个Connector关联一个Container.之所以需要多个Connector,是为了处理多种协议 ...
- eclipse GIT使用
新建工程(要和GIT上同名,同类型)->右键->team->add to index->commit->更新config文件->remote: fetch from ...
- Android之Activity与Service通信
一.当Acitivity和Service处于同一个Application和进程时,通过继承Binder类来实现. 当一个Activity绑定到一个Service上时,它负责维护Service实例的引用 ...