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

SpringBoot整合RabbitMQ實現郵件異步發送

開發 架構
本文主要以實現郵件自動推送這個業務場景為例,通過 Springboot 整合 rabbitMQ 技術來實現高可用的效果。

本篇文章將介紹另一種高可用的服務架構,以便實現郵件 100% 被投遞成功。類似的短信推送等服務,實現邏輯也大體類似。

01、先來一張流程圖

圖片圖片

本文內容主要圍繞這個流程圖展開,利用 RabbitMQ 消息隊列來實現郵件 100% 被投遞,內容涵蓋了 RabbitMQ 很多知識點,如:

  • 生產者和消費者模型
  • 消息發送機制
  • 消費確認機制
  • 消息的重新投遞
  • 消息消費失敗的處理方案

02、實現思路

  • 1.準備一臺電腦,并安裝 RabbitMQ 服務
  • 2.開放 QQ 郵箱或者其它郵箱授權碼,用于發送郵件
  • 3.創建郵件發送項目并編寫代碼
  • 4.發送郵件測試
  • 5.消息消費失敗的處理介紹

03、環境準備

3.1、安裝 RabbitMQ 服務

安裝 RabbitMQ 服務,這一步比較簡單,可以訪問下面的官方地址,下載軟件包并依次按照步驟進行安裝即可。

https://rabbitmq.org.cn/docs/download

安裝成功之后,登陸 RabbitMQ 控制臺,可以看到類似于如下界面。

圖片圖片

3.1.1、創建交換器

點擊“Exchanges”菜單,進入“交換器”管理界面。

圖片圖片

進入之后,點擊最下方“Add a new exchange”按鈕,創建一個類型為topic,名稱叫mail.exchange的交換器,并提交。

圖片圖片

3.1.2、創建消息隊列

接著,點擊“Queues”菜單,進入消息隊列管理界面。

圖片圖片

同樣的,點擊最下方“Add a new queue”按鈕,創建一個名稱叫mq.mail.ack的消息隊列,并提交。

圖片圖片

保存之后,在列表中可以看到剛剛創建的消息隊列,然后點擊進入詳情。

圖片圖片

在詳情中,將當前消息隊列與上文創建的交換器進行綁定,便于后續通過交換器來發送消息到隊列,操作如下。

圖片圖片

對于topic類型的交換器,通常不直接與消息隊列進行交互,而是通過一個路由鍵,將消息路由到目標消息隊列,這樣設計的目的是讓消息投遞更加靈活。路由鍵,可以簡單理解為類似于路由器,對數據進行路由分發處理。

3.2、配置郵箱發送服務器

為了實現郵件自動發送功能,我們還需要準備一個郵箱發送服務器,這一步在之前的文章中已經詳細的介紹過,在此,我們簡單的再介紹一下。

以 QQ 郵箱為例,登陸進去之后,在設置里面開啟 POP3/SMTP 服務,并獲取授權碼記錄下來。

圖片圖片

圖片圖片

該授權碼,就是下文配置文件中spring.mail.password需要的密碼!

04、方案實踐

4.1、構建項目

在 IDEA 下創建一個名稱為smail的 Spring Boot 項目,pom文件中加入amqp和mail相關依賴包,示例如下:

<!--mail 支持-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-mail</artifactId>
</dependency>
<!--amqp 支持-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-amqp</artifactId>
</dependency>

4.2、添加相關配置

在application.properties中添加 rabbitmq、郵箱相關配置,示例如下:

# 配置郵件發送主機地址
spring.mail.host=smtp.exmail.qq.com
# 配置郵件發送服務端口號
spring.mail.port=465
# 配置郵件發送服務協議
spring.mail.protocol=smtp
# 配置郵件發送者用戶名或者賬戶
spring.mail.username=xxxx
# 配置郵件發送者密碼或者授權碼
spring.mail.password=xxxx
# 配置郵件默認編碼
spring.mail.default-encoding=UTF-8
# 配置smtp相關屬性
spring.mail.properties.mail.smtp.auth=true
spring.mail.properties.mail.smtp.ssl.enable=true
spring.mail.properties.mail.smtp.ssl.required=true

