1.先理解为什么要抛出异常?
一句话就是为了终止程序,一般是终止业务层也就是service层。
2.为什么要自定义异常抛出?
因为系统提供的异常种类很多,而且代表的含义很多,所以我们需要自己定义一个通用的异常,然后只要是业务层的异常我都抛出这个,只是给它不同的提示信息进行区别。其实大部分业务层抛出异常只是为了快速终止程序,提示给用户到底发生了什么错误。
3.为什么要进行全局异常捕获处理?
(1)如果不捕获当然也可以,但是很不友好,第一请求的响应结果是一个错误页面的标签,并且在控制台会直接打印出一堆很乱的错误信息的追踪。如图:
(2)所以一般情况下还是要捕获,但是很多人可能好奇,try catch不是能捕获吗?虽然能捕获但是不能终止异常,它后面的代码依然会执行,并且全局的异常也没办法做,一般只有编译器异常才会用try catch 例如文件找不到,因为不try catch程序一直报错,一般这种我们也是在catch里面重新抛出我们自定义的异常,然后再进行全局异常捕获。
(3)全局异常捕获的好处,第一可以指定捕获到的全局异常,然后还可以定义响应码和响应结果进行返回,不会出现刚才响应一个html标签奇怪的东西,第二不会在控制台打印出那个异常的错误信息,也很友好。
4.项目中如何自定义异常和全局捕获(实战)
(1)自定义业务层异常ServiceException放在exception包下面
一般包括错误码code和msg,此处多了一个响应枚举ResponseEnum,是因为有些错误很常见,可以统一提前定义在枚举里面,以后写的时候可以直接new throw ServiceException(ResponseEnum.xxx)更方便一些,当然一般情况下还是直接传入code和msg
package com.fzy.exception;import com.fzy.constant.ResponseEnum;
import lombok.Data;@Data
public class ServiceException extends RuntimeException {private ResponseEnum responseEnum;private Integer code;private String msg;public ServiceException(ResponseEnum responseEnum) {super(responseEnum.getMessage());this.responseEnum = responseEnum;this.code = responseEnum.getCode();this.msg = responseEnum.getMessage();}public ServiceException(Integer code, String msg) {super(msg);this.code = code;this.msg = msg;}public ServiceException(String msg) {super(msg);this.code = ResponseEnum.FAILURE.getCode();this.msg = msg;}
}
(2)响应的异常枚举ResponseEnum
package com.fzy.constant;import lombok.AllArgsConstructor;
import lombok.Getter;@AllArgsConstructor
@Getter
public enum ResponseEnum {SUCCESS(200,"成功"),FAILURE(500,"服务器错误"),FILE_SIZE_ERROR(500, "文件大小异常");private Integer code;private String message;
}
(3)返回给前端的ResponseVO
package com.fzy.result;import com.fzy.constant.ResponseEnum;
import lombok.Data;@Data
public class ResponseVO<T> {private Integer code;private String message;private T data;public ResponseVO(ResponseEnum resultEnum) {this.code = resultEnum.getCode();this.message = resultEnum.getMessage();}public ResponseVO(Integer code, String message) {this.code = code;this.message = message;}public ResponseVO(Integer code, String message, T data) {this.code = code;this.message = message;this.data = data;}public ResponseVO(T data) {this.data = data;}
}
(4)全局异常处理类SystemGlobalExceptionHandler,放到handler包下面
其中@ExceptionHandler主要是表明捕获哪个异常,可以给参数进行指定,e.getMessage是它父类的方法,并且我们在 new ServiceException时调用的super方法就是给父类中的Message赋值。
package com.fzy.handler;import com.fzy.exception.ServiceException;
import com.fzy.result.ResponseVO;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;@RestControllerAdvice
public class SystemGlobalExceptionHandler {@ExceptionHandler(value = RuntimeException.class)public ResponseVO exceptionHandler(ServiceException e){System.out.println(e.getMessage());if (e.getResponseEnum() != null) {return new ResponseVO<>(e.getResponseEnum());} else {return new ResponseVO<>(e.getCode(), e.getMsg());}}
}
总结:上面这种写法是为了更好的封装和规范开发,多理解一下,一般只在Service层进行抛出异常终止程序。