一:

spring-mvc.xml:

<!--配置日志切面 start,必须与mvc配置在同一个配置文件,否则无法切入Controller层-->
<!-- 声明自动为spring容器中配置@aspectj切面的bean创建代理 ,织入切面 -->
<context:component-scan base-package="org.jeecgframework.core.aop" />
<aop:aspectj-autoproxy />
<aop:config proxy-target-class="true"></aop:config>
<!--配置日志切面 end-->  二:
LoginLog.java:
import java.lang.annotation.*;

/**
* <ul>
* <li>使用运行时参数值(用法:1-->#p{下标} 2-->#{形参名称.属性名} 3-->${形参名称.属性名})</li>
* <li>第一种适合参数为基本类型或String</li>
* <li>第二种适合参数为实体类</li>
* <li>第三种适合参数为实体类List集合,会将属性按照","隔开再返回</li>
* <li>备注:</li>
* <li>需要多个值用","隔开,前后可加说明性文字,举例:</li>
* <li>@AdminLog(module = "更新#p{0}模块",content = "更新地址:#{bcContact.address}完毕,电话:${bcContactSubList.phone}完毕")
* </li>
* <li>
public void updateMain(String test,BcContactEntity bcContact,
List<BcContactSubEntity> bcContactSubList)</li>
<li>module结果-->更新测试模块,content结果-->更新地址:****完毕,电话:***,***完毕</li>
* <ul/>
*/
@Retention(RetentionPolicy.RUNTIME) //注解会在class中存在,运行时可通过反射获取
@Target(ElementType.METHOD) //注解到方法
@Documented //注解包含在javadoc中
@Inherited //注解可以被继承
public @interface LoginLog {
/** 登录时长 */
String time() default ""; /** 登录类型 */
String type() default ""; } 三:
LoginLogAspect.java:
import com.aiitec.log.entity.BcLoginLogEntity;
import com.aiitec.log.service.BcLoginLogServiceI;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.jeecgframework.core.annotation.LoginLog;
import org.jeecgframework.core.util.AspectUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; import java.lang.reflect.Method; @Aspect
@Component
public class LoginLogAspect {
@Autowired
private BcLoginLogServiceI bcLoginLogServiceI;
private static final Logger log = LoggerFactory.getLogger(LoginLogAspect.class); // 配置织入点
@Pointcut("@annotation(org.jeecgframework.core.annotation.LoginLog)")
public void logPointCut() {
} /**
* 前置通知 用于拦截操作,在方法返回后执行
* @param joinPoint 切点
*/
@AfterReturning(pointcut = "logPointCut()")
public void doAfter(JoinPoint joinPoint) {
handleLog(joinPoint,null);
} /**
* 拦截异常操作,有异常时执行
*
* @param joinPoint
* @param e
*/
@AfterThrowing(value = "logPointCut()", throwing = "e")
public void doAfter(JoinPoint joinPoint, Exception e) {
handleLog(joinPoint, e);
} private void handleLog(JoinPoint joinPoint,Exception e) {
try {
// 获得注解
LoginLog controllerLog = getAnnotationLog(joinPoint);
if (controllerLog == null) {
return;
}
// 获得方法名称
String className = joinPoint.getTarget().getClass().getName();
String methodName = joinPoint.getSignature().getName();
String type = controllerLog.type();
String time = controllerLog.time();
//打印日志,如有需要还可以存入数据库
log.info(">>>>>>>>>>>>>模块名称:{}",time);
log.info(">>>>>>>>>>>>>操作名称:{}",type);
log.info(">>>>>>>>>>>>>类名:{}",className);
log.info(">>>>>>>>>>>>>方法名:{}",methodName);
//获取所有的参数
Object[] args = joinPoint.getArgs();
String resultTime = AspectUtil.getAttributeValue(className,methodName,args,time);
String resultType = AspectUtil.getAttributeValue(className,methodName,args,type); log.info(">>>>>>>>>>>>>属性值:{}",resultTime);
//保存登录日志信息到数据库
BcLoginLogEntity bcLoginLogEntity=new BcLoginLogEntity();
bcLoginLogEntity.setContent(resultType+","+resultTime);
bcLoginLogEntity.setLoginType(0);
bcLoginLogEntity.setLoginTime(3600);
bcLoginLogServiceI.save(bcLoginLogEntity);
} catch (Exception exp) {
// 记录本地异常日志
log.error("==登录日志后置通知异常==");
log.error("异常信息:{}", exp.getMessage());
exp.printStackTrace();
}
} /**
* 是否存在注解,如果存在就获取
*/
private static LoginLog getAnnotationLog(JoinPoint joinPoint) throws Exception {
Signature signature = joinPoint.getSignature();
MethodSignature methodSignature = (MethodSignature) signature;
Method method = methodSignature.getMethod();
if (method != null) {
return method.getAnnotation(LoginLog.class);
}
return null;
} } 四:
AspectUtil.java
import org.apache.commons.lang.StringUtils;
import org.springframework.core.DefaultParameterNameDiscoverer;
import org.springframework.core.ParameterNameDiscoverer; import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap; public class AspectUtil {
/**
* 判断是否为实体类使用
*/
public final static HashMap<String, Class> IS_ENTITY_MAP = new HashMap<String, Class>() {
{
put("java.lang.Integer", int.class);
put("java.lang.Double", double.class);
put("java.lang.Float", float.class);
put("java.lang.Long", long.class);
put("java.lang.Short", short.class);
put("java.lang.Boolean", boolean.class);
put("java.lang.Char", char.class);
}
};
/**
* 解析实体类,获取实体类中的属性
* @param obj
* @param arg
* @return
*/
public static String getFieldsValue(Object obj,String arg) {
//通过反射获取所有的字段,getFileds()获取public的修饰的字段
//getDeclaredFields获取private protected public修饰的字段
Field[] fields = obj.getClass().getDeclaredFields();
StringBuilder sb = new StringBuilder();
for (Field f : fields) {
//在反射时能访问私有变量
f.setAccessible(true);
try {
if (f.get(obj)!=null){
if(arg.equals(f.getName())){//找到对应属性
sb.append(f.get(obj) + "");//取值
}
}
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
return sb.toString();
} /**
* 获取指定参数的值
* @param className 类名
* @param methodName 方法名
* @param args 参数数组
* @param key 自定义字段(用法:1-->#p{下标} 2-->#{形参名称.属性名} 3-->${形参名称.属性名})
* <ul>
* <li>第一种适合参数为基本类型或String</li>
* <li>第二种适合参数为实体类</li>
* <li>第三种适合参数为实体类List集合,会将属性按照","隔开再返回</li>
* <ul/>
* @return
* @throws ClassNotFoundException
* @throws NoSuchMethodException
*/
public static String getAttributeValue(String className,String methodName,Object[] args,String key) throws ClassNotFoundException, NoSuchMethodException {
Class<?>[] classes = new Class[args.length];
for (int k = 0; k < args.length; k++) {
if (!args[k].getClass().isPrimitive()) {
//获取的是封装类型而不是基础类型
String result = args[k].getClass().getName();
Class s = IS_ENTITY_MAP.get(result);
if (result.equals("java.util.ArrayList")){//如果是ArrayList替换为List,否则找不到该方法(因为方法声明为List,传入的是ArrayList)
classes[k] = Class.forName("java.util.List");
}else{
classes[k] = s == null ? args[k].getClass() : s;
}
}
}
ParameterNameDiscoverer pnd = new DefaultParameterNameDiscoverer();
//获取指定的方法,第二个参数可以不传,但是为了防止有重载的现象,还是需要传入参数的类型
Method method = Class.forName(className).getMethod(methodName, classes);
String[] parameterNames = pnd.getParameterNames(method); StringBuffer sb=new StringBuffer();
if (StringUtils.isNotBlank(key)){
String[] vars=key.split(",");
for(String var:vars){
if(var.indexOf("#p")>-1){//包含#p
String index = var.substring(var.indexOf("{") + 1,var.indexOf("}"));
sb.append(var.replaceAll("#p\\{.*\\}",args[Integer.valueOf(index)]+"")+",");//通过注解属性值中的"#p[n]"n的值,确定参数下标,获取参数值 }else if(var.indexOf("#")>-1){//包含# String paramName= var.substring(var.indexOf("{")+1,var.indexOf("."));//参数名
int index= Arrays.asList(parameterNames).indexOf(paramName);//参数下标
String temp=getFieldsValue(args[index],var.substring(var.indexOf(".")+1,var.indexOf("}")));//传入参数对象和属性名
sb.append(var.replaceAll("#\\{.*\\}",temp)+",");
}else if(var.indexOf("$")>-1){//包含$
String paramName= var.substring(var.indexOf("{")+1,var.indexOf("."));//参数名
String attrName=var.substring(var.indexOf(".")+1,var.indexOf("}"));//属性名
int index=Arrays.asList(parameterNames).indexOf(paramName);//参数下标
final ArrayList argList = (ArrayList<?>) args[index];
StringBuffer temp=new StringBuffer();
for (Object o : argList) {
String keys=getFieldsValue(o,attrName);
temp.append(keys+",");
}
if(temp.length()>0){
if (',' == temp.charAt(temp.length() - 1)){
temp.deleteCharAt(temp.length() - 1);//去掉最后一个","
}
}
sb.append(var.replaceAll("\\$\\{.*\\}",temp.toString())+",");
}else{//普通字符串
sb.append(var+",");
}
}
if(sb.length()>0){
if (',' == sb.charAt(sb.length() - 1)){
sb.deleteCharAt(sb.length() - 1);//去掉最后一个","
}
}
} return sb.toString();
}
}
 

Spring自定义注解配置切面实现日志记录的更多相关文章

  1. springboot aop 自定义注解方式实现完善日志记录(完整源码)

    版权声明:本文为博主原创文章,欢迎转载,转载请注明作者.原文超链接 一:功能简介 本文主要记录如何使用aop切面的方式来实现日志记录功能. 主要记录的信息有: 操作人,方法名,参数,运行时间,操作类型 ...

  2. 010-Spring aop 001-核心说明-拦截指定类与方法、基于自定义注解的切面

    一.概述 面向切面编程(AOP)是针对面向对象编程(OOP)的补充,可以非侵入式的为多个不具有继承关系的对象引入相同的公共行为例如日志.安全.事务.性能监控等等.SpringAOP允许将公共行为从业务 ...

  3. SpringAop切面实现日志记录

    SpringAop切面实现日志记录代码实现:https://www.cnblogs.com/wenjunwei/p/9639909.html 问题记录 1.signature.getMethod(). ...

  4. 自定义注解结合切面和spel表达式

    在我们的实际开发中可能存在这么一种情况,当方法参数中的某些条件成立的时候,需要执行一些逻辑处理,比如输出日志.而这些代码可能都是差不多的,那么这个时候就可以结合自定义注解加上切面加上spel表达式进行 ...

  5. JavaWeb_(Spring框架)注解配置

    系列博文 JavaWeb_(Spring框架)xml配置文件  传送门 JavaWeb_(Spring框架)注解配置 传送门 Spring注解配置 a)导包和约束:基本包.aop包+context约束 ...

  6. spring自定义注解实现登陆拦截器

    1.spring自定义注解实现登陆拦截器 原理:定义一个注解和一个拦截器,拦截器拦截所有方法请求,判断该方法有没有该注解.没有,放行:有,要进行验证.从而实现方法加注解就需要验证是否登陆. 2.自定义 ...

  7. Spring 自定义注解,配置简单日志注解

    java在jdk1.5中引入了注解,spring框架也正好把java注解发挥得淋漓尽致. 下面会讲解Spring中自定义注解的简单流程,其中会涉及到spring框架中的AOP(面向切面编程)相关概念. ...

  8. Spring 自定义注解,结合AOP,配置简单日志注解 (转)

    java在jdk1.5中引入了注解,spring框架也正好把java注解发挥得淋漓尽致. 下面会讲解Spring中自定义注解的简单流程,其中会涉及到spring框架中的AOP(面向切面编程)相关概念. ...

  9. Spring AOP中使用@Aspect注解 面向切面实现日志横切功能详解

    引言: AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术.AOP是OOP的延续,是软件开发中的一 ...

随机推荐

  1. multiset的应用

    multiset 和set差不多 ,但是可以存储多个一样的元素

  2. Object detection with deep learning and OpenCV

    目录 Single Shot Detectors for Object Detection Deep learning-based object detection with OpenCV   这篇文 ...

  3. go语言实战教程之管理员查询功能、退出功能

    前面第10节课内容中已经学习开发完成了管理员登陆功能.本节课我们将继续学习开发完成管理员信息查询功能.管理员退出功能 管理员信息查询功能 请求及路由映射 管理员信息查询接口 接口名称:获取管理员信息. ...

  4. C语言和sh脚本的杂交代码

    在网上看到了一个把 C语言和bash杂并起来的例子,这个示子如下所示.在下面这个例子中,我们把脚本用#if 0这个预编译给起来,这样就不会让其编译到C语言中了. #if 0 echo "He ...

  5. hdu1403(后缀数组模板)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1403 题意: 给出两个字符串, 求他们的最长公共子串 思路: 两个字符串的最长公共子串长度显然就是两个 ...

  6. Flask 程序的基本结构

    1.初始化 所有Flask程序都必须创建一个程序实例.web服务器使用一种名为Web服务器网关借口的协议,把接收自客户端的所有请求都转交给这个对象处理. from flask import Flask ...

  7. Eclipse导入GitHub项目两处报错处理

    1.项目出现Could not calculate build plan:pligin 错误解决办法: 删除本地.m2仓库中 org.apache.maven.plugins:maven-resour ...

  8. The requested profile "account" could not be activated because it does not exist 无法maven install的 解决办法,勾选红框选择的选项即可

  9. Hibernate上传数据到数据库,从数据库读取数据到本地模板代码

    1.Hibernate上传数据到数据库: //创建一个session对象 Session session1=HibernateTools.getSession(); //Fenciresult数据库表 ...

  10. Python内置函数、作用域、闭包、递归

    1.几个可能用到的内置函数 2.函数内变量的作用域 3.内嵌函数和闭包 4.递归函数 1.常见的内置函数 常见的内置函数:    查看内置函数:        print(dir(__builtins ...