自定義springboot-starter實(shí)現(xiàn)通用基礎(chǔ)配置(數(shù)據(jù)庫案例)

背景說明

數(shù)據(jù)庫基礎(chǔ)配置如數(shù)據(jù)源配置,mybatis配置,sharding相關(guān)配置等在多個(gè)項(xiàng)目中如果都進(jìn)行配置,大致會(huì)有以下幾個(gè)問題

  • 需要編寫代碼(雖然可以復(fù)制,還是有些東西需要改),調(diào)試等,需要耗費(fèi)一定的時(shí)間
  • 不同項(xiàng)目的這些基礎(chǔ)配置不一致,會(huì)帶來一些問題(我們總是希望同一體系的這些通用組件盡量一致)
  • 當(dāng)有些內(nèi)容需要修改時(shí),需要識(shí)別哪些項(xiàng)目使用并一一修改.耗費(fèi)時(shí)間的同時(shí),也帶來一定風(fēng)險(xiǎn).如遺漏等

這些都是通用基礎(chǔ)配置普遍的問題,解決方案很自然的想到抽離封裝成通用組件.
本案例采用方式為抽離封裝成自定義springboot-starter組件.

starter組件說明

先看使用步驟以及效果

  • 引入自定義starter依賴
<dependency>
    <groupId>com.jiujiu</groupId>
    <artifactId>jiu-spring-boot-starter</artifactId>
    <version>0.0.1-SNAPSHOT</version>
</dependency>
  • 啟動(dòng)類添加數(shù)據(jù)庫開關(guān)注解,指定需要注冊(cè)的數(shù)據(jù)庫列表.
    如@EnableDB(value = {DBConfigEnum.TEST_DB, DBConfigEnum.ZCJ_DB})
@SpringBootApplication
@EnableDB(value = {DBConfigEnum.TEST_DB, DBConfigEnum.ZCJ_DB})
public class JiuDemoApplication {

    public static void main(String[] args) {
        SpringApplication.run(JiuDemoApplication.class, args);
    }
}
  • 配置文件指定加載starter項(xiàng)目配置文件以及指定mapper的位置(包含mapper和對(duì)應(yīng)的xml)
spring:
  application:
    name: jiu-demo
  profiles:
    # 指定加載starter項(xiàng)目配置文件,這個(gè)順序會(huì)以排在后面的為準(zhǔn)
    active: starter,starter-dev,dev

db:
  mapperLocation:
    test_db: com.example.jiudemo.mapper.testdb
    zcj_db: com.example.jiudemo.mapper.zcjdb
  mapperXmlLocation:
    test_db: classpath:mapper/testdb/*.xml
    zcj_db: classpath:mapper/zcjdb/*.xml
image.png

測(cè)試結(jié)果
調(diào)用mapper,返回?cái)?shù)據(jù)


image.png

自定義組件jiu-spring-boot-starter核心代碼(如何自定義starter網(wǎng)上很多資料)

  • 依賴在文章末尾

  • @EnableDB

/**
 * 通過定義枚舉列表動(dòng)態(tài)注冊(cè)數(shù)據(jù)庫
 */
@Retention(RUNTIME)
@Target(TYPE)
@Import({DBCommonAutoConfiguration.class,
//        DBSelector.class
        DBRegistrar.class

})
public @interface EnableDB {

    DBConfigEnum[] value() default {};

}
  • 配置類DBCommonAutoConfiguration主要解決MapperScannerConfigurer讀取不到配置文件屬性的問題
@Configuration
@ConditionalOnMissingBean(value = {DBCommonAutoConfiguration.class})
@EnableAutoConfiguration(exclude= {DataSourceAutoConfiguration.class, TransactionAutoConfiguration.class, MybatisAutoConfiguration.class})
// 解決MapperScannerConfigurer讀取不到配置文件屬性的問題
@Import(value = {CustomPropertySourcesPlaceholder.class})
public class DBCommonAutoConfiguration {
}
  • 配置類DBRegistrar或者DBSelector(實(shí)現(xiàn)動(dòng)態(tài)注冊(cè)bean的不同方式,選其一即可)
