try,catch中的嵌套和全局异常的基本使用

一、try,catch中的嵌套使用分析
 

1.在被调用法的catch中不加throw进行异常抛出处理,(开发中遇到的bug:代码中出现sql新增报错,但是给前端返回的信息仍然是新增成功)代码如下:

 public static void main(String[] args) {
        try {
            int num=1+3;
            test();
            System.out.println("num1的值如下:"+num);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    public static void test() {
        try {
            int num2=1/0;
            System.out.println("num2:"+num2);
        } catch (Exception e) {
            log.info("错误信息:"+"除数为0");
            //在不抛出被调用方使用了try,catch,但是没有在catch中使用throw抛出异常,
            // 调用方虽然在调用一个方法上java语句上加上了try,catch,并在catch中异常抛出,
            // 但是控制台打印的信息如下:
//            14:10:57.793 [main] INFO com.as.test.controller.ThridController - 错误信息:除数为0
//            num1的值如下:4
            //分析:并未达到,被调用方出错,调用法的程序到此为止的目的
//            throw new RuntimeException(e);
        }


    }

运行结果如下:

14:22:58.922 [main] INFO com.as.test.controller.ThridController - 错误信息:除数为0
num1的值如下:4

分析:被调用方出现异常,程序并没有到此结束,而是继续执行调用方的后续代码,原因:如下,被调用方出现异常,使用catch进行了捕获,但是并没有对异常(抛出)进行处理,所以调用方无法在catch中进行异常捕获并抛出。

为了达到被调用方出现异常,程序到此结束,并在控制台抛出异常的代码修改如下:

public static void main(String[] args) {
        try {
            int num=1+3;
            test();
            System.out.println("num1的值如下:"+num);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    public static void test() {
        try {
            int num2=1/0;
            System.out.println("num2:"+num2);
        } catch (Exception e) {
            log.info("错误信息:"+"除数为0");
            throw new RuntimeException(e);
        }
    }

达到的目标效果如下:

14:19:59.073 [main] INFO com.as.test.controller.ThridController - 错误信息:除数为0
Exception in thread "main" java.lang.RuntimeException: java.lang.RuntimeException: java.lang.ArithmeticException: / by zero
	at com.as.test.controller.ThridController.main(ThridController.java:71)
Caused by: java.lang.RuntimeException: java.lang.ArithmeticException: / by zero
	at com.as.test.controller.ThridController.test(ThridController.java:87)
	at com.as.test.controller.ThridController.main(ThridController.java:68)
Caused by: java.lang.ArithmeticException: / by zero
	at com.as.test.controller.ThridController.test(ThridController.java:77)
	... 1 more
1.2使用接口对try,catch中进行异常捕获,后续进行处理和不处理的接口测试如下:
catch中对捕获异常,不进行处理
    @GetMapping("/tryTest")
    @ApiOperation("try,catch中进行异常捕获并抛出异常的结果测试")
    public static PublicResult test() {
        int num2=0;
        try {
             num2=1/0;
            System.out.println("num2:"+num2);
        } catch (Exception e) {
            log.info("错误信息:"+"除数为0");
//            throw new RuntimeException(e);
        }
        return new PublicResult("200","成功",num2);
    }

swagger结果测试如下:

	
Response body
Download
{
  "status": "200",
  "msg": "成功",
  "data": 0
}


catch中对捕获异常,进行处理

  @GetMapping("/tryTest")
    @ApiOperation("try,catch中进行异常捕获并抛出异常的结果测试")
    public static PublicResult test() {
        int num2=0;
        try {
             num2=1/0;
            System.out.println("num2:"+num2);
        } catch (Exception e) {
            log.info("错误信息:"+"除数为0");
            throw new RuntimeException(e);
        }
        return new PublicResult("200","成功",num2);
    }
swagger结果测试如下:
{
  "timestamp": "2024-07-27T06:41:03.950+0000",
  "status": 500,
  "error": "Internal Server Error",
  "message": "java.lang.ArithmeticException: / by zero",
  "path": "/tryTest"
try,catch也也可以在对数据库操作时,产生的异常进行捕获,可以抛出SQLExeption或者RuntimeException的异常
伪代码日如下:
try{
//调用对数据库中的数据操作的方法

dothing......

}catch(SQLException e){
throw new RuntimeException("运行时,发生的错误:"+e.getMessage());
}
1.3总结:
调用法和被调用方同时使用了try,catch都需要在catch捕获异常后,并对其进行处理,如异常抛出。

二、为什么使用全局异常?

如果我们不统一的处理异常,经常会在controller层有大量的异常处理的代码, 比如:

@Slf4j
@Api(value = "使用try,catch进行异常处理的演示")
@RestController
@RequestMapping("/user")
public class UserController {

    @ApiOperation("/add")
    @ApiImplicitParam(name = "user", type = "body", dataTypeClass = User.class, required = true)
    @PostMapping("add")
    public ResponseEntity<String> add(@Valid @RequestBody UseParam user) {
        // 每个接口充斥着大量的异常处理
        try {
            // do something
        } catch(Exception e) {
            return ResponseEntity.fail("error");
        }
        return ResponseEntity.ok("success");
    }
}

三、全局异常的实现如下:

1.定义结果状态的枚举

package com.gxa.shop.common.exception;
/**
 * 结果状态的枚举
 */
public enum ResultCode {
    /**
     * 成功  200
     */
    SUCCESS(0, "成功"),
    SUCCESS_FIND(0, "查询成功"),
    SUCCESS_CRUD(0, "更新成功"),

    //操作失败failed
    FAILED_CRUD(-1, "操作失败"),
    /**
     * 数据验证有关 -- 3000*
     */
    UN_DATA(30001, "没有数据"),
    PARAM_ERROR(30002, "参数不正确"),
    PARAM_FORMAT_ERROR(30003, "参数数据格式有误"),
    COMMENT_EMPTY(30004, "内容必须填写"),
    CODE_ERROR(30005, "验证码错误"),
    /**
     * 手机号已被注册
     */
    REGISTER_MOBILE_ERROR(30006, "手机号已被注册"),
    /**
     * 登录 -- code 4000*开始
     */
    LOGIN_PHONE_ERROR(40001, "手机号码不正确"),
    LOGIN_ACCOUNT_ERROR(40002, "账号不正确"),
    /**
     * 登陆失败
     */
    LOGIN_ERROR(31003, "登录失败,用户名或者密码错误"),
    LOGIN_PASSWORD_ERROR(40004, "密码不正确"),
    /**
     * 该用户已被禁用
     */
    LOGIN_DISABLED_ERROR(40005, "该用户已被禁用"),
    /**
     * 登录相关 token
     */
    TOKEN_EXPIRED_ERROR(40006, "token过期,请重新登录"),
    TOKEN_NULL(40007, "token不能为空,请重新登录"),
    /**
     * 权限相关  4100*
     */
    LOGIN_AUTH(41001, "需要登录"),
    LOGIN_ACL(41002, "没有权限"),
    LOGIN_ACCESS(41003, "权限问题"),
    FETCH_ACCESSTOKEN_FAIL(41004, "获取accessToken失败"),
    FETCH_USERINFO_ERROR(43004, "获取用户信息失败"),
    /**
     * 短信服务 1000
     */
    SMS_SEND_ERROR(10001, "短信发送失败"),
    SMS_SEND_ERROR_BUSINESS_LIMIT_CONTROL(10002, "短信发送过于频繁"),

    /**
     * 其他 错误信息 5000
     */
    BAD_SQL_GRAMMAR(50001, "sql语法错误"),
    JSON_PARSE_ERROR(50002, "json解析异常"),
    URL_ENCODE_ERROR(50003, "URL编码失败"),
    ILLEGAL_CALLBACK_REQUEST_ERROR(50004, "非法回调请求"),
    GATEWAY_ERROR(50005, "服务不能访问"),
    UNKNOWN_REASON(50006, "未知错误"),
    RUNTIME_EXCEPTION(50007, "服务运行报错,请联系管理员处理"),
    REQUEST_METHOD_ERROR(50008, "请求方式有误"),
    STACK_OVERFLOW_ERROR(50009, "栈溢出"),
    DATA_OCCUPIED_ERROR(50010, "数据被引用不能删除" ),
    RESULT_ERROR(500011, "结果集设置异常"),
    FILE_HEAD_ERROR(500012, "头部文件报错"),
    FILE_CONTEXT_ERROR(500013, "头部内容出错"),
    FILE_NOTHING_ERROR(500014, "文件内容为空"),
    FILE_NULL_ERROR(500015, "文件为空"),

    STOCKLT_ERROR(500016,"库存不足,不能下单");

    private Integer code;
    private String message;

    ResultCode(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;
    }
}

2.自定义异常

package com.gxa.shop.common.exception;


import com.gxa.hualianeshop.common.base.ResultCode;


public class BizException extends  RuntimeException{

    private ResultCode resultCode;

    public ResultCode getExceptionCode() {
        return resultCode;
    }

    public BizException(ResultCode exceptionCode){
        super(exceptionCode.getMessage());
        this.resultCode = exceptionCode;
    }
}

3.返回结果

package com.gxa.hualianeshop.common.base;

import lombok.Data;

import java.io.Serializable;

/**
 * 通用的返回给前端的状态信息的工具类, 本身不需要注册bean
 * @author bill
 * @date 2023/6/2 16:37
 */
@Data
public class R implements Serializable {
    private String code;
    private String msg;
    private Object data;

    public R(String code, String msg) {
        this.code = code;
        this.msg = msg;
    }
    public R() {
    }

    public R(Object data) {
        this.code = "200";
        this.msg = "success";
        this.data = data;
    }

    public static R ok(){
        return new R("200","success");
    }

    public static R ok(Object data){
        return new R(data);
    }

    public static R failed(){
        return new R("500","faild");
    }
    public static R failed(String message){
        return new R("500",message);
    }

}

4.全局处理器的实现

package com.gxa.hualianeshop.common.handler;

import com.gxa.shop.common.base.R;
import com.gxa.shop.common.base.ResultCode;
import com.gxa.shop.common.exception.BizException;
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.RestController;


@RestController
//@ControllerAdvice
@Slf4j
public class GlobalExceptionHandler {


   /*
   根据异常类型,选择不同的方法,ExceptionHandler的属性value
   @handler(Exception.class)
    public Map exceptionHandler(){

    }*/

    /**
     * 也可以选择将所有异常集中处理
     * 异常的信息是通过声明参数的形式,让SpringMVC自动注入
     * @param e
     * @return
     */
    @ExceptionHandler(Throwable.class)
    public R exceptionHandler(Exception e){

        if(e instanceof BizException){
            BizException be = ((BizException)e);
           return R.failed(be.getExceptionCode().getMessage());

        }else{
            // 记录日志
            log.error(e.toString());
           return R.failed(ResultCode.RUNTIME_EXCEPTION.getMessage());
        }
    }
}

四、使用try,catch或者全局异常的一起使用对异常进行捕获并处理的顺序

        try的优先级高于全局异常,并且尽量两者不要同时使用,可能会导致一些异常捕获,达不到预期的效果

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

莳光.

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值