断言+异常处理优雅解决丑陋的抛异常方式

前沿

在平时的工作中,我们对异常的处理大体上包括2种,一种是主动处理异常,另外一种是系统自动抛出异常,那么不管是哪种异常,我们应该如何优雅的处理?在项目里,你是否看到过类似的代码:

if(xxx){

return xx;

}

或者是

if(xx){

throw new Exception("xx");

}

有没有觉得上面的处理方式不太优雅呢?

这边文章我们主要解决以下问题:

1、如何创建自己断言类

2、如何拦截各种异常,统一构造简单明了的返回对象

正文

断言

自定义异常

public class BusinessException extends RuntimeException {
    private String code = "E200001";

    public BusinessException(String code, String message, Throwable cause) {
        super(message, cause);
        this.code = code;
    }

    public BusinessException(String message, Throwable cause) {
        super(message, cause);
    }

    public BusinessException(String message) {
        super(message);
    }

    public BusinessException(Throwable cause) {
        super(cause);
    }

    public String getCode() {
        return this.code;
    }
}

自定义断言类

创建一个断言类BusinessAssert,这里继承了org.springframework.util.Assert断言

package com.eim.ac.trans.config;
import com.eim.ac.trans.config.sqlexecutor.BusinessException;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.util.Collection;
import java.util.Objects;
public class BusinessAssert extends Assert {
    private static final int ZERO = 0;

    /**
     * <p>
     * 服务调用异常
     *
     * </p>
     *
     * @param message 消息
     * @author Mr Zan
     * @since 2022/7/12 4:11 下午
     */
    public static void serviceInvokerError(String message) {
        throw new BusinessException(message);
    }

    /**
     * <p>
     * 服务调用判断是否合法
     * 若expression 为true则合法
     * 反之不合法
     * </p>
     *
     * @param expression 表达式
     * @param message    消息
     * @author Mr Zan
     * @since 2022/7/12 4:16 下午
     */
    public static void serviceInvokerValid(boolean expression, String message) {
        if (expression) {
            return;
        }
        throw new BusinessException(message);
    }

    /**
     * <p>
     * 服务调用判断不合法
     * 若expression 为true 则 不合法
     * 反正合法
     * </p>
     *
     * @param expression 表达式
     * @param message    消息
     * @author Mr Zan
     * @since 2022/7/12 4:17 下午
     */
    public static void serviceInvokerInvalid(boolean expression, String message) {
        if (expression) {
            throw new BusinessException(message);
        }
    }

    /**
     * <p>
     * 表达是是否为true
     * 若表达式为true 则合法
     * 反之不合法
     * </p>
     *
     * @param expression 表达式
     * @param message    消息
     * @author Mr Zan
     * @since 2022/7/12 4:20 下午
     */
    public static void isTrue(boolean expression, String message) {
        if (expression) {
            return;
        }
        throw new BusinessException(message);
    }

    /**
     * <p>
     * 表达是是否为false
     * 若表达式为false 则合法
     * 反之不合法
     * </p>
     *
     * @param expression 表达式
     * @param message    消息
     * @author Mr Zan
     * @since 2022/7/12 4:20 下午
     */
    public static void isFalse(boolean expression, String message) {
        if (expression) {
            throw new BusinessException(message);
        }
    }

    /**
     * <p>
     * 判断集合是否为空
     * 若为不为空 则不合法
     * </p>
     *
     * @param collection 集合
     * @param message    消息
     * @author Mr Zan
     * @since 2022/7/12 4:30 下午
     */
    public static void isEmpty(Collection<?> collection, String message) {
        if (CollectionUtils.isEmpty(collection)) {
            return;
        }
        throw new BusinessException(message);
    }

    /**
     * <p>
     * 判断集合是否不为空
     * 若为空则不合法
     * </p>
     *
     * @param collection 集合
     * @param message    消息
     * @author Mr Zan
     * @since 2022/7/12 4:31 下午
     */
    public static void isNotEmpty(Collection<?> collection, String message) {
        if (CollectionUtils.isEmpty(collection)) {
            throw new BusinessException(message);
        }
    }

    /**
     * <p>
     * 判断对象是否为空
     * 若不为空则不合法
     * </p>
     *
     * @param obj     对象
     * @param message 消息
     * @author Mr Zan
     * @since 2022/7/12 4:32 下午
     */
    public static void isNull(Object obj, String message) {
        if (Objects.isNull(obj)) {
            return;
        }
        throw new BusinessException(message);
    }

    /**
     * <p>
     * 判断对象是否不为空
     * 若为空则不合法
     * </p>
     *
     * @param obj     对象
     * @param message 消息
     * @author Mr Zan
     * @since 2022/7/12 4:33 下午
     */
    public static void isNotNull(Object obj, String message) {
        if (Objects.isNull(obj)) {
            throw new BusinessException(message);
        }
    }

