Springboot 引入shiro后配置了realm和全局异常处理后发现。该异常无法被@RestControllerAdvice中的异常捕获处理。(这个问题是源代码问题,与自身代码无关)
出现问题的原因就不再说明,现在来说解决思路。
由于该异常在进去全局处理前被其他异常处理器捕获,所以我决定采用AOP在那些抛出异常且无法被全局处理捕获的方法上添加一个AOP标志,再自定义一个异常处理机制来处理此类异常。代码如下:
pom.xml引入aop模块
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
定义一个注解类
import java.lang.annotation.*;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ExceptionCatch {
/**
* 用于捕获 shiro#ream中抛出的异常
* (此异常无法被全局@RestControllerAdvice捕获处理,所以进行单独处理)
* @return 自定义名称
*/
String value() default "";
}
再定义一个业务处理类来捕获处理异常
import cn.hutool.core.util.StrUtil;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.bobi.station.http.Result;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.stereotype.Component;
@Component
@Aspect
public class AspectHandleException {
@Around("@annotation(exceptionCatch)")
public Result<Object> around(ProceedingJoinPoint joinPoint, ExceptionCatch exceptionCatch) {
try{
return Result.buildSuccess(joinPoint.proceed());
}catch (Throwable throwable){
MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
String value = exceptionCatch.value();
if(StrUtil.isEmpty(value)){
value = methodSignature.getMethod().getDeclaringClass().getName()+"#"+
methodSignature.getMethod().getName();
}
String[] parameterNames = methodSignature.getParameterNames();
Object[] args = joinPoint.getArgs();
StringBuilder sb = new StringBuilder();
sb.append("【").append(value).append("】")
.append("调用异常, 异常参数【");
if(parameterNames.length>0){
for(int i=0;i<parameterNames.length;i++){
sb.append(parameterNames[i]).append(" : ").append(args[i]);
if(i<parameterNames.length-1){
sb.append(",");
}
}
}
sb.append("】");
System.err.println(sb);
return Result.buildError(throwable.getMessage());
}
}
}
业务类上使用
@PostMapping("/doLogin")
@ExceptionCatch
public Result<Object> doLogin(@RequestBody LoginReq loginReq){
Subject subject = SecurityUtils.getSubject();
subject.login(new UsernamePasswordToken(loginReq.getUsername(), loginReq.getPassword()));
subject.getPrincipal();
return Result.buildSuccess(subject.getSession());
}
即可完成异常的正确处理。
如果出现了406 或 Not Acceptable,请确保自己的Result中的属性有get方法。