mirror of https://gitee.com/y_project/RuoYi.git
feat: 1、新增操作日志增加处理器,方便业务进行扩展(如针对响应内容超过2000字符的处理、或操作日志其他属性的增强);2、以配置的方式扩展Job的白名单;3、修复Job方法所在的Bean是一个AOP代理类时会出现空指针异常的问题
parent
4f5bf990bf
commit
b66e9cd7b6
|
@ -2,8 +2,10 @@ package com.ruoyi.framework.aspectj;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
import javax.servlet.http.HttpServletResponse;
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
import org.apache.commons.lang3.ArrayUtils;
|
import org.apache.commons.lang3.ArrayUtils;
|
||||||
import org.aspectj.lang.JoinPoint;
|
import org.aspectj.lang.JoinPoint;
|
||||||
import org.aspectj.lang.annotation.AfterReturning;
|
import org.aspectj.lang.annotation.AfterReturning;
|
||||||
|
@ -12,10 +14,12 @@ import org.aspectj.lang.annotation.Aspect;
|
||||||
import org.aspectj.lang.annotation.Before;
|
import org.aspectj.lang.annotation.Before;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.core.NamedThreadLocal;
|
import org.springframework.core.NamedThreadLocal;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
import org.springframework.validation.BindingResult;
|
import org.springframework.validation.BindingResult;
|
||||||
import org.springframework.web.multipart.MultipartFile;
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
import com.alibaba.fastjson.JSONObject;
|
import com.alibaba.fastjson.JSONObject;
|
||||||
import com.alibaba.fastjson.support.spring.PropertyPreFilters;
|
import com.alibaba.fastjson.support.spring.PropertyPreFilters;
|
||||||
import com.ruoyi.common.annotation.Log;
|
import com.ruoyi.common.annotation.Log;
|
||||||
|
@ -24,6 +28,7 @@ import com.ruoyi.common.enums.BusinessStatus;
|
||||||
import com.ruoyi.common.utils.ServletUtils;
|
import com.ruoyi.common.utils.ServletUtils;
|
||||||
import com.ruoyi.common.utils.ShiroUtils;
|
import com.ruoyi.common.utils.ShiroUtils;
|
||||||
import com.ruoyi.common.utils.StringUtils;
|
import com.ruoyi.common.utils.StringUtils;
|
||||||
|
import com.ruoyi.framework.handler.OperLogEnhanceHandler;
|
||||||
import com.ruoyi.framework.manager.AsyncManager;
|
import com.ruoyi.framework.manager.AsyncManager;
|
||||||
import com.ruoyi.framework.manager.factory.AsyncFactory;
|
import com.ruoyi.framework.manager.factory.AsyncFactory;
|
||||||
import com.ruoyi.system.domain.SysOperLog;
|
import com.ruoyi.system.domain.SysOperLog;
|
||||||
|
@ -45,6 +50,9 @@ public class LogAspect
|
||||||
/** 计算操作消耗时间 */
|
/** 计算操作消耗时间 */
|
||||||
private static final ThreadLocal<Long> TIME_THREADLOCAL = new NamedThreadLocal<Long>("Cost Time");
|
private static final ThreadLocal<Long> TIME_THREADLOCAL = new NamedThreadLocal<Long>("Cost Time");
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private OperLogEnhanceHandler operLogEnhanceHandler;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 处理请求前执行
|
* 处理请求前执行
|
||||||
*/
|
*/
|
||||||
|
@ -116,6 +124,8 @@ public class LogAspect
|
||||||
getControllerMethodDescription(joinPoint, controllerLog, operLog, jsonResult);
|
getControllerMethodDescription(joinPoint, controllerLog, operLog, jsonResult);
|
||||||
// 设置消耗时间
|
// 设置消耗时间
|
||||||
operLog.setCostTime(System.currentTimeMillis() - TIME_THREADLOCAL.get());
|
operLog.setCostTime(System.currentTimeMillis() - TIME_THREADLOCAL.get());
|
||||||
|
// 操作日志扩展点
|
||||||
|
operLogEnhanceHandler.extension(operLog);
|
||||||
// 保存数据库
|
// 保存数据库
|
||||||
AsyncManager.me().execute(AsyncFactory.recordOper(operLog));
|
AsyncManager.me().execute(AsyncFactory.recordOper(operLog));
|
||||||
}
|
}
|
||||||
|
@ -155,7 +165,7 @@ public class LogAspect
|
||||||
// 是否需要保存response,参数和值
|
// 是否需要保存response,参数和值
|
||||||
if (log.isSaveResponseData() && StringUtils.isNotNull(jsonResult))
|
if (log.isSaveResponseData() && StringUtils.isNotNull(jsonResult))
|
||||||
{
|
{
|
||||||
operLog.setJsonResult(StringUtils.substring(JSONObject.toJSONString(jsonResult), 0, 2000));
|
operLog.setJsonResult(operLogEnhanceHandler.getJsonResult(log, operLog, jsonResult));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,13 @@
|
||||||
package com.ruoyi.framework.config;
|
package com.ruoyi.framework.config;
|
||||||
|
|
||||||
import org.mybatis.spring.annotation.MapperScan;
|
import org.mybatis.spring.annotation.MapperScan;
|
||||||
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
import org.springframework.context.annotation.EnableAspectJAutoProxy;
|
import org.springframework.context.annotation.EnableAspectJAutoProxy;
|
||||||
|
|
||||||
|
import com.ruoyi.framework.handler.OperLogEnhanceHandler;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 程序注解配置
|
* 程序注解配置
|
||||||
*
|
*
|
||||||
|
@ -17,4 +21,10 @@ import org.springframework.context.annotation.EnableAspectJAutoProxy;
|
||||||
public class ApplicationConfig
|
public class ApplicationConfig
|
||||||
{
|
{
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
@ConditionalOnMissingBean
|
||||||
|
public OperLogEnhanceHandler operLogEnhanceHandler() {
|
||||||
|
return new OperLogEnhanceHandler() {};
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,32 @@
|
||||||
|
package com.ruoyi.framework.handler;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson.JSONObject;
|
||||||
|
import com.ruoyi.common.annotation.Log;
|
||||||
|
import com.ruoyi.common.utils.StringUtils;
|
||||||
|
import com.ruoyi.system.domain.SysOperLog;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 操作日志增强处理器
|
||||||
|
* @author 潇湘振宇
|
||||||
|
*/
|
||||||
|
public interface OperLogEnhanceHandler {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取JSON结果
|
||||||
|
* @param log
|
||||||
|
* @param operLog
|
||||||
|
* @param jsonResult
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
default String getJsonResult(Log log, SysOperLog operLog, Object result) {
|
||||||
|
return StringUtils.substring(JSONObject.toJSONString(result), 0, 2000);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 系统操作日志扩展
|
||||||
|
* @param operLog
|
||||||
|
*/
|
||||||
|
default void extension(SysOperLog operLog) {
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -4,6 +4,7 @@ import java.util.List;
|
||||||
import org.apache.shiro.authz.annotation.RequiresPermissions;
|
import org.apache.shiro.authz.annotation.RequiresPermissions;
|
||||||
import org.quartz.SchedulerException;
|
import org.quartz.SchedulerException;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
import org.springframework.stereotype.Controller;
|
import org.springframework.stereotype.Controller;
|
||||||
import org.springframework.ui.ModelMap;
|
import org.springframework.ui.ModelMap;
|
||||||
import org.springframework.validation.annotation.Validated;
|
import org.springframework.validation.annotation.Validated;
|
||||||
|
@ -38,6 +39,9 @@ public class SysJobController extends BaseController
|
||||||
{
|
{
|
||||||
private String prefix = "monitor/job";
|
private String prefix = "monitor/job";
|
||||||
|
|
||||||
|
@Value("${job.whiteList:}")
|
||||||
|
private List<String> whiteList;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private ISysJobService jobService;
|
private ISysJobService jobService;
|
||||||
|
|
||||||
|
@ -153,7 +157,7 @@ public class SysJobController extends BaseController
|
||||||
{
|
{
|
||||||
return error("新增任务'" + job.getJobName() + "'失败,目标字符串存在违规");
|
return error("新增任务'" + job.getJobName() + "'失败,目标字符串存在违规");
|
||||||
}
|
}
|
||||||
else if (!ScheduleUtils.whiteList(job.getInvokeTarget()))
|
else if (!ScheduleUtils.whiteList(job.getInvokeTarget(), whiteList.toArray(new String[whiteList.size()])))
|
||||||
{
|
{
|
||||||
return error("新增任务'" + job.getJobName() + "'失败,目标字符串不在白名单内");
|
return error("新增任务'" + job.getJobName() + "'失败,目标字符串不在白名单内");
|
||||||
}
|
}
|
||||||
|
@ -201,7 +205,7 @@ public class SysJobController extends BaseController
|
||||||
{
|
{
|
||||||
return error("修改任务'" + job.getJobName() + "'失败,目标字符串存在违规");
|
return error("修改任务'" + job.getJobName() + "'失败,目标字符串存在违规");
|
||||||
}
|
}
|
||||||
else if (!ScheduleUtils.whiteList(job.getInvokeTarget()))
|
else if (!ScheduleUtils.whiteList(job.getInvokeTarget(), whiteList.toArray(new String[whiteList.size()])))
|
||||||
{
|
{
|
||||||
return error("修改任务'" + job.getJobName() + "'失败,目标字符串不在白名单内");
|
return error("修改任务'" + job.getJobName() + "'失败,目标字符串不在白名单内");
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package com.ruoyi.quartz.util;
|
package com.ruoyi.quartz.util;
|
||||||
|
|
||||||
|
import org.apache.commons.lang3.ArrayUtils;
|
||||||
import org.quartz.CronScheduleBuilder;
|
import org.quartz.CronScheduleBuilder;
|
||||||
import org.quartz.CronTrigger;
|
import org.quartz.CronTrigger;
|
||||||
import org.quartz.Job;
|
import org.quartz.Job;
|
||||||
|
@ -10,6 +11,8 @@ import org.quartz.Scheduler;
|
||||||
import org.quartz.SchedulerException;
|
import org.quartz.SchedulerException;
|
||||||
import org.quartz.TriggerBuilder;
|
import org.quartz.TriggerBuilder;
|
||||||
import org.quartz.TriggerKey;
|
import org.quartz.TriggerKey;
|
||||||
|
import org.springframework.aop.support.AopUtils;
|
||||||
|
|
||||||
import com.ruoyi.common.constant.Constants;
|
import com.ruoyi.common.constant.Constants;
|
||||||
import com.ruoyi.common.constant.ScheduleConstants;
|
import com.ruoyi.common.constant.ScheduleConstants;
|
||||||
import com.ruoyi.common.exception.job.TaskException;
|
import com.ruoyi.common.exception.job.TaskException;
|
||||||
|
@ -123,19 +126,26 @@ public class ScheduleUtils
|
||||||
* 检查包名是否为白名单配置
|
* 检查包名是否为白名单配置
|
||||||
*
|
*
|
||||||
* @param invokeTarget 目标字符串
|
* @param invokeTarget 目标字符串
|
||||||
|
* @param extendedWhiteList 扩展的名单单
|
||||||
* @return 结果
|
* @return 结果
|
||||||
*/
|
*/
|
||||||
public static boolean whiteList(String invokeTarget)
|
public static boolean whiteList(String invokeTarget, String... extendedWhiteList)
|
||||||
{
|
{
|
||||||
|
String[] whiteList = StringUtils.isEmpty(extendedWhiteList) ? Constants.JOB_WHITELIST_STR
|
||||||
|
: ArrayUtils.addAll(extendedWhiteList, Constants.JOB_WHITELIST_STR);
|
||||||
String packageName = StringUtils.substringBefore(invokeTarget, "(");
|
String packageName = StringUtils.substringBefore(invokeTarget, "(");
|
||||||
int count = StringUtils.countMatches(packageName, ".");
|
int count = StringUtils.countMatches(packageName, ".");
|
||||||
if (count > 1)
|
if (count > 1)
|
||||||
{
|
{
|
||||||
return StringUtils.containsAnyIgnoreCase(invokeTarget, Constants.JOB_WHITELIST_STR);
|
return StringUtils.containsAnyIgnoreCase(invokeTarget, whiteList);
|
||||||
}
|
}
|
||||||
Object obj = SpringUtils.getBean(StringUtils.split(invokeTarget, ".")[0]);
|
Object obj = SpringUtils.getBean(StringUtils.split(invokeTarget, ".")[0]);
|
||||||
|
if (AopUtils.isAopProxy(obj)) {
|
||||||
|
obj = AopUtils.getTargetClass(obj);
|
||||||
|
}
|
||||||
String beanPackageName = obj.getClass().getPackage().getName();
|
String beanPackageName = obj.getClass().getPackage().getName();
|
||||||
return StringUtils.containsAnyIgnoreCase(beanPackageName, Constants.JOB_WHITELIST_STR)
|
return StringUtils.containsAnyIgnoreCase(beanPackageName, whiteList)
|
||||||
&& !StringUtils.containsAnyIgnoreCase(beanPackageName, Constants.JOB_ERROR_STR);
|
&& !StringUtils.containsAnyIgnoreCase(beanPackageName, Constants.JOB_ERROR_STR);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
Loading…
Reference in New Issue