AOP切面、自定义注解、参数获取
说明:由于在处理日志的时候,发现登录的相关日志获取不到用户的相关信息,导致关键信息无法展示,无法追溯;单独定义跟业务区分的注解来处理登录相关的日志信息;
自定义注解
package com.db.common.annotation;
import com.db.common.enums.BusinessType;
import com.db.common.enums.OperatorType;
import java.lang.annotation.*;
/**
* 自定义登录日志记录注解
*
*/
@Target({ ElementType.PARAMETER, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface LoginLog
{
/**
* 模块
*/
public String title() default "";
/**
* 功能
*/
public BusinessType businessType() default BusinessType.OTHER;
/**
* 操作人类别
*/
public OperatorType operatorType() default OperatorType.MANAGE;
/**
* 是否保存请求的参数
*/
public boolean isSaveRequestData() default true;
}
切面
import com.alibaba.fastjson.JSONObject;
import com.db.common.annotation.LoginLog;
import com.db.common.core.domain.entity.SysUser;
import com.db.common.enums.BusinessStatus;
import com.db.common.json.JSON;
import com.db.common.utils.ServletUtils;
import com.db.common.utils.ShiroUtils;
import com.db.common.utils.StringUtils;
import com.db.framework.manager.AsyncManager;
import com.db.framework.manager.factory.AsyncFactory;
import com.db.system.domain.SysOperLog;
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.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpMethod;
import org.springframework.stereotype.Component;
import org.springframework.validation.BindingResult;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.HandlerMapping;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Method;
import java.util.Collection;
import java.util.Map;
/**
* 操作日志记录处理
*
* @author db
*/
@Aspect
@Component
public class LogAspect {
private static final Logger log = LoggerFactory.getLogger(LogAspect.class);
/**
* 配置登录织入点
*/
@Pointcut("@annotation(com.db.common.annotation.LoginLog)")
public void loginPointCut() {
}
/**
* 处理完请求后执行
*
* @param joinPoint 切点
* @param jsonResult 返回result
*/
@AfterReturning(pointcut = "loginPointCut()", returning = "jsonResult")
public void doAfterReturninglogin(JoinPoint joinPoint, Object jsonResult) {
handleLoginlog(joinPoint, null, jsonResult);
}
/**
* 拦截异常操作
*
* @param joinPoint 切点
* @param e 异常
*/
@AfterThrowing(value = "loginPointCut()", throwing = "e")
public void doAfterThrowinglogin(JoinPoint joinPoint, Exception e) {
handleLoginlog(joinPoint, e, null);
}
/**
* 日志处理
*
* @param joinPoint 切点
* @param e 异常
* @param jsonResult 返回result
*/
protected void handleLoginlog(final JoinPoint joinPoint, final Exception e, Object jsonResult) {
try {
// 获得注解
LoginLog controllerLog = getAnnotationLoginlog(joinPoint);
if (controllerLog == null) {
return;
}
//获取所有参数的值
Object[] args = joinPoint.getArgs();
JSONObject jsonObject = new JSONObject();
if (args.length > 0) {
jsonObject = (JSONObject) JSONObject.toJSON(args[0]);
}
// 获取用户对象
SysUser sysUser = JSONObject.parseObject(jsonObject.get("sysUser").toString(), SysUser.class);
// *========数据库日志=========*//
SysOperLog operLog = new SysOperLog();
operLog.setStatus(BusinessStatus.SUCCESS.ordinal());
// 请求的地址
String ip = ShiroUtils.getIp();
operLog.setOperIp(ip);
// 返回参数
operLog.setJsonResult(StringUtils.substring(JSON.marshal(jsonResult), 0, 2000));
operLog.setOperUrl(ServletUtils.getRequest().getRequestURI());
if (sysUser != null) {
operLog.setOperPhone(sysUser.getPhonenumber());
operLog.setOperName(sysUser.getLoginName());
if (StringUtils.isNotNull(sysUser.getDept()) && StringUtils.isNotEmpty(sysUser.getDept().getDeptName())) {
operLog.setDeptName(sysUser.getDept().getDeptName());
}
}
if (e != null) {
operLog.setStatus(BusinessStatus.FAIL.ordinal());
operLog.setErrorMsg(StringUtils.substring(e.getMessage(), 0, 2000));
}
// 设置方法名称
String className = joinPoint.getTarget().getClass().getName();
String methodName = joinPoint.getSignature().getName();
operLog.setMethod(className + "." + methodName + "()");
// 设置请求方式
operLog.setRequestMethod(ServletUtils.getRequest().getMethod());
// 处理设置注解上的参数
getControllerMethodDescriptionLogin(joinPoint, controllerLog, operLog);
// 保存数据库
AsyncManager.me().execute(AsyncFactory.recordOper(operLog));
} catch (Exception exp) {
// 记录本地异常日志
log.error("==前置通知异常==");
log.error("异常信息:{}", exp.getMessage());
exp.printStackTrace();
}
}
/**
* 是否存在注解,如果存在就获取
*
* @param joinPoint 切点
*/
private LoginLog getAnnotationLoginlog(JoinPoint joinPoint) {
Signature signature = joinPoint.getSignature();
MethodSignature methodSignature = (MethodSignature) signature;
Method method = methodSignature.getMethod();
if (method != null) {
return method.getAnnotation(LoginLog.class);
}
return null;
}
/**
* 获取注解中对方法的描述信息 用于Controller层注解
*
* @param log 日志
* @param operLog 操作日志
*/
public void getControllerMethodDescriptionLogin(JoinPoint joinPoint, LoginLog log, SysOperLog operLog) {
// 设置action动作
operLog.setBusinessType(log.businessType().ordinal());
// 设置标题
operLog.setTitle(log.title());
// 设置操作人类别
operLog.setOperatorType(log.operatorType().ordinal());
// 是否需要保存request,参数和值
if (log.isSaveRequestData()) {
// 获取参数的信息,传入到数据库中。
setRequestValue(joinPoint, operLog);
}
}
/**
* 获取请求的参数,放到log中
*
* @param operLog 操作日志
*/
private void setRequestValue(JoinPoint joinPoint, SysOperLog operLog) {
String requestMethod = operLog.getRequestMethod();
if (HttpMethod.PUT.name().equals(requestMethod) || HttpMethod.POST.name().equals(requestMethod)) {
String params = argsArrayToString(joinPoint.getArgs());
operLog.setOperParam(StringUtils.substring(params, 0, 2000));
} else {
Map<?, ?> paramsMap = (Map<?, ?>) ServletUtils.getRequest().getAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE);
operLog.setOperParam(StringUtils.substring(paramsMap.toString(), 0, 2000));
}
}
/**
* 参数拼装
*
* @param paramsArray 参数
* @return 拼接之后的字符串
*/
private String argsArrayToString(Object[] paramsArray) {
StringBuilder params = new StringBuilder();
if (paramsArray != null && paramsArray.length > 0) {
for (Object o : paramsArray) {
if (StringUtils.isNotNull(o) && !isFilterObject(o)) {
try {
Object jsonObj = com.alibaba.fastjson.JSON.toJSON(o);
params.append(jsonObj.toString()).append(" ");
} catch (Exception ignored) {
}
}
}
}
return params.toString().trim();
}
/**
* 判断是否需要过滤的对象。
*
* @param o 对象信息。
* @return 如果是需要过滤的对象,则返回true;否则返回false。
*/
@SuppressWarnings("rawtypes")
public boolean isFilterObject(final Object o) {
Class<?> clazz = o.getClass();
if (clazz.isArray()) {
return clazz.getComponentType().isAssignableFrom(MultipartFile.class);
} else if (Collection.class.isAssignableFrom(clazz)) {
Collection collection = (Collection) o;
for (Object value : collection) {
return value instanceof MultipartFile;
}
} else if (Map.class.isAssignableFrom(clazz)) {
Map map = (Map) o;
for (Object value : map.entrySet()) {
Map.Entry entry = (Map.Entry) value;
return entry.getValue() instanceof MultipartFile;
}
}
return o instanceof MultipartFile || o instanceof HttpServletRequest || o instanceof HttpServletResponse || o instanceof BindingResult;
}
}
Controller代码
@LoginLog(title = "登录", businessType = BusinessType.OTHER)
@PostMapping("/accessToken")
@ResponseBody
@RepeatSubmit
public AjaxResult accessToken(@RequestBody Map<String, Object> params)
{
return iSysUserService.accessToken(params);
}