package com.foen.foensys.config;
import com.alibaba.fastjson.JSON;
import com.foen.foensys.model.SysLogsOper;
import com.foen.foensys.model.Users;
import com.foen.foensys.service.SysLogsOperService;
import com.foen.foensys.controller.admin.BaseController;
import com.foen.foensys.utils.DateUtils;
import com.foen.foensys.utils.Utils;
import com.google.common.collect.Maps;
import org.apache.shiro.SecurityUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.lang.reflect.Method;
import java.util.Date;
import java.util.Enumeration;
import java.util.Map;
/**
* AOP
* @auther: 作者 gzh
* @description: 类说明
* @Date: created in 15:33 2019/7/5
*/
@Component
@Aspect
public class SystemLogsOperAopAction {
private static final Logger logger = LoggerFactory.getLogger(SystemLogsOperAopAction.class);
@Autowired
private SysLogsOperService sysLogsOperService;
/**
* 00配置接入点:定义一个切入点
*/
//@Pointcut("execution(* com.foen.foensys.controller..*.*(..))")
@Pointcut("execution(@com.foen.foensys.config.SystemLogs * *(..))")
private void controllerAspect(){
logger.info("==》 Controller Log记录!");
}
/**
* 环绕通知
* @param proceedingJoinPoint
* @return Object
* @throws Throwable
*/
@Around("controllerAspect()")
public Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
//常见日志实体对象
logger.info("==>环绕通知的目标方法名为 : "+proceedingJoinPoint.getSignature().getName());
SysLogsOper log = new SysLogsOper();
//获取登录用户账户
//HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
//String name = (String)request.getSession().getAttribute("userID");
Users user = (Users) SecurityUtils.getSubject().getSession().getAttribute("user");
if(user!=null){
log.setUserId(user.getId().toString());
log.setUserName(user.getUsername());
}
log.setOperTime(DateUtils.dateToStringDetail(new Date()));
log.setIp(Utils.getLocalIP());
log.setPort(Utils.getLocalPort());
log.setPath("/**");
log.setParam("{**}");
//方法通知前获取时间,为什么要记录这个时间呢?当然是用来计算模块执行时间的
long start = System.currentTimeMillis();
// 拦截的实体类,就是当前正在执行的controller
Object target = proceedingJoinPoint.getTarget();
// 拦截的方法名称。当前正在执行的方法
String methodName = proceedingJoinPoint.getSignature().getName();
// 拦截的方法参数
Object[] args = proceedingJoinPoint.getArgs();
// 拦截的放参数类型
Signature sig = proceedingJoinPoint.getSignature();
MethodSignature msig = null;
if (!(sig instanceof MethodSignature)) {
throw new IllegalArgumentException("该注解只能用于方法");
}
msig = (MethodSignature) sig;
Class[] parameterTypes = msig.getMethod().getParameterTypes();
Object object = null;
// 获得被拦截的方法
Method method = null;
try {
method = target.getClass().getMethod(methodName, parameterTypes);
} catch (NoSuchMethodException e1) {
e1.printStackTrace();
} catch (SecurityException e1) {
e1.printStackTrace();
}
if (null != method) {
// 判断是否包含自定义的注解,说明一下这里的SystemLog就是我自己自定义的注解
if (method.isAnnotationPresent(SystemLogs.class)) {
logger.info("==>判断是否包含自定义的注解:包含注解!");
SystemLogs systemlog = method.getAnnotation(SystemLogs.class);
log.setModule(systemlog.module());
log.setMethod(systemlog.methods());
try {
object = proceedingJoinPoint.proceed();
long end = System.currentTimeMillis();
//将计算好的时间保存在实体中
log.setResponseTime(""+(end-start));
log.setRemark("执行成功!");
//保存进数据库
sysLogsOperService.save(log);
} catch (Throwable e) {
long end = System.currentTimeMillis();
log.setResponseTime(""+(end-start));
log.setRemark("执行失败");
sysLogsOperService.save(log);
}
} else {
logger.info("==>没有包含注解");
object = proceedingJoinPoint.proceed();
}
} else {
logger.info("==>不需要拦截直接执行");
object = proceedingJoinPoint.proceed();
}
logger.info("==> 退出 环绕通知! object:"+object);
return object;
}
/**
* 前置
* 1. 通过JoinPoint 获取通知的签名信息,如目标方法名,目标方法参数信息等
* @param joinPoint
*/
@Before(value = "controllerAspect()")
public void doAccessCheck(JoinPoint joinPoint){
logger.info("==>:前置通知");
Object[] obj=joinPoint.getArgs();//获取目标方法的参数信息
joinPoint.getThis(); // AOP代理类信息
joinPoint.getTarget(); // 代理的目标对象
Signature signature=joinPoint.getSignature(); // 用的最多,通知的签名
logger.info("代理的方法是 : "+signature.getName()); // 打印 代理的是哪一个方法
// AOP 代理的名字
logger.info("AOP 代理的名字 : "+signature.getDeclaringTypeName());
signature.getDeclaringType();// AOP代理类的类(class)信息
// 获取RequestAttributes
RequestAttributes requestAttributes= RequestContextHolder.getRequestAttributes();
// 从requestAttributes中获取HttpServletRequest信息
HttpServletRequest request=(HttpServletRequest)requestAttributes.resolveReference(RequestAttributes.REFERENCE_REQUEST);
// 获取session信息
HttpSession session=(HttpSession)requestAttributes.resolveReference(RequestAttributes.REFERENCE_SESSION);
logger.info("请求 : "+request+" , HttpSession : "+session);
Enumeration<String> enumerations=request.getParameterNames();
Map<String,Object> parameterMaps= Maps.newHashMap();
while(enumerations.hasMoreElements()){
String parameter=enumerations.nextElement();
parameterMaps.put(parameter,request.getParameter(parameter));
}
logger.info("请求参数信息为 : "+ JSON.toJSONString(parameterMaps) );
// this.map = parameterMaps;
// this.request = request;
}
/**
* 后置通知
* @param joinPoint
* @param keys 返回值的信息
*/
@AfterReturning(value = "controllerAspect()",returning = "keys")
public void doAfter(JoinPoint joinPoint,Object keys){
logger.info("==>:后置通知:keys:"+keys+",joinPoint:"+joinPoint);
}
/**
* 04. 后置最终通知(目标方法只要执行完了就会执行后置通知方法)
*/
@After("controllerAspect()")
public void after(JoinPoint joinPoint){
logger.info("==>:最终通知:"+joinPoint);
}
/**
* 03 . 后置异常通知
* 定义一个名字,该名字用于匹配通知实现方法的一个参数名,当目标方法抛出异常返回后,将把目标方法抛出的异常传给通知方法;
* throwing 限定了只有目标方法抛出的异常与通知方法相应参数异常类型时才能执行后置异常通知,否则不执行,
* 对于throwing对应的通知方法参数为Throwable类型将匹配任何异常。
*/
@AfterThrowing(value = "controllerAspect()" ,throwing = "exception")
public void doAfterThrow(JoinPoint joinPoint,Throwable exception){
logger.error("目标方法名[后置异常]:"+joinPoint.getSignature().getName());
if(exception instanceof NullPointerException){
logger.error("发生了空指针异常");
}
}
}