public static BasicDataUser getCurrentUser() {
return (BasicDataUser) getHttpSession().getAttribute(ConstantUtils.LOGIN_ACCOUNT);
}
报错代码如上,会报空指针,因为上下文失效了。具体报错如下:
getHttpSession().getAttribute(ConstantUtils.LOGIN_ACCOUNT);?
because the return value of "org.springframework.web.context.request.RequestContextHolder.getRequestAttributes()"
is null
解决方法是对切面进行上下文保存并重置,具体代码如下:
@Around("execution(* *(..)) && (within(@org.springframework.stereotype.Controller *) || within(@org.springframework.web.bind.annotation.RestController *))")
public Object checkControllerExecutionTime(ProceedingJoinPoint joinPoint) throws Throwable {
// 判断方法是否被指定注解标记,如果是,则直接执行方法而不进行超时检查
if (isAnnotationPresent(joinPoint, SkipTimeoutCheck.class)) {
return joinPoint.proceed();
}
Signature signature = joinPoint.getSignature();
String controllerName = joinPoint.getTarget().getClass().getName();
String methodName = signature.getName();
long startTime = System.currentTimeMillis(); // 记录方法执行开始时间
// 保存请求上下文
RequestAttributes attributes = RequestContextHolder.getRequestAttributes();
CompletableFuture<Object> future = CompletableFuture.supplyAsync(() -> {
try {
// 恢复请求上下文
RequestContextHolder.setRequestAttributes(attributes, true);
return joinPoint.proceed();
} catch (Throwable throwable) {
throw new RuntimeException(throwable);
} finally {
// 清除请求上下文
RequestContextHolder.resetRequestAttributes();
}
});
long timeout = 10000; // 设置超时时间为10秒
try {
Object result = future.get();
long endTime = System.currentTimeMillis(); // 记录方法执行结束时间
long elapsedTime = endTime - startTime; // 计算方法执行所耗时间
if (elapsedTime > timeout){
dingTalk.sendText("超时方法: " + controllerName + "." + methodName + ", 超时时间: " + elapsedTime + "ms");
}
return result;
} catch (Exception e) {
long endTime = System.currentTimeMillis(); // 记录方法执行结束时间
long elapsedTime = endTime - startTime; // 计算方法执行所耗时间
if (e instanceof java.util.concurrent.TimeoutException) {
dingTalk.sendText("超时方法: " + controllerName + "." + methodName + ", 超时时间: " + elapsedTime + "ms");
}
return null;
}
}
重点是上下文相关的几行代码。
对于切面拦截的相关控制器,如果控制器里面的方法有private修饰的,且里面有使用注入的service等,会报空指针异常,需修改为public修饰的。报错代码如下:
@Controller
@RequestMapping("/packageContent")
public class BasicDataPackageContentController extends BaseController{
private final static String CURRENT_PATH=BASICDATA_PATH+"package/";
@Autowired
private BasicDataPackageTypeService basicDataPackageTypeService;
@AccessAuth(authority = "packageContent:main")
@GetMapping("/main")
private String main(HttpServletRequest request){
request.setAttribute("packageType",basicDataPackageTypeService.getValidList());
return CURRENT_PATH+"packagecontent";
}
}
报错信息为:
Cannot invoke "com.itomcat.shinva.service.BasicData.BasicDataPackageTypeService.getValidList()" because "this.basicDataPackageTypeService" is null
解决方法就是修改private 为public。