在上一篇最后提到就是面对业务代码中出现异常的情况,如果不处理,则展示给用户的信息是非常不友好的。比如以下代码出现空指针时
那么前端得到的响应是啥样?
此外在业务代码中可能会用很多的校验,有的校验返回一些提示信息,有的校验可能需要抛出指定的异常。
通常我们使用try {...} catch {...} finally {...} 代码块来处理异常,而这些异常我们是不能直接展现给用户。所以对异常进行分类统一处理,减少冗余代码,使代码风格统一更优雅。
像上图中一个代码块中会有很多的校验,而实际项目中非空或者一些业务判断都是很频繁的。我们来改造一下上图中的代码,使用断言后两行代码就解决了
到这里不用看源码大家肯定也已经猜到了,它肯定用的if(){}
是null就抛出异常,而state()却不一样,为false时抛出异常,所以这里的表达式填我们想要的结果。
用之前去Assert类中看一看,多用几次自然就熟练了,开发起来也会更加的快速。
实际项目中我们可能还需要调用其他服务暴露出来的接口,调用失败后抛出自定义的异常
此时我们也可以写个断言工具类
public class AssertUtil {
/**
* 服务调用异常
* @param expression
* @param message
*/
public static void isTrueServiceInvoke(boolean expression, String message) {
if (!expression) {
throw new ServiceInvokeException(message);
}
}
}
那么这一类问题,都可以使用,解决了代码冗余问题
通过以上描述我们也可以看出,项目中除了空指针这种异常,还有断言抛出的异常,还有自定义异常,对各种各样的异常统一处理,使得返回更加友好的信息。
主要通过 @RestControllerAdive
提升作用域,通过 @ExceptionHandler
注解来处理不同的异常。
import com.example.assertdemo.common.exception.ServiceInvokeException;
import com.example.assertdemo.constant.ResultCodeEnum;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
@Slf4j
@ControllerAdvice
public class GlobalExceptionHandler {
@ResponseBody
@ExceptionHandler(NullPointerException.class)
public ApiResult nullPointerExceptionHandler(NullPointerException exception) {
log.error(exception.getMessage());
return ApiResult.fail(ResultCodeEnum.SERVE_EXCEPTION);
}
@ResponseBody
@ExceptionHandler(ServiceInvokeException.class)
public ApiResult serviceInvokeExceptionHandler(ServiceInvokeException exception){
log.error(exception.getMessage());
return ApiResult.fail(ResultCodeEnum.SERVE_EXCEPTION);
}
}
返回的状态码和提示信息搞个枚举类
@Getter
public enum ResultCodeEnum{
/**
* success
*/
SUCCESS(0,"操作成功"),
/**
* fail
*/
FAIL(-1,"操作失败"),
/**
* 参数错误:1001-1999
*/
PARAM_IS_INVALID(1001,"参数无效"),
PARAM_TYPE_ERROR(1002,"参数类型错误"),
/**
* 业务错误:2001-2999
*/
TERMINATE_CONTRACT_FAIL(2001,"终止合同失败,请联系管理员"),
SERVE_EXCEPTION(3001,"当前服务出小差了,请联系管理员"),
;
/**
* 状态码
*/
private final int code;
/**
* 提示信息
*/
private final String message;
ResultCodeEnum(Integer code, String message){
this.code = code;
this.message = message;
}
}
此时我们再去请求2、断言处理中的接口,这种提示就非常友好,不会给用户展示看不懂的一连串异常信息,还能让开发者及时定位到问题去处理。
说白了很多方法就是填入你希望的结果,比如isTrue(a==1,""),也就是我希望a等于1,如果不等于就抛出异常。
对象和类型断言
方法 |
说明 |
notNull() |
对象是null抛出异常 |
isNull() |
对象不是null抛出异常 |
isInstanceOf() |
检查对象必须为另一个特定类型的实例 |
isAssignable() |
检查类型 |
文本断言
方法 |
说明 |
hasLength() |
只要不是null和空字符串就不会报异常 |
hasText() |
增强检查条件,字符串至少包含一个非空白字符,可以使用hasText()方法 |
doesNotContain() |
检查参数不包含特定子串 |
逻辑断言
方法 |
说明 |
isTrue() |
条件为假抛出IllegalArgumentException 异常 |
state() |
该方法与isTrue一样,但抛出IllegalStateException异常 |
Collection和map断言
方法 |
说明 |
Collection应用notEmpty() |
Collection不是null并包含至少一个元素 |
map应用notEmpty() |
检查map不null,并至少包含一个entry(key,value键值对) |
数组断言
方法 |
说明 |
notEmpty() |
可以检查数组不null,且至少包括一个元素 |
noNullElements() |
确保数组不包含null元素 |