精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

SpringBoot 定義優雅全局統一 Restful API 響應和統一異常處理,太優雅了!

開發 架構
統一接口響應能夠減少團隊內部不必要的溝通;減輕接口消費者校驗數據的負擔;降低其他同事接手代碼的難度;提高接口的健壯性和可擴展性。

大家好,我是碼哥,《Redis 高手心法》作者。

假如你作為項目組長,為 Spring Boot 項目設計一個規范的統一的RESTfulAPI 響應框架。

前端或者移動端開發人員通過調用后端提供的RESTful接口完成數據的交換。

常見的統一響應數據結構如下所示:

public class Result<T> implements Serializable {

    private Integer code;

    private String message;

    private T data;
}

統一接口響應能夠減少團隊內部不必要的溝通;減輕接口消費者校驗數據的負擔;降低其他同事接手代碼的難度;提高接口的健壯性和可擴展性。

除此之外,還需要實現一個統一的異常處理框架。通過這個全局異常處理,可以避免將異常信息和系統敏感信息直接拋出給客戶端。

針對特定異常捕獲后可以重新對異常輸出信息做編排,提高交互友好度,同時可以記錄異常信息。

實現思路

我們需要定義一個 Result類,在類中定義需要返回的字段信息,比如狀態碼、結果描述、結果數據集等。

接口的狀態碼很多,我們可以用一個枚舉類進行封裝。于是就有了下面的代碼。順便說一句,推薦大家使用 lombok,減少繁瑣的 set、get、構造方法。

狀態碼枚舉

@Getter
@AllArgsConstructor
public enum ResultEnum {

    /**
     * return success result.
     */
    SUCCESS(200, "接口調用成功"),
    /**
     * return business common failed.
     */
    COMMON_FAILED(400, "接口調用失敗"),

    NOT_FOUND(404, "接口不存在"),
    FORBIDDEN(403, "資源拒絕訪問"),
    UNAUTHORIZED(401, "未認證(簽名錯誤)"),

    INTERNAL_SERVER_ERROR(500, "服務器內部錯誤"),


    NULL_POINT(200002, "空指針異常"),
    PARAM_ERROR(200001, "參數錯誤");

    private Integer code;

    private String message;

}

統一響應封裝

封裝一個固定返回格式的結構對象:Result。

@Setter
@Getter
public class Result<T> implements Serializable {

    private Integer code;

    private String message;

    private T data;

    public static <T> Result<T> success() {
        return new Result<>(ResultEnum.SUCCESS.getCode(), ResultEnum.SUCCESS.getMessage());
    }

    public static <T> Result<T> success(T data) {
        return new Result<>(ResultEnum.SUCCESS.getCode(), ResultEnum.SUCCESS.getMessage(),
                data);
    }

    public static <T> Result<T> success(String message, T data) {
        return new Result<>(ResultEnum.SUCCESS.getCode(), message, data);
    }

    public static Result<?> failed() {
        return new Result<>(ResultEnum.COMMON_FAILED.getCode(),
                ResultEnum.COMMON_FAILED.getMessage(), null);
    }

    public static Result<?> failed(String message) {
        return new Result<>(ResultEnum.COMMON_FAILED.getCode(), message, null);
    }

    public static Result<?> failed(IResult errorResult) {
        return new Result<>(errorResult.getCode(), errorResult.getMessage(), null);
    }

    public Result() {
    }

    public Result(Integer code, String message) {
        this.code = code;
        this.message = message;
    }

    public Result(Integer code, String message, T data) {
        this.code = code;
        this.message = message;
        this.data = data;
    }

    public static <T> Result<T> instance(Integer code, String message, T data) {
        Result<T> result = new Result<>();
        result.setCode(code);
        result.setMessage(message);
        result.setData(data);
        return result;
    }

}

有了統一響應體,于是你就可以在 Controller 返回結果時這樣寫:

@RestController
public class UserController {

    @Autowired
    private UserService userService;

    @RequestMapping(value = "/queryUser")
    public Result<User> query(@RequestParam("userId") Long userId){
        try {
            // 業務代碼...
            User user = userService.queryId(userId);
            return ResultMsg.success(user);
        } catch (Exception e){
            return ResultMsg.fail(e.getMessage());
        }
    }
}

唐二婷:Controller 類中每一個方法的返回值類型都只能是這個響應對象類,太不優雅了。

這個問題問得好。