    /**
     * <p>
     * 判断字符串是否为空
     * 不为空则不合法
     * </p>
     *
     * @param obj     字符窜
     * @param message 消息
     * @author Mr Zan
     * @since 2022/7/12 4:33 下午
     */
    public static void isEmpty(String obj, String message) {
        if (StringUtils.isEmpty(obj)) {
            return;
        }
        throw new BusinessException(message);
    }

    /**
     * <p>
     * 判断字符串是否不为空
     * 为空则不合法
     * </p>
     *
     * @param obj     对象
     * @param message 消息
     * @author Mr Zan
     * @since 2022/7/12 4:34 下午
     */
    public static void isNotEmpty(String obj, String message) {
        if (StringUtils.isEmpty(obj)) {
            throw new BusinessException(message);
        }
    }

    /**
     * <p>
     * 判断数字是否大于0
     * 若小于等于0 则不合法
     * </p>
     *
     * @param number  数字
     * @param message 消息
     * @author Mr Zan
     * @since 2022/7/12 4:35 下午
     */
    public static void gtZero(int number, String message) {
        if (BusinessAssert.ZERO >= number) {
            throw new BusinessException(message);
        }
    }

    /**
     * <p>
     * 判断数字是否大于等于0
     * 若小于0 则不合法
     * </p>
     *
     * @param number  数字
     * @param message 消息
     * @author Mr Zan
     * @since 2022/7/12 4:35 下午
     */
    public static void geZero(int number, String message) {
        if (BusinessAssert.ZERO > number) {
            throw new BusinessException(message);
        }
    }

    /**
     * <p>
     * 判断数字是否小于0
     * 若大于等于0 则不合法
     * </p>
     *
     * @param number  数字
     * @param message 消息
     * @author Mr Zan
     * @since 2022/7/12 4:35 下午
     */
    public static void ltZero(int number, String message) {
        if (number >= BusinessAssert.ZERO) {
            throw new BusinessException(message);
        }
    }

    /**
     * <p>
     * 判断数字是否小于等于0
     * 若大于0 则不合法
     * </p>
     *
     * @param number  数字
     * @param message 消息
     * @author Mr Zan
     * @since 2022/7/12 4:35 下午
     */
    public static void leZero(int number, String message) {
        if (number > BusinessAssert.ZERO) {
            throw new BusinessException(message);
        }
    }

}

说明

BusinessAssert类中包含了下面几部分方法:

1、service层的异常处理

2、service层根据boolean表达式来决定是否抛出异常

3、普通的校验表达式来抛出异常,包含对字符串校验、集合校验、对象校验、数字校验是否大于等于0、大于0、小于等于0、小于0 等情况

我们在项目中有时候会判断自增ID是否是合法的或者判断某些字段是否是合法的,那么这里数字校验就很方便了。

统一拦截异常类

封装统一返回类

public class ResponseData<T> {
    private String code;
    private String message;
    private T data;
    private String redirectUrl;

    public String getRedirectUrl() {
        return this.redirectUrl;
    }

    public void setRedirectUrl(String redirectUrl) {
        this.redirectUrl = redirectUrl;
    }

    public ResponseData() {
    }

    public ResponseData(ResponseCode responseCode) {
        this.code = responseCode.getCode();
        this.message = responseCode.getMessage();
    }

    public String getCode() {
        return this.code;
    }

    public void setCode(String code) {
        this.code = code;
    }

    public String getMessage() {
        return this.message;
    }

    public void setMessage(String message) {
        this.message = message;
    }

    public T getData() {
        return this.data;
    }

    public void setData(T data) {
        this.data = data;
    }

    public String toString() {
        return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
    }

    public static <T> ResponseData<T> createSuccessResult(String message, T data) {
        ResponseData<T> result = createSuccessResult(data);
        result.setMessage(message);
        return result;
    }

    public static <T> ResponseData<T> createSuccessResult(T data) {
        ResponseData<T> result = createSuccessResult();
        result.setData(data);
        return result;
    }

    public static <T> ResponseData<T> createSuccessResult() {
        return new ResponseData(ResponseCode.SUCCESS);
    }

    public static <T> ResponseData<T> createSuccessNullDataResult(String message) {
        ResponseData<T> result = createSuccessResult();
        result.setMessage(message);
        return result;
    }

    public static ResponseData createFailResult(String message) {
        ResponseData result = new ResponseData(ResponseCode.SYSTEM_ERROR);
        result.setMessage(message);
        return result;
    }

    public static ResponseData createFailResult(String message, String code) {
        ResponseData result = new ResponseData();
        result.setCode(code);
        result.setMessage(message);
        return result;
    }

    public static ResponseData createResult(ResponseCode responseCode) {
        return new ResponseData(responseCode);
    }

    public static <T> ResponseData<T> createResult(ResponseCode responseCode, T data) {
        ResponseData result = new ResponseData(responseCode);
        result.setData(data);
        return result;
    }

