異常:java.lang.IllegalStateException: It is illegal to call this method if the current request is not in asynchronous mode (i.e. isAsyncStarted() returns false)
package cn.bainuo.gene.aspect;
import cn.bainuo.gene.common.utils.RedisUserUtil;
import cn.bainuo.gene.security.domain.User;
import cn.bainuo.gene.security.domain.vo.UserInfoVo;
import cn.bainuo.gene.security.service.LoginService;
import cn.bainuo.gene.utils.utils.HttpRequestUtil;
import cn.bainuo.gene.utils.utils.StringUtils;
import cn.bainuo.gene.utils.utils.SystemControllerLog;
import cn.bainuo.gene.utils.utils.SystemServiceLog;
import com.alibaba.fastjson.JSON;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
@Aspect
@Component
@SuppressWarnings("all")
public class SystemLogAspect {
Logger logger = LoggerFactory.getLogger(this.getClass());
@Autowired
private LoginService loginService;
@Autowired
private RedisUserUtil redisUserUtil;
@Pointcut("@annotation(cn.bainuo.gene.utils.utils.SystemServiceLog)")
public void serviceAspect(){
}
@Pointcut("@annotation(cn.bainuo.gene.utils.utils.SystemControllerLog)")
public void controllerAspect(){
}
@Before("controllerAspect()")
public void doBefore(JoinPoint joinPoint) {
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
String token =(String)request.getAttribute("token");
String userName="";
if(StringUtils.isNotBlank(token)) {
//讀取session中的用戶,注意:proai項目中讀取redis緩存用戶數據異常.
// UserInfoVo user = redisUserUtil.getCurrentUser(token);
User userInfoVo = loginService.getUserInfo(token);
userName=userInfoVo.getUserName();
}
//請求的IP
String ip = request.getRemoteAddr();
String params = "";
Object[] arguments = new Object[joinPoint.getArgs().length];
if (joinPoint.getArgs() != null && joinPoint.getArgs().length > 0) {
for (int i = 0; i < joinPoint.getArgs().length; i++) {
//這裏出現參數不能轉換問題,想了半天最後發現裏面有request對象不能被序列化
//最後把這些對象過濾了。
// params += JSON.toJSON(joinPoint.getArgs()[i]) + ";";
if (joinPoint.getArgs()[i] instanceof ServletRequest || joinPoint.getArgs()[i] instanceof ServletResponse || joinPoint.getArgs()[i] instanceof MultipartFile) {
//HttpServletRequest不能序列化,從入參裏排除,否則報異常:java.lang.IllegalStateException:
// It is illegal to call this method if the current request is not in asynchronous mode
// (i.e. isAsyncStarted() returns false)
continue;
}
arguments[i] = joinPoint.getArgs()[i];
}
}
if (arguments != null && arguments.length > 0) {
try {
params = JSON.toJSONString(arguments);
} catch (Exception e) {
params = arguments.toString();
}
}
try {
//*========控制檯輸出=========*//
logger.info("=====前置通知開始=====");
logger.info("請求方法:" + (joinPoint.getTarget().getClass().getName() + "." + joinPoint.getSignature().getName() + "()"));
logger.info("方法描述:" + getControllerMethodDescription(joinPoint));
logger.info("請求人:" + userName);
logger.info("請求IP:" + ip);
logger.info("請求參數:" + params);
logger.info("=====前置通知結束=====");
} catch (Exception e) {
//記錄本地異常日誌
logger.error("==前置通知異常==");
logger.error("異常信息:{}", e.getMessage());
}
}
@AfterThrowing(pointcut = "serviceAspect()",throwing = "e")
public void doAfterThrowing(JoinPoint joinPoint, Throwable e){
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
String token =(String)request.getAttribute("token");
String userName="";
if(StringUtils.isNotBlank(token)) {
//讀取session中的用戶 注意:proai項目中讀取redis緩存用戶數據異常.
// UserInfoVo user = redisUserUtil.getCurrentUser(token);
User userInfoVo = loginService.getUserInfo(token);
userName=userInfoVo.getUserName();
}
//獲取請求ip
String ip = HttpRequestUtil.getHost(request);
//獲取用戶請求方法的參數並序列化爲JSON格式字符串
String params = "";
Object[] arguments = new Object[joinPoint.getArgs().length];
if (joinPoint.getArgs() != null && joinPoint.getArgs().length > 0) {
for (int i = 0; i < joinPoint.getArgs().length; i++) {
// params += JSON.toJSON(joinPoint.getArgs()[i]) + ";";
if (joinPoint.getArgs()[i] instanceof ServletRequest || joinPoint.getArgs()[i] instanceof ServletResponse || joinPoint.getArgs()[i] instanceof MultipartFile) {
//HttpServletRequest不能序列化,從入參裏排除,否則報異常:java.lang.IllegalStateException:
// It is illegal to call this method if the current request is not in asynchronous mode
// (i.e. isAsyncStarted() returns false)
continue;
}
arguments[i] = joinPoint.getArgs()[i];
}
}
if (arguments != null && arguments.length > 0) {
try {
params = JSON.toJSONString(arguments);
} catch (Exception e1) {
params = arguments.toString();
}
}
try {
StackTraceElement s= e.getStackTrace()[0];
/*========控制檯輸出=========*/
logger.info("=====異常通知開始=====");
logger.info("異常代碼類/方法/行數:" +joinPoint.getTarget().getClass().getName()+"/"+s.getMethodName()+"/"+s.getLineNumber());
/*logger.info("異常方法:" + (joinPoint.getTarget().getClass().getName() + "." + joinPoint.getSignature().getName() + "()"));*/
logger.info("方法描述:" + getServiceMethodDescription(joinPoint));
logger.info("請求人:" + userName);
// logger.info("請求IP:" + ip);
logger.info("請求參數:" + params);
logger.info("=====異常通知結束=====");
} catch (Exception ex) {
//記錄本地異常日誌
logger.error("==異常通知異常==");
logger.error("異常信息:{}", ex.getMessage());
}
}
public static String getServiceMethodDescription(JoinPoint joinPoint)throws Exception{
String targetName = joinPoint.getTarget().getClass().getName();
String methodName = joinPoint.getSignature().getName();
Object[] arguments = joinPoint.getArgs();
Class targetClass = Class.forName(targetName);
Method[] methods = targetClass.getMethods();
String description = "";
for (Method method:methods) {
if (method.getName().equals(methodName)){
Class[] clazzs = method.getParameterTypes();
if (clazzs.length==arguments.length){
description = method.getAnnotation(SystemServiceLog.class).description();
break;
}
}
}
return description;
}
public static String getControllerMethodDescription(JoinPoint joinPoint) throws Exception {
String targetName = joinPoint.getTarget().getClass().getName();
String methodName = joinPoint.getSignature().getName();
Object[] arguments = joinPoint.getArgs();
Class targetClass = Class.forName(targetName);
Method[] methods = targetClass.getMethods();
String description = "";
for (Method method : methods) {
if (method.getName().equals(methodName)) {
Class[] clazzs = method.getParameterTypes();
if (clazzs.length == arguments.length) {
description = method.getAnnotation(SystemControllerLog. class).description();
break;
}
}
}
return description;
}
}
最初的觀察並沒有發現明顯的問題,因爲paramter本身就是String類型; 後進行debug後,定位出問題所在位置: paramter = JSON.toJSONString(args); 在執行後報錯:java.lang.IllegalStateException: It is illegal to call this method if the current request is not in asynchronous mode (i.e. isAsyncStarted() returns false)
上網查詢資料後發現,是因爲使用 Object[] args = joinPoint.getArgs(); 獲取入參的時候,args還包含了一些其他的內容,比如ServletRequest等,而這些入參並不能進行序列化,所以JSON.toJSONString時報錯,只能註釋這行代碼了,重新改造一下,在上面的代碼中已經實現了。
if (joinPoint.getArgs() != null && joinPoint.getArgs().length > 0) {
for (int i = 0; i < joinPoint.getArgs().length; i++) {
//這裏出現參數不能轉換問題,想了半天最後發現裏面有request對象不能被序列化
//最後把這些對象過濾了。
// params += JSON.toJSON(joinPoint.getArgs()[i]) + ";";
arguments[i] = joinPoint.getArgs()[i];
}
}