#rabbitmq配置
spring.rabbitmq.host=127.0.0.1
spring.rabbitmq.port=5672
spring.rabbitmq.virtual-host=/
spring.rabbitmq.username=test
spring.rabbitmq.password=test
# 開啟confirms回調 P -> Exchange
spring.rabbitmq.publisher-cnotallow=true
# 開啟returnedMessage回調 Exchange -> Queue
spring.rabbitmq.publisher-returns=true
# 設置手動確認(ack) Queue -> C
spring.rabbitmq.listener.simple.acknowledge-mode=manual
spring.rabbitmq.listener.simple.prefetch=100

其中,spring.mail.username和spring.mail.password指的就是上文中創建的郵箱賬號和授權碼,將其配置進去即可。

4.3、編寫 RabbitMQ 配置類

編寫一個 RabbitMQ 配置類,用于監聽消息的發送情況,示例如下。

@Configuration
public class RabbitConfig {

    private static final Logger LOGGER = LoggerFactory.getLogger(RabbitConfig.class);


    @Autowired
    private CachingConnectionFactory connectionFactory;

    @Bean
    public RabbitTemplate rabbitTemplate() {
        RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory);
        // 設置消息轉換器為json格式
        rabbitTemplate.setMessageConverter(new Jackson2JsonMessageConverter());

        // 消息是否成功發送到Exchange
        rabbitTemplate.setConfirmCallback((correlationData, ack, cause) -> {
            if (ack) {
                LOGGER.info("消息發送到Exchange成功,{}", correlationData);
            } else {
                LOGGER.error("消息發送到Exchange失敗, {}, cause: {}", correlationData, cause);
            }
        });

        // 觸發setReturnCallback回調必須設置mandatory=true, 否則Exchange沒有找到Queue就會丟棄掉消息, 而不會觸發回調
        rabbitTemplate.setMandatory(true);

        // 消息是否從Exchange路由到Queue, 注意: 這是一個失敗回調, 只有消息從Exchange路由到Queue失敗才會回調這個方法
        rabbitTemplate.setReturnCallback((message, replyCode, replyText, exchange, routingKey) -> {
            LOGGER.error("消息從Exchange路由到Queue失敗: exchange: {}, route: {}, replyCode: {}, replyText: {}, message: {}", exchange, routingKey, replyCode, replyText, message);
        });

        return rabbitTemplate;
    }
}

4.4、編寫生產者服務

在 Spring Boot 中,我們可以利用RabbitTemplate工具,將數據通過交換器發送到目標消息隊列,示例如下。

@Service
public class ProduceService {

    @Autowired
    private RabbitTemplate rabbitTemplate;

    /**
     * 發送消息
     * @param mail
     * @return
     */
    public boolean sendByAck(Mail mail) {
        // 創建uuid
        String msgId = UUID.randomUUID().toString().replaceAll("-", "");
        mail.setMsgId(msgId);

        // 發送消息到mq服務器中(附帶消息ID)
        CorrelationData correlationData = new CorrelationData(msgId);
        rabbitTemplate.convertAndSend("mail.exchange", "route.mail.ack", MessageHelper.objToMsg(mail), correlationData);
        return true;
    }
}

4.5、編寫消費者服務

在 Spring Boot 中,我們可以利用@RabbitListener注解,監聽指定的消息隊列,如果隊列中有消息會第一時間收到回調,示例如下。

@Component
public class ConsumerService {

    private static final Logger LOGGER = LoggerFactory.getLogger(ConsumerService.class);

    @Autowired
    private SendMailService sendMailService;

