思考一下,前面写的代码还有啥问题: 就是我们没有考虑异常出现的时候 例如:
发现代码中有 int a = 100 / 0; 项目依然可以跑起来,但是实际上我们都知道,代码执行到这里可以是会报错的。 那么如果这个错误不明显,不像int a = 100 / 0; 那么我们要找到这个错误是一件很困难的事情 注意:判断密码错误等不属于异常,这只是逻辑错误的判断
如果都加try catch会让代码变得很丑陋,因此我们要使用全局异常处理
异常:
@RestControllerAdvice注解
: 当抛出异常时,@RestControllerAdvice
标注的类将被自动调用,并根据异常类型和处理程序的注解来决定如何处理该异常。这使得开发者可以在整个应用程序范围内统一处理异常。@ExceptionHandler注解
:@ExceptionHandler
一般与@RestControllerAdvice
配合使用,使用其来捕获和处理不同类型的异常。 注意: 1.我们尽量将抛出的异常都使用自定义异常,这样便于在异常处理处进行异常处理,比如统一返回json格式,或者统一进行日志记录等。 2.对于其他微服务来讲,它也是外部bean,因此要加上这个文件,才能将这个bean交给Spring容器去管理 3.为了让用户不看到我们的后台具体出什么问题了,因此就返回一个服务器异常就行了,而我们程序员就看日志的错误就行了
package com.qyy.common.security.handler;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.qyy.common.core.domain.R;
import com.qyy.common.core.enums.ResultCode;
import com.qyy.common.security.exception.ServiceException;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.support.DefaultMessageSourceResolvable;
import org.springframework.validation.BindException;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import java.util.Collection;
import java.util.Objects;
import java.util.function.Function;
import java.util.stream.Collectors;
/**
* 全局异常处理器
*/
@RestControllerAdvice//全局异常处理器
@Slf4j
//我们尽量将抛出的异常都使用自定义异常,这样便于在异常处理处进行异常处理,比如统一返回json格式,或者统一进行日志记录等。
public class GlobalExceptionHandler {
/**
* 请求方式不支持
*/
@ExceptionHandler(HttpRequestMethodNotSupportedException.class)
public R<?> handleHttpRequestMethodNotSupported(HttpRequestMethodNotSupportedException e,
HttpServletRequest request) {
String requestURI = request.getRequestURI();
log.error("请求地址'{}',不支持'{}'请求", requestURI, e.getMethod());
return R.fail(ResultCode.ERROR);
}
//拦截业务异常
@ExceptionHandler(ServiceException.class)
public R<?> handleServiceException(ServiceException e, HttpServletRequest request) {
String requestURI = request.getRequestURI();
ResultCode resultCode = e.getResultCode();
log.error("请求地址'{}',发生业务异常: {}", requestURI, resultCode.getMsg(), e);
return R.fail(resultCode);
}
//拦截参数校验异常
@ExceptionHandler(BindException.class)
public R<Void> handleBindException(BindException e) {
log.error(e.getMessage());
String message = join(e.getAllErrors(),
DefaultMessageSourceResolvable::getDefaultMessage, ", ");
return R.fail(ResultCode.FAILED_PARAMS_VALIDATE.getCode(), message);
}
//拦截验证异常
private <E> String join(Collection<E> collection, Function<E, String>
function, CharSequence delimiter) {
if (CollUtil.isEmpty(collection)) {
return StrUtil.EMPTY;
}
return collection.stream().map(function).filter(Objects::nonNull).collect(Collectors.joining(delimiter));
}
/**
* 拦截运行时异常
*/
@ExceptionHandler(RuntimeException.class)
public R<?> handleRuntimeException(RuntimeException e, HttpServletRequest request) {
String requestURI = request.getRequestURI();
log.error("请求地址'{}',发生运行时异常.", requestURI, e);
return R.fail(ResultCode.ERROR);
}
/**
* 系统异常(兜底)
*/
@ExceptionHandler(Exception.class)
public R<?> handleException(Exception e, HttpServletRequest request) {
String requestURI = request.getRequestURI();
log.error("请求地址'{}',发生异常.", requestURI, e);
return R.fail(ResultCode.ERROR);
}
}
@ExceptionHandler(BindException.class)
public R<Void> handleBindException(BindException e) {
log.error(e.getMessage());
String message = join(e.getAllErrors(),
DefaultMessageSourceResolvable::getDefaultMessage, ", ");
return R.fail(ResultCode.FAILED_PARAMS_VALIDATE.getCode(), message);
}
有些异常不想直接让用户知道,但是有一些异常,有些错误是想让用户知道的。比如新增管理员用户这个接口而言,你传了用户名为空的。那么想让你知道错误原因。
因此我们还要看一下这个异常想不想让用户知道。如果不想就返回:服务器繁忙请稍后重试。
出现空指针异常的话,我们肯定不想让用户知道。