為了能夠實現統一的響應對象,又能優雅的定義 Controller 類的方法,使其每個方法的返回值是其應有的類型。

主要是借助RestControllerAdvice注解和ResponseBodyAdvice接口來實現對接口響應給客戶端之前封裝成 Result。

全局統一 Restful API 統一返回

Spring Boot 框架其實已經幫助開發者封裝了很多實用的工具,比如 ResponseBodyAdvice 接口,我們可以利用來實現數據格式的統一返回。

忽略響應包裝

有些場景下我們不希望 Controller 方法的返回值被包裝為統一響應對象,可以先定義一個忽略響應封裝的注解,配合后續代碼實現。

@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface IgnoreRestFulAPI {
}

ResponseBodyAdvice 接口

這是 Spring 框架提供的一個接口,我們可以利用它實現對接口數據格式統一封裝。

ResponseBodyAdvice可以對 controller 層中的擁有@ResponseBody 注解屬性的方法進行響應攔截,用戶可以利用這一特性來封裝數據的返回格式,也可以進行加密、簽名等操作。

實現該接口的類還需要添加 @RestControllerAdvice注解,這是一個組合注解,由@ControllerAdvice、@ResponseBody組成,而@ControllerAdvice繼承了@Component,因此@RestControllerAdvice本質上是個Component。

本質上就是使用 Spring AOP 定義的一個切面,作用于 Controller 方法執行完成后的增強操作。

ResponseBodyAdvice接口有兩個方法需要重寫。

  • supports方法:實際開發中不一定所有的方法封裝統一接口響應,這里可以根據MethodParameter進行過濾,此方法返回 true 則會走過濾,即會調用beforeBodyWrite方法,否則不會調用。
  • beforeBodyWrite:編寫具體響應客戶端之前的的數據邏輯。
@RestControllerAdvice
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)
public class GlobalResponseAdvice implements ResponseBodyAdvice<Object> {


    private static final ObjectMapper mapper = new ObjectMapper();

    @Override
    public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
        // 方法沒有IgnoreRestFulAPI注解,且返回類型不是 Result類型時調用 beforeBodyWrite 實現響應數據封裝
        return !returnType.hasMethodAnnotation(IgnoreRestFulAPI.class)
                && !returnType.getParameterType().isAssignableFrom(Result.class);
    }

    @Override
    public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType
            , Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {

        // 如果返回值是void類型,直接返回200狀態信息
        if (returnType.getParameterType().isAssignableFrom(Void.TYPE)) {
            return Result.success();
        }

        // 返回類型不是 Result,是 String 類型
        if (!(body instanceof Result)) {
            // warning: RestController方法上返回值類型為String時,默認響應的Content-Type是text/plain,
            // 需要手動指定為application/json 才能對結果進行包裝成 json
            if (body instanceof String) {
                return toJson(Result.success(body));
            }
            return Result.success(body);
        }

        // 返回類型是 Result,直接返回
        return body;
    }

    private Object toJson(Object body) {
        try {
            return mapper.writeValueAsString(body);
        } catch (JsonProcessingException e) {
            throw new RuntimeException("無法轉發json格式", e);
        }
    }
}

@RestControllerAdvice 未生效?

ResponseBodyAdvice 接口實現類 GlobalResponseAdvice 沒有被 Spring 管理。

因為啟動類上的 @SpringbootApplication 默認掃描本包和子包。

比如 GlobalResponseAdvice 在 zero.magebyte.shop.common 包下,而啟動類在 zero.magebyte.shop.order.server 包,那么 GlobalResponseAdvice 就不會生效。

為了防止全局接口統一響應處理器 GlobalResponseAdvice類未被掃描到,建議在啟動類上加上包掃描。

測試

定義一個 Controller 類來進行簡單的開發和測試。

@RestController
@RequestMapping("/demo")
public class DemoController {
    @GetMapping("/method1")
    public Result<Integer> method1() {
        return Result.success(100);
    }

    @GetMapping("/method2")
    public void method2() {

    }

    @GetMapping(value = "/method3")
    @IgnoreRestFulAPI
    public String method3() {
        return "不會被封裝,直接返回 String";
    }

    /**
     * RestController中返回值類型是String的方法默認響應類型是text/plain,需要手動指定為application/json方可對其進行包裝
     */
    @GetMapping(value = "/method4", produces = MediaType.APPLICATION_JSON_VALUE)
    public String method4() {
        return "會被封裝 Result 結構 JSON";
    }

