RESTful
API 调用时发生异常,需要拦截Exception
,并转换成前端能处理统一响应的格式
通过
Spring MVC
提供的注解@ControllerAdvice
+@ExceptionHandler
,来实现指定异常类的异常处理,转换成统一R
响应
GlobalExceptionHandler
异常捕获:
- Validator 异常捕获处理
- ServiceException 异常捕获处理
- Exception 异常默认处理
/**
* 全局异常处理类
*
* @author zhanghp
* @date 2022-07-21 14:12
*/
@RestControllerAdvice
@AllArgsConstructor
@Slf4j
public class GlobalExceptionHandler {
/**
* 自定义全局异常处理调用方法
*
* @param req servlet request
* @param ex 异常信息
* @return R
*/
public R<?> allExceptionHandler(HttpServletRequest req, Throwable ex){
if (ex instanceof ServiceException) {
return serviceExceptionHandler((ServiceException) ex);
}
return exceptionHandler(ex);
}
/**
* 自定义异常处理
*
* @param ex 异常信息
* @return R
*/
@ExceptionHandler(ServiceException.class)
public R<?> serviceExceptionHandler(ServiceException ex){
log.warn("[serviceException]");
return fail(INTERNAL_SERVER_ERROR.getCode(), ex.getMessage());
}
/**
* 默认异常处理,兜底处理
*
* @param ex 异常信息
* @return R
*/
@ExceptionHandler(Exception.class)
public R<?> exceptionHandler(Throwable ex){
log.warn("[exception]");
return fail(INTERNAL_SERVER_ERROR.getCode(), ex.getMessage());
}
}
ServiceException
说明:封装个性化异常处理
/**
* @author zhanghp
* @date 2022-07-22 17:49
*/
public class ServiceException extends RuntimeException{
/**
* 错误码
*/
private Integer code;
/**
* 错误信息
*/
private String msg;
public ServiceException(ErrorCode errorCode){
this.code = errorCode.getCode();
this.msg = errorCode.getMsg();
}
public ServiceException(Integer code, String msg){
this.code = code;
this.msg = msg;
}
public ServiceException(){}
}
ExController
调用即可,这里不做演示了
/**
* @author zhanghp
* @date 2022-07-21 14:14
*/
@RestController
@SuppressWarnings("all")
public class ExController {
@GetMapping(value = "/ex", produces = "application/json; charset=utf-8")
public R ex() {
throw new ServiceException(400, "自定义异常");
}
}
ServiceUtils
/**
* @author zhanghp
* @date 2022-07-22 16:39
*/
public class ServletUtils {
/**
* 渲染数据
*
* @param response servlet response
* @param object 数据
*/
public static void writeJson(HttpServletResponse response, Object object){
String json = JsonUtils.toJsonString(object);
ServletUtil.write(response, json, MediaType.APPLICATION_JSON_VALUE);
}
}
JsonUtils
/**
* @author zhanghp
* @date 2022-07-22 16:42
*/
public class JsonUtils {
private static final ObjectMapper objectMapper = new ObjectMapper();
/**
* 数据 -》json string
*
* @param object 数据
* @return json string
*/
@SneakyThrows
public static String toJsonString(Object object) {
return objectMapper.writeValueAsString(object);
}
}
过滤器
的异常被拦截后,走不到全局异常处理类里,所以在其里面catch异常并统一处理
MyFilter
/**
* @author zhanghp
* @date 2022-07-22 16:01
*/
@Component
@RequiredArgsConstructor
public class MyFilter extends OncePerRequestFilter {
private final GlobalExceptionHandler globalExceptionHandler;
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws ServletException, IOException {
try {
System.out.println("123");
// int i = 1/0;
} catch (Exception e) {
R<?> r = globalExceptionHandler.allExceptionHandler(e);
ServletUtils.writeJson(response, r);
return;
}
chain.doFilter(request, response);
}
}
FilterConfig
/**
* @author zhanghp
* @date 2022-07-22 16:24
*/
@Component
public class FilterConfig implements WebMvcConfigurer {
/**
* 创建过滤器实例
*
* @param filter 过滤器
* @param order 过滤顺序
* @param 继承Filter
* @return FilterRegistrationBean
*/
public static <T extends Filter> FilterRegistrationBean<T> createFilterBean(T filter, Integer order) {
FilterRegistrationBean<T> bean = new FilterRegistrationBean<>(filter);
bean.setOrder(order);
return bean;
}
/**
* 添加MyFilter Bean
*
* @param globalExceptionHandler 自定义全局异常
* @return 过滤器bean
*/
@Bean
public FilterRegistrationBean<MyFilter> demoFilter(GlobalExceptionHandler globalExceptionHandler) {
return createFilterBean(new MyFilter(globalExceptionHandler), 1);
}
}
调用1.3接口编写的Controller即可
拦截器
的异常也不走全局异常,在过滤时,直接抛出了,也拦截不到,所以在其里面catch异常并返回,做到统一处理
和过滤器异常处理
方式大径相庭,给大家写简单写一下
MyInterceptor
/**
* @author zhanghp
* @date 2022-07-22 15:51
*/
@Component
public class MyInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
HandlerInterceptor.super.postHandle(request, response, handler, modelAndView);
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
HandlerInterceptor.super.afterCompletion(request, response, handler, ex);
}
}
InterceptorConfig
/**
* @author zhanghp
* @date 2022-07-22 15:58
*/
@Component
public class InterceptorConfig implements WebMvcConfigurer {
@Autowired
private MyInterceptor filter;
@Override
public void addInterceptors(InterceptorRegistry registry) {
// 添加拦截器
registry.addInterceptor(filter);
}
}
调用1.3接口编写的Controller即可
源码:https://gitee.com/zhp1221/ruoyi/tree/master/lab_01_web_module/lab_02_unified_handle