亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 開發(fā) > Java > 正文

詳解Spring MVC/Boot 統(tǒng)一異常處理最佳實踐

2024-07-14 08:43:25
字體:
供稿:網(wǎng)友

前言

在 Web 開發(fā)中, 我們經(jīng)常會需要處理各種異常, 這是一件棘手的事情, 對于很多人來說, 可能對異常處理有以下幾個問題:

  • 什么時候需要捕獲(try-catch)異常, 什么時候需要拋出(throws)異常到上層.
  • 在 dao 層捕獲還是在 service 捕獲, 還是在 controller 層捕獲.
  • 拋出異常后要怎么處理. 怎么返回給頁面錯誤信息.

異常處理反例

既然談到異常, 我們先來說一下異常處理的反例, 也是很多人容易犯的錯誤, 這里我們同時講到前端處理和后端處理 :

捕獲異常后只輸出到控制臺

前端代碼

$.ajax({  type: "GET",  url: "/user/add",  dataType: "json",  success: function(data){    alert("添加成功");  }});

后端代碼

try {  // do something} catch (Exception e) {  e.printStackTrace();}

這是見過最多的異常處理方式了, 如果這是一個添加商品的方法, 前臺通過 ajax 發(fā)送請求到后端, 期望返回 json 信息表示添加結(jié)果. 但如果這段代碼出現(xiàn)了異常:

  • 那么用戶看到的場景就是點擊了添加按鈕, 但沒有任何反應(其實是返回了 500 錯誤頁面, 但這里前端沒有監(jiān)聽 error 事件, 只監(jiān)聽了 success 事件. 但即使加上了error: function(data) {alert("添加失敗");}) 又如何呢? 到底因為啥失敗了呢, 用戶也不得而知.
  • 后臺 e.printStackTrace() 打印在控制臺的日志也會在漫漫的日志中被埋沒, 很可能會看不到輸出的異常. 但這并不是最糟的情況, 更糟糕的事情是連 e.printStackTrace() 都沒有, catch 塊中是空的, 這樣后端的控制臺中更是什么都看不到了, 這段代碼會像一個隱形的炸彈一樣一直埋伏在系統(tǒng)中.

混亂的返回方式

前端代碼

$.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")@ResponseBodypublic 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;}

這種方式捕獲異常后, 返回了錯誤信息, 且前臺做了一定的處理, 看起來很完善? 但用 HashMap 中的 flag 和 message 這種字符串來當鍵很容易處理, 例如你這里叫 message, 別人起名叫 msg, 甚至有時手抖打錯了, 怎么辦? 前臺再改成 msg 或其他的字符?, 前端后端這樣一直來回改?

更有甚者在情況 A 的情況下, 返回 json, 在情況 B 的情況下, 重定向到某個頁面, 這就更亂了. 對于這種不統(tǒng)一的結(jié)構(gòu)處理起來非常麻煩.

異常處理規(guī)范

既然要進行統(tǒng)一異常處理, 那么肯定要有一個規(guī)范, 不能亂來. 這個規(guī)范包含前端和后端.

不要捕獲任何異常

對的, 不要在業(yè)務代碼中進行捕獲異常, 即 dao、service、controller 層的所以異常都全部拋出到上層. 這樣不會導致業(yè)務代碼中的一堆 try-catch 會混亂業(yè)務代碼.

統(tǒng)一返回結(jié)果集

不要使用 Map 來返回結(jié)果, Map 不易控制且容易犯錯, 應該定義一個 Java 實體類. 來表示統(tǒng)一結(jié)果來返回, 如定義實體類:

public class ResultBean<T> {  private int code;  private String message;  private Collection<T> 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 <V> ResultBean<V> success(Collection<V> data) {    ResultBean resultBean = new ResultBean();    resultBean.setCode(0);    resultBean.setMessage("success");    resultBean.setData(data);    return resultBean;  }  // getter / setter 略}

正常情況: 調(diào)用 ResultBean.success() 或 ResultBean.success(Collection<V> data), 不需要返回數(shù)據(jù), 即調(diào)用前者, 需要返回數(shù)據(jù), 調(diào)用后者. 如:

@RequestMapping("/goods/add")@ResponseBodypublic ResultBean<Goods> getAllGoods() {  List<Goods> goods = goodsService.findAll();  return ResultBean.success(goods);}
@RequestMapping("/goods/update")@ResponseBodypublic ResultBean updateGoods(Goods goods) {  goodsService.update(goods);  return ResultBean.success();}

一般只有查詢方法需要調(diào)用 ResultBean.success(Collection<V> data) 來返回 N 條數(shù)據(jù), 其他諸如刪除, 修改等方法都應該調(diào)用 ResultBean.success(), 即在業(yè)務代碼中只處理正確的功能, 不對異常做任何判斷. 也不需要對 update 或 delete 的更新條數(shù)做判斷(個人建議, 實際需要根據(jù)業(yè)務). 只要沒有拋出異常, 我們就認為用戶操作成功了. 且操作成功的提示信息在前端處理, 不要后臺返回 “操作成功” 等字段.

前臺接受到的信息為:

{  "code": 0,  "message": "success",  "data": [    {      "name": "商品1",      "price": 50.00,    },    {      "name": "商品2",      "price": 99.99,    }  ]}

拋出異常: 拋出異常后, 我們應該調(diào)用 ResultBean.error(int code, String message), 來將狀態(tài)碼和錯誤信息返回, 我們約定 code 為 0 表示操作成功, 1 或 2 等正數(shù)表示用戶輸入錯誤, -1, -2 等負數(shù)表示系統(tǒng)錯誤.
前臺接受到的信息為:

{  "code": -1,  "message": "XXX 參數(shù)有問題, 請重新填寫",  "data": null}

前端統(tǒng)一處理:

返回的結(jié)果集規(guī)范后, 前端就很好處理了:

/** * 顯示錯誤信息 * @param result: 錯誤信息 */function showError(s) {  alert(s);}/** * 處理 ajax 請求結(jié)果 * @param result: ajax 返回的結(jié)果 * @param fn: 成功的處理函數(shù) ( 傳入data: fn(result.data) ) */function handlerResult(result, fn) {  // 成功執(zhí)行操作,失敗提示原因  if (result.code == 0) {    fn(result.data);  }  // 用戶操作異常, 這里可以對 1 或 2 等錯誤碼進行單獨處理, 也可以 result.code > 0 來粗粒度的處理, 根據(jù)業(yè)務而定.  else if (result.code == 1) {    showError(result.message);  }  // 系統(tǒng)異常, 這里可以對 -1 或 -2 等錯誤碼進行單獨處理, 也可以 result.code > 0 來粗粒度的處理, 根據(jù)業(yè)務而定.  else if (result.code == -1) {    showError(result.message);  }  // 如果進行細粒度的狀態(tài)碼判斷, 那么就應該重點注意這里沒出現(xiàn)過的狀態(tài)碼. 這個判斷僅建議在開發(fā)階段保留用來發(fā)現(xiàn)未定義的狀態(tài)碼.  else {    showError("出現(xiàn)未定義的狀態(tài)碼:" + result.code);  }}/** * 根據(jù) id 刪除商品 */function deleteGoods(id) {  $.ajax({    type: "GET",    url: "/goods/delete",    dataType: "json",    success: function(result){      handlerResult(result, deleteDone);    }  });}function deleteDone(data) {  alert("刪除成功");}

showError  handlerResult 是公共方法, 分別用來顯示錯誤和統(tǒng)一處理結(jié)果集.

然后將主要精力放在發(fā)送請求和處理正確結(jié)果的方法上即可, 如這里的 deleteDone 函數(shù), 用來處理操作成功給用戶的提示信息, 正所謂各司其職, 前端負責操作成功的消息提示更合理, 而錯誤信息只有后臺知道, 所以需要后臺來返回.

后端統(tǒng)一處理異常

說了這么多, 還沒講到后端不在業(yè)務層捕獲任何異常的事, 既然所有業(yè)務層都沒有捕獲異常, 那么所有的異常都會拋出到 Controller 層, 我們只需要用 AOP 對 Controller 層的所有方法處理即可.

好在 Spring 為我們提供了一個注解, 用來統(tǒng)一處理異常:

@ControllerAdvice@ResponseBodypublic class WebExceptionHandler {  private static final Logger log = LoggerFactory.getLogger(WebExceptionHandler.class);  @ExceptionHandler  public ResultBean unknownAccount(UnknownAccountException e) {    log.error("賬號不存在", e);    return ResultBean.error(1, "賬號不存在");  }  @ExceptionHandler  public ResultBean incorrectCredentials(IncorrectCredentialsException e) {    log.error("密碼錯誤", e);    return ResultBean.error(-2, "密碼錯誤");  }  @ExceptionHandler  public ResultBean unknownException(Exception e) {    log.error("發(fā)生了未知異常", e);    // 發(fā)送郵件通知技術(shù)人員.    return ResultBean.error(-99, "系統(tǒng)出現(xiàn)錯誤, 請聯(lián)系網(wǎng)站管理員!");  }}

在這里統(tǒng)一配置需要處理的異常, 同樣, 對于未知的異常, 一定要及時發(fā)現(xiàn), 并進行處理. 推薦出現(xiàn)未知異常后發(fā)送郵件, 提示技術(shù)人員.

總結(jié)

總結(jié)一下統(tǒng)一異常處理的方法:

  1. 不使用隨意返回各種數(shù)據(jù)類型, 要統(tǒng)一返回值規(guī)范.
  2. 不在業(yè)務代碼中捕獲任何異常, 全部交由 @ControllerAdvice 來處理.

一個簡單的演示項目: https://github.com/zhaojun1998/exception-handler-demo

以上就是本文的全部內(nèi)容,希望對大家的學習有所幫助,也希望大家多多支持VeVb武林網(wǎng)。


注:相關教程知識閱讀請移步到JAVA教程頻道。
發(fā)表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發(fā)表
国产精品福利无圣光在线一区| 99精品一区二区三区的区别| 91网站观看| 国产一区二区黑人欧美xxxx| 蜜臀av一区二区在线免费观看| 在线国产三级| 激情影院在线| 国产亚洲自拍偷拍| 午夜久久资源| 国产成人亚洲综合无码| 欧美日韩在线观看不卡| 亚洲制服欧美中文字幕中文字幕| av大片在线播放| 国产精品免费无遮挡无码永久视频| www.男人天堂.com| 欧美电影免费网站| 色综合亚洲精品激情狠狠| 国产成人综合在线视频| 日韩黄色碟片| 亚洲激情自拍图| 日韩美女视频一区| 精品自拍偷拍| 艳妇乳肉豪妇荡乳av无码福利| avtt综合网| 成年人视频在线看| 国产原创欧美精品| 黄色免费的网站| 91久久精品国产性色| 久久久久亚洲av无码专区首jn| 诱人的瑜伽老师3hd中字| av在线第一页| 国产精品69久久久| 在线观看亚洲一区二区| 2020国产精品极品色在线观看| 在线精品一区二区| 一不卡在线视频| 欧美亚洲爱爱另类综合| 欧美性猛交xxxx乱大交| 亚洲片av在线| 国产按摩一区二区三区| 亚洲日本香蕉视频| 成熟老妇女视频| 亚洲成人影院在线观看| 精品中文字幕不卡在线视频| 亚洲综合一区二区不卡| 亚洲深夜福利在线观看| 欧美精品成人在线| 亚洲不卡在线| 国产福利电影在线| 一道精品视频一区二区三区男同| 97精品视频在线观看| 阿v视频在线观看| xfplay资源站夜色先锋| 国产伦理一区二区三区| 日本一区二区在线看| 无限国产资源| 精品调教chinesegay| 成人免费高清在线播放| 国产一卡二卡3卡4卡四卡在线| 国产精品视频第一区二区三区| 中文字幕亚洲一区二区三区| 色综合天天综合在线视频| 亚洲成人福利视频| av资源网一区| 色婷婷精品久久二区二区蜜臂av| 国产精品久久久久久久小唯西川| 99色精品视频| 香蕉久久国产| 69av视频在线播放| 欧美一区二区三区综合| 欧美激情中文网| 头脑特工队2在线播放| swag国产精品一区二区| 在线日韩中文字幕| 久久九九热re6这里有精品| 国产欧美日韩丝袜精品一区| 91成人网在线| 蜜桃专区在线| 蜜桃av免费在线观看| 亚洲av无码国产综合专区| 天堂综合网久久| 日韩欧美一区在线观看| 蜜臀国产一区二区三区在线播放| 欧美不卡高清| 麻豆电影在线播放| 国产性xxxx18免费观看视频| 日韩av高清在线观看| 五月激情丁香网| 黄色大片在线播放| 婷婷激情综合五月天| 国产精品乱码一区二区三区| 俺也去精品视频在线观看| 日韩一级免费视频| 久草视频免费在线| eeuss网址直达入口| 免费观看国产视频在线| 欧美一级淫片aaaaaaa视频| 韩国精品福利一区二区三区| 久久久精品国产免费观看同学| 日韩在线不卡| 久久中文欧美| 国产精品久久色| 一级免费a一片| 第一页在线视频| 青青草娱乐视频| 欧美在线www| 国产乱人伦精品一区二区三区| 欧美成人3dxxxx| 国语精品视频| 亚洲精品国产成人| 芒果视频成人app| 99久久er热在这里只有精品66| jizz18日本| 九七久久人人| 红杏视频成人| 国产尤物视频在线观看| 国产又猛又黄的视频| 国产精品久久久久久久久夜色| 精品人妻在线视频| 91精品婷婷国产综合久久蝌蚪| 国产一区2区| 国产毛片毛片毛片毛片毛片| 国产剧情一区二区在线观看| 庆余年2免费日韩剧观看大牛| 国产 福利 在线| 蜜桃免费一区二区三区| 最近2019年中文视频免费在线观看| 国产麻豆视频| 国产suv精品一区二区33| 人妻无码一区二区三区免费| 97在线观视频免费观看| 激情欧美成人久久综合小说| 日韩精品极品| 性の欲びの女javhd| 亚洲ab电影| 国产乡下妇女做爰| 亚洲一区中文字幕| 国产欧美日韩精品一区二区三区| 日韩大片在线免费观看| 亚洲av无码不卡| www.一区二区.com| 91社区在线| 中文字幕人妻一区| 欧美艳星brazzers| 亚洲国产精品无码久久久久高潮| 国产精品入口夜色视频大尺度| 亚洲天堂av电影| 中国女人内谢69xxx视频| 视频一区视频二区视频三区视频四区国产| 欧美日韩综合在线观看| 91久久国产综合久久91| 日韩电影在线一区二区| 91免费在线看片| 成人免费观看毛片| 欧美调教在线| 小鲜肉gaygays免费动漫| 精品视频在线观看免费| 亚洲影院色无极综合| 精品国产人妻一区二区三区| 神马久久影视大全| 亚洲不卡1卡2卡三卡2021麻豆| 久久久久久av无码免费网站| 国产真人做爰视频免费| 久久资源中文字幕| 国产精品久久一| 91在线色戒在线| 日韩视频免费大全中文字幕| 91在线看黄| 国产午夜视频在线| 99精品视频在线播放观看| 免费无码毛片一区二区app| 欧美成人se01短视频在线看| 国产chinese男男gaygay网站| 欧洲乱码伦视频免费| 亚洲第一福利视频| 亚洲国内精品在线| 91免费视频播放| 亚洲狼人精品一区二区三区| 欧美熟女一区二区| 人妻少妇偷人精品久久久任期| 国产伦精品一区二区三区四区| 狠狠色丁香婷婷| 先锋av资源在线| 午夜精品久久久内射近拍高清| 成人淫片在线看| 久久婷婷国产| 黄色小视频在线观看| 国产喷水在线观看| 探花国产精品| 亚洲AV无码乱码国产精品牛牛| 在线播放av中文字幕| 国模私拍视频在线播放| 无码人妻av一区二区三区波多野| 日韩在线视频二区| jizzjizzjizz中国| 123成人网| 日韩av片网站| 久久久久亚洲精品成人网小说| 超碰在线一区二区三区| 一道本无吗dⅴd在线播放一区| 少妇精品无码一区二区免费视频| 偷窥自拍亚洲色图| 麻豆精品在线视频| 欧美性生交大片免网| 亚洲一级片在线观看| 午夜一区二区三区不卡视频| 一区二区三区视频| 91精品国产综合久久久久久久久久| 欧美白人最猛性xxxxx| 圆产精品久久久久久久久久久| 日本在线啊啊| 亚洲中文字幕无码专区| 国产精品第六页| 波多野结衣亚洲| eeuss国产一区二区三区四区| 久久本道综合色狠狠五月| 在线视频2区| 免费av网站大全久久| 亚洲女人小视频在线观看| 蜜桃一区二区三区在线观看| xfplay5566色资源网站| 久一视频在线观看| 91av手机在线| 国产精品333| 轻轻草成人在线| 91精选在线| 亚洲成人资源网| 国产91在线播放九色| 一精品久久久| 欧美高清hd| 国产99视频精品免视看7| 人妻精品久久久久中文字幕69| 国产一区二区在线视频聊天| 欧美色图俺去了| 日本高清不卡一区二区三区视频| 免费的国产精品| 在线观看导航| 麻豆成全视频免费观看在线看| 亚洲一级在线播放| 五月婷婷另类国产| 最近2019中文字幕在线高清| 免费在线国产| 日韩成人免费电影| 97免费视频在线| 日韩av网站在线观看| 亚洲欧美综合乱码精品成人网| 黄视频网站免费看| 男人天堂资源网| 3d欧美精品动漫xxxx无尽| 91亚洲精品久久久蜜桃网站| 久久日本片精品aaaaa国产| 成人免费一区二区三区牛牛| 国产日韩欧美精品一区二区三区| 成人在线观看你懂的| 国产精品久久久久久模特| 国产探花在线播放| 欧美激情综合在线| 亚洲欧美激情一区二区| 色综合久久六月婷婷中文字幕| 亚洲成人av片在线观看| 欧美一区二区三区免费看| 久操视频在线播放| 麻豆一区二区99久久久久| 校园春色欧美| 五月天激情在线| 亚洲精品成人无码熟妇在线| 在线一级成人| 亚洲色图100p| 久久九九精品视频| 天天免费综合色| 国产精品国产一区二区| 亚洲精品一区二区三区蜜桃| 国产精品中文字幕欧美| 中文字幕一区二区久久人妻| 夜夜操夜夜操| 欧美妇乱xxxxx视频| 热99精品里视频精品| 蜜臀av性久久久久蜜臀aⅴ四虎| 蜜臀av性久久久久av蜜臀妖精| 91网页版在线登录入口| 欧美一区在线看| 国产裸体舞一区二区三区| 老司机亚洲精品| 亚洲激情图片网| 91老师片黄在线观看| 欧美高潮视频| 少妇精品高潮欲妇又嫩中文字幕| 成人xxxx视频| 国产va免费精品观看精品| 免费精品一区二区三区在线观看| 国产精品中文字幕日韩精品| 久久网站免费视频| 欧洲成人在线观看| 中文字幕在线看| 在线观看国产免费视频| 视频三区在线| www.大网伊人| 日韩av一二三区| 亚洲国产成人久久| 久久香蕉精品香蕉| 国产精品一区毛片| 久久人人爽人人爽人人片av免费| 天天影视网天天综合色在线播放| 久久婷婷亚洲| 激情五月色综合国产精品| 国产欧美熟妇另类久久久| 国产精品入口芒果| www精品久久| 天堂中文在线资| 亚洲精品免费一区二区三区| 国产精品高清在线| 激情五月婷婷在线| 国产视频手机在线| 影音先锋日韩av| 成人免费视频一区二区| 国产aⅴ精品一区二区三区黄| 欧美精品hd| 91狠狠综合久久久久久| 欧美色网址大全| 久久久青草婷婷精品综合日韩| 麻豆久久婷婷| 久久精品久久久久久| 成人免费毛片糖心| 波多野结衣不卡视频| 国产视频在线一区| 成人免费视频在线观看| 欧美一区二区久久久| 奇米精品一区二区三区四区|