    /**
     * 會被封裝,但是響應類型是text/plain
     * @return
     */
    @GetMapping(value = "/method5")
    public String method5() {
        return "會被封裝為 Result 的 text/html";
    }
}

Result 返回類型

method1 方法返回類型是 Result,所以不會再次封裝,而是直接返回 Result 結構,并以 Content-Type: application/json格式響應給客戶端。

{
  "code": 200,
  "message": "接口調用成功",
  "data": 100
}

void 類型

method2 方法返回類型是 void,會封裝成 Result 結構,并以 Content-Type: application/json格式響應給客戶端。只不過 data 數據是 null。

{
  "code": 200,
  "message": "接口調用成功",
  "data": null
}

@IgnoreRestFulAPI 注解

method3 被 @IgnoreRestFulAPI 注解,不會被封裝 Result 結構,直接返回。

String 類型

默認 String 類型的數據響應給客戶端的格式為 text/html,為了統一響應格式,需要手動設置響應類型為 json,如下所示。

@GetMapping(value = "/method4", produces = MediaType.APPLICATION_JSON_VALUE)

響應給客戶端的格式就是一個 Result JSON 對象,Content-Type: application/json。

{
  "code": 200,
  "message": "接口調用成功",
  "data": "會被封裝 Result 結構 JSON"
}

否則將會以 Content-Type: text/html;charset=UTF-8響應呵客戶端。

另外需要注意的是,如果你使用了 swagger,以上代碼會導致 swagger 無法訪問。

報錯如下:

Unable to infer base url. This is common when using dynamic servlet registration or when the API is behind an API Gateway. The base url is the root of where all the swagger resources are served. For e.g. if the api is available at http://example.org/api/v2/api-docs then the base url is http://example.org/api/. Please enter the location manually:

原因:因為統一響應攔截器對 swagger 的接口做了攔截并對結果做了包裝,導致返回結構發生后變化,swagger 無法解析。

解決方案:修改統一響應處理器攔截的范圍,配置散列包路徑。你可以指定 @RestControllerAdvice(basePackages = {"xxx.xxx"})項目的 controller 目錄即可。

統一異常處理

唐二婷:雖然有了統一結構響應,接口可以直接返回實際數據,但是每個接口都要根據業務的要求進行不同程度的 try..catch 處理異常,如果有幾百個接口,不僅編程工作量大,可讀性也差。

@RestController
public class UserController {

    @Autowired
    private UserService userService;

    @RequestMapping(value = "/queryUser")
    public User query(@RequestParam("userId") Long userId){
        try {
            // 業務代碼...
            User user = userService.queryId(userId);
            return user;
        } catch (Exception e){
            return Result.fail(e.getMessage());
        }
    }
}

兵來將擋,水來土掩。這樣寫代碼并不是不好看,而是十分垃圾!!!

如下是我們自定義的業務異常。

@Setter
@Getter
public class BusinessException extends RuntimeException {

    private Integer code;

    private String message;

    public BusinessException(Throwable cause) {
        super(cause);
    }

    public BusinessException(String message) {
        super(message);
        this.message = message;
    }

    public BusinessException(Integer code, String message, Throwable cause) {
        super(cause);
        this.code = code;
        this.message = message;
    }

}

在 Spring Boot 中,我們不用這樣寫,可以繼續利用 @RestControllerAdvice 注解和@ExceptionHandler注解實現全局異常處理器,攔截 Controller 層拋出的異常。

實現方式

新增 GlobalExceptionHandler 類,編寫統一異常處理,類上面添加 @RestControllerAdvice 注解就開啟了全局異常處理。

我們可以在類面創建多個方法,并在方法上添加 @ExceptionHandler 注解,對不同的異常進行定制化處理,并統一返回 Result 結構響應給客戶端。

@RestControllerAdvice
@Slf4j
public class GlobalExceptionHandler {

    /**
     * 處理自定義的業務異常
     *
     * @param req
     * @param e
     * @return
     */
    @ExceptionHandler(value = BusinessException.class)
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    public <T> Result<T> baseExceptionHandler(HttpServletRequest req, BusinessException e) {
        log.error("發生業務異常!", e);
        int code = Objects.isNull(e.getCode()) ? ResultEnum.INTERNAL_SERVER_ERROR.getCode() : e.getCode();
        String message = StringUtils.isBlank(e.getMessage()) ? ResultEnum.INTERNAL_SERVER_ERROR.getMessage() : e.getMessage();
        return new Result<>(code, message);
    }

