spring AOP自定义注解方式实现日志管理

时间:2022-12-28 19:54:57

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

关于配置我还是的再说一遍。

在applicationContext-mvc.xml中要添加的

<mvc:annotation-driven />
     <!-- 激活组件扫描功能,在包com.gcx及其子包下面自动扫描通过注解配置的组件 -->
     <context:component-scan base-package="com.gcx" />

<!-- 启动对@AspectJ注解的支持 -->
     <!-- proxy-target-class等于true是强制使用cglib代理,proxy-target-class默认是false,如果你的类实现了接口 就走JDK代理,如果没有,走cglib代理  -->
     <!-- 注:对于单利模式建议使用cglib代理,虽然JDK动态代理比cglib代理速度快,但性能不如cglib -->

<!--如果不写proxy-target-class="true"这句话也没问题-->
     <aop:aspectj-autoproxy proxy-target-class="true"/>

<!--切面-->
     <bean id="systemLogAspect" class="com.gcx.annotation.SystemLogAspect"></bean>

接下来开始编写代码。

创建日志类实体

 public class SystemLog {
private String id; private String description; private String method; private Long logType; private String requestIp; private String exceptioncode; private String exceptionDetail; private String params; private String createBy; private Date createDate; public String getId() {
return id;
} public void setId(String id) {
this.id = id == null ? null : id.trim();
} public String getDescription() {
return description;
} public void setDescription(String description) {
this.description = description == null ? null : description.trim();
} public String getMethod() {
return method;
} public void setMethod(String method) {
this.method = method == null ? null : method.trim();
} public Long getLogType() {
return logType;
} public void setLogType(Long logType) {
this.logType = logType;
} public String getRequestIp() {
return requestIp;
} public void setRequestIp(String requestIp) {
this.requestIp = requestIp == null ? null : requestIp.trim();
} public String getExceptioncode() {
return exceptioncode;
} public void setExceptioncode(String exceptioncode) {
this.exceptioncode = exceptioncode == null ? null : exceptioncode.trim();
} public String getExceptionDetail() {
return exceptionDetail;
} public void setExceptionDetail(String exceptionDetail) {
this.exceptionDetail = exceptionDetail == null ? null : exceptionDetail.trim();
} public String getParams() {
return params;
} public void setParams(String params) {
this.params = params == null ? null : params.trim();
} public String getCreateBy() {
return createBy;
} public void setCreateBy(String createBy) {
this.createBy = createBy == null ? null : createBy.trim();
} public Date getCreateDate() {
return createDate;
} public void setCreateDate(Date createDate) {
this.createDate = createDate;
}
}

编写dao接口

 package com.gcx.dao;

 import com.gcx.entity.SystemLog;

 public interface SystemLogMapper {
int deleteByPrimaryKey(String id); int insert(SystemLog record); int insertSelective(SystemLog record); SystemLog selectByPrimaryKey(String id); int updateByPrimaryKeySelective(SystemLog record); int updateByPrimaryKey(SystemLog record);
}

编写service层

 package com.gcx.service;

 import com.gcx.entity.SystemLog;

 public interface SystemLogService {

     int deleteSystemLog(String id);

     int insert(SystemLog record);

     int insertTest(SystemLog record);

     SystemLog selectSystemLog(String id);

     int updateSystemLog(SystemLog record);
}

编写service实现类serviceImpl

 package com.gcx.service.impl;

 import javax.annotation.Resource;

 import org.springframework.stereotype.Service;

 import com.gcx.annotation.Log;
import com.gcx.dao.SystemLogMapper;
import com.gcx.entity.SystemLog;
import com.gcx.service.SystemLogService; @Service("systemLogService")
public class SystemLogServiceImpl implements SystemLogService { @Resource
private SystemLogMapper systemLogMapper; @Override
public int deleteSystemLog(String id) { return systemLogMapper.deleteByPrimaryKey(id);
} @Override public int insert(SystemLog record) { return systemLogMapper.insertSelective(record);
} @Override
public SystemLog selectSystemLog(String id) { return systemLogMapper.selectByPrimaryKey(id);
} @Override
public int updateSystemLog(SystemLog record) { return systemLogMapper.updateByPrimaryKeySelective(record);
} @Override
public int insertTest(SystemLog record) { return systemLogMapper.insert(record);
} }

到这里基本程序编写完毕

