package appapi.config;
import appapi.Vo.AppVo.AppLoginVo;
import appapi.common.ResponseBean;
import appapi.entity.Zhongjiao.SysLogEntity;
import appapi.entity.basic.UserInfo;
import appapi.service.ISysLogService;
import appapi.utils.HttpContextUtils;
import appapi.utils.IPUtils;
import appapi.utils.JwtUtil;
import appapi.utils.List2MapUtil;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
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.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.LocalVariableTableParameterNameDiscoverer;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.*;
@Aspect
@Component
@Slf4j
public class LogAspect {
@Autowired
private ISysLogService iSysLogService;
/**
* @annotation(MyLog类的路径) 在idea中,右键自定义的MyLog类-> 点击Copy Reference
*/
@Pointcut("@annotation(appapi.config.MyLog)")
public void logPointCut() {
log.info("------>配置织入点");
}
/**
* 处理完请求后执行
*
* @param joinPoint 切点
*/
@AfterReturning(pointcut = "logPointCut()", returning = "result")
public void doAfterReturning(JoinPoint joinPoint, Object result) throws Exception {
handleLog(joinPoint, result, null);
}
/**
* 拦截异常操作
*
* @param joinPoint 切点
* @param e 异常
*/
@AfterThrowing(value = "logPointCut()", throwing = "e")
public void doAfterThrowing(JoinPoint joinPoint, Exception e) throws Exception {
handleLog(joinPoint, null, e);
}
private void handleLog(final JoinPoint joinPoint, Object result, final Exception e) throws Exception {
SysLogEntity operLog = new SysLogEntity();
ResponseBean resultData = (ResponseBean) result;
// 获得MyLog注解
MyLog controllerLog = getAnnotationLog(joinPoint);
if (controllerLog == null) {
return;
}
String title = controllerLog.title();
// 获取request
HttpServletRequest request = HttpContextUtils.getHttpServletRequest();
Map<String, Object> data = new HashMap<>();
if (request.getRequestURI().contains("app")&&title.contains("登录")){
List<AppLoginVo> appData = (List<AppLoginVo>) resultData.getData();
if (appData!=null){
AppLoginVo vo = appData.get(0);
data = List2MapUtil.setConditionMap(vo);
data.put("staffAccount",vo.getUserPhone());
data.put("staffName",vo.getUserName());
}
}else if (!(resultData.getData() instanceof Map)){
data = List2MapUtil.setConditionMap(resultData.getData());
}else {
data = (Map<String, Object>) resultData.getData();
}
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
Method method = signature.getMethod();
// 请求的方法名
String className = joinPoint.getTarget().getClass().getName();
String methodName = signature.getName();
// 请求的方法参数值
Object[] args = joinPoint.getArgs();
// 请求的方法参数名称
LocalVariableTableParameterNameDiscoverer u = new LocalVariableTableParameterNameDiscoverer();
String[] paramNames = u.getParameterNames(method);
if (args != null && paramNames != null) {
String params = "";
for (int i = 0; i < args.length; i++) {
params += " " + paramNames[i] + ": " + args[i];
}
operLog.setRequestParam(params);
}
operLog.setMethod(className + "." + methodName + "()");
//日志类型 0=登录日志,1=操作日志,2=异常日志,3=告警日志'
if (title.contains("登录")) {
operLog.setOperateAccount(resultData.getCode() != 200 ? "" : data.get("staffAccount").toString());
operLog.setOperateName(resultData.getCode() != 200 ? "" : data.get("staffName").toString());
operLog.setLogType(0);
} else {
operLog.setLogType(1);
//拿到操作人员的账号与名称,现在暂时存入的手机号
UserInfo token = JwtUtil.getUserInfo(request.getHeader("token"));
operLog.setOperateAccount(token.getMobile());
operLog.setOperateName(token.getUsername());
}
// 操作状态(0正常 1异常)
operLog.setOperateResult(0);
// 操作时间
operLog.setOperateTime(new Date());
//code返回值为-1
if (resultData.getCode() != 200) {
operLog.setOperateResult(1);
operLog.setErrorMsg(resultData.getMessage());
operLog.setLogType(2);
}
//如果有异常则捕获返回
if (e != null) {
operLog.setOperateResult(1);
operLog.setErrorMsg(e.getMessage());
operLog.setLogType(2);
}
// 设置IP地址
operLog.setIp(IPUtils.getIpAddr(request));
// 设置uri
operLog.setUri(request.getRequestURI());
//操作类别
operLog.setOperatorType(operLog.getUri().contains("app") ? 2 : 1);
//请求方式
operLog.setRequestMethod(request.getMethod());
// 处理注解上的参数
getControllerMethodDescription(joinPoint, controllerLog, operLog);
//暂不用
//operLog.setResult(JSONObject.toJSON(result).toString());
// 保存数据库
iSysLogService.saveSysLog(operLog);
}
/**
* 是否存在注解,如果存在就获取,不存在则返回null
*
* @param joinPoint
* @return
*/
private MyLog getAnnotationLog(JoinPoint joinPoint) {
Signature signature = joinPoint.getSignature();
MethodSignature methodSignature = (MethodSignature) signature;
Method method = methodSignature.getMethod();
if (method != null) {
return method.getAnnotation(MyLog.class);
}
return null;
}
/**
* 获取Controller层上MyLog注解中对方法的描述信息
*
* @param joinPoint 切点
* @param myLog 自定义的注解
* @param operLog 操作日志实体类
*/
private void getControllerMethodDescription(JoinPoint joinPoint, MyLog myLog, SysLogEntity operLog) {
operLog.setOperateType(myLog.businessType().ordinal());
// 设置模块标题,eg:登录
operLog.setBizModule(myLog.title());
// 对方法上的参数进行处理,处理完:userName=xxx,password=xxx
// String optParam = getAnnotationValue(joinPoint, myLog.optParam());
//operLog.setOptParam(optParam);
}
/**
* 对方法上的参数进行处理
*
* @param joinPoint
* @param name
* @return
*/
private String getAnnotationValue(JoinPoint joinPoint, String name) {
String paramName = name;
// 获取方法中所有的参数
Map<String, Object> params = getParams(joinPoint);
// 参数是否是动态的:#{paramName}
if (paramName.matches("^#\\{\\D*\\}")) {
// 获取参数名,去掉#{ }
paramName = paramName.replace("#{", "").replace("}", "");
// 是否是复杂的参数类型:对象.参数名
if (paramName.contains(".")) {
String[] split = paramName.split("\\.");
// 获取方法中对象的内容
Object object = getValue(params, split[0]);
// 转换为JsonObject
JSONObject jsonObject = (JSONObject) JSONObject.toJSON(object);
// 获取值
Object o = jsonObject.get(split[1]);
return String.valueOf(o);
} else {// 简单的动态参数直接返回
StringBuilder str = new StringBuilder();
String[] paraNames = paramName.split(",");
for (String paraName : paraNames) {
String val = String.valueOf(getValue(params, paraName));
// 组装成 userName=xxx,password=xxx,
str.append(paraName).append("=").append(val).append(",");
}
// 去掉末尾的,
if (str.toString().endsWith(",")) {
String substring = str.substring(0, str.length() - 1);
return substring;
} else {
return str.toString();
}
}
}
// 非动态参数直接返回
return name;
}
/**
* 获取方法上的所有参数,返回Map类型, eg: 键:"userName",值:xxx 键:"password",值:xxx
*
* @param joinPoint
* @return
*/
public Map<String, Object> getParams(JoinPoint joinPoint) {
Map<String, Object> params = new HashMap<>(8);
// 通过切点获取方法所有参数值["zhangsan", "123456"]
Object[] args = joinPoint.getArgs();
// 通过切点获取方法所有参数名 eg:["userName", "password"]
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
String[] names = signature.getParameterNames();
for (int i = 0; i < args.length; i++) {
params.put(names[i], args[i]);
}
return params;
}
/**
* 从map中获取键为paramName的值,不存在放回null
*
* @param map
* @param paramName
* @return
*/
private Object getValue(Map<String, Object> map, String paramName) {
for (Map.Entry<String, Object> entry : map.entrySet()) {
if (entry.getKey().equals(paramName)) {
return entry.getValue();
}
}
return null;
}
}
@Target({ElementType.PARAMETER, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MyLog {
// 自定义模块名,eg:登录
String title() default “”;
// 操作类型,eg:INSERT, UPDATE…
BusinessTypeEnum businessType() default BusinessTypeEnum.other;
}