@Slf4j
public class DBRegistrar implements ImportBeanDefinitionRegistrar {

    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {


        // 根據(jù)注解的枚舉值,注入對(duì)應(yīng)的XXXAutoConfiguration
        Map<String, Object> annotationAttributes = importingClassMetadata.getAnnotationAttributes(EnableDB.class.getName());
        DBConfigEnum[] values = (DBConfigEnum[]) annotationAttributes.get("value");

        if (ArrayUtils.isEmpty(values)) {
            return;
        }
        List<String> dbList = Arrays.stream(values).map(DBConfigEnum::getDbName).collect(Collectors.toList());
        log.info("準(zhǔn)備注冊(cè)數(shù)據(jù)庫,dbList->{}", dbList);
        for (int i = 0; i < values.length; i++) {
            DBConfigEnum dbConfigEnum = values[i];
            BeanDefinition beanDefinition = new GenericBeanDefinition();
            beanDefinition.setBeanClassName(dbConfigEnum.getConfigClassName());
            registry.registerBeanDefinition(dbConfigEnum.getConfigClassName(), beanDefinition);
        }
    }
}
@Slf4j
public class DBSelector implements ImportSelector {

    @Override
    public String[] selectImports(AnnotationMetadata importingClassMetadata) {

        // 根據(jù)注解的枚舉值,注入對(duì)應(yīng)的XXXAutoConfiguration
        Map<String, Object> annotationAttributes = importingClassMetadata.getAnnotationAttributes(EnableDB.class.getName());
        DBConfigEnum[] values = (DBConfigEnum[]) annotationAttributes.get("value");

        if (ArrayUtils.isEmpty(values)) {
            return new String[0];
        }
        String[] array = new String[values.length];
        List<String> dbList = Arrays.stream(values).map(DBConfigEnum::getDbName).collect(Collectors.toList());
        log.info("準(zhǔn)備注冊(cè)數(shù)據(jù)庫,dbList->{}", dbList);
        for (int i = 0; i < values.length; i++) {
            DBConfigEnum dbConfigEnum = values[i];
            array[i] = dbConfigEnum.getConfigClassName();
        }

        return array;
    }
}
  • DBConfigEnum
public enum DBConfigEnum {

    TEST_DB("test_db", TestDBAutoConfiguration.class.getName()),
    ZCJ_DB("zcj_db", ZcjDBAutoConfiguration.class.getName())
    ;


    private String dbName;

    private String configClassName;

    DBConfigEnum(String dbName, String configClassName) {
        this.dbName = dbName;
        this.configClassName = configClassName;
    }

    public String getDbName() {
        return dbName;
    }

    public String getConfigClassName() {
        return configClassName;
    }
}
  • TestDBAutoConfiguration
