国产秋霞理论久久久电影-婷婷色九月综合激情丁香-欧美在线观看乱妇视频-精品国avA久久久久久久-国产乱码精品一区二区三区亚洲人-欧美熟妇一区二区三区蜜桃视频

如何優(yōu)雅的設計 Java 異常

共 16658字,需瀏覽 34分鐘

 ·

2020-11-08 21:42

  • 導語
  • 如何選擇異常類型
    • 異常的類別
    • 如何選擇異常
    • 什么時候才需要拋異常
    • 應該拋出怎樣的異常
    • 應該選用哪種異常
  • 場景介紹和技術選型
    • 架構描述
    • 業(yè)務場景描述
    • 構建約束條件
    • 約束判斷和技術選型
  • 如何優(yōu)雅的設計java異常
    • domain介紹
    • dao介紹
    • Service異常設計
    • api異常設計
  • 總結


導語

異常處理是程序開發(fā)中必不可少操作之一,但如何正確優(yōu)雅的對異常進行處理確是一門學問,筆者根據自己的開發(fā)經驗來談一談我是如何對異常進行處理的。

由于本文只作一些經驗之談,不涉及到基礎知識部分,如果讀者對異常的概念還很模糊,請先查看基礎知識。

如何選擇異常類型

異常的類別

正如我們所知道的,java中的異常的超類是java.lang.Throwable(后文省略為Throwable),它有兩個比較重要的子類,java.lang.Exception(后文省略為Exception)和java.lang.Error(后文省略為Error),其中Error由JVM虛擬機進行管理,如我們所熟知的OutOfMemoryError異常等,所以我們本文不關注Error異常,那么我們細說一下Exception異常。Exception異常有個比較重要的子類,叫做RuntimeException。我們將RuntimeException或其他繼承自RuntimeException的子類稱為非受檢異常(unchecked Exception),其他繼承自Exception異常的子類稱為受檢異常(checked Exception)。本文重點來關注一下受檢異常和非受檢異常這兩種異常。

如何選擇異常

從筆者的開發(fā)經驗來看,如果在一個應用中,需要開發(fā)一個方法(如某個功能的service方法),這個方法如果中間可能出現異常,那么你需要考慮這個異常出現之后是否調用者可以處理,并且你是否希望調用者進行處理,如果調用者可以處理,并且你也希望調用者進行處理,那么就要拋出受檢異常,提醒調用者在使用你的方法時,考慮到如果拋出異常時如果進行處理,相似的,如果在寫某個方法時,你認為這是個偶然異常,理論上說,你覺得運行時可能會碰到什么問題,而這些問題也許不是必然發(fā)生的,也不需要調用者顯示的通過異常來判斷業(yè)務流程操作的,那么這時就可以使用一個RuntimeException這樣的非受檢異常. 好了,估計我上邊說的這段話,你讀了很多遍也依然覺得晦澀了。那么,請跟著我的思路,在慢慢領會一下。

什么時候才需要拋異常

首先我們需要了解一個問題,什么時候才需要拋異常?異常的設計是方便給開發(fā)者使用的,但不是亂用的,筆者對于什么時候拋異常這個問題也問了很多朋友,能給出準確答案的確實不多。其實這個問題很簡單,如果你覺得某些”問題”解決不了了,那么你就可以拋出異常了。比如,你在寫一個service,其中在寫到某段代碼處,你發(fā)現可能會產生問題,那么就請拋出異常吧,相信我,你此時拋出異常將是一個最佳時機。

應該拋出怎樣的異常

了解完了什么時候才需要拋出異常后,我們再思考一個問題,真的當我們拋出異常時,我們應該選用怎樣的異常呢?究竟是受檢異常還是非受檢異常呢(RuntimeException)呢?我來舉例說明一下這個問題,先從受檢異常說起,比如說有這樣一個業(yè)務邏輯,需要從某文件中讀取某個數據,這個讀取操作可能是由于文件被刪除等其他問題導致無法獲取從而出現讀取錯誤,那么就要從redis或mysql數據庫中再去獲取此數據,參考如下代碼,getKey(Integer)為入口程序.

public?String?getKey(Integer?key){
????String??value;
????try?{
????????InputStream?inputStream?=?getFiles("/file/nofile");
????????//接下來從流中讀取key的value指
????????value?=?...;
????}?catch?(Exception?e)?{
????????//如果拋出異常將從mysql或者redis進行取之
????????value?=?...;
????}
}

public?InputStream?getFiles(String?path)?throws?Exception?{
????File?file?=?new?File(path);
????InputStream?inputStream?=?null;
????try?{
????????inputStream?=?new?BufferedInputStream(new?FileInputStream(file));
????}?catch?(FileNotFoundException?e)?{
????????throw?new?Exception("I/O讀取錯誤",e.getCause());
????}
????return?inputStream;
}

ok,看了以上代碼以后,你也許心中有一些想法,原來受檢異??梢钥刂屏x務邏輯,對,沒錯,通過受檢異常真的可以控制業(yè)務邏輯,但是切記不要這樣使用,我們應該合理的拋出異常,因為程序本身才是流程,異常的作用僅僅是當你進行不下去的時候找到的一個借口而已,它并不能當成控制程序流程的入口或出口,如果這樣使用的話,是在將異常的作用擴大化,這樣將會導致代碼復雜程度的增加,耦合性會提高,代碼可讀性降低等問題。那么就一定不要使用這樣的異常嗎?其實也不是,在真的有這樣的需求的時候,我們可以這樣使用,只是切記,不要把它真的當成控制流程的工具或手段。那么究竟什么時候才要拋出這樣的異常呢?要考慮,如果調用者調用出錯后,一定要讓調用者對此錯誤進行處理才可以,滿足這樣的要求時,我們才會考慮使用受檢異常。接下來,我們來看一下非受檢異常呢(RuntimeException),對于RuntimeException這種異常,我們其實很多見,比如java.lang.NullPointerException/java.lang.IllegalArgumentException等,那么這種異常我們時候拋出呢?當我們在寫某個方法的時候,可能會偶然遇到某個錯誤,我們認為這個問題時運行時可能為發(fā)生的,并且理論上講,沒有這個問題的話,程序將會正常執(zhí)行的時候,它不強制要求調用者一定要捕獲這個異常,此時拋出RuntimeException異常,舉個例子,當傳來一個路徑的時候,需要返回一個路徑對應的File對象:

public?void?test()?{
????myTest.getFiles("");
}

public?File?getFiles(String?path)?{
????if(null?==?path?||?"".equals(path)){
????????throw??new?NullPointerException("路徑不能為空!");
????}
????File?file?=?new?File(path);

????return?file;
}

上述例子表明,如果調用者調用getFiles(String)的時候如果path是空,那么就拋出空指針異常(它是RuntimeException的子類),調用者不用顯示的進行try…catch…操作進行強制處理.這就要求調用者在調用這樣的方法時先進行驗證,避免發(fā)生RuntimeException.如下:

public?void?test()?{
????String?path?=?"/a/b.png";
????if(null?!=?path?&&?!"".equals(path)){
????????myTest.getFiles("");
????}
}

public?File?getFiles(String?path)?{
????if(null?==?path?||?"".equals(path)){
????????throw??new?NullPointerException("路徑不能為空!");
????}
????File?file?=?new?File(path);

????return?file;
}

