一 自定义操作日志注解
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import com.myt.common.enums.BusinessType;
import com.myt.common.enums.OperatorType;
@Target({
ElementType.PARAMETER, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Log
{
public String title() default "";
public BusinessType businessType() default BusinessType.OTHER;
public OperatorType operatorType() default OperatorType.MANAGE;
public boolean isSaveRequestData() default true;
public boolean isSaveResponseData() default true;
}
二 业务操作类型
public enum BusinessType
{
OTHER,
INSERT,
UPDATE,
DELETE,
GRANT,
EXPORT,
IMPORT,
FORCE,
GENCODE,
CLEAN,
}
三 操作日志记录处理
import java.util.Collection;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.validation.BindingResult;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.HandlerMapping;
import com.alibaba.fastjson2.JSON;
import com.myt.common.annotation.Log;
import com.myt.common.core.domain.model.LoginUser;
import com.myt.common.enums.BusinessStatus;
import com.myt.common.enums.HttpMethod;
import com.myt.common.filter.PropertyPreExcludeFilter;
import com.myt.common.utils.SecurityUtils;
import com.myt.common.utils.ServletUtils;
import com.myt.common.utils.StringUtils;
import com.myt.common.utils.ip.IpUtils;
import com.myt.framework.manager.AsyncManager;
import com.myt.framework.manager.factory.AsyncFactory;
import com.myt.system.domain.SysOperLog;
@Aspect
@Component
public class LogAspect
{
private static final Logger log = LoggerFactory.getLogger(LogAspect.class);
public static final String[] EXCLUDE_PROPERTIES = {
"password", "oldPassword", "newPassword", "confirmPassword" };
@AfterReturning(pointcut = "@annotation(controllerLog)", returning = "jsonResult")
public void doAfterReturning(JoinPoint joinPoint, Log controllerLog, Object jsonResult)
{
handleLog(joinPoint, controllerLog, null, jsonResult);
}
@AfterThrowing(value = "@annotation(controllerLog)", throwing = "e")
public void doAfterThrowing(JoinPoint joinPoint, Log controllerLog, Exception e)
{
handleLog(joinPoint, controllerLog, e, null);
}
protected void handleLog(final JoinPoint joinPoint, Log controllerLog, final Exception e, Object jsonResult)
{
try
{
LoginUser loginUser = SecurityUtils.getLoginUser();
SysOperLog operLog = new SysOperLog();
operLog.setStatus(BusinessStatus.SUCCESS.ordinal());
String ip = IpUtils.getIpAddr(ServletUtils.getRequest());
operLog.setOperIp(ip);
operLog.setOperUrl(StringUtils.substring(ServletUtils.getRequest().getRequestURI(), 0, 255));
if (loginUser != null)
{
operLog.setOperName(loginUser.getUsername());
}
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());
getControllerMethodDescription(joinPoint, controllerLog, operLog, jsonResult);
AsyncManager.me().execute(AsyncFactory.recordOper(operLog));
}
catch (Exception exp)
{
log.error("==前置通知异常==");
log.error("异常信息:{}", exp.getMessage());
exp.printStackTrace();
}
}
public void getControllerMethodDescription(JoinPoint joinPoint, Log log, SysOperLog operLog, Object jsonResult) throws Exception
{
operLog.setBusinessType(log.businessType().ordinal());
operLog.setTitle(log.title());
operLog.setOperatorType(log.operatorType().ordinal());
if (log.isSaveRequestData())
{
setRequestValue(joinPoint, operLog);
}
if (log.isSaveResponseData() && StringUtils.isNotNull(jsonResult))
{
operLog.setJsonResult(StringUtils.substring(JSON.toJSONString(jsonResult), 0, 2000));
}
}
private void setRequestValue(JoinPoint joinPoint, SysOperLog operLog) throws Exception
{
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));
}
}
private String argsArrayToString(Object[] paramsArray)
{
String params = "";
if (paramsArray != null && paramsArray.length > 0)
{
for (Object o : paramsArray)
{
if (StringUtils.isNotNull(o) && !isFilterObject(o))
{
try
{
String jsonObj = JSON.toJSONString(o, excludePropertyPreFilter());
params += jsonObj.toString() + " ";
}
catch (Exception e)
{
}
}
}
}
return params.trim();
}
public PropertyPreExcludeFilter excludePropertyPreFilter()
{
return new PropertyPreExcludeFilter().addExcludes(EXCLUDE_PROPERTIES);
}
@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;
}
}
四 异步工厂
import java.util.TimerTask;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.myt.common.constant.Constants;
import com.myt.common.utils.LogUtils;
import com.myt.common.utils.ServletUtils;
import com.myt.common.utils.StringUtils;
import com.myt.common.utils.ip.AddressUtils;
import com.myt.common.utils.ip.IpUtils;
import com.myt.common.utils.spring.SpringUtils;
import com.myt.system.domain.SysLogininfor;
import com.myt.system.domain.SysOperLog;
import com.myt.system.service.ISysLogininforService;
import com.myt.system.service.ISysOperLogService;
import eu.bitwalker.useragentutils.UserAgent;
public class AsyncFactory
{
private static final Logger sys_user_logger = LoggerFactory.getLogger("sys-user");
public static TimerTask recordLogininfor(final String username, final String status, final String message,
final Object... args)
{
final UserAgent userAgent = UserAgent.parseUserAgentString(ServletUtils.getRequest().getHeader("User-Agent"));
final String ip = IpUtils.getIpAddr(ServletUtils.getRequest());
return new TimerTask()
{
@Override
public void run()
{
String address = AddressUtils.getRealAddressByIP(ip);
StringBuilder s = new StringBuilder();
s.append(LogUtils.getBlock(ip));
s.append(address);
s.append(LogUtils.getBlock(username));
s.append(LogUtils.getBlock(status));
s.append(LogUtils.getBlock(message));
sys_user_logger.info(s.toString(), args);
String os = userAgent.getOperatingSystem().getName();
String browser = userAgent.getBrowser().getName();
SysLogininfor logininfor = new SysLogininfor();
logininfor.setUserName(username);
logininfor.setIpaddr(ip);
logininfor.setLoginLocation(address);
logininfor.setBrowser(browser);
logininfor.setOs(os);
logininfor.setMsg(message);
if (StringUtils.equalsAny(status, Constants.LOGIN_SUCCESS, Constants.LOGOUT, Constants.REGISTER))
{
logininfor.setStatus(Constants.SUCCESS);
}
else if (Constants.LOGIN_FAIL.equals(status))
{
logininfor.setStatus(Constants.FAIL);
}
SpringUtils.getBean(ISysLogininforService.class).insertLogininfor(logininfor);
}
};
}
public static TimerTask recordOper(final SysOperLog operLog)
{
return new TimerTask()
{
@Override
public void run()
{
operLog.setOperLocation(AddressUtils.getRealAddressByIP(operLog.getOperIp()));
SpringUtils.getBean(ISysOperLogService.class).insertOperlog(operLog);
}
};
}
}
五 操作日志记录表 oper_log对应的实体类
import java.util.Date;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.myt.common.annotation.Excel;
import com.myt.common.annotation.Excel.ColumnType;
import com.myt.common.core.domain.BaseEntity;
public class SysOperLog extends BaseEntity
{
private static final long serialVersionUID = 1L;
@Excel(name = "操作序号", cellType = ColumnType.NUMERIC)
private Long operId;
@Excel(name = "操作模块")
private String title;
@Excel(name = "业务类型", readConverterExp = "0=其它,1=新增,2=修改,3=删除,4=授权,5=导出,6=导入,7=强退,8=生成代码,9=清空数据")
private Integer businessType;
private Integer[] businessTypes;
@Excel(name = "请求方法")
private String method;
@Excel(name = "请求方式")
private String requestMethod;
@Excel(name = "操作类别", readConverterExp = "0=其它,1=后台用户,2=手机端用户")
private Integer operatorType;
@Excel(name = "操作人员")
private String operName;
@Excel(name = "部门名称")
private String deptName;
@Excel(name = "请求地址")
private String operUrl;
@Excel(name = "操作地址")
private String operIp;
@Excel(name = "操作地点")
private String operLocation;
@Excel(name = "请求参数")
private String operParam;
@Excel(name = "返回参数")
private String jsonResult;
@Excel(name = "状态", readConverterExp = "0=正常,1=异常")
private Integer status;
@Excel(name = "错误消息")
private String errorMsg;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@Excel(name = "操作时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss")
private Date operTime;
}
六 使用@Log注解
@Log(title = "类别维护", businessType = BusinessType.UPDATE)
@PutMapping
public AjaxResult edit(@RequestBody MytCategory mytCategory) {
return toAjax(mytCategoryService.updateMytCategory(mytCategory));
}