您的位置:首页 > 编程语言 > Java开发

SpringAOP拦截Controller,Service实现日志管理(自定义注解的方式)

2017-03-20 16:53 951 查看
http://blog.csdn.net/czmchen/article/details/42392985

首先我们为什么需要做日志管理,在现实的上线中我们经常会遇到系统出现异常或者问题。这个时候就马上打开CRT或者SSH连上服务器拿日子来分析。受网络的各种限制。于是我们就想为什么不能直接在管理后台查看报错的信息呢。于是日志管理就出现了。

其次个人觉得做日志管理最好的是Aop,有的人也喜欢用拦截器。都可以,在此我重点介绍我的实现方式。

Aop有的人说拦截不到Controller。有的人说想拦AnnotationMethodHandlerAdapter截到Controller必须得拦截org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter。

首先Aop可以拦截到Controller的,这个是毋容置疑的其次须拦截AnnotationMethodHandlerAdapter也不是必须的。最起码我没有验证成功过这个。我的spring版本是4.0.3。

Aop之所以有的人说拦截不到Controller是因为Controller被jdk代理了。我们只要把它交给cglib代理就可以了。

第一步定义两个注解:

[java] view
plain copy

package com.annotation;

import java.lang.annotation.*;

/**

*自定义注解 拦截Controller

*/

@Target({ElementType.PARAMETER, ElementType.METHOD})

@Retention(RetentionPolicy.RUNTIME)

@Documented

public @interface SystemControllerLog {

String description() default "";

<
1d80f
/span>

}

package com.annotation;

import java.lang.annotation.*;

/**

*自定义注解 拦截service

*/

@Target({ElementType.PARAMETER, ElementType.METHOD})

@Retention(RetentionPolicy.RUNTIME)

@Documented

public @interface SystemServiceLog {

String description() default "";

}

第二步创建一个切点类:

[java] view
plain copy

package com.annotation;

import com.model.Log;

import com.model.User;

import com.service.LogService;

import com.util.DateUtil;

import com.util.JSONUtil;

import com.util.SpringContextHolder;

import com.util.WebConstants;

import org.aspectj.lang.JoinPoint;

import org.aspectj.lang.annotation.*;

import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

import org.springframework.stereotype.Component;

import org.springframework.web.context.request.RequestContextHolder;

import org.springframework.web.context.request.ServletRequestAttributes;

import javax.annotation.Resource;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpSession;

import java.lang.reflect.Method;

/**

* 切点类

* @author tiangai

* @since 2014-08-05 Pm 20:35

* @version 1.0

*/

@Aspect

@Component

