统一异常处理到底应该怎么做呢?

叙述

============================================================

为什么需要统一异常处理?


使用异常处理的反例

捕获异常后只输出到控制台

前端代码

$.ajax({

type: “GET”,

url: “/user/add”,

dataType: “json”,

success: function(data){

alert(“添加成功”);

}

});

后端代码

try {

// do something

} catch (Exception e) {

e.printStackTrace();

}

这是见过最多的异常处理方式了, 如果这是一个添加商品的方法, 前台通过 ajax 发送请求到后端, 期望返回 json 信息表示添加结果. 但如果这段代码出现了异常:

那么用户看到的场景就是点击了添加按钮, 但没有任何反应(其实是返回了 500 错误页面, 但这里前端没有监听 error 事件, 只监听了 success 事件. 但即使加上了error: function(data) {alert(“添加失败”);}) 又如何呢? 到底因为啥失败了呢, 用户也不得而知.

后台 e.printStackTrace() 打印在控制台的日志也会在漫漫的日志中被埋没, 很可能会看不到输出的异常. 但这并不是最糟的情况, 更糟糕的事情是连 e.printStackTrace() 都没有, catch 块中是空的, 这样后端的控制台中更是什么都看不到了, 这段代码会像一个隐形的炸弹一样一直埋伏在系统中.

混乱的返回方式

前端代码

$.ajax({

type: “GET”,

url: “/goods/add”,

dataType: “json”,

success: function(data) {

if (data.flag) {

alert(“添加成功”);

} else {

alert(data.message);

}

},

error: function(data){

alert(“添加失败”);

}

});

后端代码

@RequestMapping(“/goods/add”)

@ResponseBody

public Map add(Goods goods) {

Map map = new HashMap();

try {

// do something

map.put(flag, true);

} catch (Exception e) {

e.printStackTrace();

map.put(“flag”, false);

map.put(“message”, e.getMessage());

}

reutrn map;

}

一大堆的try catch语句

我们在有的项目中会发现try catch的代码很多,看起来很头疼啊。

导致前后端严重耦合

使用异常处理的好处

  • 代码更加干净清爽

  • 异常统一由项目经理leader使用AOP来进行处理和定义,不需要每个开发自己定义维护

  • 统一的接口返回值,前后端交互更简单。

  • 充分解耦前后端,面向接口编程(符合契约式编程原则)


Java异常分类


在这里插入图片描述

Java把异常当做对象来处理。Throwable是所有错误或异常的超类。Throwable类有两个直接子类:Error类和Exception类。

1、Error是指java运行时系统的内部错误和资源耗尽错误,是程序无法处理的异常,应用程序不会抛出该类对象。

2、Exception是程序本身可以处理的异常,应尽可能去处理这些异常。Exception分两类,一个是运行时异常RuntimeException,一个是检查异常CheckedException。

3、CheckedException一般是外部错误,这种异常都发生在编译阶段,Java编译器会强制程序去捕获此类异常。

4、RuntimeException是那些可能在Java 虚拟机正常运行期间抛出的异常的超类。这种错误是由程序员引起的错误,可以修正代码解决。

异常处理规范应用


不要捕获任何异常

不要在业务代码中进行捕获异常, 即 dao、service、controller 层的所以异常都全部抛出到上层. 这样不会导致业务代码中的一堆 try-catch 会混乱业务代码.

统一返回结果集

不要使用 Map 来返回结果, Map 不易控制且容易犯错, 应该定义一个 Java 实体类. 来表示统一结果来返回, 如定义实体类:

public class ResultBean {

private int code;

private String message;

private Collection data;

private ResultBean() {

}

public static ResultBean error(int code, String message) {

ResultBean resultBean = new ResultBean();

resultBean.setCode(code);

resultBean.setMessage(message);

return resultBean;

}

public static ResultBean success() {

ResultBean resultBean = new ResultBean();

resultBean.setCode(0);

resultBean.setMessage(“success”);

return resultBean;

}

public static ResultBean success(Collection data) {

ResultBean resultBean = new ResultBean();

resultBean.setCode(0);

resultBean.setMessage(“success”);

resultBean.setData(data);

return resultBean;

}

// getter / setter 略

}

前端代码

{

“code”: 0,

“message”: “success”,

“data”: [

{

“name”: “商品1”,

“price”: 50.00,

},

{

“name”: “商品2”,

“price”: 99.99,

}

]

}

前端统一处理异常

/**

  • 显示错误信息

  • @param result: 错误信息

*/

function showError(s) {

alert(s);

}

/**

  • 处理 ajax 请求结果

  • @param result: ajax 返回的结果

  • @param fn: 成功的处理函数 ( 传入data: fn(result.data) )

*/

function handlerResult(result, fn) {

// 成功执行操作,失败提示原因

if (result.code == 0) {

fn(result.data);

}

// 用户操作异常, 这里可以对 1 或 2 等错误码进行单独处理, 也可以 result.code > 0 来粗粒度的处理, 根据业务而定.

else if (result.code == 1) {

showError(result.message);

}

// 系统异常, 这里可以对 -1 或 -2 等错误码进行单独处理, 也可以 result.code > 0 来粗粒度的处理, 根据业务而定.

else if (result.code == -1) {

showError(result.message);

}

// 如果进行细粒度的状态码判断, 那么就应该重点注意这里没出现过的状态码. 这个判断仅建议在开发阶段保留用来发现未定义的状态码.

else {

showError(“出现未定义的状态码:” + result.code);

}

}

/**

  • 根据 id 删除商品

*/

function deleteGoods(id) {

$.ajax({

本次面试答案,以及收集到的大厂必问面试题分享:

字节跳动超高难度三面java程序员面经,大厂的面试都这么变态吗?

(result.message);

}

// 系统异常, 这里可以对 -1 或 -2 等错误码进行单独处理, 也可以 result.code > 0 来粗粒度的处理, 根据业务而定.

else if (result.code == -1) {

showError(result.message);

}

// 如果进行细粒度的状态码判断, 那么就应该重点注意这里没出现过的状态码. 这个判断仅建议在开发阶段保留用来发现未定义的状态码.

else {

showError(“出现未定义的状态码:” + result.code);

}

}

/**

  • 根据 id 删除商品

*/

function deleteGoods(id) {

$.ajax({

本次面试答案,以及收集到的大厂必问面试题分享:

[外链图片转存中…(img-mH2qPfI9-1721196537638)]

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值