什么是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 实现写事件日志功能的更多相关文章

  1. Spring Boot 2.X(八):Spring AOP 实现简单的日志切面

    AOP 1.什么是 AOP ? AOP 的全称为 Aspect Oriented Programming,译为面向切面编程,是通过预编译方式和运行期动态代理实现核心业务逻辑之外的横切行为的统一维护的一 ...

  2. 利用Spring AOP自定义注解解决日志和签名校验

    转载:http://www.cnblogs.com/shipengzhi/articles/2716004.html 一.需解决的问题 部分API有签名参数(signature),Passport首先 ...

  3. spring AOP自定义注解 实现日志管理

    今天继续实现AOP,到这里我个人认为是最灵活,可扩展的方式了,就拿日志管理来说,用Spring AOP 自定义注解形式实现日志管理.废话不多说,直接开始!!! 关于配置我还是的再说一遍. 在appli ...

  4. (转)利用Spring AOP自定义注解解决日志和签名校验

    一.需解决的问题 部分API有签名参数(signature),Passport首先对签名进行校验,校验通过才会执行实现方法. 第一种实现方式(Origin):在需要签名校验的接口里写校验的代码,例如: ...

  5. spring aop通过注解实现日志记录

    首先是几个概念:连接点(Joinpoint).切点(Pointcut).增强(Advice).切面(Aspect) 另外也要使用到注解. 需求:通过注解定义LogEnable.然后程序运行能够识别定义 ...

  6. springboot—spring aop 实现系统操作日志记录存储到数据库

    原文:https://www.jianshu.com/p/d0bbdf1974bd 采用方案: 使用spring 的 aop 技术切到自定义注解上,针对不同注解标志进行参数解析,记录日志 缺点是要针对 ...

  7. Spring AOP 切面实现操作日志

    创建接口注解日志类 package com.fh.service.logAop; /** * Created by caozengling on 2018/7/21. */ import java.l ...

  8. spring AOP知识点总结以及日志的输出

    AOP的作用就是在基于OCP在不改变原有系统核心业务代码的基础上动态添加一些扩展功能.通常应用于日志的处理,事务处理,权限处理,缓存处理等等 首先,使用AOP需要添加的依赖有:spring-conte ...

  9. 采用Spring AOP+Log4j记录项目日志

    转载请注明出处:http://www.cnblogs.com/Joanna-Yan/p/6567672.html 项目日志记录是项目开发.运营必不可少的内容,有了它可以对系统有整体的把控,出现任何问题 ...

随机推荐

  1. 文件浏览器及数码相框 -2.3.2-freetype_arm-1

    交叉编译:tar xjf freetype-2.4.10.tar.bz2 ./configure --host=arm-linuxmakemake DESTDIR=$PWD/tmp install f ...

  2. visualsvn server 安装提示无法启动

    需要在服务里面给visualsvn server 用本地账户登陆权限

  3. 在oracle中使用Trigger

    1.初始目标 在对表h1插入一条数据时,同时插入一条重复的数据(只有主键不同) 2.在PL/SQL里New一个Trigger或者手动敲入代码 先说明一下,表h1包括4列ID.C1.C2.C3 crea ...

  4. SharePoint加K2,将Portal系统与BPM系统完美整合!

    K2 blackPearl与Microsoft Office SharePoint 一起为解决人员和流程相互合作的解决方案而提供一个强大的平台. K2“blackpearl”根据企业的需求提供了设计, ...

  5. 微软发布Windows Phone 8.1 Update 和中文版Cortana“小娜”

    Windows Phone 8.1 尚在推送进程中,它的第一个 GDR 更新就发布了.今天微软正式发布 Windows Phone 8.1 Update 和中文版 Cortana ——“小娜”. Wi ...

  6. IIS 6.0 401 错误

    1.错误号401.1 症状:HTTP 错误 401.1 - 未经授权:访问由于凭据无效被拒绝 分析:  由于用户匿名访问使用的账号(默认是IUSR_机器名)被禁用,或者没有权限访问计算机,将造成用户无 ...

  7. Linux信号(signal) 机制分析

    Linux信号(signal) 机制分析 [摘要]本文分析了Linux内核对于信号的实现机制和应用层的相关处理.首先介绍了软中断信号的本质及信号的两种不同分类方法尤其是不可靠信号的原理.接着分析了内核 ...

  8. (spring-第14回【IoC基础篇】)国际化信息

    国际化又称为本地化. 当你把手机的language由中文切换到英文时,你的微信也相应改用英语,这就是i18n国际化.一般来说,应用软件提供一套不同语言的资源文件,放到特定目录中,应用根据不同语言的操作 ...

  9. (spring-第7回【IoC基础篇】)BeanDefinition的载入与解析&&spring.schemas、spring.handlers的使用

    报错信息:Configuration problem: Unable to locate Spring NamespaceHandler for XML schema namespace [http: ...

  10. Java中接口作为方法的返回

    在<算法>中的散列表一节,在用拉链法实现散列表的API时要求实现以下一个方法: public Iterable<Key> keys() 我们知道Iterable是一个接口,那么 ...