應該選用哪種異常

通過以上的描述和舉例,可以總結出一個結論,RuntimeException異常和受檢異常之間的區(qū)別就是:是否強制要求調用者必須處理此異常,如果強制要求調用者必須進行處理,那么就使用受檢異常,否則就選擇非受檢異常(RuntimeException)。一般來講,如果沒有特殊的要求,我們建議使用RuntimeException異常。

場景介紹和技術選型

架構描述

正如我們所知,傳統(tǒng)的項目都是以MVC框架為基礎進行開發(fā)的,本文主要從使用restful風格接口的設計來體驗一下異常處理的優(yōu)雅。我們把關注點放在restful的api層(和web中的controller層類似)和service層,研究一下在service中如何拋出異常,然后api層如何進行捕獲并且轉化異常。使用的技術是:spring-boot,jpa(hibernate),mysql,如果對這些技術不是太熟悉,讀者需要自行閱讀相關材料。

業(yè)務場景描述

選擇一個比較簡單的業(yè)務場景,以電商中的收貨地址管理為例,用戶在移動端進行購買商品時,需要進行收貨地址管理,在項目中,提供一些給移動端進行訪問的api接口,如:添加收貨地址,刪除收貨地址,更改收貨地址,默認收貨地址設置,收貨地址列表查詢,單個收貨地址查詢等接口。

構建約束條件

ok,這個是設置好的一個很基本的業(yè)務場景,當然,無論什么樣的api操作,其中都包含一些規(guī)則:

  • 添加收貨地址: 入參:

    1. 用戶id

    2. 收貨地址實體信息


      約束:

    3. 用戶id不能為空,且此用戶確實是存在 的

    4. 收貨地址的必要字段不能為 空

    5. 如果用戶還沒有收貨地址,當此收貨地址創(chuàng)建時設置成默認收貨地址 —


  • 刪除收貨地址: 入參:


    約束:

    1. 判斷此收貨地址是否是用戶的收貨地址
    2. 判斷此收貨地址是否為默認收貨地址,如果是默認收貨地址,那么不能進行刪除
    1. 用戶id不能為空,且此用戶確實是存在的

    2. 收貨地址不能為空,且此收貨地址確實是存在的


    1. 用戶id
    2. 收貨地址id
  • 更改收貨地址: 入參:

    1. 收貨地址id
    1. 用戶id不能為空,且此用戶確實是存在的
    1. 用戶id


      約束:

    2. 收貨地址不能為空,且此收貨地址確實是存在的

    3. 判斷此收貨地址是否是用戶的收貨地址


  • 默認地址設置: 入參:


    約束:


    1. 收貨地址不能為空,且此收貨地址確實是存在的
    2. 判斷此收貨地址是否是用戶的收貨地址
    1. 用戶id不能為空,且此用戶確實是存在的
    1. 用戶id
    2. 收貨地址id
  • 收貨地址列表查詢: 入參:

    1. 用戶id


      約束:

    2. 用戶id不能為空,且此用戶確實是存在的


  • 單個收貨地址查詢: 入參:

    1. 收貨地址id
    1. 用戶id不能為空,且此用戶確實是存在的
    1. 用戶id


      約束:

    2. 收貨地址不能為空,且此收貨地址確實是存在的

    3. 判斷此收貨地址是否是用戶的收貨地址


約束判斷和技術選型

對于上述列出的約束條件和功能列表,我選擇幾個比較典型的異常處理場景進行分析:添加收貨地址,刪除收貨地址,獲取收貨地址列表。那么應該有哪些必要的知識儲備呢,讓我們看一下收貨地址這個功能: 添加收貨地址中需要對用戶id和收貨地址實體信息就行校驗,那么對于非空的判斷,我們如何進行工具的選擇呢?傳統(tǒng)的判斷如下:

/**
?*?添加地址
?*?@param?uid
?*?@param?address
?*?@return
?*/

public?Address?addAddress(Integer?uid,Address?address){
????if(null?!=?uid){
????????//進行處理..
????}
????return?null;
}

上邊的例子,如果只判斷uid為空還好,如果再去判斷address這個實體中的某些必要屬性是否為空,在字段很多的情況下,這無非是災難性的。那我們應該怎么進行這些入參的判斷呢,給大家介紹兩個知識點:

  1. Guava中的Preconditions類實現了很多入參方法的判斷
  2. jsr 303的validation規(guī)范(目前實現比較全的是hibernate實現的hibernate-validator) 如果使用了這兩種推薦技術,那么入參的判斷會變得簡單很多。推薦大家多使用這些成熟的技術和jar工具包,他可以減少很多不必要的工作量。我們只需要把重心放到業(yè)務邏輯上。而不會因為這些入參的判斷耽誤更多的時間。

如何優(yōu)雅的設計java異常

domain介紹

根據項目場景來看,需要兩個domain模型,一個是用戶實體,一個是地址實體. Address domain如下:

@Entity
@Data
public?class?Address?{
????@Id
????@GeneratedValue
????private?Integer?id;
????private?String?province;//省
????private?String?city;//市
????private?String?county;//區(qū)
????private?Boolean?isDefault;//是否是默認地址

????@ManyToOne(cascade={CascadeType.ALL})
????@JoinColumn(name="uid")
????private?User?user;
}

User domain如下:

@Entity
@Data
public?class?User?{
????@Id
???@GeneratedValue
???private?Integer?id;
???private?String?name;//姓名

????@OneToMany(cascade=?CascadeType.ALL,mappedBy="user",fetch?=?FetchType.LAZY)
????????private?Set
?addresses;
}

ok,上邊是一個模型關系,用戶-收貨地址的關系是1-n的關系。上邊的@Data是使用了一個叫做lombok的工具,它自動生成了Setter和Getter等方法,用起來非常方便,感興趣的讀者可以自行了解一下。

dao介紹

數據連接層,我們使用了spring-data-jpa這個框架,它要求我們只需要繼承框架提供的接口,并且按照約定對方法進行取名,就可以完成我們想要的數據庫操作。用戶數據庫操作如下:

@Repository
public?interface?IUserDao?extends?JpaRepository<User,Integer>?{

}

收貨地址操作如下:

@Repository
public?interface?IAddressDao?extends?JpaRepository<Address,Integer>?{

}

正如讀者所看到的,我們的DAO只需要繼承JpaRepository,它就已經幫我們完成了基本的CURD等操作,如果想了解更多關于spring-data的這個項目,請參考一下spring的官方文檔,它比不方案我們對異常的研究。

Service異常設計

ok,終于到了我們的重點了,我們要完成service一些的部分操作:添加收貨地址,刪除收貨地址,獲取收貨地址列表. 首先看我的service接口定義:

public?interface?IAddressService?{

/**
?*?創(chuàng)建收貨地址
?*?@param?uid
?*?@param?address
?*?@return
?*/

Address?createAddress(Integer?uid,Address?address);

/**
?*?刪除收貨地址
?*?@param?uid
?*?@param?aid
?*/

void?deleteAddress(Integer?uid,Integer?aid);

/**
?*?查詢用戶的所有收貨地址
?*?@param?uid
?*?@return
?*/

List
?listAddresses(Integer?uid);
}

我們來關注一下實現:

添加收貨地址

