在程序运行的过程中,没有人能保证我们可以百分之百的没有BUG、没有异常。在程序爆出异常的时候,我们往往需要拦截一下,进行特殊的友好提示处理。
那么这里我们将针对Spring Mvc跟Spring Security的异常做一些拦截。
我们使用Spring mvc后,只需要在类上加上@RestControllerAdvice注解,就能够将程序大部分返回到客户端的异常进行处理
import com.hzw.code.common.utils.ActionException;
import com.hzw.code.common.utils.ActionResult;
import com.hzw.code.common.utils.ResultCodeEnum;
import io.jsonwebtoken.ExpiredJwtException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.http.converter.HttpMessageConversionException;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.validation.BindException;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.validation.ObjectError;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;
import java.util.List;
/**
* 全局异常处理
*
* @author: 胡汉三
* @date: 2020/5/26 12:00
*/
@RestControllerAdvice
@Slf4j
public class GlobalExceptionHandler {
private ActionResult commonHandleException(Exception e){
if(e instanceof ActionException) {
Object result = ((ActionException) e).getResult();
if (result instanceof ActionResult) {
ActionResult actionResult =(ActionResult) result;
return commonHandleException(actionResult.getCode(), actionResult.getMessage());
} else {
return commonHandleException(ResultCodeEnum.ERROR_DEFAULT, getRealExceptionMessage(e));
}
}else{
return commonHandleException(ResultCodeEnum.ERROR_DEFAULT, getRealExceptionMessage(e));
}
}
private ActionResult commonHandleException(ResultCodeEnum resultCode, String errorMsg){
log.error(errorMsg);
return commonHandleException(resultCode.getValue(), errorMsg);
}
private ActionResult commonHandleException(Integer resultCode, String errorMsg) {
return new ActionResult(resultCode, errorMsg, null);
}
/**
* 循环exception的cause,获取真正的错误信息
* @param exception
* @return
*/
public String getRealExceptionMessage(Exception exception){
// 初始化为顶级异常消息
String message = exception.getMessage();
if(StringUtils.isBlank(message)
|| message.indexOf("Exception") == -1){
message = exception.toString();
}
Throwable e = exception.getCause();
// 防止进入过多循环,最多只循环10层异常
for(int i = 0;i < 10;i++){
if(e == null){
break;
}
message = e.getMessage();
if(StringUtils.isBlank(message)
|| message.indexOf("Exception") == -1){
message = e.toString();
}
e = e.getCause();
}
return message;
}
@ExceptionHandler(ActionException.class)
public ActionResult
加上后,让我们来访问一些我们手动抛出异常的方法
@PreAuthorize("hasRole('ROLE_ADMIN')")
@GetMapping("/admin/auth")
public Object adminAuth(){
throw new ActionException("异常异常异常");
// return "ROLE_ADMIN 权限!";
}
这里可以看到,这个异常的返回根本不是我们统一的返回格式的,也就是说这个没有我们没有处理到。我们也在类里面加上了ExpiredJwtException的处理方法。但是没有效果。
程序里抛出的一些异常都没有被上面的@RestControllerAdvice处理。所以@RestControllerAdvice并不能处理程序返回的所有异常。那么我们在使用ErrorController来进行处理
import com.hzw.code.common.utils.ActionResult;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.web.servlet.error.ErrorAttributes;
import org.springframework.boot.web.servlet.error.ErrorController;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.context.request.ServletWebRequest;
import org.springframework.web.context.request.WebRequest;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Map;
import java.util.Objects;
/**
* spring security 异常处理
*
* @author: 胡汉三
* @date: 2020/5/26 12:00
*/
@Slf4j
@RestController
public class CustomErrorController implements ErrorController {
private static final String PATH = "/error";
@Autowired
private ErrorAttributes errorAttributes;
@RequestMapping(value = PATH)
ActionResult error(HttpServletRequest request, HttpServletResponse response) {
// Appropriate HTTP response code (e.g. 404 or 500) is automatically set by Spring.
// Here we just define response body.
Map errorMap = getErrorAttributes(request);
//定义返回格式
ActionResult d = new ActionResult();
d.setSuccess(false);
d.setMessage(Objects.requireNonNull(errorMap.get("message")).toString());
d.setCode(Integer.valueOf(Objects.requireNonNull(errorMap.get("status")).toString()));
d.setData(errorMap.get("error"));
response.setStatus(HttpServletResponse.SC_OK);
return d;
}
@Override
public String getErrorPath() {
return PATH;
}
/**
* 获取请求参数
* @param request
* @return
*/
private Map getErrorAttributes(HttpServletRequest request) {
WebRequest requestAttributes = new ServletWebRequest(request);
return errorAttributes.getErrorAttributes(requestAttributes,false);
}
}
我们来进行测试
加上后,我们拦截到了这个异常。
----------------------------------------------------------
项目的源码地址:https://gitee.com/gzsjd/fast
----------------------------------------------------------