    /**
     * 監聽消息隊列,手動確認模式,必須手動調用ack或者nack方法
     * 配置參數:spring.rabbitmq.listener.simple.acknowledge-mode=manual
     * @param message
     * @param channel
     * @throws IOException
     */
    @RabbitListener(queues = {"mq.mail.ack"})
    public void consumeFromAck(Message message, Channel channel) throws IOException {
        LOGGER.info("收到消息:{}", message.toString());
        //將消息轉化為對象
        Mail mail = MessageHelper.msgToObj(message, Mail.class);

        // 手動確認模式
        long tag = message.getMessageProperties().getDeliveryTag();
        boolean success = sendMailService.send(mail);
        if (success) {
            // 消費成功,消息會被刪除
            channel.basicAck(tag, false);
        } else {
            // 消費失敗,重新返回隊列
            channel.basicNack(tag, false, true);
        }
    }
}

4.6、編寫郵件發送服務

正如之前的文章中所介紹的,在 Spring Boot 中,我們可以利用JavaMailSender工具來實現郵件的自動推送,示例如下。

@Service
public class SendMailService {

    private static final Logger LOGGER = LoggerFactory.getLogger(SendMailService.class);


    @Value("${spring.mail.username}")
    private String from;

    @Autowired
    private JavaMailSender mailSender;

    /**
     * 發送簡單郵件
     *
     * @param mail
     */
    public boolean send(Mail mail) {
        String to = mail.getTo();// 目標郵箱
        String title = mail.getTitle();// 郵件標題
        String content = mail.getContent();// 郵件正文

        SimpleMailMessage message = new SimpleMailMessage();
        message.setFrom(from);
        message.setTo(to);
        message.setSubject(title);
        message.setText(content);

        try {
            mailSender.send(message);
            LOGGER.info("郵件發送成功");
            return true;
        } catch (MailException e) {
            LOGGER.error("郵件發送失敗, to: {}, title: {}", to, title, e);
            return false;
        }
    }
}

4.7、編寫 controller 接口

接著,編寫一個 controller 接口,將郵件發送服務暴露出去,示例如下:

@RestController
public class MailController {

    @Autowired
    private ProduceService produceService;

    @PostMapping("send")
    public String sendMail(Mail mail) {
        boolean result = produceService.sendByAck(mail);
        return result ? "success": "fail";
    }
}

4.8、服務測試

最后,啟動 SpringBoot 服務,用 postman 來測試一下。

圖片圖片

查看控制臺信息。

圖片圖片

查詢接受者郵件信息。

圖片圖片

可以清楚的看到,郵件發送成功!

當大批量的發送郵件,也不用擔心,因為整個郵件的發送都是異步的,不會阻塞主流程的運行。

05、消費失敗的處理方案

雖然以上的方案非常可靠,可以保證發出的消息 100% 被消費,但是其實也有弊端。

試想一下,按照上面的處理邏輯,假設其中有一條消息,因為某種原因一直發送失敗,會出現什么樣的情況?

此時,這條消息會重新返回隊列,然后一直重試,會導致其它的消息可能會無法被消費。

針對這種情況,最簡單粗暴的辦法就是,當重試失敗之后將消息丟棄,不會阻礙其它的消息被正常處理,不過會丟失數據。

那么如何正確的處理消息消費失敗的問題呢?

可以借助數據庫來記錄消費失敗的數據,針對系統無法成功處理的消息,人工進行干預。

實踐過程如下!

5.1、創建一張消息日志表

首先,在數據庫中創建一張消息日志表,用于跟蹤消息數據的狀態,示例如下:

CREATE TABLE `msg_log` (
  `msg_id` varchar(255) NOT NULL DEFAULT '' COMMENT '消息唯一標識',
  `exchange` varchar(100) NOT NULL DEFAULT '' COMMENT '交換機',
  `route_key` varchar(100) NOT NULL DEFAULT '' COMMENT '路由鍵',
  `queue_name` varchar(100) NOT NULL DEFAULT '' COMMENT '隊列名稱',
  `msg` text COMMENT '消息體, json格式化',
  `result` varchar(255) DEFAULT NULL COMMENT '處理結果',
  `status` int(11) NOT NULL DEFAULT '0' COMMENT '狀態,0:等待消費,1:消費成功,2:消費失敗,9:重試失敗',
  `try_count` int(11) NOT NULL DEFAULT '0' COMMENT '重試次數',
  `next_try_time` datetime DEFAULT NULL COMMENT '下一次重試時間',
  `create_time` datetime DEFAULT NULL COMMENT '創建時間',
  `update_time` datetime DEFAULT NULL COMMENT '更新時間',
  PRIMARY KEY (`msg_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='mq消息日志';

5.2、改寫生產者邏輯

在生產者服務類中,先將消息數據寫入數據庫,再向 rabbitMQ 服務中發消息,示例如下:

@Service
public class ProduceService {

    @Autowired
    private RabbitTemplate rabbitTemplate;

    @Autowired
    private MsgLogService msgLogService;

    /**
     * 發送消息
     * @param mail
     * @return
     */
    public boolean sendByAuto(Mail mail) {
        String msgId = UUID.randomUUID().toString().replaceAll("-", "");
        mail.setMsgId(msgId);

        // 1.存儲要消費的數據
        msgLogService.save("mail.exchange", "route.mail.auto", "mq.mail.auto", msgId, mail);

        // 2.發送消息到mq服務器中(附帶消息ID)
        CorrelationData correlationData = new CorrelationData(msgId);
        rabbitTemplate.convertAndSend("mail.exchange", "route.mail.auto", MessageHelper.objToMsg(mail), correlationData);
        return true;
    }
}

5.3、改寫消費者邏輯

在消費者服務類中,收到消息之后,不管處理成功還是失敗,都只會修改數據庫中的消息狀態,并且消息處理失敗時,不再重新返回隊列。

@Component
public class ConsumerService {

    private static final Logger LOGGER = LoggerFactory.getLogger(ConsumerService.class);

    @Autowired
    private SendMailService sendMailService;

    @Autowired
    private MsgLogService msgLogService;

    /**
     * 監聽消息隊列,自動確認模式,無需調用ack或者nack方法,當程序執行時才刪除消息
     * 配置參數:spring.rabbitmq.listener.simple.acknowledge-mode=auto
     * @param message
     */
    @RabbitListener(queues = {"mq.mail.auto"})
    public void consumeFromAuto(Message message) {
        LOGGER.info("收到消息:{}", message.toString());
        // 獲取消息ID
        Mail mail = MessageHelper.msgToObj(message, Mail.class);

        // 消息冪等性處理,如果已經處理成功,無需重復消費
        MsgLog queryObj = msgLogService.selectByMsgId(mail.getMsgId());
        if(Objects.nonNull(queryObj) && Constant.SUCCESS.equals(queryObj.getStatus())){
            return;
        }

        // 發送郵件
        boolean success = sendMailService.send(mail);
        if(success){
            msgLogService.updateStatus(mail.getMsgId(), Constant.SUCCESS, "郵件發送成功");
        } else {
            msgLogService.updateStatus(mail.getMsgId(), Constant.FAIL, "郵件發送失敗");
        }
    }
}

因為此處采用自動確認模式,因此還需要修改application.properties中的配置參數,內容如下:

# 設置自動確認(默認此模式)
spring.rabbitmq.listener.simple.acknowledge-mode=auto

5.4、編寫定時任務對失敗消息進行補償投遞

當消息消費失敗時,會自動記錄到數據庫。

實際上,不可能每條數據都需要我們進行干預,有的可能重試一次就好了,因此可以編寫一個定時任務,將消費失敗的數據篩選出來,重新放入到消息隊列中,只有當消費次數達到設置的最大值,此時進入人工干預階段,可以節省不少的工作。

示例如下:

@Component
public class ScheduledTask {

    private static final Logger LOGGER = LoggerFactory.getLogger(ScheduledTask.class);

    /**
     * 最大投遞次數
     */
    private static final int MAX_TRY_COUNT = 3;

    @Autowired
    private MsgLogService msgLogService;

    @Autowired
    private RabbitTemplate rabbitTemplate;

    /**
     * 每30s拉取消費失敗的消息, 重新投遞
     */
    @Scheduled(cron = "0/30 * * * * ?")
    public void retry() {
        LOGGER.info("開始執行重新投遞消費失敗的消息!");
        // 查詢需要重新投遞的消息
        List<MsgLog> msgLogs = msgLogService.selectFailMsg();
        for (MsgLog msgLog : msgLogs) {
            if (msgLog.getTryCount() >= MAX_TRY_COUNT) {
                msgLogService.updateStatus(msgLog.getMsgId(), Constant.RETRY_FAIL, msgLog.getResult());
                LOGGER.info("超過最大重試次數, msgId: {}", msgLog.getMsgId());
                break;
            }

            // 重新投遞消息
            CorrelationData correlationData = new CorrelationData(msgLog.getMsgId());
            rabbitTemplate.convertAndSend("", msgLog.getQueueName(), MessageHelper.objToMsg(msgLog.getMsg()), correlationData);
            // 更新下次重試時間
            msgLogService.updateNextTryTime(msgLog.getMsgId(), msgLog.getTryCount());
        }
    }
}

最后別忘了,在Application類上添加@EnableScheduling,以便讓定時調度生效,示例如下:

@EnableScheduling
@SpringBootApplication
public class Application {

    public static void main(String[] args) {
        SpringApplication.run(Application.class,args);
    }
}

利用定時任務,對投遞失敗的消息進行補償投遞,基本可以保證消息 100% 消費成功!

06、小結

本文主要以實現郵件自動推送這個業務場景為例,通過 Springboot 整合 rabbitMQ 技術來實現高可用的效果。

當然,解決這個業務需求的技術方案還有很多,例如 Springboot 整合 rocketMQ 也可以實現這個效果,不管怎么變,底層的實現思路基本都一樣。

希望本篇的知識總結,對大家有所幫助。

最后,代碼都經過自測,想要獲取項目源碼的同學,可以點擊如下地址獲取。

示例代碼地址:

https://gitee.com/pzblogs/spring-boot-example-demo

責任編輯:武曉燕 來源: 潘志的研發筆記
相關推薦

2024-12-24 08:44:55

ActiveMQRabbitMQ交換機

2024-11-04 08:02:23

SpringRabbitMQ中間件

2024-09-02 09:14:36

SpringRabbitMQ數據

2022-09-02 15:08:02

Python郵件發送

2020-09-08 07:37:44

springBoot MQ rabbitMQ

2024-11-14 12:22:37

SpringMail郵件

2025-05-29 01:33:00

微服務架構系統

2021-11-15 14:02:27

RPCSpringBootRabbitMQ

2023-08-08 08:28:03

消息消費端Spring

2025-05-16 08:55:58

2025-03-04 08:40:28

2020-04-23 15:08:41

SpringBootMyCatJava

2023-12-07 18:02:38

RabbitMQ異步通信

2009-12-02 16:31:54

PHP發送郵件

2009-12-09 15:23:36

PHP mail()函

2023-08-10 11:39:54

RabbitMQSpring交換機

2023-03-06 08:16:04

SpringRabbitMQ

2024-08-12 12:17:03

2022-04-28 07:31:41

Springkafka數據量

2017-04-26 09:00:23

Python發送郵件腳本
點贊
收藏

51CTO技術棧公眾號

爱看av在线| 91亚洲国产成人久久精品麻豆 | 91精品啪在线观看麻豆免费| 日本精品在线免费观看| 一区二区三区免费在线看| 一区二区三区四区五区视频在线观看 | 欧美黄色免费看| 色婷婷久久久| 欧美日韩国产一级片| 免费一级淫片aaa片毛片a级| 欧洲天堂在线观看| 国产精品一区在线| 欧美一级高清免费播放| 国精产品一区一区二区三区mba| 高清一区二区三区| 欧美日韩aaaaaa| 日本中文字幕网址| 老司机免费在线视频| 91麻豆.com| 91视频8mav| 黄色av一区二区| 黄色日韩精品| 久久久精品日本| 欧美特级黄色录像| 国产成人精品福利| 制服丝袜亚洲网站| 好男人www社区| 国产精品25p| 亚洲欧美日韩中文播放| 日韩av电影免费在线| 亚洲精品久久久久久久久久久久久久| 日本中文字幕一区二区视频 | 久久久久久国产精品免费播放| 精品国产一区二区三区香蕉沈先生 | 国内精品小视频在线观看| 五月天色婷婷丁香| 欧美精品一区二区久久| 日韩av在线免费观看| a级大片免费看| 91p九色成人| 日本道色综合久久| 日本一本二本在线观看| 第一福利在线视频| 一区二区三区四区激情| 男女h黄动漫啪啪无遮挡软件| 风间由美一区| 久久噜噜亚洲综合| 久久99国产精品99久久| 高h震动喷水双性1v1| 国模一区二区三区白浆| 国产主播在线一区| 一区二区三区日| 久久国产精品99精品国产| 国产精品久久久久久久久久久久久 | 国产大学生av| 91精品国产乱码久久久竹菊| 日韩午夜激情免费电影| 国产在线a视频| 天堂精品久久久久| 精品美女在线观看| 野战少妇38p| av综合网页| 欧美mv日韩mv国产网站| 精品人妻伦一二三区久| 亚洲一区二区三区日本久久九| 日韩一区二区三区免费看 | 日韩第一区第二区| 欧美成人r级一区二区三区| 男人女人拔萝卜视频| 国产95亚洲| 欧美岛国在线观看| 中文字幕人妻一区| 九色精品91| 在线观看成人黄色| 免费一级suv好看的国产网站| 四虎成人精品永久免费av九九| 久久久91精品国产一区不卡| 欧美成人精品欧美一级| 亚洲国产第一| 日本高清不卡在线| 一本到在线视频| 国产精品一区二区久激情瑜伽| 国产精品有限公司| 九九九伊在人线综合| 国产农村妇女精品| 国产精品国产三级国产专区51| 黄视频在线免费看| 日本韩国一区二区| 黄色a级三级三级三级| 国产精品va视频| 亚洲第一男人天堂| 国产jk精品白丝av在线观看| 久久精品一区二区不卡| 久久久噜噜噜久久久| 久久精品久久久久久久| 国产真实乱子伦精品视频| 国产精品二区二区三区| 男女视频在线观看| 亚洲男人的天堂av| 日韩精品一区二区三区久久| 爱情电影网av一区二区| 日韩高清不卡av| 亚洲一区电影在线观看| 9国产精品视频| 成人午夜黄色影院| 欧美日韩国产综合视频| 一区二区三区四区视频精品免费| 成人在线观看a| 人人爽人人爽人人片av| 成人黄视频在线观看| 黄色成人av在线| 午夜视频在线网站| 日韩黄色网络| 欧美乱大交做爰xxxⅹ性3| 成人a v视频| 顶级嫩模精品视频在线看| 亚洲国产一区二区精品视频 | 日本大片在线观看| 亚洲另类在线视频| 国产精品无av码在线观看| 日韩中文字幕免费在线| 99精品女人在线观看免费视频| 亚洲第一色在线| 五月天色婷婷丁香| 日本麻豆一区二区三区视频| 国产成人精品日本亚洲11 | 国产一区二区动漫| 男女免费视频网站| 极品少妇一区二区| 涩涩日韩在线| 亚洲免费福利| 亚洲黄页网在线观看| 一区视频免费观看 | 久久精品一卡二卡| 国产欧美亚洲精品a| 性欧美xxxx| 亚洲男人第一天堂| 亚洲一级二级三级在线免费观看| 伊人国产在线视频| 青青草91久久久久久久久| 欧美一区视频在线| 日本ー区在线视频| 日韩欧美国产免费播放| 亚洲精品无码一区二区| 国产综合自拍| 2019国产精品视频| 黄色片网站在线| 欧美日韩激情一区二区| 欧美88888| 久久国产综合精品| 婷婷久久青草热一区二区| japanese23hdxxxx日韩| 亚洲精品少妇网址| 国内精品福利视频| 久久女同互慰一区二区三区| 欧美精品一区二区三区三州| 国产精品调教视频| 亚洲3p在线观看| 秋霞av鲁丝片一区二区| 午夜伊人狠狠久久| 日本一区二区三区网站| 亚洲免费网址| 日本一区高清在线视频| 国产极品久久久久久久久波多结野| 一区二区三区无码高清视频| 一级片在线观看免费| 久久人人爽人人爽| 日本在线一二三区| 伊人情人综合网| 国产精品一区而去| 深夜成人在线| 正在播放国产一区| a天堂视频在线| 午夜精品福利一区二区三区av| 波多野结衣视频播放| 久久激情网站| 在线看成人av电影| 成人爽a毛片| 日本久久久a级免费| 中文字幕日本在线| 日韩午夜在线观看| 91丝袜一区二区三区| 国产精品伦一区| 91av免费观看| 久久久久久婷| 99久re热视频精品98| 日韩欧美天堂| 91精品久久久久久久久不口人| 日本三级在线观看网站| 亚洲男人第一av网站| 亚洲综合精品国产一区二区三区| 亚洲一区二区三区中文字幕| 国精产品一区一区三区免费视频| 精品系列免费在线观看| 日本欧美视频在线观看| 青青草国产免费一区二区下载| av日韩中文字幕| 午夜欧美巨大性欧美巨大 | bl视频在线免费观看| 成久久久网站| 日韩小视频在线| 亚洲AV无码精品色毛片浪潮| 色噜噜狠狠成人中文综合| 国产精品久久久精品四季影院| 久久综合久久鬼色| 人妻激情偷乱视频一区二区三区| 久久久久久9| 每日在线观看av| 98精品视频| 欧美久久久久久一卡四| 综合中文字幕| 国产欧美一区二区| 日韩电影av| 久久人人爽人人爽人人片av高请| 1区2区3区在线观看| 日韩av在线免费看| www.色呦呦| 欧美日韩黄色一区二区| 无码视频在线观看| 一级女性全黄久久生活片免费| 中文字幕在线观看免费高清| bt7086福利一区国产| 男女污污视频网站| 日韩二区三区四区| 美女日批免费视频| 欧美极品一区二区三区| 亚洲视频电影| 精品盗摄女厕tp美女嘘嘘| 精品在线视频一区二区三区| 亚洲黑人在线| 国产精品成人av在线| 亚洲天堂av影院| 高清亚洲成在人网站天堂| 在线中文字幕电影| 久久久精品中文字幕| 伊人在线视频| 在线播放国产一区中文字幕剧情欧美 | 7777精品伊人久久久大香线蕉完整版| 日韩美一区二区| 欧美日韩亚洲激情| 日本在线免费观看| 亚洲国产精品久久不卡毛片| 免费一级黄色大片| 亚洲免费观看高清完整版在线| 国产美女主播一区| 91精品国产乱码久久| 欧美综合久久久| 日韩国产亚洲欧美| 欧美综合一区二区三区| 亚洲毛片一区二区三区| 欧美午夜影院在线视频| 一区二区三区在线观看av| 狠狠躁夜夜躁人人爽天天天天97 | 91在线国产电影| www.久久99| 成人激情直播| 高潮久久久久久久久久久久久久 | 精品大片一区二区| 亚洲精品国产精品国自产| 成人在线一区| 中文字幕の友人北条麻妃| 亚洲成人av| 日韩精品视频在线观看视频| 亚洲黄色影院| 欧美成人精品欧美一级乱| 日韩精品一二三区| 免费看污污网站| 精品一区二区三区在线播放 | 中文字幕一区二区久久人妻| 欧美久久久久久久久中文字幕| 99精品人妻无码专区在线视频区| 日韩免费成人网| 亚洲欧洲综合在线| 国产一区二区三区欧美| 免费观看在线午夜影视| 欧美高清第一页| 中文一区一区三区高中清不卡免费 | 国产午夜精品一区二区三区 | 中文字幕精品国产| 黄网址在线观看| 韩国国内大量揄拍精品视频| 成人软件在线观看| 91在线中文字幕| 国内精品麻豆美女在线播放视频| 人偷久久久久久久偷女厕| 午夜精品一区二区三区国产| 91网站在线观看免费| 亚洲欧美清纯在线制服| 国产美女视频免费看| av一区二区三区四区| 麻豆视频免费在线播放| 洋洋av久久久久久久一区| 日韩一级在线视频 | 四虎精品在线| 日韩中文字幕第一页| 99爱在线观看| 国产这里只有精品| 天堂日韩电影| 日本一区二区免费高清视频| 一本色道久久| 在线播放免费视频| 久久久久久久久一| 久久亚洲国产成人精品性色| 91精品福利视频| 蜜臀久久精品久久久久| 视频在线观看99| 波多视频一区| www日韩av| 9999国产精品| 毛片av免费在线观看| 国产成人在线电影| 国产传媒视频在线 | 亚洲一卡二卡在线观看| 亚洲成人黄色在线| 美女免费久久| 欧美中文字幕在线视频| 一区二区三区国产好| 亚洲一区二区三区免费观看| 国产美女诱惑一区二区| 中文字幕第10页| 中文字幕一区二区三区在线观看| 国产精品777777| 亚洲成人精品av| 色呦呦在线观看视频| 国产一区二区在线免费| 精品日韩在线| 免费看a级黄色片| hitomi一区二区三区精品| 免费在线黄色网| 欧美酷刑日本凌虐凌虐| aiai在线| 国产精品激情av在线播放 | 亚洲精品在线视频| 超碰91在线观看| 国产日韩欧美一区二区三区四区 | 日本黄网站免费| 91色视频在线| 国产视频91在线| 亚洲国产精品成人av| 久久不射影院| 国产传媒一区二区三区| 国产精品99免费看| 巨乳女教师的诱惑| 夜夜精品视频一区二区| 国产视频在线一区| y97精品国产97久久久久久| 国产精品原创视频| 亚洲一卡二卡区| 久久精品99久久久| 在线视频这里只有精品| 欧美日韩大陆一区二区| 91精品国产91久久久久游泳池| 国产精品久久久久久久久粉嫩av| 欧美亚洲国产一区| 超碰在线公开97| 亚洲人亚洲人成电影网站色| 国产三级三级在线观看| 欧美成人精品在线视频| 亚洲国产欧美国产第一区| 丁香婷婷综合激情| 99视频热这里只有精品免费| 少妇一级淫片免费放中国| 精品亚洲一区二区| 亚洲四虎影院| 中文字幕精品一区日韩| 国产精一区二区三区| 国产精品30p| 亚洲精品之草原avav久久| 福利精品在线| 国内精品国产三级国产99| 懂色av中文字幕一区二区三区| 国产成人精品a视频一区| 亚洲欧美中文日韩v在线观看| 成人高清一区| av动漫在线播放| 久久亚洲一区二区三区明星换脸| 国产成人自拍偷拍| 久久国产精品免费视频| 欧美人妖视频| 99re精彩视频| 亚洲一区二区三区中文字幕在线| 男女视频在线观看| 91久久精品美女高潮| 一区精品久久| 卡一卡二卡三在线观看| 欧美一区二区三区婷婷月色 | 国产精品丝袜白浆摸在线 | 国产女人18水真多18精品一级做| 国产日韩在线观看一区| 欧美亚洲第一区| 91一区二区| 在线精品一区二区三区| 欧美三级日本三级少妇99| 日本成人不卡| 色婷婷精品国产一区二区三区| 国产激情精品久久久第一区二区 | 亚洲国产精品成人精品| 姬川优奈av一区二区在线电影| 91九色国产ts另类人妖| 91美女片黄在线|