在代码的编写过程当中含有的一些不可避免的情况,就是会出现异常,在后端进行处理操作。
{
"timestamp": "2023-12-21T09:49:08.199+00:00",
"status": 500,
"error": "Internal Server Error",
"message": "",
"path": "/content/course"
}
当出现异常的情况的话,若我们不对异常的信息进行处理操作的话,就会直接不断的向上抛出异常,最终抛给spring容器,但是spring容器是不会对异常进行处理操作的,那么就会直接将异常抛给前端使得前端直接报错了。
这个报错可不是简单的报错,仅仅是因为在填写表单处理的时候一个关键的课程名称没有填就直接报了一个服务器异常500.这是多么不可原谅的事情呀!!一个小错误导致整个系统都出现了一个大的问题。
那解决这个问题的方式有很多种!
在填写课程名称的时候前端工程对其进行设定操作。后端工程也是可以对其进行操作的,对异常的进行相应的处理操作。不要让后端工程出现500服务器出现问题的情况。那么异常的情况含有很多种,直接使用try catch的方式来对其进行处理操作。异常进行处理了就不会直接报错了。但是这种情况不是非常友好,首先你要只知道那一段代码可能后报错,才能准确的对其进行处理操作。还有一种情况就是会使得代码非常的冗余,很多的地方都是出现try catch的情况。
那么还有一种方法就是直接使用全局异常处理的操作。当程序中出现异常的情况直接通过全局异常处理器对异常进行处理。这个处理的方式通过获取这个异常的类型。设定专门的异常处理的相关类来进行操作。
例如:当抛出了空指针异常的时候,直接使用一个接口对这个异常进行接收。然后对其就处理操作,使得不会直接包报500错误的情况。同时还可以和前端工程师商量,向前端抛出一个什么类型的json数据格式就是属于异常信息,那么前端就可以通过获得这个异常信息进行前端的展示了。这样就可以规范出一套完整的代码。
通过这张图就可以看到以固定的格式返回json数据
那该怎么进行全局异常处理的操作呢??
首先我们知道在处理异常的情况下,我们可以直接对系统内部的异常进行抓取并进行相应的处理操作。
同时我们也可以设置我们自己编写的异常类,来对认为可能会出现异常的情况下进行我们自己异常的抛出。同时我们可以对其进行全局异常处理(自己的异常类)。
1.编写自定义异常
package com.xuecheng.base.exception;
/**
* @program: xuecheng-plus-root
* @description
* @author: YangTao
* @create: 2023-12-21 19:03
**/
public class XueChengPlusException extends RuntimeException{
private String message;
public XueChengPlusException() {
super();
}
public XueChengPlusException(String message) {
super(message);
this.message = message;
}
//直接生成一个静态的方法将异常进行抛出
public static void cast(String message){
throw new XueChengPlusException(message);
}
@Override
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}
//这里也可以使用枚举的异常信息进行抛出,对于一些比较固定的异常信息[请求参数为空 , 对象为空],这样就可以直接获取相应的枚举的异常信息,不要对所有的异常信息进行设定,可以直接就进行获取。也可以对我们抛出的大类异常进行相应枚举的操作。
2.创建枚举类(异常)
package com.xuecheng.base.exception;
/**
* @program: xuecheng-plus-root
* @description
* @author: YangTao
* @create: 2023-12-21 19:17
**/
public enum CommonError {
//生成相应的枚举类,可以对枚举类进行对象的获取
UNKOWN_ERROR("执行过程异常,请重试。"),
PARAMS_ERROR("非法参数"),
OBJECT_NULL("对象为空"),
QUERY_NULL("查询结果为空"),
REQUEST_NULL("请求参数为空");
private String message;
CommonError(String message) {
this.message = message;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}
在自定义的异常类添加的相应的枚举的异常处理操作
//这里也可以使用枚举的异常信息进行抛出,对于一些比较固定的异常信息[请求参数为空 , 对象为空]
public static void cast(CommonError error){
throw new XueChengPlusException(error.getMessage());
}
3.编写前端返回的异常处理的信息
package com.xuecheng.base.exception;
import java.io.Serializable;
/**
* @program: xuecheng-plus-root
* @description
* @author: YangTao
* @create: 2023-12-21 21:27
**/
//跟前端约定好的处理异常的时候返回的json数据,当设定的json的属性是不一样的时候就会得到一个错误的结果。前端得不到errMessage的相关信息。
public class RestErrorResponse implements Serializable {
private String errMessage;
public RestErrorResponse(String errMessage) {
this.errMessage = errMessage;
}
public String getErrMessage() {
return errMessage;
}
public void setErrMessage(String errMessage) {
this.errMessage = errMessage;
}
}
异常的抛出的相关类,枚举类,和响应给前端的类都编写完了。
那么就要一个异常处理的类来对抛出的异常统一的处理操作。以统一的格式相应给前端。
4.编写异常处理器
在Spring里,我们可以使用@ControllerAdvice来声明一些全局性的东西,最常见的是结合@ExceptionHandler注解用于全局异常的处理。
@ControllerAdvice是在类上声明的注解,其用法主要是
和@ExceptionHandler注解标注的方法结合使用的:用于捕获Controller中抛出的不同类型的异常,从而达到异常全局处理的目的;
package com.xuecheng.base.exception;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.*;
/**
* @program: xuecheng-plus-root
* @description
* @author: YangTao
* @create: 2023-12-21 19:36
**/
@ControllerAdvice
//@ControllerAdvice和@ResponseBody的结合体是ReControllerAdvice.
//直接使用这个注解就可以不需要对每一个方法进行相应的转json的格式了。方便一点
@Slf4j
public class GlobalExceptionHandler {
@ExceptionHandler(XueChengPlusException.class)
@ResponseBody
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)//对进入到异常的相关响应直接返回一个状态码
public RestErrorResponse handleXueChengPlusException(XueChengPlusException e){
//将异常打印出来
log.error(e.getMessage());
String message = e.getMessage();
return new RestErrorResponse(message);
}
@ExceptionHandler(Exception.class)
@ResponseBody
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public RestErrorResponse handleException(Exception e){
//将异常打印出来
log.error(e.getMessage());
//对于不是自己定义的异常我们可以直接使用枚举类来获得异常的信息
RestErrorResponse restErrorResponse = new RestErrorResponse(CommonError.UNKOWN_ERROR.getMessage());
String message = restErrorResponse.getErrMessage();
return restErrorResponse;
}
}
进入到这个异常当中,直接对处理并且返回相应的结果。前端得到这个结果和返回的状态码.
前端响应的结果为json的数据。
前端的约定是得到的data当中含有的属性errMessage就对其进行相应的解析操作的。得到里面的内容,当前端和后端设定的属性的名称是不一致的话就对其解析是错误的。得不到正确的结果。
使得前端得不到提示!
根据不同的异常类型来得到不同的响应结果。