下面开始自定义注解

 package com.gcx.annotation;

 import java.lang.annotation.*;

 @Target({ElementType.PARAMETER, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Log { /** 要执行的操作类型比如:add操作 **/
public String operationType() default ""; /** 要执行的具体操作比如:添加用户 **/
public String operationName() default "";
}

下面编写切面

 package com.gcx.annotation;

 import java.lang.reflect.Method;
import java.util.Date;
import java.util.UUID; import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession; import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component; import com.gcx.entity.SystemLog;
import com.gcx.entity.User;
import com.gcx.service.SystemLogService;
import com.gcx.util.JsonUtil; /**
* @author 杨建
* @E-mail: email
* @version 创建时间:2015-10-19 下午4:29:05
* @desc 切点类
*/ @Aspect
@Component
public class SystemLogAspect { //注入Service用于把日志保存数据库
@Resource //这里我用resource注解,一般用的是@Autowired,他们的区别如有时间我会在后面的博客中来写
private SystemLogService systemLogService; private static final Logger logger = LoggerFactory.getLogger(SystemLogAspect. class); //Controller层切点
@Pointcut("execution (* com.gcx.controller..*.*(..))")
public void controllerAspect() {
} /**
* 前置通知 用于拦截Controller层记录用户的操作
*
* @param joinPoint 切点
*/
@Before("controllerAspect()")
public void doBefore(JoinPoint joinPoint) {
System.out.println("==========执行controller前置通知===============");
if(logger.isInfoEnabled()){
logger.info("before " + joinPoint);
}
} //配置controller环绕通知,使用在方法aspect()上注册的切入点
@Around("controllerAspect()")
public void around(JoinPoint joinPoint){
System.out.println("==========开始执行controller环绕通知===============");
long start = System.currentTimeMillis();
try {
((ProceedingJoinPoint) joinPoint).proceed();
long end = System.currentTimeMillis();
if(logger.isInfoEnabled()){
logger.info("around " + joinPoint + "\tUse time : " + (end - start) + " ms!");
}
System.out.println("==========结束执行controller环绕通知===============");
} catch (Throwable e) {
long end = System.currentTimeMillis();
if(logger.isInfoEnabled()){
logger.info("around " + joinPoint + "\tUse time : " + (end - start) + " ms with exception : " + e.getMessage());
}
}
} /**
* 后置通知 用于拦截Controller层记录用户的操作
*
* @param joinPoint 切点
*/
@After("controllerAspect()")
public void after(JoinPoint joinPoint) { /* HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
HttpSession session = request.getSession(); */
//读取session中的用户
// User user = (User) session.getAttribute("user");
//请求的IP
//String ip = request.getRemoteAddr();
User user = new User();
user.setId(1);
user.setName("张三");
String ip = "127.0.0.1";
try { String targetName = joinPoint.getTarget().getClass().getName();
String methodName = joinPoint.getSignature().getName();
Object[] arguments = joinPoint.getArgs();
Class targetClass = Class.forName(targetName);
Method[] methods = targetClass.getMethods();
String operationType = "";
String operationName = "";
for (Method method : methods) {
if (method.getName().equals(methodName)) {
Class[] clazzs = method.getParameterTypes();
if (clazzs.length == arguments.length) {
operationType = method.getAnnotation(Log.class).operationType();
operationName = method.getAnnotation(Log.class).operationName();
break;
}
}
}
//*========控制台输出=========*//
System.out.println("=====controller后置通知开始=====");
System.out.println("请求方法:" + (joinPoint.getTarget().getClass().getName() + "." + joinPoint.getSignature().getName() + "()")+"."+operationType);
System.out.println("方法描述:" + operationName);
System.out.println("请求人:" + user.getName());
System.out.println("请求IP:" + ip);
//*========数据库日志=========*//
SystemLog log = new SystemLog();
log.setId(UUID.randomUUID().toString());
log.setDescription(operationName);
log.setMethod((joinPoint.getTarget().getClass().getName() + "." + joinPoint.getSignature().getName() + "()")+"."+operationType);
log.setLogType((long)0);
log.setRequestIp(ip);
log.setExceptioncode( null);
log.setExceptionDetail( null);
log.setParams( null);
log.setCreateBy(user.getName());
log.setCreateDate(new Date());
//保存数据库
systemLogService.insert(log);
System.out.println("=====controller后置通知结束=====");
} catch (Exception e) {
//记录本地异常日志
logger.error("==后置通知异常==");
logger.error("异常信息:{}", e.getMessage());
}
} //配置后置返回通知,使用在方法aspect()上注册的切入点
@AfterReturning("controllerAspect()")
public void afterReturn(JoinPoint joinPoint){
System.out.println("=====执行controller后置返回通知=====");
if(logger.isInfoEnabled()){
logger.info("afterReturn " + joinPoint);
}
} /**
* 异常通知 用于拦截记录异常日志
*
* @param joinPoint
* @param e
*/
@AfterThrowing(pointcut = "controllerAspect()", throwing="e")
public void doAfterThrowing(JoinPoint joinPoint, Throwable e) {
/*HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
HttpSession session = request.getSession();
//读取session中的用户
User user = (User) session.getAttribute(WebConstants.CURRENT_USER);
//获取请求ip
String ip = request.getRemoteAddr(); */
//获取用户请求方法的参数并序列化为JSON格式字符串 User user = new User();
user.setId(1);
user.setName("张三");
String ip = "127.0.0.1"; String params = "";
if (joinPoint.getArgs() != null && joinPoint.getArgs().length > 0) {
for ( int i = 0; i < joinPoint.getArgs().length; i++) {
params += JsonUtil.getJsonStr(joinPoint.getArgs()[i]) + ";";
}
}
try { String targetName = joinPoint.getTarget().getClass().getName();
String methodName = joinPoint.getSignature().getName();
Object[] arguments = joinPoint.getArgs();
Class targetClass = Class.forName(targetName);
Method[] methods = targetClass.getMethods();
String operationType = "";
String operationName = "";
for (Method method : methods) {
if (method.getName().equals(methodName)) {
Class[] clazzs = method.getParameterTypes();
if (clazzs.length == arguments.length) {
operationType = method.getAnnotation(Log.class).operationType();
operationName = method.getAnnotation(Log.class).operationName();
break;
}
}
}
/*========控制台输出=========*/
System.out.println("=====异常通知开始=====");
System.out.println("异常代码:" + e.getClass().getName());
System.out.println("异常信息:" + e.getMessage());
System.out.println("异常方法:" + (joinPoint.getTarget().getClass().getName() + "." + joinPoint.getSignature().getName() + "()")+"."+operationType);
System.out.println("方法描述:" + operationName);
System.out.println("请求人:" + user.getName());
System.out.println("请求IP:" + ip);
System.out.println("请求参数:" + params);
/*==========数据库日志=========*/
SystemLog log = new SystemLog();
log.setId(UUID.randomUUID().toString());
log.setDescription(operationName);
log.setExceptioncode(e.getClass().getName());
log.setLogType((long)1);
log.setExceptionDetail(e.getMessage());
log.setMethod((joinPoint.getTarget().getClass().getName() + "." + joinPoint.getSignature().getName() + "()"));
log.setParams(params);
log.setCreateBy(user.getName());
log.setCreateDate(new Date());
log.setRequestIp(ip);
//保存数据库
systemLogService.insert(log);
System.out.println("=====异常通知结束=====");
} catch (Exception ex) {
//记录本地异常日志
logger.error("==异常通知异常==");
logger.error("异常信息:{}", ex.getMessage());
}
/*==========记录本地异常日志==========*/
logger.error("异常方法:{}异常代码:{}异常信息:{}参数:{}", joinPoint.getTarget().getClass().getName() + joinPoint.getSignature().getName(), e.getClass().getName(), e.getMessage(), params); } }

我这里写的比较全,前置通知,环绕通知,后置通知,异常通知,后置饭后通知,都写上了,在我们实际编写中不写全也没事,我习惯上把记录日志的逻辑写在后置通知里面,我看网上也有些在前置通知里面的,但我感觉写在后置通知里比较好。

下面开始在controller中加入自定义的注解!!

 package com.gcx.controller;

 import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping; import com.gcx.annotation.Log;
import com.gcx.service.UserService; @Controller
@RequestMapping("userController")
public class UserController { @Autowired
private UserService userService; @RequestMapping("testAOP")
@Log(operationType="add操作:",operationName="添加用户")
public void testAOP(String userName,String password){
userService.addUser(userName, password);
}
}

下面编写测试类

 @Test
public void testAOP1(){
//启动Spring容器
ApplicationContext ctx = new ClassPathXmlApplicationContext(new String[]{"classpath:applicationContext-mvc.xml","classpath:applicationContext-dataSource.xml"});
//获取service或controller组件
UserController userController = (UserController) ctx.getBean("userController");
userController.testAOP("zhangsan", "123456");
}

spring AOP自定义注解方式实现日志管理

数据库数据:

spring AOP自定义注解方式实现日志管理

我原本想写两个切点,一个是service层,一个是controller层,service层是用来记录异常信息的日志,而controller层的是用来记录功能的日志,运行结果如下。     spring AOP自定义注解方式实现日志管理

这样做的话不知道在实际的项目中运行效率好不好,在这里请看到博客的大牛给点建议!!

spring AOP自定义注解方式实现日志管理的更多相关文章

  1. Spring AOP 自定义注解实现统一日志管理

    一.AOP的基本概念: AOP,面向切面编程,常用于日志,事务,权限等业务处理.AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容(Spring核心之一),是函数式编程 ...

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

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

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

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

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

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

  5. spring aop 使用注解方式总结

    spring aop的注解方式:和xml的配置方式略有区别,详细如下: 1.首先还是建立需要的切面类:切面类里面定义好切点配置,以及所有的需要实现的通知方法. /** * */ package com ...

  6. ssm&plus;redis整合&lpar;通过aop自定义注解方式&rpar;

    此方案借助aop自定义注解来创建redis缓存机制. 1.创建自定义注解类 package com.tp.soft.common.util; import java.lang.annotation.E ...

  7. Spring AOP的注解方式实现

    spring也支持注解方式实现AOP,相对于配置文件方式,注解配置更加的轻量级,配置.修改更加方便. 1.开启AOP的注解配置方式 <!-- 开启aop属性注解 --> <aop:a ...

  8. springboot搭建环境之使用&commat;Slf4j注解方式&comma;进行日志管理

    如果不想每次都写private  final Logger logger = LoggerFactory.getLogger(XXX.class); 可以用注解@Slf4j 需要引入依赖为: < ...

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

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

随机推荐

  1. Pwn~

    Pwn Collections Date from 2016-07-11 Difficult rank: $ -> $$... easy -> hard CISCN 2016 pwn-1 ...

  2. 2 Add Two Numbers

    // Java public ListNode addTwoNumbers(ListNode l1, ListNode l2) { return add(l1, l2, false); } priva ...

  3. SQL速记

    集合操作       WITH a AS ( SELECT 1 id UNION SELECT 2 ), b AS ( SELECT 1 id UNION SELECT 3 ) SELECT * FR ...

  4. Android引导指示层的制作 (ViewStub &plus; SharePreference)

    引导指示界面是个什么鬼东西?一张图即明了:

  5. eclipse的安装

    eclipse的安装只要记住一条就好,那就是eclipse安装的时候版本要一致(就是,安装eclipse 32位的,同时要配套jdk 32位,tomcat 32位的),同理64位的也是一样的. 本人安 ...

  6. LeetCode题解——Palindrome Number

    题目: 判断一个数字是不是回文数字,即最高位与最低位相同,次高位与次低位相同,... 解法: 求出数字的位数,然后依次求商和求余判断是否相等. 代码: class Solution { public: ...

  7. 设计模式(十二): Flyweight享元模式 -- 结构型模式

    说明: 相对于其它模式,Flyweight模式在PHP实现似乎没有太大的意义,因为PHP的生命周期就在一个请求,请求执行完了,php占用的资源都被释放.我们只是为了学习而简单做了介绍. 1. 概述 面 ...

  8. 用RBG颜色设置自定义颜色

    这个是Mac自带的测色计   快捷键shift + command + c即可复制RBG格式的颜色 #DD0000 这个是csdn 的logo里的红色 我们得到的是十六位颜色代码 但是UIColor( ...

  9. Html 小插件2

    调用google的JS翻译插件实现页面自动翻译功能 网址http://translate.google.com/translate_tools 设置自己需要的配置生成如下代码放到自己站的页面头部 代码 ...

  10. Use weechat &lpar;IRC client&rpar; on OS X&period; MacBook Pro

    Weechat is a console IRC client. It is opensource and very easy to use. I use weechat in my Linux PC ...