Jersey 開發(fā)RESTful(十六) Jersey統(tǒng)一異常處理

【原創(chuàng)文章傲醉,轉(zhuǎn)載請注明原文章地址,謝謝呻率!】

統(tǒng)一異常處理是所有的web應(yīng)用都需要考慮的硬毕。在Jersey中,也提供了很簡單的統(tǒng)一異常處理方式筷凤。

Jersey中的異常處理

Web應(yīng)用的異常處理基本思路昭殉,服務(wù)層隱藏底層的Checked Exception,服務(wù)層的異常統(tǒng)一包裝為RuntimeException拋出到Web層藐守,由Web層統(tǒng)一對服務(wù)層異常進(jìn)行處理挪丢。常見的兩種處理方式,針對Json格式的請求卢厂,返回包含異常代碼乾蓬,異常消息或者異常數(shù)據(jù)的對象返回,針對web頁面的請求慎恒,統(tǒng)一返回到異常結(jié)果展示頁面任内。

WebApplicationException

第一種方式撵渡,我們可以利用Jersey本身的異常對象,在資源方法中使用HTTP代碼來給客戶端返回指定錯誤死嗦。比如直接返回500錯誤等趋距。

在Jersey中,提供了一個javax.ws.rs.WebApplicationException類越除,在資源方法中节腐,可以簡單的通過返回該異常類,讓Jersey統(tǒng)一處理異常返回:

@Path("exception")
public class ExceptionResource {
    
    @POST
    @Path("register")
    public Response register(@FormParam("name")String username) {
        if ("admin".equals(username)) {
            throw new WebApplicationException("用戶名已經(jīng)存在!",
                    Response.Status.CONFLICT);
        } else {
            return Response.ok("注冊成功!", MediaType.TEXT_PLAIN).build();
        }
    }
}

這里提供了一段代碼摘盆,exception/register資源方法返回一個Response翼雀,我們假設(shè)傳入一個用戶名username,在代碼中孩擂,我們最簡單的模擬了一個業(yè)務(wù):如果傳入的用戶名為admin狼渊,則判定為用戶名已經(jīng)存在(在實際的代碼中,可能是由業(yè)務(wù)層返回一個注冊成功后的用戶對象类垦,如果該用戶對象為空狈邑,則表明用戶名沖突),則直接拋出一個WebApplicationException护锤,在該類的構(gòu)造方法中官地,傳入了消息內(nèi)容和響應(yīng)狀態(tài)碼,這里我們設(shè)置的異常消息為:用戶名已經(jīng)存在烙懦,使用的狀態(tài)碼為Status.CONFLICT(409)驱入;

當(dāng)我們在POSTMAN中對代碼進(jìn)行測試


image.png

如果傳入的參數(shù)不是admin,則提示注冊成功氯析,如果傳入的參數(shù)為admin:


image.png

可以看到服務(wù)端正確返回409異常狀態(tài)碼亏较;
再簡單介紹一下WebApplicationException:
1,WebApplicationException可以在資源方法中掩缓,或者Provider中(攔截器雪情,過濾器,Entity Provider)拋出你辣;
2巡通,WebApplicationException有非常多的構(gòu)造方法,可以傳入不同的參數(shù)構(gòu)造Response舍哄;具體的可以看看對應(yīng)的API文檔宴凉;
3,使用WebApplicationException對于統(tǒng)一異常處理表悬,還是差距很遠(yuǎn)弥锄,最重要的原因在于針對實際的開發(fā),要求客戶端針對不同的狀態(tài)碼進(jìn)行處理,還是比較麻煩籽暇。

ExceptionMapper

第二種方式温治,Jersey提供了ExceptionMapper接口來更方便的根據(jù)異常類型來執(zhí)行對應(yīng)的異常處理方法。
我們先來看看ExceptionMapper接口聲明:

public interface ExceptionMapper<E extends Throwable> {
    Response toResponse(E exception);
}

在該接口中戒悠,定義了Response toResponse(E exception);方法熬荆,很容易理解,針對匹配的exception類型救崔,怎么去生成一個對應(yīng)的Response對象惶看。

在我們具體構(gòu)建我們自己的異常處理之前,我們先來看看第三方框架中做好的示例代碼六孵。在Jackson框架中,如果在JSON->實體對象的映射過程中幅骄,出現(xiàn)解析錯誤劫窒,Jackson都會拋出一個com.fasterxml.jackson.databind.JsonMappingException異常,注意一下拆座,這個異常是一個checked exception主巍,因為這個異常屬于框架級別異常(集成IOException)。

