一、注解(日志方面)
在一个项目中日志还是很有必要的,所以日志的写法,所以这里用操作日志的记录保存来解读。
想更了解注解可以看看Java-Java5.0注解解读
- 这个注解用法,即给方法上注解后,再给上参数,然后通过切面编程获取注解上的参数等,进行其他相关处理。
- 注解的使用:
@Log(title = "操作日志", businessType = BusinessType.DELETE)
@PreAuthorize("@ss.hasPermi('monitor:operlog:remove')")
@DeleteMapping("/{operIds}")
public AjaxResult remove(@PathVariable Long[] operIds)
{
return toAjax(operLogService.deleteOperLogByIds(operIds));
}
- 注解的写法:
/**
* 自定义操作日志记录注解
*
* @author ruoyi
*
*/
//@Inherited如果被用于一个class,这个注解(annotation)将被用于该class的子类
// 声明注解的保留期限
@Target({ ElementType.PARAMETER, ElementType.METHOD })
// 声明可以使用该注解的目标类型
@Retention(RetentionPolicy.RUNTIME)
// 标记可被如javadoc的工具文档化
@Documented
public @interface Log
{
/**
* 所有的注解都隐式继承与java.lang.annotation.Annotation,但注解不允许显示继承其他的接口。
*/
/**
* 模块
*/
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;
}
二、面向切面编程
Spring-AOP @AspectJ切点函数之@annotation()
细说Spring——AOP详解(AOP概览)
/**
* 操作日志记录处理
*
* @author ruoyi
*/
//切面声明
@Aspect
//组件声明
@Component
public class LogAspect
{
/**slf4j打印日志简便写法
* 获取后之间使用
* log.error("异常信息:{}", exp.getMessage());
*/
private static final Logger log = LoggerFactory.getLogger(LogAspect.class);
/**
*这个切面 LogAspect就两种advice,对应方法两种不同结束情况:
* 1、方法正常返回后@AfterReturning
* 2、方法抛出异常后@AfterThrowing
* ----
* 一个方法一个时间只会织入一种,并调用处理handleLog()
*/
/**
* 处理完请求后执行
*
* @param joinPoint 切点
* @annotation表示标注了某个注解的所有方法。
* returning将返回值绑定到的参数名称
*/
@AfterReturning(pointcut = "@annotation(controllerLog)", returning = "jsonResult")
public void doAfterReturning(JoinPoint joinPoint, Log controllerLog, Object jsonResult)
{
handleLog(joinPoint, controllerLog, null, jsonResult);
}
/**
* 拦截异常操作
*
* @param joinPoint 切点
* @param e 异常
*/
@AfterThrowing(value = "@annotation(controllerLog)", throwing = "e")
public void doAfterThrowing(JoinPoint joinPoint, Log controllerLog, Exception e)
{
//调用后面的处理
handleLog(joinPoint, controllerLog, e, null);
}
}
-后面这些方法也是在日志切面类中
//------------------后面的都是处理方法--------------------
/**
*@Date: 2021/11/16 9:48
*@Param [joinPoint, controllerLog, e, jsonResult]
*@return void
* joinPoint用于获取类名、方法名
* controllerLog是注解,注解有属性(对方法的描述信息)
* e异常
* jsonResult结果---设置给操作日志实体
*/
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(ServletUtils.getRequest().getRequestURI());
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();//通过joinPoint获取类名
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();
}
}
/**
* 获取注解中对方法的描述信息 用于Controller层注解
*
* @param log 日志
* @param operLog 操作日志
* @throws Exception
*/
public void getControllerMethodDescription(JoinPoint joinPoint, Log log, SysOperLog operLog, Object jsonResult) throws Exception
{
// 设置action动作
operLog.setBusinessType(log.businessType().ordinal());
// 设置标题
operLog.setTitle(log.title());
// 设置操作人类别
operLog.setOperatorType(log.operatorType().ordinal());
// 是否需要保存request,参数和值
if (log.isSaveRequestData())
{
// 获取参数的信息,传入到数据库中。
setRequestValue(joinPoint, operLog);
}
// 是否需要保存response,参数和值
if (log.isSaveResponseData() && StringUtils.isNotNull(jsonResult))
{
operLog.setJsonResult(StringUtils.substring(JSON.toJSONString(jsonResult), 0, 2000));
}
}
/**
* 获取请求的参数,放到log中
*
* @param operLog 操作日志
* @throws Exception 异常
*/
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
{
Object jsonObj = JSON.toJSON(o);
params += jsonObj.toString() + " ";
}
catch (Exception e)
{
}
}
}
}
return params.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;
}