首先再來看一下之前整理的約束條件:

入參:

  1. 用戶id
  2. 收貨地址實體信息

約束:

  1. 用戶id不能為空,且此用戶確實是存在的
  2. 收貨地址的必要字段不能為空
  3. 如果用戶還沒有收貨地址,當此收貨地址創(chuàng)建時設置成默認收貨地址

先看以下代碼實現:

?@Override
public?Address?createAddress(Integer?uid,?Address?address)?{
????//============?以下為約束條件???==============
????//1.用戶id不能為空,且此用戶確實是存在的
????Preconditions.checkNotNull(uid);
????User?user?=?userDao.findOne(uid);
????if(null?==?user){
????????throw?new?RuntimeException("找不到當前用戶!");
????}
????//2.收貨地址的必要字段不能為空
????BeanValidators.validateWithException(validator,?address);
????//3.如果用戶還沒有收貨地址,當此收貨地址創(chuàng)建時設置成默認收貨地址
????if(ObjectUtils.isEmpty(user.getAddresses())){
????????address.setIsDefault(true);
????}

????//============?以下為正常執(zhí)行的業(yè)務邏輯???==============
????address.setUser(user);
????Address?result?=?addressDao.save(address);
????return?result;
}

其中,已經完成了上述所描述的三點約束條件,當三點約束條件都滿足時,才可以進行正常的業(yè)務邏輯,否則將拋出異常(一般在此處建議拋出運行時異常-RuntimeException)。

介紹以下以上我所用到的技術:

  1. Preconfitions.checkNotNull(T t)這個是使用Guava中的com.google.common.base.Preconditions進行判斷的,因為service中用到的驗證較多,所以建議將Preconfitions改成靜態(tài)導入的方式:

    import?static?com.google.common.base.Preconditions.checkNotNull;

    當然Guava的github中的說明也建議我們這樣使用。

  2. BeanValidators.validateWithException(validator, address); 這個使用了hibernate實現的jsr 303規(guī)范來做的,需要傳入一個validator和一個需要驗證的實體,那么validator是如何獲取的呢,如下:

    @Configuration public class BeanConfigs {

    @Bean
    public?javax.validation.Validator?getValidator(){
    ????return?new?LocalValidatorFactoryBean();
    }

    }

他將獲取一個Validator對象,然后我們在service中進行注入便可以使用了:

?@Autowired
private?Validator?validator?;

那么BeanValidators這個類是如何實現的?其實實現方式很簡單,只要去判斷jsr 303的標注注解就ok了。那么jsr 303的注解寫在哪里了呢?當然是寫在address實體類中了:

@Entity
@Setter
@Getter
public?class?Address?{
@Id
????@GeneratedValue
????private?Integer?id;
????@NotNull
private?String?province;//省
@NotNull
private?String?city;//市
@NotNull
private?String?county;//區(qū)
private?Boolean?isDefault?=?false;//是否是默認地址

@ManyToOne(cascade={CascadeType.ALL})
@JoinColumn(name="uid")
private?User?user;
}

寫好你需要的約束條件來進行判斷,如果合理的話,才可以進行業(yè)務操作,從而對數據庫進行操作。這塊的驗證是必須的,一個最主要的原因是:這樣的驗證可以避免臟數據的插入。如果讀者有正式上線的經驗的話,就可以理解這樣的一個事情,任何的代碼錯誤都可以容忍和修改,但是如果出現了臟數據問題,那么它有可能是一個毀滅性的災難。程序的問題可以修改,但是臟數據的出現有可能無法恢復。所以這就是為什么在service中一定要判斷好約束條件,再進行業(yè)務邏輯操作的原因了。

  1. 此處的判斷為業(yè)務邏輯判斷,是從業(yè)務角度來進行篩選判斷的,除此之外,有可能在很多場景中都會有不同的業(yè)務條件約束,只需要按照要求來做就好。

對于約束條件的總結如下:

  • 基本判斷約束(null值等基本判斷)
  • 實體屬性約束(滿足jsr 303等基礎判斷)
  • 業(yè)務條件約束(需求提出的不同的業(yè)務約束)

當這個三點都滿足時,才可以進行下一步操作

ok,基本介紹了如何做一個基礎的判斷,那么再回到異常的設計問題上,上述代碼已經很清楚的描述如何在適當的位置合理的判斷一個異常了,那么如何合理的拋出異常呢?只拋出RuntimeException就算是優(yōu)雅的拋出異常嗎?當然不是,對于service中的拋出異常,筆者認為大致有兩種拋出的方法:

  1. 拋出帶狀態(tài)碼RumtimeException異常
  2. 拋出指定類型的RuntimeException異常

相對這兩種異常的方式進行結束,第一種異常指的是我所有的異常都拋RuntimeException異常,但是需要帶一個狀態(tài)碼,調用者可以根據狀態(tài)碼再去查詢究竟service拋出了一個什么樣的異常。第二種異常是指在service中拋出什么樣的異常就自定義一個指定的異常錯誤,然后在進行拋出異常。一般來講,如果系統(tǒng)沒有別的特殊需求的時候,在開發(fā)設計中,建議使用第二種方式。但是比如說像基礎判斷的異常,就可以完全使用guava給我們提供的類庫進行操作。jsr 303異常也可以使用自己封裝好的異常判斷類進行操作,因為這兩種異常都是屬于基礎判斷,不需要為它們指定特殊的異常。但是對于第三點義務條件約束判斷拋出的異常,就需要拋出指定類型的異常了。對于

throw?new?RuntimeException("找不到當前用戶!");

定義一個特定的異常類來進行這個義務異常的判斷:

public?class?NotFindUserException?extends?RuntimeException?{
public?NotFindUserException()?{
????super("找不到此用戶");
}

public?NotFindUserException(String?message)?{
????super(message);
}
}

然后將此處改為:

throw?new?NotFindUserException("找不到當前用戶!");

or

throw?new?NotFindUserException();

ok,通過以上對service層的修改,代碼更改如下:

@Override
public?Address?createAddress(Integer?uid,?Address?address)?{
????//============?以下為約束條件???==============
????//1.用戶id不能為空,且此用戶確實是存在的
????checkNotNull(uid);
????User?user?=?userDao.findOne(uid);
????if(null?==?user){
????????throw?new?NotFindUserException("找不到當前用戶!");
????}
????//2.收貨地址的必要字段不能為空
????BeanValidators.validateWithException(validator,?address);
????//3.如果用戶還沒有收貨地址,當此收貨地址創(chuàng)建時設置成默認收貨地址
????if(ObjectUtils.isEmpty(user.getAddresses())){
????????address.setIsDefault(true);
????}

????//============?以下為正常執(zhí)行的業(yè)務邏輯???==============
????address.setUser(user);
????Address?result?=?addressDao.save(address);
????return?result;
}

這樣的service就看起來穩(wěn)定性和理解性就比較強了。

刪除收貨地址:

入參:

  1. 用戶id
  2. 收貨地址id

約束:

  1. 用戶id不能為空,且此用戶確實是存在的
  2. 收貨地址不能為空,且此收貨地址確實是存在的
  3. 判斷此收貨地址是否是用戶的收貨地址
  4. 判斷此收貨地址是否為默認收貨地址,如果是默認收貨地址,那么不能進行刪除