@Configuration
// 指定配置文件
@ImportResource(locations = {"classpath:jdbc-testdb.xml"})
public class TestDBAutoConfiguration {

}
  • jdbc-testdb.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:p="http://www.springframework.org/schema/p"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xmlns:sharding="http://shardingsphere.apache.org/schema/shardingsphere/sharding"
       xmlns:master-slave="http://shardingsphere.apache.org/schema/shardingsphere/masterslave"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
                        http://www.springframework.org/schema/beans/spring-beans.xsd
                        http://www.springframework.org/schema/context
                        http://www.springframework.org/schema/context/spring-context.xsd
                        http://www.springframework.org/schema/tx
                        http://www.springframework.org/schema/tx/spring-tx.xsd
                        http://shardingsphere.apache.org/schema/shardingsphere/sharding
                        http://shardingsphere.apache.org/schema/shardingsphere/sharding/sharding.xsd
                        http://shardingsphere.apache.org/schema/shardingsphere/masterslave
                        http://shardingsphere.apache.org/schema/shardingsphere/masterslave/master-slave.xsd">
    <context:annotation-config />
    <context:component-scan base-package="io.shardingsphere.example.spring.namespace.jpa" />

    <context:property-placeholder location="classpath:**/*.yml" ignore-unresolvable="true"/>

    <bean id="ds-testdb-master" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close" >
        <property name="name" value="ds-testdb-master"/>
        <property name="driverClassName" value="${db.driver-class-name}"/>
        <property name="url" value="${db.testdb-master.url}"/>
        <property name="username" value="${db.testdb-master.username}"/>
        <property name="password" value="${db.testdb-master.password}"/>

        <!-- 啟動(dòng)程序時(shí)皂甘,在連接池中初始化多少個(gè)連接 -->
        <property name="initialSize" value="10"/>
        <!-- 啟動(dòng)程序時(shí)蓖议,在連接池中初始化多少個(gè)連接 -->
        <property name="minIdle" value="5"/>
        <!-- 連接池中最多支持多少個(gè)活動(dòng)會(huì)話 -->
        <property name="maxActive" value="300"/>
        <!-- 程序向連接池中請(qǐng)求連接時(shí),超過maxWait的值后捺弦,認(rèn)為本次請(qǐng)求失敗犯犁,即連接池沒有可用連接,單位毫秒桃犬,設(shè)置-1時(shí)表示無限等待 -->
        <property name="maxWait" value="60000"/>
        <property name="queryTimeout" value="600000"/>
        <property name="socketTimeout" value="600000"/>
        <!-- 檢查空閑連接的頻率颅悉,單位毫秒, 非正整數(shù)時(shí)表示不進(jìn)行檢查 -->
        <property name="timeBetweenEvictionRunsMillis" value="60000"/>
        <!-- 池中某個(gè)連接的空閑時(shí)長達(dá)到 N 毫秒后, 連接池在下次檢查空閑連接時(shí)嚣镜,將回收該連接,要小于防火墻超時(shí)設(shè)置 -->
        <property name="minEvictableIdleTimeMillis" value="300000"/>

        <property name="transactionQueryTimeout" value="600000"/>
        <!-- 用來檢測(cè)連接是否有效的sql -->
        <property name="validationQuery" value="SELECT 'x'"/>
        <!-- 空間時(shí)執(zhí)行 validationQuery -->
        <property name="testWhileIdle" value="true"/>
        <!-- 程序 申請(qǐng) 連接時(shí),進(jìn)行連接有效性檢查(低效,影響性能) -->
        <property name="testOnBorrow" value="false"/>
        <!-- 程序 返還 連接時(shí),進(jìn)行連接有效性檢查(低效辰狡,影響性能) -->
        <property name="testOnReturn" value="false"/>
        <!-- 別名的方式配置擴(kuò)展插件. stat:監(jiān)控統(tǒng)計(jì) -->
        <property name="filters" value="stat"/>
    </bean>


    <bean id="ds-testdb-slave" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close" >
        <property name="name" value="ds-testdb-slave"/>
        <property name="driverClassName" value="${db.driver-class-name}"/>
        <property name="url" value="${db.testdb-slave.url}"/>
        <property name="username" value="${db.testdb-slave.username}"/>
        <property name="password" value="${db.testdb-slave.password}"/>

        <!-- 啟動(dòng)程序時(shí)锋叨,在連接池中初始化多少個(gè)連接 -->
        <property name="initialSize" value="10"/>
        <!-- 啟動(dòng)程序時(shí),在連接池中初始化多少個(gè)連接 -->
        <property name="minIdle" value="5"/>
        <!-- 連接池中最多支持多少個(gè)活動(dòng)會(huì)話 -->
        <property name="maxActive" value="300"/>
        <!-- 程序向連接池中請(qǐng)求連接時(shí),超過maxWait的值后宛篇,認(rèn)為本次請(qǐng)求失敗娃磺,即連接池沒有可用連接,單位毫秒叫倍,設(shè)置-1時(shí)表示無限等待 -->
        <property name="maxWait" value="60000"/>
        <property name="queryTimeout" value="600000"/>
        <property name="socketTimeout" value="600000"/>
        <!-- 檢查空閑連接的頻率偷卧,單位毫秒, 非正整數(shù)時(shí)表示不進(jìn)行檢查 -->
        <property name="timeBetweenEvictionRunsMillis" value="60000"/>
        <!-- 池中某個(gè)連接的空閑時(shí)長達(dá)到 N 毫秒后, 連接池在下次檢查空閑連接時(shí),將回收該連接,要小于防火墻超時(shí)設(shè)置 -->
        <property name="minEvictableIdleTimeMillis" value="300000"/>

        <property name="transactionQueryTimeout" value="600000"/>
        <!-- 用來檢測(cè)連接是否有效的sql -->
        <property name="validationQuery" value="SELECT 'x'"/>
        <!-- 空間時(shí)執(zhí)行 validationQuery -->
        <property name="testWhileIdle" value="true"/>
        <!-- 程序 申請(qǐng) 連接時(shí),進(jìn)行連接有效性檢查(低效吆倦,影響性能) -->
        <property name="testOnBorrow" value="false"/>
        <!-- 程序 返還 連接時(shí),進(jìn)行連接有效性檢查(低效听诸,影響性能) -->
        <property name="testOnReturn" value="false"/>
        <!-- 別名的方式配置擴(kuò)展插件. stat:監(jiān)控統(tǒng)計(jì) -->
        <property name="filters" value="stat"/>
    </bean>


    <!-- 讀寫分離 -->
    <master-slave:load-balance-algorithm id="randomStrategy" type="RANDOM" />

    <sharding:inline-strategy id="orderTableStrategy" sharding-column="account_no" algorithm-expression="product_order_$->{ account_no % 2 }" />

    <sharding:data-source id="testdb-shardingDataSource">
        <sharding:sharding-rule data-source-names="ds-testdb-master,ds-testdb-slave">
            <sharding:master-slave-rules>
                <sharding:master-slave-rule id="ds_testdb_ms" master-data-source-name="ds-testdb-master" slave-data-source-names="ds-testdb-slave" strategy-ref="randomStrategy" />
            </sharding:master-slave-rules>
            <sharding:table-rules>
                <sharding:table-rule logic-table="product_order" actual-data-nodes="ds_testdb_ms.product_order_$->{0..1}" table-strategy-ref="orderTableStrategy" />
            </sharding:table-rules>
        </sharding:sharding-rule>

        <sharding:props>
            <prop key="sql.show">true</prop>
        </sharding:props>
    </sharding:data-source>

    <!-- myBatis文件 -->
    <bean id="sqlSessionFactory-testdb" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="testdb-shardingDataSource"/>
        <!-- mapperXml路徑 -->
        <property name="mapperLocations" value="${db.mapperXmlLocation.test_db}"/>
        <property name="configLocation" value="classpath:mybatis-config.xml"/>
    </bean>

    <bean id="mapperScan-testdb" class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <!-- mapper路徑 -->
        <property name="basePackage" value="${db.mapperLocation.test_db}"/>
