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

网友投稿 217 2023-02-25


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

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

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

在applicationContext-mvc.xml中要添加的

接下来开始编写代码。

创建日志类实体

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 == nuhttp://ll ? 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;

}

publicQCdzdXEgkw void setParams(String params) {

this.params = params == null ? null : params.trim();

}

public String getCreateBy() {

return createBy;QCdzdXEgkw

}

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");

}

数据库数据:

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


版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:基于openlayers4实现点的扩散效果
下一篇:网页搜索接口测试用例(网页搜索接口测试用例设计)
相关文章

 发表评论

暂时没有评论,来抢沙发吧~