它與上述添加收貨地址類似,故不再贅述,delete的service設計如下:

@Override
public?void?deleteAddress(Integer?uid,?Integer?aid)?{
????//============?以下為約束條件???==============
????//1.用戶id不能為空,且此用戶確實是存在的
????checkNotNull(uid);
????User?user?=?userDao.findOne(uid);
????if(null?==?user){
????????throw?new?NotFindUserException();
????}
????//2.收貨地址不能為空,且此收貨地址確實是存在的
????checkNotNull(aid);
????Address?address?=?addressDao.findOne(aid);
????if(null?==?address){
????????throw?new?NotFindAddressException();
????}
????//3.判斷此收貨地址是否是用戶的收貨地址
????if(!address.getUser().equals(user)){
????????throw?new?NotMatchUserAddressException();
????}
????//4.判斷此收貨地址是否為默認收貨地址,如果是默認收貨地址,那么不能進行刪除
????if(address.getIsDefault()){
???????throw??new?DefaultAddressNotDeleteException();
????}

????//============?以下為正常執(zhí)行的業(yè)務邏輯???==============
????addressDao.delete(address);
}

設計了相關的四個異常類:NotFindUserException,NotFindAddressException,NotMatchUserAddressException,DefaultAddressNotDeleteException.根據不同的業(yè)務需求拋出不同的異常。

獲取收貨地址列表:

入參:

  1. 用戶id

約束:

  1. 用戶id不能為空,且此用戶確實是存在的

代碼如下:

?@Override
public?List
?listAddresses(Integer?uid)?{
????//============?以下為約束條件???==============
????//1.用戶id不能為空,且此用戶確實是存在的
????checkNotNull(uid);
????User?user?=?userDao.findOne(uid);
????if(null?==?user){
????????throw?new?NotFindUserException();
????}

????//============?以下為正常執(zhí)行的業(yè)務邏輯???==============
????User?result?=?userDao.findOne(uid);
????return?result.getAddresses();
}

api異常設計

大致有兩種拋出的方法:

  1. 拋出帶狀態(tài)碼RumtimeException異常
  2. 拋出指定類型的RuntimeException異常

這個是在設計service層異常時提到的,通過對service層的介紹,我們在service層拋出異常時選擇了第二種拋出的方式,不同的是,在api層拋出異常我們需要使用這兩種方式進行拋出:要指定api異常的類型,并且要指定相關的狀態(tài)碼,然后才將異常拋出,這種異常設計的核心是讓調用api的使用者更能清楚的了解發(fā)生異常的詳細信息,除了拋出異常外,我們還需要將狀態(tài)碼對應的異常詳細信息以及異常有可能發(fā)生的問題制作成一個對應的表展示給用戶,方便用戶的查詢。(如github提供的api文檔,微信提供的api文檔等),還有一個好處:如果用戶需要自定義提示消息,可以根據返回的狀態(tài)碼進行提示的修改。

api驗證約束

首先對于api的設計來說,需要存在一個dto對象,這個對象負責和調用者進行數據的溝通和傳遞,然后dto->domain在傳給service進行操作,這一點一定要注意,第二點,除了說道的service需要進行基礎判斷(null判斷)和jsr 303驗證以外,同樣的,api層也需要進行相關的驗證,如果驗證不通過的話,直接返回給調用者,告知調用失敗,不應該帶著不合法的數據再進行對service的訪問,那么讀者可能會有些迷惑,不是service已經進行驗證了,為什么api層還需要進行驗證么?這里便設計到了一個概念:編程中的墨菲定律,如果api層的數據驗證疏忽了,那么有可能不合法數據就帶到了service層,進而講臟數據保存到了數據庫。

所以縝密編程的核心是:永遠不要相信收到的數據是合法的。

api異常設計

設計api層異常時,正如我們上邊所說的,需要提供錯誤碼和錯誤信息,那么可以這樣設計,提供一個通用的api超類異常,其他不同的api異常都繼承自這個超類:

public?class?ApiException?extends?RuntimeException?{
protected?Long?errorCode?;
protected?Object?data?;

public?ApiException(Long?errorCode,String?message,Object?data,Throwable?e){
????super(message,e);
????this.errorCode?=?errorCode?;
????this.data?=?data?;
}

public?ApiException(Long?errorCode,String?message,Object?data){
????this(errorCode,message,data,null);
}

public?ApiException(Long?errorCode,String?message){
????this(errorCode,message,null,null);
}

public?ApiException(String?message,Throwable?e){
????this(null,message,null,e);
}

public?ApiException(){

}

public?ApiException(Throwable?e){
????super(e);
}

public?Long?getErrorCode()?{
????return?errorCode;
}

public?void?setErrorCode(Long?errorCode)?{
????this.errorCode?=?errorCode;
}

public?Object?getData()?{
????return?data;
}

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

}

然后分別定義api層異常:ApiDefaultAddressNotDeleteException,ApiNotFindAddressException,ApiNotFindUserException,ApiNotMatchUserAddressException。以默認地址不能刪除為例:

public?class?ApiDefaultAddressNotDeleteException?extends?ApiException?{

public?ApiDefaultAddressNotDeleteException(String?message)?{
????super(AddressErrorCode.DefaultAddressNotDeleteErrorCode,?message,?null);
}

}

AddressErrorCode.DefaultAddressNotDeleteErrorCode就是需要提供給調用者的錯誤碼。錯誤碼類如下:

public?abstract?class?AddressErrorCode?{
????public?static?final?Long?DefaultAddressNotDeleteErrorCode?=?10001L;//默認地址不能刪除
????public?static?final?Long?NotFindAddressErrorCode?=?10002L;//找不到此收貨地址
????public?static?final?Long?NotFindUserErrorCode?=?10003L;//找不到此用戶
????public?static?final?Long?NotMatchUserAddressErrorCode?=?10004L;//用戶與收貨地址不匹配
}

ok,那么api層的異常就已經設計完了,在此多說一句,AddressErrorCode錯誤碼類存放了可能出現的錯誤碼,更合理的做法是把他放到配置文件中進行管理。

api處理異常

api層會調用service層,然后來處理service中出現的所有異常,首先,需要保證一點,一定要讓api層非常輕,基本上做成一個轉發(fā)的功能就好(接口參數,傳遞給service參數,返回給調用者數據,這三個基本功能),然后就要在傳遞給service參數的那個方法調用上進行異常處理。

此處僅以添加地址為例:

?@Autowired
private?IAddressService?addressService;


/**
?*?添加收貨地址
?*?@param?addressDTO
?*?@return
?*/

@RequestMapping(method?=?RequestMethod.POST)
public?AddressDTO?add(@Valid?@RequestBody?AddressDTO?addressDTO){
????Address?address?=?new?Address();
????BeanUtils.copyProperties(addressDTO,address);
????Address?result;
????try?{
????????result?=?addressService.createAddress(addressDTO.getUid(),?address);
????}catch?(NotFindUserException?e){
????????throw?new?ApiNotFindUserException("找不到該用戶");
????}catch?(Exception?e){//未知錯誤
????????throw?new?ApiException(e);
????}
????AddressDTO?resultDTO?=?new?AddressDTO();
????BeanUtils.copyProperties(result,resultDTO);
????resultDTO.setUid(result.getUser().getId());

????return?resultDTO;
}