    public Boolean isSuccess() {
        return "200".equals(this.code);
    }

默认提供一些成功或者失败的静态方法,方便业务调用,同时提供范形T data 类型返回值,方便兼容所有类型的返回值,多个不同参数的构造方法,灵活调用,扩展性,灵活性更强。

拦截异常类

拦截api返回时的异常类,将异常信息转换成统一返回格式,通过@ControllerAdvice注解实现该功能。

简单介绍下这个注解,@ControllerAdvice注解的作用是可以处理一些全局性的事情,例如配合下面几个注解,实现不同的公共。

@ControllerAdvice是在类上声明的注解,其用法主要有三点:

在方法上添加下面的注解,实现不同的功能:

@ExceptionHandler注解:用来捕获Controller中抛出的不同类型的异常,从而达到异常全局处理的目的,这也是我们这次用到的功能。
@InitBinder注解:解析请求中注册的自定义参数,从而达到自定义请求参数格式的目的;
@ModelAttribute注解:表示此方法会在执行目标Controller方法之前执行 。

@ControllerAdvice
public class GlobalExceptionHandler {

    protected Logger log = LoggerFactory.getLogger(GlobalExceptionHandler.class);

    @ExceptionHandler(value = com.alibaba.fastjson.JSONException.class)
    public ResponseData alibabaJsonExceptionHandler(com.alibaba.fastjson.JSONException e) {
        log.error("GlobalExceptionHandler| alibabaJsonExceptionHandler| alibabaJson异常", e);
        return ResponseData.createFailResult(e.getMessage());
    }

    @ExceptionHandler(value = JsonParseException.class)
    @ResponseBody
    public ResponseData jsonParseExceptionHandler(JsonParseException e) {
        log.error("GlobalExceptionHandler| jsonParseExceptionHandler| json解析异常", e);
        return ResponseData.createFailResult(e.getMessage());
    }

    @ExceptionHandler(value = Exception.class)
    @ResponseBody
    public ResponseData exceptionHandler(Exception e) {
        log.error("GlobalExceptionHandler| exceptionHandler| 其他异常", e);
        return ResponseData.createFailResult(e.getMessage());
    }

    @ExceptionHandler(value = MethodArgumentTypeMismatchException.class)
    @ResponseBody
    public ResponseData methodArgumentTypeMismatchExceptionHandle(MethodArgumentTypeMismatchException e) {
        log.error("GlobalExceptionHandler| methodArgumentTypeMismatchExceptionHandle| 方法参数缺失异常", e);
        return ResponseData.createFailResult(e.getMessage());
    }

    @ExceptionHandler(value = IllegalArgumentException.class)
    @ResponseBody
    public ResponseData illegalArgumentExceptionHandler(IllegalArgumentException e) {
        log.error("GlobalExceptionHandler| illegalArgumentExceptionHandler| 不合法参数异常", e);
        return ResponseData.createFailResult(e.getMessage());
    }

    @ExceptionHandler(value = BusinessException.class)
    @ResponseBody
    public ResponseData businessExceptionHandler(BusinessException e) {
        log.error("GlobalExceptionHandler| businessExceptionHandler| 业务异常", e);
        return ResponseData.createFailResult(e.getMessage());
    }

    @ResponseBody
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public ResponseData methodArgumentNotValidExceptionHandler(MethodArgumentNotValidException e) {
        log.error("GlobalExceptionHandler| methodArgumentNotValidExceptionHandler| 方法参数不合法异常", e);
        String message = e.getBindingResult().getFieldError().getDefaultMessage();
        return ResponseData.createFailResult(message);
    }

    @ExceptionHandler(value = ServiceException.class)
    @ResponseBody
    public ResponseData businessExceptionHandler(ServiceException e) {
        log.error("GlobalExceptionHandler| businessExceptionHandler| service异常", e);
        return ResponseData.createFailResult(e.getMessage());
    }

其中BusinessException、ServiceException 是我们在上面自定义的异常,如果我们要新家拦截的异常,只需要在这里添加即可

测试

测试断言异常

public class AssertTest {
    public static void main(String[] args) {
        String str = "测试输入为空操作";
        BusinessAssert.isEmpty(str, "输入不为空");
        System.out.println("输入为空");
    }
}

期望:返回输入为空

实际:如下图

没问题

测试api的请求

创建一个controller

@RestController
public class AssertExceptionTestController {

    private Logger logger = LoggerFactory.getLogger(AssertExceptionTestController.class);

    @RequestMapping(value = "/api/assert/exception/test",method = RequestMethod.GET)
    public ResponseData dealFinIncome(String param) {
        logger.info("AssertExceptionTestController| dealFinIncome begin, dt:{}", param);
        BusinessAssert.isNotEmpty(param, "入参不能为空");
        logger.info("业务处理成功");
        return ResponseData.createSuccessResult();
    }
}

启动执行后,返回,如下图所示

 结果却是按照我们预想的那样返回,上面程序是没问题。

猜你喜欢

转载自blog.csdn.net/zanpengfei/article/details/125810144
今日推荐