    @ExceptionHandler(value = RuntimeException.class)
    @ResponseBody
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    public <T> Result<T> runtimeExceptionHandler(HttpServletRequest req, RuntimeException e) {
        log.error("發生運行時異常!", e);
        return Result.failed(ResultEnum.INTERNAL_SERVER_ERROR);
    }

    /**
     * 處理空指針的異常
     *
     * @param req
     * @param e
     * @return
     */
    @ExceptionHandler(value = NullPointerException.class)
    @ResponseBody
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    public <T> Result<T> exceptionHandler(HttpServletRequest req, NullPointerException e) {
        log.error("發生空指針異常!", e);
        return Result.failed(ResultEnum.INTERNAL_SERVER_ERROR);
    }


    /**
     * 處理其他異常
     *
     * @param req
     * @param e
     * @return
     */
    @ExceptionHandler(value = Exception.class)
    @ResponseBody
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    public <T> Result<T> exceptionHandler(HttpServletRequest req, Exception e) {
        log.error("未知異常!", e);
        return Result.failed(ResultEnum.INTERNAL_SERVER_ERROR);
    }

    @ExceptionHandler(value = BindException.class)
    @ResponseBody
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public Result<String> handlerBindException(HttpServletRequest request, BindException e) {
        StringBuilder sb = new StringBuilder();
        List<FieldError> fieldErrors = e.getBindingResult().getFieldErrors();
        for (FieldError fe : fieldErrors) {
            sb.append(fe.getField()).append(":").append(fe.getDefaultMessage()).append(";");
        }
        String errorStr = sb.length() == 0 ? "" : sb.substring(0, sb.length() - 1);
        return new Result(HttpStatus.BAD_REQUEST.value(), errorStr);
    }