這里的處理方案是調用service時,判斷異常的類型,然后將任何service異常都轉化成api異常,然后拋出api異常,這是常用的一種異常轉化方式。相似刪除收貨地址和獲取收貨地址也類似這樣處理,在此,不在贅述。

api異常轉化

已經講解了如何拋出異常和何如將service異常轉化為api異常,那么轉化成api異常直接拋出是否就完成了異常處理呢?答案是否定的,當拋出api異常后,我們需要把api異常返回的數據(json or xml)讓用戶看懂,那么需要把api異常轉化成dto對象(ErrorDTO),看如下代碼:

@ControllerAdvice(annotations?=?RestController.class)

class ApiExceptionHandlerAdvice {

/**
?*?Handle?exceptions?thrown?by?handlers.
?*/

@ExceptionHandler(value?=?Exception.class)
@ResponseBody
public?ResponseEntity?exception(Exception?exception,HttpServletResponse?response)?{
????ErrorDTO?errorDTO?=?new?ErrorDTO();
????if(exception?instanceof?ApiException){//api異常
????????ApiException?apiException?=?(ApiException)exception;
????????errorDTO.setErrorCode(apiException.getErrorCode());
????}else{//未知異常
????????errorDTO.setErrorCode(0L);
????}
????errorDTO.setTip(exception.getMessage());
????ResponseEntity?responseEntity?=?new?ResponseEntity<>(errorDTO,HttpStatus.valueOf(response.getStatus()));
????return?responseEntity;
}

@Setter
@Getter
class?ErrorDTO{
????private?Long?errorCode;
????private?String?tip;
}

}

ok,這樣就完成了api異常轉化成用戶可以讀懂的DTO對象了,代碼中用到了@ControllerAdvice,這是spring MVC提供的一個特殊的切面處理。

當調用api接口發(fā)生異常時,用戶也可以收到正常的數據格式了,比如當沒有用戶(uid為2)時,卻為這個用戶添加收貨地址,postman(Google plugin 用于模擬http請求)之后的數據:

{
??"errorCode":?10003,
??"tip":?"找不到該用戶"
}

總結

本文只從如何設計異常作為重點來講解,涉及到的api傳輸和service的處理,還有待優(yōu)化,比如api接口訪問需要使用https進行加密,api接口需要OAuth2.0授權或api接口需要簽名認證等問題,文中都未曾提到,本文的重心在于異常如何處理,所以讀者只需關注涉及到異常相關的問題和處理方式就可以了。希望本篇文章對你理解異常有所幫助。

來源:lrwinx.github.io/2016/04/28/

——————END——————


歡迎關注“Java引導者”,我們分享最有價值的Java的干貨文章,助力您成為有思想的Java開發(fā)工程師!


瀏覽 42
點贊
評論
收藏
分享

手機掃一掃分享

分享
舉報
評論
圖片
表情
推薦
點贊
評論
收藏
分享

手機掃一掃分享

分享
舉報

感谢您访问我们的网站,您可能还对以下资源感兴趣:

国产秋霞理论久久久电影-婷婷色九月综合激情丁香-欧美在线观看乱妇视频-精品国avA久久久久久久-国产乱码精品一区二区三区亚洲人-欧美熟妇一区二区三区蜜桃视频 国产福利视频| 欧美三级一级| 在线观看精品视频| 蜜桃精品一区二区| 强开小嫩苞毛片一二三区| 亚欧av无码| 黄色视频| 操操操操操操| 狼人久久| AV麻豆| 男人天堂V| 人人看人人草| 另类老妇奶BBBBwBB| 99久久99久久久精品棕色圆| 久久婷香| 午夜成人中文字幕| 在线免费观看黄色视频网站| 日韩专区中文字幕| 人妻HDHDHD96XXXX| 综合网操笔| 拍拍拍免费视频| 无套内射免费视频| 一级A片久久久免费直播间| 69视频在线免费观看| 永久免费看A人片无码精| 国产黄色电影| 大香蕉AV在线| 91成人做爰A片| 色婷婷精品国产一区二区三区| 双飞少妇| 色99999| 17c.白丝喷水自慰| 久久久久99精品成人网站| 国产一卡二卡在线观看| 黄色AV免费在线观看| 欧美成人黄色小说| 蜜臀网在线| 日韩在线视频中文字幕| 黄色电影天堂| 91精品在线观看视频| 九九A片| 日本电影一区二区| 麻豆91精品91久久久| 婷婷五月天影视| 黄色动漫在线免费观看| 人人艹在线| 黑人亚洲娇小videos∞ | 色色播播| 黄色操逼| 乱伦一级| 久久久无码视频| 日韩黄色在线| 亚洲一级AV| 国产综合久久777777麻豆| 爆操熟女| 国产亚洲中文字幕| 中文字幕在线观看AV| 婷婷狠狠| 欧美久久久久| 欧美精产国品一二三产品在哪买| 一区二区三区不卡视频| 国产福利视频在线| 黄色日逼视频| 日本爱爱视频| 欧美日韩国产不卡视频| 日韩黄色电影在线免费观看| 亚洲精品色色| 欧美日韩一区二区三区视频| 六月综合激情| 在线观看免费视频a| 日本一级片免费看| 欧美综合婷婷| 日韩一级毛| 亚洲精品视频免费在线观看| 熟妇人妻中文| 欧美成人视屏| 国产激情福利| 欧美成在线| 高清无码视频免费观看| 操逼在线观看| 豆花视频logo| 黄片免费看视频| 国产色五月| 国产一区二区三区视频在线观看| 色欲av伊人久久大香线蕉影院| 亚洲免费三级| 亚洲一区二区三| 大香蕉官网| 成人H动漫精品一区二区三区蘑菇 高清无码视频在线免费观看 | 无码精品一区二区免费| 狠狠搞狠狠操| 翔田千里无码免费播放| 91.xxxx| 毛片aaa| 日韩一a| 无码一区二区北条| 淫荡少妇美红久久久久久久久久| 猛男大粗猛爽H男人味| 91视频在线网站| 少妇搡BBBB搡BBB搡造水多/| 青青草原网站在线观看| 亚洲AV偷拍| 亚洲精品一级二级三级| 你懂的在线观看视频| 夜夜爽天天爽| 久久久久久久久久久国产| 性爱视频99| 好男人一区二区三区在线观看| 欧美国产日韩欧美亚洲国产| 亚洲激情性爱| 国产精品无码一区二区三| 欧美精品成人免费片| 成人色播播| 丁香婷婷久久久综合精品国产| 麻豆疯狂做受XXXX高潮视频| 欧美性生活视频| 人妻黄色| 亚洲天堂成人在线| 国产乱子伦一区二区三区在线观看| 婷婷综合亚洲| 免费看国产黄色视频| 国产在线无码视频| www.99爱| 亚洲热热| 国产AV无码区亚洲| 黄色的视频网站| 亚洲日本中文字幕在线观看| 一本色道久久综合无码人妻四虎 | 2025av中文字幕| 成人免费无码毛片| 日韩最新无码发布| 成年人黄色视频| 天堂网av2014| 老司机一区二区三区| 精品三级网站| 亚洲天堂一区在线观看| 九九热这里有精品| 亚洲AV成人无码AV小说| 国产女主播在线观看| 青春草在线观看国产| 一级a片免费观看| 无码人妻精品一区二区三| 成人天堂| 大香蕉A片| 麻豆视频在线观看| 夜夜嗨老熟女AV一区二区三区 | 久久草视频在线播放| 四虎网站| 黄色视频免费在线观看| 久久肏屄视频| 神马午夜福利视频| 欧美天天干| 亚洲AV无码乱码AV| 日韩中文字幕一区二区| 久草免费福利| 丁香五月婷婷五月天| 无码精品视频在线观看| 在线播放内射| 亚洲精品乱码久久久久久| 无码囯无精品毛片大码| 午夜福利AV在线| 香蕉一区二区| 伊人激情五月天| 欧美一区二区三区视频| 国产人国产视频成人免费观看…| 日韩最新高清无码| 国产中文字幕第一页| 午夜在线观看视频| 亚洲无码AV一区二区三区| 午夜精品无码| 青青草东路热vv| 欧美老妇XX| 伊人大香蕉精品| 亚洲视频在线视频| 操逼电影| 亚洲色图15P| 狠狠狠久久久| 亚洲中文无码AV在线| 吹潮喷水高潮HD| 青青操日日干| yw视频在线观看| 91无码在线视频| 91豆花视频| 四川少妇BBB凸凸凸BBB安慰我| 天天干少妇| 国产九九九视频| 激情五月婷婷丁香| 特极西西444WWW大胆无码| 国产激情视频在线| 艹B视频| 欧美天天撸| 精品亚洲无码视频| www.高清无码| 亚洲无码三级片在线观看| 欧美一区在线视频| 久久久久久久久久成人永久免费视频 | 国产91无码网站在线观看| 日韩AV毛| 亚洲AV无码久久久| 中文字幕在线网| 国产精品九九| 国产女人免费| 日本中文字幕网| 亚洲理伦| 国产ts在线| 欧洲肥胖BBBBBBBBBB| 中文资源在线a| 翔田千里50岁无码| 天天日天天干天天日| 色秘乱码一区二区三区| 成人毛片视频网站| 欧美一级AA大片免费看视频| 大荫蒂HD大荫蒂视频| 日本久久久久久久久视频在线观看 | 欧美在线播放| 日韩一级A| 农村三级片| 91麻豆影院| 亚洲成人在线播放| 欧美一级A片免费看视频小说| 中文字幕av免费观看| 极品人妻疯狂3p超刺激| 国产成人在线视频| 成人网站一区二区| 青娱乐偷拍视频| 青青草免费公开视频| 欧美成人精品无| 肏逼免费视频| 色天天综合| 91精东传媒果冻传媒| 三级无码视频在线观看| 国产99自拍| 午夜福利毛片| 久久无码成人| 影音先锋av在线资源| 久操操| 亚洲中文在线观看| 国产一区二区不卡视频| 美女自慰网站免费| 欧美精品久久久久久久久老牛影院| 亚洲中文视频免费| 成人免费一区| 在线免费看毛片| 日本A片一级| 91三级片在线观看| 一级A片免费视频| 午夜操日在线| 91社区成人影院| 精品人妻午夜一区二区三区四区| 色婷婷视频在线观看| 亚洲无码理论片| 亚洲理论视频| 黄色福利| 久久久在线视频| 激情五月天在线观看| 中文字幕成人在线| 精品国产精品三级精品AV网址 | 国产欧美精品AAAAAA片| 国产老熟女久久久| 成人AV天堂| 高清无码久久| AV一区二区在线观看| www深夜成人a√在线| 精品操逼视频| 91农村站街老熟女露脸| 国产乱伦网站| 天堂网一区二区三区| 大香蕉看片| 女人的天堂AAA| 欧美日韩一区在线观看| 国产视频99| 99精品偷自拍| 欧美在线色| 国产一级AAAAA片免费| 婷婷男人天堂| 婷婷久久网| 国产精品美女| 密桃视频网站| 岛国AV免费看| 色久悠悠综合网| 无码颜射| 一级av| 精品免费一区二区三区四区| 亚洲欧美日韩综合| 三上悠亚一区二区| 亚洲精品中文字幕成人片| 热无码| 91丨PORN首页| 91精品国产三级| 影视先锋成人在线| 亚洲中文字幕2019| 欧美一区二区三区视频| PORNY九色视频9l自拍| 欧美天堂在线观看| 国产成人精品a区在线观看| 91久久精品无码一区| 亚洲一区视频| 午夜激情毛片| 五月婷婷丁香综合| 欧洲精品在线视频| 亚洲美女视频在线观看| 无码三级在线免费观看| 欧美人操逼视频| 一区二区三区亚洲| 亚洲毛片亚洲毛片亚洲毛片| 午夜高清无码视频| 无码一级A片| 免费播放婬乱男女婬视频国产| 久草福利视频| 天堂网亚洲| 天堂一区二区三区| 成人性爱视频免费观看| 在线观看亚洲天堂| 久久久久中文字幕| 东京热在线免费观看| 欧美视频手机在线| 婷婷性爱五月天| 免费成人黄视频| 日韩在线观看一区二区| 黄色成人视频在线观看| 人人夜夜人人| 无码aa| 无码波多野结衣| 91成人精品视频| 日韩3级片| 肏屄视频免费观看| 精品无码一区二区三区四区五区| 中文字幕在线视频免费观看| 免费人成年激情视频在线观看| 69福利网| 亚洲无码人妻| 91在线不卡| 亚洲一区二区无码| 国产免费一级特黄A片| 91探花足浴店少妇在线| 婷婷深爱激情| 在线观看污视频| 天堂网一区二区三区| 蝌蚪窝在线观看| 九一成人网| 中文在线字幕电视剧免费平台| 一级片操逼| 亚洲一区二区三区在线| 91精品国产综合久久久蜜臀粉嫩 | 久久夜色精品噜噜亚洲AV| 日本乱伦网| 日韩无码专区| 女同久久另类99精品国产91 | 中文人妻| 五月天久久精品| 最新午夜综合福利视频| 九九性爱网| 国产激情艹逼| 久久久久久久久久国产| 大香蕉大香蕉大香蕉| 国产女主播在线观看| 欧美黄片免费视频| 91人妻人人| 少妇在线视频| 91精品国产麻豆国产自产在线| 国产AV无码一区| 牛牛影视av| 五月天色婷婷丁香| 精品1234| 爱爱视频免费网站| 综合久久久| 日韩在线观看网址| 内射在线播放| 韩国三级HD中文字幕的背景音乐| 麻豆av人人乐| www.97超碰| 天堂8在线19| 免费看18禁| 五月丁香天堂| 欧美强开小嫩苞| 屁屁影院CCYYCOM发布地| 国产成人AV在线| 麻豆AV片| 蜜桃视频一区二区三区| 先锋资源一区| 国产特黄| 精品A区| 欧美日韩在线视频免费播放| www.黄色在线观看| 国产我不卡| 日本无码一区二区三三| 亚洲一区二区三区在线视频| 人人操人人干97| 国产小电影在线| 国产a毛一级,a毛一级| 国产jk在线观看| 国产精品久久久久无码AV| 婷婷在线播放| 丰满人妻一区二区三区视频54| 久久中文字幕电影| 欧美性爱五月天| 欧美老司机| 日逼图| 午夜黄色视频在线观看| 亚洲婷婷三级成人网| 在线观看无码av| 国产精品99久久免费黑人人妻| 无码视频在线观看免费| 特级444www| 欧美性爱在线观看| 四虎成人免费视频| 人人操人人透| 俺来也俺就去www色情网| 69av网站| 在线一区二区三区| 天天日夜夜草| 国产小毛片| 日韩一级网站| 黃色一級片黃色一級片尖叫声-百度-百 | WWW.99热| 色青草影院久久综合| 成人毛片100免费观看| 69AV网站| 青娱乐国产在线| 日韩无码精品一区二区三区| 中文无码日本高潮喷水| 综合成人| 91人妻人人澡人人爽人人玩| 无码一区二区三区四季| 97看片| 激情视频小说| 亚洲AV无码乱码| 黄色在线视频网站| www.大香蕉伊人| 国产熟女视频| 欧美一级婬片AAAAAA片| 性欧美丰满熟妇XXXX性久久久| 人人操人人插| 国产伦精品一区二区三区视频女| 啪啪人妻| 欧美黄色小视频| 日本一本草久p| 日色色色| 亚洲日韩中文字幕在线| 婷婷激情视频| 亚洲av无码精品| 操b在线观看| 国产又爽又黄免费网站在| 四川少妇搡bbbb搡bbbb| 亚洲成人日韩| 久一久久| 丁香婷婷五月综合影院| 淫香淫色综合网| 亚洲乱伦小说网| 亚洲无码A片在线| 天天干天天撸| 少妇推油呻吟白浆啪啪成人片| 国产传媒av| 婷婷激情四射| 国产精品秘久久久久久1-~/\v7-/| 操逼专区| 欧美国产精品| 性饥渴熟妇乱子伦| 丁香婷婷五月基地| 极品美女援交在线| 在线免费观看毛片| 九色首页| 操B视频在线免费观看| 欧美精品99| 久久超碰精品| 91人人妻人人爽| 久久丁香五月婷婷五月天激情视频 | 色婷婷亚洲色| 欧美视频在线播放| 3d动漫精品H区XXXXX区| 色情五月婷婷| 4444操| 免费一级黄| 7799综合| 嫩BBB槡BBBB槡BBBB| 免费v片| 人妻无码久久| 久久久成人影片| 九色偷拍| 777在线视频| 影音先锋av中文字幕| 美女超碰| 一级a片在线免费观看| 狼人久久| 亚洲激情黄色| 天天狠狠操| 国产伊人自拍| 亚洲国产成人精品女人| 俺去啦俺去啦| 人妻超碰在线| 日韩日逼视频| 免费无人区一码二码乱码怎么办| 色老板在线观看视频| 夜夜bb| 国产激情欧洲在线观看一区二区三区 | 日韩欧美人妻| 亚洲人人| 香蕉成人视频| 无码精品ThePorn| 日韩小电影免费观看高清完整版在线观 | 18禁网站免费观看| 亚洲久久色| 欧美日韩一| 欧美视频免费在线观看| 毛片中文字幕| 欧美国产精品一区二区三区| 超碰自拍99| 亚洲无码播放| 成人做爰黄A片免费看直播室动漫 中文字幕一区二区三区四虎在线 欧美熟妇精品一级A片视色 | 国产九九九九| 国产精品porn| 俄罗斯老熟妇与子伦| 日本一级黄色电影网| 操B网站| www超碰| 97久久人人| 色欲AV网站| 成人做爰100片免费着| 欧洲肥胖BBBBBBBBBB| 51福利视频| 91精品网站| 一区二区三区无码高清| www.91熊猫成人网| 中文字幕资源在线| 伊人AV在线| 玩弄小怮女在线观看| 中文字幕日韩在线视频| 成年人视频在线免费观看| 四川少妇搡bbw搡bbbb| 色就色欧美| 成人小视频十八禁免费观看| 日韩人妻精品中文字幕免费 | 亚洲香蕉在线观看| 国产精品高清网站| 亚洲AV无码一区二区三竹菊| 日韩高清欧美| 小草久久95| 日韩电影免费在线观看| 国产人妖在线| 蜜桃成人AV| 成人免费毛片AAAAAA片| 丁香婷婷一区二区三区| 亚洲视频免费在线播放| 久久婷婷成人综合色怡春院| 高潮毛片| 亚洲性爱大全| 男女网站在线观看| 黄片视频免费看| 男人的天堂视频| 香蕉三级片| 可以免费观看的av| 青春草在线免费视频| 免费黄色一级视频| 港澳日韩黄片| 日本伊人网| 亚洲二区后入极品| 亚洲第一影院| 久久无码一区二区三区| 亚洲成人AV在线观看| 在线欧美亚洲| 人人操美女| 日韩国产免费| 青青操青青干| 午夜H片| 欧美亚洲成人精品| 国产精品视频免费观看| 免费一级电影| www.污| 一区二区三区精品视频| 亚洲www在线观看| 91黄色视频在线播放| 插穴网站| 日韩无码系列| 国产噜噜噜噜噜久久久久久久久| 亚洲啊V| 大香蕉伊人在线手机网| 黄色视频免费在线观看| 一夲道无码专区av无码A片| 人人人人人操| 亚洲青青草| 国产成人a亚洲精品无码| 五月天婷婷导航| 黄色视频a| 三级黄片网站| 黑人一区二区三区四区| 久久伊人在| 亚洲av综合在线| 青草青青视频| 成人一二区| 日本高清视频九区| 内射视频网站| 91精品国产乱码久久久竹菊| 动漫3d啪啪成人h动漫| 国产精品片| 免费在线观看a| 国产欧美成人| 四虎av在线| 99久久婷婷国产精品2020| 亚洲黄色视频网站在线观看| 一本一本久久a久久精品牛牛影视| 成人伊人电影| 欧美人成人无码| 嫩草嫩草69| 91二区三区| 欧美韩日一区二区| 国产3p露脸普通话对白| 国产精品偷拍视频| 欧美大胆视频| 欧美激情婷婷| 伊人性视频| 久久黄色A片| 日本黄A级A片国产免费| 国产免费黄色av| 天天操天天干欧美精品| 欧美激情伊人久久五月天| 一区二区三区精品| 国产精品自拍视频| 黄片免费大全| 黄色一级大片| 色婷婷精品国产一区二区三区| 成人网站在线免费| 91嫖妓站街按摩店老熟女| 国产精品扒开腿做爽爽爽A片唱戏| 婷婷伊人綜合中文字幕| 国产成人91| 日韩黄色av| 黄色片A片| 免费无码一区二区三区| 久草中文视频| 五月婷婷在线播放| 色哟哟av| 精品人妻一区| 日韩欧美色图| 日韩精品人妻一区二区| 丁香五月欧美| 免费看无码一级A片放24小时| 国产午夜成人福利在线| 97干干| 加勒比无码在线| 五月丁香啪| 狠狠狠操| 91成人视频| 雾水情缘电影港片| 中文字幕福利电影| 中日美朝美女一级片免费看 | 国产又粗又长又硬又大毛苴茸图片 | 亚洲不卡| 性A免费在线播放| 色就是色欧美成人网| 国产激情视频在线免费观看| 囯产精品久久久久久久久久久久久久 | 日韩无码人妻系列| 北条麻妃精品视频| 亚洲图片中文字幕| 亚洲少妇性爱视频| 人人妻人人躁人人DVD| 久久五月亭亭| 18害羞勿进网站国产| 国产操骚逼| 国产精品AV网站| 超碰自拍99| 国产无码乱伦内射| 色五月天导航| 天天拍夜夜爽| 中文字幕婷婷五月天| 4388亚洲最大| 国产欧美综合一区二区| 亚洲自拍网站| 自拍偷拍综合网| 国产麻豆精品成人毛片| 免费黄色三级片| 色视频在线| 国产午夜精品电影| 日韩精品电影| 亚洲中文无码字幕| 亚洲人妻AV| 美女自慰网站免费| 欧美日韩v| 在线黄色av| 8x8x黄色| 国精产品一品二品国精| 天天日夜夜艹| 亚洲v天堂| 啪啪啪免费视频| 中国AV网| 国产欧美日韩在线播放| 免费日韩无码| 插插插菊花综合网| 国产精品一| 无码人妻精品一区二区蜜桃网站| 欧美一级三级| 九色91PORNY国产| 国语操逼| 成人无码免费视频| 黄色网页免费观看| 尤物视频入口| AV电影一区| 91久久午夜无码鲁丝片久久人妻| 欧美日韩在线视频免费观看| 欧美三级推荐| 最近中文字幕免费mv第一季歌词大全 | 大香蕉在线伊| 不卡AV在线| 少妇免费视频| 江苏妇搡BBBB搡BBBB-百度| 国产人妻一区二区三区欧美毛片| 大鸡巴视频在线| 国产狼友| jizz丝袜| 成年人免费视频在线观看| www.热久久| 久福利| 亚洲AV秘无码不卡在线观看 | 亚洲欧美日韩综合| 91AV在线看| 少妇高潮喷水视频| 欧美色视频在线观看| 一级a一级a免费观看视频Al明星 | 日本免费黄| 69国产在线| 五月天婷婷av| 性无码一区二区三区| 大香蕉网址| 国产免费精彩视频| 91精品国产一区二区三区四区大 | 西西444WWW无码视频软件功能介绍 | 人人人人人人人人操| 在线无码免费视频| 内射一区二区三区| 亚洲AV无码久久久| 久久午夜无码人妻精品蜜桃冫| 欧美日韩无码视频| 国产一级二级视频| 激情五月天影院| 成人性爱在线观看| 亚洲婷婷三级成人网| 黑人中文字幕| 国产91在线看| 黄色一级片免费观看| 亚洲性天堂| 在线观看欧美日韩| 99久久久99久久91熟女| 人妻77777| 九九伊人大香蕉| 黑人乱伦| 欧美拍拍| 国产精品三级在线观看| 熟妇一区| 日本特级黄色毛片| 一级片AA| 西西4444WWW无视频| 91亚色视频| 四虎影院污| 爱爱午夜福利| 三级无码中文| 安徽妇搡BBB搡BBBB户外老太太 | 国产高清在线观看| 在线观看免费完整版中文字幕视频| 黄色毛片,男人天堂| 亚洲欧洲免费看| 亚洲中文字幕在线无码| 大香蕉伊人综合网| 少妇白洁在线观看| 精品人妻一区二区三区-国产精品| 北条麻妃在线无码| 无码免费中文字幕| 粉嫩99国产精品久久久久久人妻| 波多野结衣国产区42部| 国产豆花视频| av中文字幕网| 精品在线播放| 亚洲精品色色| 国产69视频在线观看| 成人理伦A级A片在线论坛| 美日韩免费视频| 无码人妻丰满熟妇| 91麻豆免费视频网站| 91麻豆精品在线| 特黄无码| 欧美高清无码在线观看| 一区二区色| av在线天堂| 久久黄色视频免费看| 999这里只有精品| 亚洲码无人客一区二区三区| 亚洲第一免费视频| 天天做天天爱天天高潮| 欧美综合网在线观看| 91亚洲精华国产精华精华液| 免费观看高清无码| 欧美成人激情视频| 久久69| 大香蕉伊人成人网| 大香蕉偷拍视频| 精品人妻二区三区蜜桃| 宅男视频| 国产av一区二区三区| 青草成人在线| 影音先锋av成人电影| 杨贵妃一级婬片90分钟| 极品一区| 操极品美女| 99热青青| 久久99国产乱子伦...| 美女啪啪视频| 中文无码在线观看| 草久在线视频| 深夜福利一区二区| 69视频在线观看免费| 国产AV一级片| 人人操超碰在线| 一牛影视精品av| 一区二区三区视频在线观看| 99国产热| 婷婷五月六月| 人妻夜夜爽天天爽三区麻豆AV网站| 高清AV在线| 色欲大香蕉| 丁香五月欧美激情| 亚洲国产成人精品女人| 一区二区高清无码视频| 特级西西444www| 人妻AV一区| 亚洲欧美在线播放| 中文字幕高清AⅤ| 操B图| 国产夫妻自拍AV| 国产精品一区二区在线| 在线中文字幕777| 9l蝌蚪PORNY中文| 在线观看免费黄片| 在线视频亚洲| 北条麻妃99精品| 欧美69影院| 国产老熟女高潮毛片A片仙踪林| 特级西西444www高清| 理论毛片| 国产操逼免费| 免费无码在线观看| 精品人妻一区二区三区阅读全文 | 国产精品欧美一区二区三区苍井空 | 久久久www| 嫩草视频| 91亚洲精品久久久久久久久久久久 | 国产一视频| 99爱视频| 亚洲无码视频在线看| 欧美日韩人妻| 黄色免费视频网站| 日韩天堂av| 日本午夜福利电影| 成人无码交配视频国产网站| 67194国产| 黄页网站免费观看| 亚洲AV无码第一区二区三区蜜桃| 97午夜福利视频| 毛片在线观看视频| 欧美日韩国产在线| 四虎无码视频| 九色PORN视频成人蝌蚪自拍 | 3D动漫啪啪精品一区二区中文字幕 | 日本色婷婷| 影音先锋男人站| 北条麻妃二区三区| 日韩中文字幕在线免费观看| 天天日天天插| 欧美日韩伊人| 操比视频在线观看| 中文字幕网站| 一级日韩一级欧美| 日韩香蕉视频| 江苏妇搡BBBB搡BBBB小说| 成人水蜜桃| 亚洲区中文字幕| av在线精品| 无码婬片A片AAA毛片艳谭| 国产精品欧美一区二区| 俺来也俺也啪www色| 国产婷婷五月天| 成人爱爱免费视频| 中文字字幕在线中文乱码| 肉色超薄丝袜脚交一区二区| 中文字幕丰满熟妇人妻| 国产三级在线播放| 九九美女视频| 老婆中文字幕乱码中文乱码| 免费一级黄色电影| 久久精品视频免费看| 欧美v| 日韩精品一区二区三区四区蜜桃视频 | 白嫩在线| 亚洲成人AV| 午夜精品久久久久久久91蜜桃| 91人人妻人人澡人人爽人人| 三级片在线看片AV| 操逼视频网站免费| 五月婷婷中文| 懂色一区二区二区在线播放视频| 超碰在线人人| 成人网站在线免费|