接著挪凑,Jackson為我們提供了一個專門用于處理JsonMappingException的錯誤處理孕索,我們就從這個類開始學(xué)習(xí):

public class JsonMappingExceptionMapper implements ExceptionMapper<JsonMappingException> {
    @Override
    public Response toResponse(JsonMappingException exception) {
        return Response.status(Response.Status.BAD_REQUEST)
                  .entity(exception.getMessage())
                  .type("text/plain").build();
    }
}

首先我們看到,JsonMappingExceptionMapper實現(xiàn)了ExceptionMapper接口躏碳,在接口的泛型類型中只針對JsonMappingException進(jìn)行處理搞旭。在實現(xiàn)的toResponse方法中,使用Response構(gòu)造了Status.BAD_REQUEST(400狀態(tài)碼)菇绵,并傳入異常消息返回肄渗。

要使用ExceptionMapper,也只需要添加@Provider注解或者通過ResourceConfig.register方法注冊即可咬最。

我們簡單介紹一種統(tǒng)一處理方法翎嫡。首先確定目標(biāo)結(jié)果,我們就針對Json的數(shù)據(jù)格式永乌。其次惑申,針對整個應(yīng)用,我們構(gòu)建一個基礎(chǔ)的異常類翅雏,再針對不同的服務(wù)錯誤圈驼,創(chuàng)建不同的異常子類。在ExceptionMapper中枚荣,統(tǒng)一將錯誤包裝為響應(yīng)對象返回碗脊,下面簡單展示一些代碼:

首先我們創(chuàng)建一個異常類型枚舉類,用來表示不同的應(yīng)用異常類型和對應(yīng)的異常狀態(tài)碼:

@Getter
public enum ExceptionCode {
    DEFAULT_ERROR(0), 
    PERMISSION_EXCEPTION(1), 
    MONEY_CHECK_EXCEPTION(2), 
    ACCOUNT_STATUS_ERROR(3);

    private ExceptionCode(int code) {
        this.code = code;
    }

    private int code;
}

接著,創(chuàng)建一個應(yīng)用的基礎(chǔ)異常類:

@Getter
public abstract class ApplicationException extends RuntimeException {

    private static final long serialVersionUID = 1L;
    private ExceptionCode code = ExceptionCode.DEFAULT_ERROR;

    public ApplicationException(String msg) {
        super(msg);
    }

    public ApplicationException(String msg, ExceptionCode code) {
        super(msg);
        this.code = code;
    }

    public ApplicationException(String msg, ExceptionCode code,
            Throwable cause) {
        super(msg, cause);
        this.code = code;
    }
}

在該基礎(chǔ)異常類中衙伶,額外保存了一個異常類型祈坠;接著針對不同的服務(wù),提供不同的異常子類矢劲,比如針對權(quán)限訪問的異常:

public class PermissionException extends ApplicationException {

    private static final long serialVersionUID = 1L;

    public PermissionException(String msg, Throwable ex) {
        super(msg, ExceptionCode.PERMISSION_EXCEPTION, ex);
    }
}

代碼很簡單赦拘,僅僅只是額外規(guī)定了異常狀態(tài)類型為ExceptionCode.PERMISSION_EXCEPTION;

接著創(chuàng)建自己的ExceptionMapper:

@Provider
public class ApplicationExceptionMapper
        implements ExceptionMapper<ApplicationException> {

    @Override
    public Response toResponse(ApplicationException exception) {
        AjaxResult result = new AjaxResult(false, exception.getMessage(), null,
                exception.getCode().getCode());
        return Response.ok(result, MediaType.APPLICATION_JSON).build();
    }

}

在該方法中芬沉,我們使用攔截到的ApplicationException躺同,構(gòu)建了一個AjaxResult對象。AjaxResult對象是我們應(yīng)用對于客戶端統(tǒng)一的返回對象:

@Setter
@Getter
@NoArgsConstructor
@AllArgsConstructor
public class AjaxResult {
    private boolean success;//請求是否執(zhí)行成功
    private String msg;//本次請求的消息
    private Object data;//本次請求可能攜帶的內(nèi)容對象
    private int code;//如果出現(xiàn)異常丸逸,code代表異常類型碼
}

最后蹋艺,我們來寫一個測試資源方法測試我們的異常處理:

@GET
@Path("resource")
@Produces(MediaType.APPLICATION_JSON)
public AjaxResult doSomething(@HeaderParam("token") String token) {
    if ("token".equals(token)) {
        return new AjaxResult(true, "正常訪問資源", "some logic value", 0);
    } else {
        throw new PermissionException("沒有權(quán)限訪問該資源", null);
    }
}

