场景: 用户手太快了,可能出现重复点击按钮
或有耗时较长请求,用户等不及一直刷新
场景:给运维用的,记录方法执行时间、执行状态等内容,提高运维效率
判定重复请求,可以在处理controller之前,对一些重复的请求直接拦截,推荐使用拦截器(interceptor) 实现。
记录方法执行状态,需要在很多场景使用,推荐使用Aspect实现。
下文是注解,是切面开始执行的定位坐标
/**
* 自定义注解防止表单重复提交
*/
@Inherited
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface RepeatSubmit
{
/**
* 间隔时间(ms),小于此时间视为重复提交
*/
public int interval() default 5000;
/**
* 提示消息
*/
public String message() default "不允许重复提交";
}
下文是拦截器(interceptor),如何实现注解对应的功能
/**
* 防止重复提交拦截器
*/
@Component
public abstract class RepeatSubmitInterceptor extends HandlerInterceptorAdapter
{
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception
{
if (handler instanceof HandlerMethod)
{
HandlerMethod handlerMethod = (HandlerMethod) handler;
Method method = handlerMethod.getMethod();
// 拿到注解对象
RepeatSubmit annotation = method.getAnnotation(RepeatSubmit.class);
if (annotation != null)
{
if (this.isRepeatSubmit(request)) // 判定请求是否重复的代码
{
// 这里获取注解中的mes
AjaxResult ajaxResult = AjaxResult.error(annotation.message());
response.setContentType("application/json");
response.setCharacterEncoding("utf-8");
response.getWriter().print(ajaxResult);
return false;
}
}
return true;
}
else
{
return super.preHandle(request, response, handler);
}
}
}
下文是注解,是切面开始执行的定位坐标
/**
* 自定义操作日志记录注解
*/
@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;
}
下文是拦截器(Aspect),如何实现注解对应的功能
/**
* 操作日志记录处理
*/
@Aspect // 切面注解
@Component
public class LogAspect
{
// 配置织入点 当有这个注解的时候触发此切面
@Pointcut("@annotation(com.common.annotation.Log)")
public void logPointCut(){}
/**
* 处理完请求后执行
*
* @param joinPoint 切点
*/
@AfterReturning(pointcut = "logPointCut()", returning = "jsonResult")
public void doAfterReturning(JoinPoint joinPoint, Object jsonResult)
{
String className = joinPoint.getTarget().getClass().getName();
String methodName = joinPoint.getSignature().getName();
System.out.println(className +"函数执行");
//TODO 持久化进数据库也可以
}
/**
*
* @param joinPoint 切点
* @param e 异常
*/
@AfterThrowing(value = "logPointCut()", throwing = "e")
public void doAfterThrowing(JoinPoint joinPoint, Exception e)
{
// 获取注解对象 begin
Signature signature = joinPoint.getSignature();
MethodSignature methodSignature = (MethodSignature) signature;
Method method = methodSignature.getMethod();
if (method != null)
{
return method.getAnnotation(Log.class); // 获取注解对象成功
}
// 获取注解对象 end
/* 上文 单纯记录 一下如何获取 注解对象*/
// 当发生错误时进行处理
String methodName = joinPoint.getSignature().getName();
System.out.println(className +"函数执行失败,失败内容:"+e.getMessage());
//TODO 持久化进数据库也可以
}
}