什么是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. 二模 (11) day1

    第一题: 题目大意:用邻接矩阵给出一棵树(边权非负)上N个节点相互之间的最短路距离,求这棵树所有边权的和. 解题过程: 1.暂时还没想出来,待AC. 第二题: 题目大意:给出一些单词,然后建立Trie ...

  2. PhpStorm WebMatrix xDebug 配置开发环境

    1.首先下载WebMatrix安装程序,下载地址 http://www.microsoft.com/web/webmatrix/  安装步骤 参考:http://www.jb51.net/softjc ...

  3. mac 安装memcached服务

    使用homebrew安装,homebrew安装方法http://brew.sh/ 安装memcached服务 brew install memcached 配置开机启动(用brew安装之后下面会提示怎 ...

  4. js字符转换成整型 parseInt()函数规程Number()函数

    今天在做一个js加法的时候,忘记将字符转换成整型,导致将加号认为是连接符,  在运算前要先对字符井行类型转换,使用parseInt()函数   使用Number()将字符转换成int型效果更好

  5. C# WinForm程序向datagridview里添加数据

    在C#开发的winform程序中,datagridview是一个经常使用到的控件.它可以以类似excel表格的形式规范的展示或操作数据,我也经常使用这个控件.使用这个控件首先要掌握的就是如何向其中插入 ...

  6. C++全局变量的声明和定义

    (1)编译单元(模块)     在VC或VS上编写完代码,点击编译按钮准备生成exe文件时,编译器做了两步工作: 第一步,将每个.cpp(.c)和相应的.h文件编译成obj文件: 第二步,将工程中所有 ...

  7. [安卓]AndroidManifest.xml文件简介及结构

    1.AndroidManifest.xml文件简介: 每个应用程序在它的根目录中都必须要有一个AndroidManifest.xml(名字须精确一致)文件.这个清单把应用程序的基本信息提交给Andro ...

  8. 项目管理软件---redmine安装配置

    redmine是一个开源的项目管理软件,其主页是:http://www.redmine.org redmine是基于Ruby on Rails框架的,跨平台和跨数据库. 安装过程 ========== ...

  9. Interview---一道有趣的推理题

    题目描述: 一个岛上有100个人,他们的眼睛只有两种颜色,蓝色和红色.95个人是黑色,其余5人是红色. 他们有个宗教信仰,从不照镜子,所以他们自己不知道自己的眼睛的颜色.但是能看到其他人的眼睛. 他们 ...

  10. 爬虫再探实战(五)———爬取APP数据——超级课程表【四】——情感分析

    仔细看的话,会发现之前的词频分析并没有什么卵用...文本分析真正的大哥是NLP,不过,这个坑太大,小白不大敢跳...不过还是忍不住在坑边上往下瞅瞅2333. 言归正传,今天刚了解到boson公司有py ...