package com.hivekion.common.annotation;
import com.hivekion.common.enums.OperationTypeEnum;
import com.hivekion.common.enums.OperationUnitEnum;
import java.lang.annotation.*;
/**
* @author admin
*/
@Documented
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface AutoLog {
/**
* 方法描述,可使用占位符获取参数:{{tel}}
*/
String value() default "";
/**
* 日志等级:自己定,此处分为1-9
*/
int level() default 0;
/**
* 操作类型(enum):主要是select,insert,update,delete,导入、导出
*/
OperationTypeEnum operationType() default OperationTypeEnum.UNKNOWN;
/**
* 被操作的对象(此处使用enum):可以是任何对象,如表名(user),或者是工具(redis)
*/
OperationUnitEnum operationUnit() default OperationUnitEnum.UNKNOWN;
String module() default "";
}
package com.hivekion.common.enums;
/**
* 操作类型
* @author admin
*/
public enum OperationTypeEnum {
/**
* 操作类型
*/
UNKNOWN("unknown"),
DELETE("delete"),
SELECT("select"),
UPDATE("update"),
CLEAN("clean"),
DOWNLOAD("download"),
LOGIN("login"),
INSERT("insert");
private String value;
OperationTypeEnum(String s) {
this.value = s;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
}
package com.hivekion.common.enums;
/**
* 被操作的单元
* @author admin
*/
public enum OperationUnitEnum {
/**
* 操作单元
*/
UNKNOWN("unknown"),
USER("user"),
EMPLOYEE("employee"),
Redis("redis");
private String value;
OperationUnitEnum(String value) {
this.value = value;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
}
package com.hivekion.common.aspects;
import cn.hutool.extra.servlet.ServletUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.serializer.PropertyFilter;
import com.hivekion.common.annotation.AutoLog;
import com.hivekion.system.domain.SysOperationLog;
import com.hivekion.system.mapper.SysOperationLogMapper;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
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.beans.factory.annotation.Autowired;
import org.springframework.core.LocalVariableTableParameterNameDiscoverer;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
/**
* @author admin
*/
@Component
@Aspect
public class ControllerLogAspect {
public static final Logger logger = LoggerFactory.getLogger(ControllerLogAspect.class);
@Autowired
SysOperationLogMapper mapper;
@Pointcut("@annotation(com.hivekion.common.annotation.AutoLog)")
public void operationLog() {
}
@Pointcut("execution(* com.hivekion.*.controller.*.*(..))")
public void controllerThrowLog() {
}
@Around("operationLog()")
public Object handleControllerMethod(ProceedingJoinPoint point) throws Throwable {
// 执行时长
Object result = null;
// 开始时间
long beginTime = System.currentTimeMillis();
result = point.proceed();
try {
// 计算运行时间
long time = System.currentTimeMillis() - beginTime;
addOperationLog(point, result, time, 0);
} catch (Exception ex) {
logger.error("LogAspect 操作失败: " + ex.getMessage());
}
return result;
}
@AfterThrowing(value = "controllerThrowLog()", throwing = "e")
public void handleControllerThrowMethod(JoinPoint point, Throwable e) {
addOperationLog(point, e, 0, 1);
}
private void addOperationLog(JoinPoint point, Object res, long time, int status) {
HttpServletRequest request =
((ServletRequestAttributes) RequestContextHolder.getRequestAttributes())
.getRequest();
MethodSignature signature = (MethodSignature) point.getSignature();
SysOperationLog operationLog = new SysOperationLog();
// 记录运行时间
operationLog.setRunTime(time);
String returnV = JSON.toJSONString(res);
int length = returnV.length();
// 记录返回结果
operationLog.setReturnValue(returnV);
operationLog.setMethod(signature.getDeclaringTypeName() + "." + signature.getName());
operationLog.setRequestParams(getReqestParams(request, point));
// 访问IP地址
operationLog.setIp(ServletUtil.getClientIP(request));
operationLog.setStatus(status);
// 注解
AutoLog annotation = signature.getMethod().getAnnotation(AutoLog.class);
if (annotation != null) {
operationLog.setLevel(annotation.level());
operationLog.setTitle(annotation.value());
// operationLog.setDescribe(getDetail(((MethodSignature)
operationLog.setOperationType(annotation.operationType().getValue());
// 被操作对象
operationLog.setOperationUnit(annotation.operationUnit().getValue());
// 操作模块
operationLog.setModule(annotation.module());
}
// TODO 这里保存日志
//System.out.println("记录日志:" + operationLog.toString());
mapper.insert(operationLog);
}
private String getReqestParams(HttpServletRequest request, JoinPoint joinPoint) {
String httpMethod = request.getMethod();
String params = "";
if (RequestMethod.POST.toString().equalsIgnoreCase(httpMethod) || RequestMethod.PUT.toString().equalsIgnoreCase(httpMethod)
|| RequestMethod.PATCH.toString().equalsIgnoreCase(httpMethod)) {
Object[] paramsArray = joinPoint.getArgs();
Object[] arguments = new Object[paramsArray.length];
for (int i = 0; i < paramsArray.length; i++) {
if (paramsArray[i] instanceof ServletRequest
|| paramsArray[i] instanceof ServletResponse
|| paramsArray[i] instanceof MultipartFile
|| paramsArray[i] instanceof MultipartFile[]) {
continue;
}
arguments[i] = paramsArray[i];
}
// update-begin-author:taoyan date:20200724 for:日志数据太长的直接过滤掉
PropertyFilter profilter =
new PropertyFilter() {
@Override
public boolean apply(Object o, String name, Object value) {
if (value != null && value.toString().length() > HttpStatus.INTERNAL_SERVER_ERROR.value()) {
return false;
}
return true;
}
};
params = JSONObject.toJSONString(arguments, profilter);
// update-end-author:taoyan date:20200724 for:日志数据太长的直接过滤掉
} else {
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
Method method = signature.getMethod();
// 请求的方法参数值
Object[] args = joinPoint.getArgs();
// 请求的方法参数名称
LocalVariableTableParameterNameDiscoverer u =
new LocalVariableTableParameterNameDiscoverer();
String[] paramNames = u.getParameterNames(method);
if (args != null && paramNames != null) {
for (int i = 0; i < args.length; i++) {
params += " " + paramNames[i] + ": " + args[i];
}
}
}
return params;
}
}
package com.hivekion.system.domain;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
import com.gitee.sunchenbin.mybatis.actable.annotation.ColumnComment;
import com.gitee.sunchenbin.mybatis.actable.annotation.ColumnType;
import com.gitee.sunchenbin.mybatis.actable.annotation.TableComment;
import com.gitee.sunchenbin.mybatis.actable.constants.MySqlTypeConstant;
import com.hivekion.common.entity.BaseEntity;
import lombok.Data;
/**
* @author admin
*/
@Data
@TableName("base_sys_operation_log")
@TableComment("操作日志表")
public class SysOperationLog extends BaseEntity {
@TableField
@ColumnType(value = MySqlTypeConstant.INT, length = 8)
@ColumnComment("日志等级")
private Integer level;
@TableField
@ColumnType(value = MySqlTypeConstant.VARCHAR, length = 50)
@ColumnComment("被操作的对象")
private String operationUnit;
@TableField
@ColumnType(value = MySqlTypeConstant.VARCHAR, length = 250)
@ColumnComment("方法名")
private String method;
@TableField
@ColumnType(value = MySqlTypeConstant.VARCHAR, length = 5000)
@ColumnComment("参数")
private String args;
@TableField
@ColumnType(value = MySqlTypeConstant.VARCHAR, length = 250)
@ColumnComment("日志描述")
private String title;
@TableField
@ColumnType(value = MySqlTypeConstant.VARCHAR, length = 50)
@ColumnComment("操作类型")
private String operationType;
@TableField
@ColumnType(value = MySqlTypeConstant.BIGINT, length = 8)
@ColumnComment("方法运行时间")
private Long runTime;
@TableField
@ColumnType(value = MySqlTypeConstant.LONGTEXT)
@ColumnComment("方法返回值")
private String returnValue;
@TableField
@ColumnType(value = MySqlTypeConstant.VARCHAR, length = 5000)
@ColumnComment("请求的参数")
private String requestParams;
@TableField
@ColumnType(value = MySqlTypeConstant.VARCHAR, length = 5000)
@ColumnComment("操作模块")
private String module;
@TableField
@ColumnType(value = MySqlTypeConstant.VARCHAR, length = 50)
@ColumnComment("IP地址")
private String ip;
@TableField
@ColumnType(value = MySqlTypeConstant.INT, length = 8)
@ColumnComment("结果状态")
private Integer status;
}
package com.hivekion.system.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.hivekion.system.domain.SysOperationLog;
import org.apache.ibatis.annotations.Mapper;
/**
* @author admin
*/
@Mapper
public interface SysOperationLogMapper extends BaseMapper<SysOperationLog> {
/**
* 清空日志
*/
void cleanOperationLog();
}
@PostMapping("/checkDeptNameUnique")
@ApiOperation("部门名称是否存在")
@AutoLog(value = "部门名称是否存在", operationType = OperationTypeEnum.SELECT, module = "系统管理/部门管理")
public boolean checkDeptNameUnique(String deptName, String deptId) {
return deptService.checkDeptNameUnique(deptName, deptId);
}