public class SystemLogAspect {

//注入Service用于把日志保存数据库

@Resource

private LogService logService;

//本地异常日志记录对象

private static final Logger logger = LoggerFactory.getLogger(SystemLogAspect. class);

//Service层切点

@Pointcut("@annotation(com.annotation.SystemServiceLog)")

public void serviceAspect() {

}

//Controller层切点

@Pointcut("@annotation(com.annotation.SystemControllerLog)")

public void controllerAspect() {

}

/**

* 前置通知 用于拦截Controller层记录用户的操作

*

* @param joinPoint 切点

*/

@Before("controllerAspect()")

public void doBefore(JoinPoint joinPoint) {

HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();

HttpSession session = request.getSession();

//读取session中的用户

User user = (User) session.getAttribute(WebConstants.CURRENT_USER);

//请求的IP

String ip = request.getRemoteAddr();

try {

//*========控制台输出=========*//

System.out.println("=====前置通知开始=====");

System.out.println("请求方法:" + (joinPoint.getTarget().getClass().getName() + "." + joinPoint.getSignature().getName() + "()"));

System.out.println("方法描述:" + getControllerMethodDescription(joinPoint));

System.out.println("请求人:" + user.getName());

System.out.println("请求IP:" + ip);

//*========数据库日志=========*//

Log log = SpringContextHolder.getBean("logxx");

log.setDescription(getControllerMethodDescription(joinPoint));

log.setMethod((joinPoint.getTarget().getClass().getName() + "." + joinPoint.getSignature().getName() + "()"));

log.setType("0");

log.setRequestIp(ip);

log.setExceptionCode( null);

log.setExceptionDetail( null);

log.setParams( null);

log.setCreateBy(user);

log.setCreateDate(DateUtil.getCurrentDate());

//保存数据库

logService.add(log);

System.out.println("=====前置通知结束=====");

} catch (Exception e) {

//记录本地异常日志

logger.error("==前置通知异常==");

logger.error("异常信息:{}", e.getMessage());

}

}

/**

* 异常通知 用于拦截service层记录异常日志

*

* @param joinPoint

* @param e

*/

@AfterThrowing(pointcut = "serviceAspect()", 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格式字符串

String params = "";

if (joinPoint.getArgs() != null && joinPoint.getArgs().length > 0) {

for ( int i = 0; i < joinPoint.getArgs().length; i++) {

params += JSONUtil.toJsonString(joinPoint.getArgs()[i]) + ";";

}

}

try {

/*========控制台输出=========*/

System.out.println("=====异常通知开始=====");

System.out.println("异常代码:" + e.getClass().getName());

System.out.println("异常信息:" + e.getMessage());

System.out.println("异常方法:" + (joinPoint.getTarget().getClass().getName() + "." + joinPoint.getSignature().getName() + "()"));

System.out.println("方法描述:" + getServiceMthodDescription(joinPoint));

System.out.println("请求人:" + user.getName());

System.out.println("请求IP:" + ip);

System.out.println("请求参数:" + params);

/*==========数据库日志=========*/

Log log = SpringContextHolder.getBean("logxx");

log.setDescription(getServiceMthodDescription(joinPoint));

log.setExceptionCode(e.getClass().getName());

log.setType("1");

log.setExceptionDetail(e.getMessage());

log.setMethod((joinPoint.getTarget().getClass().getName() + "." + joinPoint.getSignature().getName() + "()"));

log.setParams(params);

log.setCreateBy(user);

log.setCreateDate(DateUtil.getCurrentDate());

log.setRequestIp(ip);

//保存数据库

logService.add(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);

}

/**

* 获取注解中对方法的描述信息 用于service层注解

*

* @param joinPoint 切点

* @return 方法描述

* @throws Exception

*/

public static String getServiceMthodDescription(JoinPoint joinPoint)

throws Exception {

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 description = "";

for (Method method : methods) {

if (method.getName().equals(methodName)) {

Class[] clazzs = method.getParameterTypes();

if (clazzs.length == arguments.length) {

description = method.getAnnotation(SystemServiceLog. class).description();

break;

}

}

}

return description;

}

/**

* 获取注解中对方法的描述信息 用于Controller层注解

*

* @param joinPoint 切点

* @return 方法描述

* @throws Exception

*/

public static String getControllerMethodDescription(JoinPoint joinPoint) throws Exception {

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 description = "";

for (Method method : methods) {

if (method.getName().equals(methodName)) {

Class[] clazzs = method.getParameterTypes();

if (clazzs.length == arguments.length) {

description = method.getAnnotation(SystemControllerLog. class).description();

break;

}

}

}

return description;

}

}

第三步把Controller的代理权交给cglib

在实例化ApplicationContext的时候需要加上

Xml代码

<!-- 启动对@AspectJ注解的支持 -->
<aop:aspectj-autoproxy/>

在调用Controller的时候AOP发挥作用所以在SpringMVC的配置文件里加上

Xml代码

<!--通知spring使用cglib而不是jdk的来生成代理方法 AOP可以拦截到Controller->
<aop:aspectj-autoproxy proxy-target-class="true" />

第四步使用

Controller层的使用

Java代码

[java] view
plain copy

/**

* 删除用户

*

* @param criteria 条件

* @param id id

* @param model 模型

* @return 数据列表

*/

@RequestMapping(value = "/delete")

//此处为记录AOP拦截Controller记录用户操作

@SystemControllerLog(description = "删除用户")

public String del(Criteria criteria, String id, Model model, HttpSession session) {

try {

User user = (User) session.getAttribute(WebConstants.CURRENT_USER);

if ( null != user) {

if (user.getId().equals(id)) {

msg = "您不可以删除自己!";

criteria = userService.selectByCriteriaPagination(criteria);

} else {

//删除数据并查询出数据

criteria = userService.delete(id, criteria);

msg = "删除成功!";

}

}

} catch (Exception e) {

msg = "删除失败!";

} finally {

model.addAttribute("msg", msg);

model.addAttribute("criteria", criteria);

}

//跳转列表页

return "user/list";

}

Service层的使用

[java] view
plain copy







/**

* 按照分页查询

* @param criteria

* @return

*/

//此处为AOP拦截Service记录异常信息。方法不需要加try-catch

@SystemServiceLog(description = "查询用户")

public Criteria<User> selectByCriteriaPagination(Criteria<User> criteria)

{

criteria.getList().get(0).getAccount();

//查询总数

long total=userMapper.countByCriteria(criteria);

//设置总数

criteria.setRowCount(total);

criteria.setList(userMapper.selectByCriteriaPagination(criteria));

return criteria;

}

效果图

用户操作:



异常



文章来源http://itindex.net/detail/50710-springaop-controller-service

以上是转载内容,我这边使用的dubbo,想要监控provider的serviceImpl所有接口方法

于是自己写了个

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;

import org.apache.log4j.Logger;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;

import com.hulk.common.constant.Constant;
import com.hulk.common.util.BusinessUtil;

/**
* 记录所有被调用service类日志
*/
@Aspect
@Component
public class ProviderLogAspect {
// 本地异常日志记录对象
private static final Logger logger = Logger.getLogger(ProviderLogAspect.class);

static ThreadLocal<HashMap> threadmap = new ThreadLocal<HashMap>() {
@Override
protected HashMap initialValue() {
return new HashMap();
}
};

//所有serviceImpl层切点
@Pointcut("execution(* com.hulk.service.impl.*Service*.*(..))")
public void providerAspect() {
}

/**
* 前置通知 用于拦截Provider层记录用户的操作
* @param joinPoint 切点
*
*/
@Before("providerAspect()")
public void doBefore(JoinPoint joinPoint) {
if(Constant.PRESSURETEST){
return;
}
// 获取操作内容
try {
String methodName = joinPoint.getSignature().getName();
Date startTime = new Date();
threadmap.get().put("startTime", startTime);
} catch (Exception e) {
e.printStackTrace();
}
}

@AfterReturning(pointcut = "providerAspect()", argNames = "rtv", returning = "rtv")
public void doAfter(JoinPoint joinPoint, Object rtv) {
if(Constant.PRESSURETEST){
return;
}
try {
Date endTime = new Date();
long threadId =  Thread.currentThread().getId();
String providerName = joinPoint.getSignature().getName();
String providerPath = joinPoint.getTarget().getClass().getName() + "." + providerName + "()";
Date startTime = (Date) threadmap.get().get("startTime");
SimpleDateFormat sd = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
BusinessUtil.writeLog("providerMethod",	threadId +"\t" + sd.format(startTime) + "\t" + sd.format(endTime) + "\t" + (endTime.getTime() - startTime.getTime()) + "ms" + "\t" + providerPath);
System.out.println(threadId +"\t" + sd.format(startTime) + "\t" + sd.format(endTime) + "\t" + (endTime.getTime() - startTime.getTime()) + "ms" + "\t" + providerPath);
} catch (Exception e) {
e.printStackTrace();
}
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  aop 日志
相关文章推荐