    @ExceptionHandler(value = MethodArgumentNotValidException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public Result<String> handlerMethodArgumentNotValidException(HttpServletRequest request, MethodArgumentNotValidException e) {
        StringBuilder sb = new StringBuilder();
        List<FieldError> fieldErrors = e.getBindingResult().getFieldErrors();
        for (FieldError fe : fieldErrors) {
            sb.append(fe.getField()).append(":").append(fe.getDefaultMessage()).append(";");
        }
        String errorStr = sb.isEmpty() ? "" : sb.substring(0, sb.length() - 1);
        return new Result<String>(HttpStatus.BAD_REQUEST.value(), errorStr);
    }

    @ExceptionHandler(value = SQLException.class)
    @ResponseBody
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    public Result<String> handlerSQLException(SQLException e) {
        log.error("數據庫異常!", e);
        return Result.failed(ResultEnum.INTERNAL_SERVER_ERROR);
    }

}

測試代碼

故意制造一個除 0 異常。

@GetMapping(value = "/method6")
public Order method6() {
    int a = 1/0;
    Order order = new Order();
    order.setId(1);
    order.setMoney(999);
    return order;
}

自定義拋出業務異常。

@GetMapping(value = "/method7")
public Order method7() {
    Order order = new Order();
    order.setId(1);
    order.setMoney(999);
    if (order.getCreateTime() == null) {
        throw new BusinessException("創建時間不能為空");
    }
    return order;
}

總結

RestControllerAdvice注解和ResponseBodyAdvice接口來實現對接口響應給客戶端之前封裝成 Result。

統一接口響應客戶端,減少團隊內部不必要的溝通;減輕接口消費者校驗數據的負擔;降低其他同事接手代碼的難度;提高接口的健壯性和可擴展性。

通過 @RestControllerAdvice 注解和@ExceptionHandler` 注解實現統一異常處理,能夠減少代碼的重復度和復雜度,有利于代碼的維護,并且能夠快速定位到 BUG,大大提高我們的開發效率。

責任編輯:姜華 來源: 碼哥跳動
相關推薦

2025-04-09 08:00:00

FastAPI統一響應全局異常處理

2019-01-24 16:11:19

前端全局異常數據校驗

2025-02-05 14:28:19

2022-08-03 07:07:10

Spring數據封裝框架

2023-11-28 14:32:04

2019-08-22 14:02:00

Spring BootRestful APIJava

2021-04-20 10:50:38

Spring Boot代碼Java

2025-02-05 08:43:40

2017-05-18 14:14:25

過濾器Spring ClouZuul

2024-08-09 08:25:32

Spring流程注解

2022-05-07 10:09:01

開發Java日志

2023-12-05 14:10:00

接口可讀性

2020-03-16 17:20:02

異常處理Spring Boot

2024-12-11 09:16:38

2023-11-30 07:00:56

SpringBoot處理器

2023-10-10 13:23:18

空指針異常Java

2017-05-19 15:13:05

過濾器Spring ClouZuul

2017-07-31 15:47:50

Zuul統一處理

2025-02-13 00:34:22

Spring對象系統

2025-10-31 04:11:00

點贊
收藏

51CTO技術棧公眾號

99精品视频免费版的特色功能| 视频一区二区在线观看| 五月天婷婷网站| 亚洲天堂日韩在线| 欧美另类videos死尸| 欧美人与动牲交xxxxbbbb| 污污网站在线免费观看| 蜜臀久久久99精品久久久久久| 欧美美最猛性xxxxxx| 亚洲一区二区乱码| 久久亚洲国产精品尤物| 亚洲韩国一区二区三区| 欧美日韩精品免费看| 国产精品羞羞答答在线| 美女精品网站| 久久天天躁狠狠躁夜夜av| 182在线视频| 国产精品久久久久久av公交车| 精品人伦一区二区三区蜜桃网站| 一区精品在线| 日韩a在线看| 国产激情一区二区三区| 国产成人中文字幕| 国产一级特黄a高潮片| 色综合五月天| 亚洲欧洲第一视频| 无码人妻精品一区二区三| 九七电影院97理论片久久tvb| 性做久久久久久免费观看| 伊人久久99| 久久久pmvav| 北岛玲一区二区三区四区| 91免费人成网站在线观看18| 在线观看你懂的网站| 亚洲日本视频| 欧美黑人性猛交| 老司机成人免费视频| 九一亚洲精品| 日韩精品免费在线视频| 亚洲av无码久久精品色欲| 亚洲人成777| 欧美天堂一区二区三区| 女人另类性混交zo| 日本а中文在线天堂| 亚洲一区二区三区四区五区中文| 中文一区一区三区免费| 触手亚洲一区二区三区| 久久精品日产第一区二区三区高清版| 成人免费在线看片| www.国产麻豆| 国产精品2024| ts人妖另类在线| 精品人妻久久久久一区二区三区| 激情综合色播五月| 成人国产精品久久久| 中文字幕日产av| 日韩av网站在线观看| 国产精品久久久久久网站| 日本黄色一级视频| 日韩高清在线不卡| 国产日韩在线精品av| 一级黄色片视频| 激情综合色播激情啊| 91黄在线观看| 亚洲欧美黄色片| 成人网在线播放| 国产区欧美区日韩区| 天堂在线资源网| 91麻豆产精品久久久久久| 久久久水蜜桃| 国产日韩精品在线看| 红杏成人性视频免费看| 欧美一区二区三级| 免费黄视频在线观看| 伊人久久大香线蕉av超碰| 欧美va天堂va视频va在线| 日本性生活一级片| 台湾亚洲精品一区二区tv| 亚洲欧美一区二区激情| 美女av免费看| 欧美日韩精品| 亚洲欧洲高清在线| 极品人妻videosss人妻| 欧美高清视频在线观看mv| 久久久国产精彩视频美女艺术照福利| 福利所第一导航| 国产精品婷婷| 国产精品永久在线| 性中国xxx极品hd| 免费观看久久久4p| 91精品啪aⅴ在线观看国产| 丰满人妻妇伦又伦精品国产| 国产亚洲一区二区三区在线观看| 一本久道久久综合狠狠爱亚洲精品| 宅男网站在线免费观看| 欧美午夜女人视频在线| 中文字幕成人在线视频| 国产精品nxnn| 中文字幕亚洲欧美日韩高清| 国产性猛交普通话对白| 丝袜美腿亚洲综合| 91在线短视频| www亚洲人| 亚洲高清免费观看高清完整版在线观看| 免费男同深夜夜行网站| 视频一区视频二区欧美| 在线播放亚洲激情| 日本亚洲欧美在线| 精品午夜一区二区三区在线观看| 国产精品久久久久久久久婷婷 | 黄毛片在线观看| 欧美精品自拍偷拍| 亚洲一级中文字幕| 国产一区二区三区四区老人| 国产精品一区二区久久久| 熟妇高潮一区二区高潮| 亚洲色图欧洲色图| 一级黄色香蕉视频| 欧美偷窥清纯综合图区| 久久影院中文字幕| 成人黄色三级视频| 99re视频这里只有精品| 毛片在线视频观看| 亚洲国产91视频| 亚洲无限av看| 特一级黄色大片| 成人免费视频播放| 8x8ⅹ国产精品一区二区二区| 免费污视频在线一区| 疯狂做受xxxx高潮欧美日本| aaa一级黄色片| 日本不卡二三区| 欧美整片在线观看| 俄罗斯嫩小性bbwbbw| 亚洲女厕所小便bbb| 五月天av在线播放| 99久久99久久精品国产片桃花 | 懂色av蜜臀av粉嫩av分享吧最新章节| 国产99久久久久| 真人做人试看60分钟免费| 日韩黄色三级在线观看| 最新69国产成人精品视频免费| 久久久久99精品成人片我成大片| 成人午夜在线播放| 高清欧美精品xxxxx| 91成人午夜| 欧美激情区在线播放| 亚洲第九十九页| 亚洲国产你懂的| 毛茸茸free性熟hd| 国产精品一国产精品k频道56| 国产亚洲精品自在久久| 国产中文在线播放| 日韩高清av一区二区三区| 好吊妞视频一区二区三区| 91免费版在线| 成年人视频在线免费| 国产精品欧美日韩一区| 国产精品久久久久久超碰| 在线观看完整版免费| 777午夜精品视频在线播放| 国产精品视频看看| 国产精品资源在线看| 国产91在线亚洲| 第四色在线一区二区| 欧美一级黄色网| av在线资源站| 91精品国产色综合久久ai换脸 | 国产一在线精品一区在线观看| 99久久国产免费免费| 7777kkk亚洲综合欧美网站| 亚洲乱码国产乱码精品精天堂| 亚洲无码精品一区二区三区| 中文字幕av一区二区三区| 黄色一级片免费的| 国内视频精品| 欧美日韩国产精品一区二区| 中文成人在线| 久久久亚洲国产| 国内在线精品| 欧美一区二区福利视频| 日韩美女视频网站| 国产视频一区在线播放| 永久免费黄色片| 日韩一级在线| 亚洲欧美日韩国产yyy| 欧美特黄不卡| 国产成人精品亚洲精品| 国产二区三区在线| 日韩精品久久久久| 国产免费黄色录像| 欧美视频第一页| 一区二区三区影视| 91麻豆高清视频| 亚洲高清视频免费| 美女精品在线| 小泽玛利亚av在线| 黑人操亚洲人| 成人免费看片网址| 久久av影院| 国内偷自视频区视频综合 | 久久久久久久国产| av在线免费观看网| 欧美精品一区二区精品网| 中文无码av一区二区三区| 亚洲国产精品欧美一二99| 美女网站视频色| 91免费视频大全| 深爱五月综合网| 日本视频一区二区三区| 精品视频免费在线播放| 久久精品青草| 日韩三级电影免费观看| 露出调教综合另类| 91久久精品一区| 日韩在线观看不卡| 2019中文字幕在线| 女子免费在线观看视频www| 国产一区二区三区在线观看网站 | 91视频免费播放| 黑人巨大猛交丰满少妇| 蜜桃av一区二区在线观看| 黑鬼大战白妞高潮喷白浆| 亚洲片区在线| 精品无码国产一区二区三区av| 日韩理论电影院| 日本一区二区三区四区高清视频| 神马午夜久久| 国产尤物99| 精品欧美午夜寂寞影院| 2020国产精品久久精品不卡| 亚洲国产aⅴ精品一区二区三区| 国产精品第七影院| xx欧美视频| 欧美中文字幕视频| 僵尸再翻生在线观看| 国内久久久精品| 僵尸再翻生在线观看免费国语| 国产+人+亚洲| 国产白丝在线观看| 久久久久久久久久久国产| 黄色美女视频在线观看| 九九精品在线观看| 色操视频在线| 色综合男人天堂| 波多野在线观看| 久久久这里只有精品视频| 草草视频在线| 欧美一区二三区| 欧洲亚洲两性| 国产福利精品视频| 91大神在线观看线路一区| 国产精品极品在线| 啪啪av大全导航福利综合导航| 国产精品网站入口| 99精品女人在线观看免费视频| 成人激情在线播放| 嫩呦国产一区二区三区av| a级国产乱理论片在线观看99| 91麻豆精品激情在线观看最新| 99国产视频| 精品女人视频| 欧洲精品国产| 999久久久国产精品| 九一免费在线观看| 亚洲免费播放| 熟女少妇精品一区二区| 极品销魂美女一区二区三区| 91精产国品一二三| 久久综合资源网| 成人在线手机视频| 亚洲欧美另类在线| 日韩久久精品视频| 欧美日韩一级片网站| 国产伦理吴梦梦伦理| 日韩一区二区视频| 日韩在线视频第一页| 亚洲色图美腿丝袜| 国产午夜精品久久久久免费视| 欧美激情一区二区三区高清视频 | 99免费在线观看视频| 美女福利一区| 亚洲一区二区精品在线观看| 欧美日韩国产高清| 国产成人无码一二三区视频| 久久99精品视频| 国产视频久久久久久| 国产精品网曝门| 久久精品女人毛片国产| 91久久香蕉国产日韩欧美9色| a级片在线视频| 亚洲男人天堂久| 污视频网站免费在线观看| 青青草国产精品一区二区| 国产午夜精品一区在线观看| 久久精品中文字幕一区二区三区| 99久久精品国产亚洲精品| 国产精品无码人妻一区二区在线| 蜜桃av一区二区| 亚洲精品女人久久久| √…a在线天堂一区| 在线观看日本网站| 精品久久久久久久久久久院品网| av在线免费一区| 91高清视频免费| 天堂av一区| 中文字幕在线亚洲三区| 性高湖久久久久久久久| 亚洲熟妇一区二区| 国产精品毛片高清在线完整版| 亚洲精品视频在线观看免费视频| 欧美日韩国产天堂| 国产一级二级三级在线观看| 久久久久久国产精品美女| 涩涩涩久久久成人精品| 免费一区二区三区在在线视频| 欧美精品国产| 色18美女社区| 国产精品日产欧美久久久久| 亚洲国产综合久久| 日韩久久精品一区| 一区二区小视频| 亚洲精品天天看| 韩国成人二区| 国产一区二区黄色| 欧美日本不卡| 两性午夜免费视频| 国产日韩欧美综合在线| 国产成人无码一区二区三区在线| 日韩视频免费观看高清在线视频| 日本网站在线免费观看视频| 青青草成人在线| 亚洲精品亚洲人成在线| 日韩黄色短视频| 国产69精品一区二区亚洲孕妇 | 欧美黄色小说| 97国产精品免费视频| 成人av影音| 青青草精品视频在线| 成人av午夜电影| 久久精品视频久久| 精品国精品国产| 三级福利片在线观看| 成人黄视频免费| 亚洲狼人精品一区二区三区| 欧美激情一区二区三区p站| 亚洲一区二三区| 人人妻人人澡人人爽久久av| 国产综合在线看| 欧美有码在线| 99色精品视频| 国产亚洲精品精华液| 91视频在线视频| 最新中文字幕亚洲| 在线视频成人| 97超碰国产精品| av一区二区久久| 亚洲精品中文字幕乱码三区91| 亚洲欧美一区二区三区在线| 欧美日韩免费看片| 夜夜爽www精品| 国产黄人亚洲片| 五月天婷婷综合网| 亚洲人成电影网站色| 欧美特黄色片| 亚洲爆乳无码精品aaa片蜜桃| 粉嫩av亚洲一区二区图片| 久草视频在线观| 中文字幕精品在线| 免费观看性欧美大片无片| 僵尸世界大战2 在线播放| 久久日韩精品一区二区五区| 亚洲天堂中文在线| 欧美激情久久久久久| 中文字幕av一区二区三区人| 天堂一区在线观看| 亚洲成人在线免费| 国产鲁鲁视频在线观看免费| 亚洲一区二区自拍| 国产欧美午夜| 国产精品久久久视频| 日韩精品影音先锋| 免费日韩电影| 国产成人免费高清视频| 91在线视频播放地址| 91禁在线观看| 97av视频在线| 亚洲国产精品成人| 成人h动漫精品一区| 欧美人与禽zozo性伦| 擼擼色在线看观看免费| 在线电影看在线一区二区三区| 成人午夜视频福利| 亚洲熟妇av乱码在线观看| 久久免费视频在线观看| 欧美午夜精彩| 朝桐光av一区二区三区| 91精品啪在线观看国产60岁| 一区二区精品伦理...| 久久久久福利视频|