自定义异常
系统中的异常可以分为我们能预知的异常和未知的系统异常,对于我们能预知的异常如空值判断,用户名错误,密码错误等异常我们需要返回客户端,对于系统内部异常如SQL语法错误,参数格式转换错误等需要统一包装成友好的提示后再返回客户端,否则用户也看不懂系统内部的异常。
定义响应码ResponseCode ,方便之后的自定义异常
public enum ResponseCode {
RESPONSE_CODE_200(200, "操作成功"),
RESPONSE_CODE_400(400, "参数错误"),
RESPONSE_CODE_1001(1001, "激活失败已过期"),
RESPONSE_CODE_1002(1002, "密码不一致")
private Integer code;
private String message;
ResponseCode(Integer code, String message) {
this.code = code;
this.message = message;
}
public Integer getCode() {
return code;
}
public void setCode(Integer code) {
this.code = code;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}
定义已知异常BusinessException,用于区分项目中的已知异常和未知异常
public class BusinessException extends RuntimeException{
private Integer code;
public BusinessException(ResponseCode responseCode) {
super(responseCode.getMessage());
this.code = responseCode.getCode();
}
public Integer getCode() {
return code;
}
public void setCode(Integer code) {
this.code = code;
}
public BusinessException() {
super();
}
public BusinessException(String s) {
super(s);
}
public BusinessException(String message, Throwable cause) {
super(message, cause);
}
public BusinessException(Throwable cause) {
super(cause);
}
protected BusinessException(String message, Throwable cause,
boolean enableSuppression,
boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
}
}
自定义断言工具类,避免大量if判断
public class AssertUtils {
public static void isTrue(Boolean flag, ResponseCode responseCode) {
if (!flag) {
throw new BusinessException(responseCode);
}
}
public static void isBlank(String str, ResponseCode responseCode) {
if (StrUtil.isNotBlank(str)) {
throw new BusinessException(responseCode);
}
}
public static void isNotBlank(String str, ResponseCode responseCode) {
if (StrUtil.isBlank(str)) {
throw new BusinessException(responseCode);
}
}
public static void isNull(Object object, ResponseCode responseCode) {
if (Objects.nonNull(object)) {
throw new BusinessException(responseCode);
}
}
public static void isNotNull(Object object, ResponseCode responseCode) {
if (Objects.isNull(object)) {
throw new BusinessException(responseCode);
}
}
public static void isNull(Collection collection, ResponseCode responseCode) {
if (collection != null && !collection.isEmpty()) {
throw new BusinessException(responseCode);
}
}
public static void isNotNull(Collection collection, ResponseCode responseCode) {
if (collection == null || collection.isEmpty()) {
throw new BusinessException(responseCode);
}
}
public static void isEq(String str1, String st2, ResponseCode responseCode) {
if (!str1.equals(st2)) {
throw new BusinessException(responseCode);
}
}
public static void isEqIgnoreCase(String str1, String str2, ResponseCode responseCode) {
if (!str1.equalsIgnoreCase(str2)) {
throw new BusinessException(responseCode);
}
}
public static void smallerThan(Long second, int i, ResponseCode responseCode) {
if (second > i) {
throw new BusinessException(responseCode);
}
}
}
全局异常处理类,不再写大量try - catch,由全局异常处理类自动捕获
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(BusinessException.class)
public AjaxResult businessExceptionHandler(BusinessException e) {
e.printStackTrace();
return AjaxResult.me()
.setSuccess(false)
.setMessage(e.getMessage())
.setCode(e.getCode());
}
//JSR-303校验所抛出的异常
@ExceptionHandler(MethodArgumentNotValidException.class)
public AjaxResult MethodArgumentNotValidExceptionHandler(MethodArgumentNotValidException e) {
e.printStackTrace();
BindingResult bindingResult = e.getBindingResult();
List<ObjectError> allErrors = bindingResult.getAllErrors();
StringBuffer sb = new StringBuffer();
allErrors.forEach(objectError -> sb.append(objectError.getDefaultMessage()).append("! "));
return AjaxResult.me()
.setSuccess(false)
.setMessage(sb.toString())
.setCode(ResponseCode.RESPONSE_CODE_400.getCode());
}
@ExceptionHandler(Exception.class)
public AjaxResult ExceptionHandler(Exception e) {
e.printStackTrace();
return AjaxResult.me()
.setSuccess(false)
.setMessage(ResponseCode.RESPONSE_CODE_500.getMessage())
.setCode(ResponseCode.RESPONSE_CODE_500.getCode());
}
}
在使用dto接受前端参数时,可以使用JSR-303校验
@Data
public class PlaceOrderDTO {
private String parentOrderNo;
@NotNull(message = "请选择收货地址") // 当为空时会报错 -> "请选择收货地址"
private OrderGiftAddress address;
}
可以将异常信息定义在properties中在resources包下ValidationMessages.properties配置文件中,将中文转换为Unicode转义序列的UTF-16编码格式
example.error.blank = \u4e0d\u80fd\u4e3a\u7a7a
\u4e0d 表示中文字符“不”。
\u80fd 表示中文字符“能”。
\u4e3a 表示中文字符“为”。
\u7a7a 表示中文字符“空”。
ValidationMessages.properties配置文件原本是在org.hibernate.validator包下的,因为javaapi中只定义了jsr303规范,具体实现是由其他包实现的,springboot-starter下是由org.hibernate.validator来实现的
@NotBlank(message = "${example.error.blank}")
private String username;
在controller接口参数位置打上@Valid,JSR303才能生效
@PostMapping("/placeorder")
public AjaxResult placeOrder(@Valid @RequestBody PlaceOrderDTO dto) {
orderGiftService.placeOrder(dto);
return AjaxResult.me().setResultObj(dto.getUniPayOrderSn());
}
```