在這里我們的演示資源方法是一個很簡單的測試,我們直接判斷請求頭中是否存在token字段黄刚,如果沒有捎谨,我們直接拋出一個PermissionException異常。

簡單的測試(正常的訪問):


image.png

錯誤的訪問:


image.png

小結(jié)

在本節(jié)中憔维,我們重點介紹了使用ExceptionMapper來做異常的統(tǒng)一處理涛救,額外的,在Jersey中還提供了一個擴展異常處理接口ExtendedExceptionMapper业扒,提供了更靈活的異常和異常處理器的匹配检吆,關(guān)于這個接口,建議大家可以去看看API文檔程储。
下一節(jié)蹭沛,我們將介紹Jersey和Spring以及SpringBoot的集成開發(fā)。

WechatIMG7.jpeg
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末虱肄,一起剝皮案震驚了整個濱河市致板,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌咏窿,老刑警劉巖斟或,帶你破解...
    沈念sama閱讀 211,042評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異集嵌,居然都是意外死亡萝挤,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,996評論 2 384
  • 文/潘曉璐 我一進(jìn)店門根欧,熙熙樓的掌柜王于貴愁眉苦臉地迎上來怜珍,“玉大人,你說我怎么就攤上這事凤粗∷址海” “怎么了?”我有些...
    開封第一講書人閱讀 156,674評論 0 345
  • 文/不壞的土叔 我叫張陵,是天一觀的道長柔袁。 經(jīng)常有香客問我呆躲,道長,這世上最難降的妖魔是什么捶索? 我笑而不...
    開封第一講書人閱讀 56,340評論 1 283
  • 正文 為了忘掉前任插掂,我火速辦了婚禮,結(jié)果婚禮上腥例,老公的妹妹穿的比我還像新娘辅甥。我一直安慰自己,他們只是感情好燎竖,可當(dāng)我...
    茶點故事閱讀 65,404評論 5 384
  • 文/花漫 我一把揭開白布璃弄。 她就那樣靜靜地躺著,像睡著了一般构回。 火紅的嫁衣襯著肌膚如雪谢揪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,749評論 1 289
  • 那天捐凭,我揣著相機與錄音,去河邊找鬼凳鬓。 笑死茁肠,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的缩举。 我是一名探鬼主播垦梆,決...
    沈念sama閱讀 38,902評論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼仅孩!你這毒婦竟也來了托猩?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,662評論 0 266
  • 序言:老撾萬榮一對情侶失蹤辽慕,失蹤者是張志新(化名)和其女友劉穎京腥,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體溅蛉,經(jīng)...
    沈念sama閱讀 44,110評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡公浪,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,451評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了船侧。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片欠气。...
    茶點故事閱讀 38,577評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖镜撩,靈堂內(nèi)的尸體忽然破棺而出预柒,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 34,258評論 4 328
  • 正文 年R本政府宣布宜鸯,位于F島的核電站憔古,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏顾翼。R本人自食惡果不足惜投放,卻給世界環(huán)境...
    茶點故事閱讀 39,848評論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望适贸。 院中可真熱鬧灸芳,春花似錦、人聲如沸拜姿。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,726評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽蕊肥。三九已至谒获,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間壁却,已是汗流浹背批狱。 一陣腳步聲響...
    開封第一講書人閱讀 31,952評論 1 264
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留展东,地道東北人赔硫。 一個月前我還...
    沈念sama閱讀 46,271評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像盐肃,于是被迫代替她去往敵國和親爪膊。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,452評論 2 348

推薦閱讀更多精彩內(nèi)容

  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語法砸王,類相關(guān)的語法推盛,內(nèi)部類的語法,繼承相關(guān)的語法谦铃,異常的語法耘成,線程的語...
    子非魚_t_閱讀 31,597評論 18 399
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn)荷辕,斷路器凿跳,智...
    卡卡羅2017閱讀 134,628評論 18 139
  • (一)Java部分 1、列舉出JAVA中6個比較常用的包【天威誠信面試題】 【參考答案】 java.lang;ja...
    獨云閱讀 7,079評論 0 62
  • 時間這個維度是可以感受到的疮方,如果你愿相信智慧的話控嗜。當(dāng)你達(dá)到另一精神境界時,這份思維樂趣所帶來的美妙是不言而...
    7b6f343252a7閱讀 164評論 0 0
  • 你說實在太悶 想要去過向往的生活 可背上了行囊 走過了一個又一個村落 卻發(fā)現(xiàn)到處都唱著同樣的歌 你看著落日 心情像...
    風(fēng)過且住閱讀 132評論 0 1