<!--        <property name="basePackage" value="com.example.jiudemo.mapper.testdb"/>-->
        <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory-testdb"/>
    </bean>

    <bean id="sqlSessionTemplate-zcjdb" class="org.mybatis.spring.SqlSessionTemplate">
        <constructor-arg ref="sqlSessionFactory-testdb"/>
    </bean>

    <!-- 事務(wù) -->
    <bean id="transactionManager-testdb" name="transactionManager-testdb" primary="false" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="testdb-shardingDataSource"/>
    </bean>

    <!-- 配置 Annotation 驅(qū)動(dòng),掃描@Transactional注解的類定義事務(wù)  -->
<!--    <tx:annotation-driven transaction-manager="transactionManager-testdb" proxy-target-class="true"/>-->

</beans>
  • 配置文件


    image.png
db:
  driver-class-name: com.mysql.cj.jdbc.Driver
  maxActive: 30
  zcjdb:
    url: jdbc:mysql://${instance.ip}:3306/zcjdb?useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&serverTimezone=GMT%2B8&useSSL=false
    username: root
    password: xxxxxx
  testdb-master:
    url: jdbc:mysql://${instance.ip}:3306/testdb_master?useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&serverTimezone=GMT%2B8&useSSL=false
    username: root
    password: xxxxxx
  testdb-slave:
    url: jdbc:mysql://${instance.ip}:3306/testdb_slave?useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&serverTimezone=GMT%2B8&useSSL=false
    username: root
    password: xxxxxx
  • 相關(guān)依賴
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.5.5</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.jiujiu</groupId>
    <artifactId>jiu-spring-boot-starter</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>jiu-spring-boot-starter</name>
    <description>Demo project for Spring Boot</description>
    <properties>
        <java.version>1.8</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <!-- 配置自動(dòng)提示 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-configuration-processor</artifactId>
            <optional>true</optional>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aop</artifactId>
            <version>5.3.8</version>
        </dependency>
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.9.5</version>
        </dependency>


        <!--數(shù)據(jù)庫連接-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>

        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.2.12</version>
        </dependency>

        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.1.0</version>
        </dependency>

        <!-- pagehelper 分頁插件 -->
        <dependency>
            <groupId>com.github.pagehelper</groupId>
            <artifactId>pagehelper-spring-boot-starter</artifactId>
            <version>1.3.0</version>
            <exclusions>
                <exclusion>
                    <artifactId>mybatis-spring-boot-starter</artifactId>
                    <groupId>org.mybatis.spring.boot</groupId>
                </exclusion>
            </exclusions>
        </dependency>

        <dependency>
            <groupId>org.apache.shardingsphere</groupId>
            <artifactId>sharding-jdbc-core</artifactId>
            <version>4.1.1</version>
        </dependency>

        <dependency>
            <groupId>org.apache.shardingsphere</groupId>
            <artifactId>sharding-jdbc-spring-namespace</artifactId>
            <version>4.1.1</version>
        </dependency>


        <!-- 工具包 -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.16</version>
        </dependency>

        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
            <version>3.7</version>
        </dependency>

        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-pool2</artifactId>
            <version>2.6.2</version>
        </dependency>

        <!--用于加密-->
        <dependency>
            <groupId>commons-codec</groupId>
            <artifactId>commons-codec</artifactId>
            <version>1.15</version>
        </dependency>

        <dependency>
            <groupId>com.google.guava</groupId>
            <artifactId>guava</artifactId>
            <version>17.0</version>
        </dependency>

        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.8.10</version>
        </dependency>

        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.69</version>
        </dependency>

    </dependencies>

</project>

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末蚕泽,一起剝皮案震驚了整個(gè)濱河市晌梨,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖仔蝌,帶你破解...
    沈念sama閱讀 218,451評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件泛领,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡敛惊,警方通過查閱死者的電腦和手機(jī)渊鞋,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,172評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來瞧挤,“玉大人篓像,你說我怎么就攤上這事∶笏牛” “怎么了员辩?”我有些...
    開封第一講書人閱讀 164,782評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長鸵鸥。 經(jīng)常有香客問我奠滑,道長,這世上最難降的妖魔是什么妒穴? 我笑而不...
    開封第一講書人閱讀 58,709評(píng)論 1 294
  • 正文 為了忘掉前任宋税,我火速辦了婚禮,結(jié)果婚禮上讼油,老公的妹妹穿的比我還像新娘杰赛。我一直安慰自己,他們只是感情好矮台,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,733評(píng)論 6 392
  • 文/花漫 我一把揭開白布乏屯。 她就那樣靜靜地躺著,像睡著了一般瘦赫。 火紅的嫁衣襯著肌膚如雪辰晕。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,578評(píng)論 1 305
  • 那天确虱,我揣著相機(jī)與錄音含友,去河邊找鬼。 笑死校辩,一個(gè)胖子當(dāng)著我的面吹牛窘问,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播宜咒,決...
    沈念sama閱讀 40,320評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼惠赫,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了荧呐?” 一聲冷哼從身側(cè)響起汉形,我...
    開封第一講書人閱讀 39,241評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤纸镊,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后概疆,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體逗威,經(jīng)...
    沈念sama閱讀 45,686評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,878評(píng)論 3 336
  • 正文 我和宋清朗相戀三年岔冀,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了凯旭。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,992評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡使套,死狀恐怖罐呼,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情侦高,我是刑警寧澤嫉柴,帶...
    沈念sama閱讀 35,715評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站奉呛,受9級(jí)特大地震影響计螺,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜瞧壮,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,336評(píng)論 3 330
  • 文/蒙蒙 一登馒、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧咆槽,春花似錦陈轿、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,912評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至小渊,卻和暖如春法褥,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背酬屉。 一陣腳步聲響...
    開封第一講書人閱讀 33,040評(píng)論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留揍愁,地道東北人呐萨。 一個(gè)月前我還...
    沈念sama閱讀 48,173評(píng)論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像莽囤,于是被迫代替她去往敵國和親谬擦。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,947評(píng)論 2 355

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