一、Spring Boot快速入門

本系列教程根據(jù)本人實際學習使用 SpringBoot2.x 過程總結整理而來点楼。

1扫尖、Spring Boot 簡介

Spring Boot 用來簡化 Spring 應用開發(fā),約定大于配置掠廓,刪繁就簡换怖,just run 就能創(chuàng)建一個獨立的、產品級的應用

  • 出現(xiàn)背景:

    J2EE(例如 Spring ) 笨重的開發(fā)蟀瞧、繁多的配置沉颂、低下的開發(fā)效率、負責的部署流程和第三方技術集成難度大黄橘。

  • 解決方案:

    “Spring 全家桶” 時代:

    Spring Boot → J2EE 一站式解決方案

    Spring Cloud → 分布式整體解決方案

  • 優(yōu)點:

    快速創(chuàng)建獨立運行的 Spring 項目以及與主流框架集成

    使用嵌入式的 Servlet 容器兆览,應用無需打成 war包

    starters 自動依賴于版本控制

    大量的自動配置,簡化開發(fā),也可以修改默認屬性值

    開箱即用馋辈,無需配置 xml硫戈,無代碼生成

    生產環(huán)境的運行時應用監(jiān)控

    與云計算天然集成

總結:

  • 簡化Spring應用開發(fā)的一個框架茶敏;
  • 整個Spring技術棧的一個大整合小压;
  • J2EE開發(fā)的一站式解決方案线梗;
1-20

2、微服務

  • 2014由martin fowler提出
  • 微服務:架構風格(服務微化)
  • 一個應用應該是一組小型服務怠益;可以通過HTTP的方式進行互通仪搔;
  • 單體應用:ALL IN ONE
  • 微服務:每一個功能元素最終都是一個可獨立替換和獨立升級的軟件單元;
  • 詳細參照微服務文檔

單體應用:

1-21

微服務:

1-22
1-23

3蜻牢、環(huán)境準備

開發(fā)環(huán)境:

  • jdk1.8:Spring Boot 推薦jdk1.7及以上烤咧;java version "1.8.0_221"
  • maven3.x:maven 3.3以上版本;apache-maven-3.6.1
  • IntelliJIDEA2019:IntelliJ IDEA 2019.1.3 x64
  • SpringBoot 2.2.1.RELEASE:2.2.1抢呆;

開發(fā)配置:

1煮嫌、MAVEN設置:

給 maven 的 settings.xml 配置文件的 profiles 標簽添加下面的配置,設置 maven 的創(chuàng)建項目時的默認編譯版本使用 jdk8

<profile>
<id>jdk-1.8</id>
<activation>
<activeByDefault>true</activeByDefault>
<jdk>1.8</jdk>
</activation>
<properties>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<maven.compiler.compilerVersion>1.8</maven.compiler.compilerVersion>
</properties>
</profile>

2抱虐、IDEA設置:

Idea 整合 Maven:

1-1
1-2

4昌阿、創(chuàng)建 Spring Boot HelloWorld

1、快速開始

首先我們先創(chuàng)建一個統(tǒng)一的 maven 工程恳邀,用來管理我們之后學習中所有的項目:

1懦冰、新建項目

1-3

2、選擇Maven項目
1-4

3谣沸、填寫GroupId刷钢、ArtifactId

GroupId:com.demo.springboot

ArtifactId:SpringBoot-In-Action

1-5

5、填寫項目名和項目路徑
1-6

6鳄抒、創(chuàng)建一個空的maven項目完成闯捎,選擇允許自動導入
1-7

7、刪除多余的目錄

只保留一個pom.xml文件即可许溅,同時在pom文件中添加springboot依賴和打包類型

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.2.1.RELEASE</version>
</parent>
<packaging>pom</packaging>
1-8

2瓤鼻、現(xiàn)在開始我們的 Spring Boot HelloWorld 項目:

一個功能:瀏覽器發(fā)送hello請求,服務器接受請求并處理贤重,響應Hello World字符串茬祷;

1、創(chuàng)建一個maven工程并蝗;(jar)

在SpringBoot-In-Action項目中新建一個module,選擇maven工程祭犯,命名為 spring-boot-01-helloworld

1-9

2、導入spring boot相關的依賴

因為springboot的依賴已經在父pom中導入

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.2.1.RELEASE</version>
</parent>

所以在當前的pom中只需要導入spring-boot-starter-web的依賴即可:

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
</dependencies>

完整 pom 文件如下:

<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>SpringBoot-In-Action</artifactId>
        <groupId>com.demo.springboot</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>spring-boot-01-helloworld</artifactId>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
    </dependencies>

</project>

3滚停、編寫一個主程序沃粗;啟動Spring Boot應用

1-10
/**
 * @SpringBootApplication 來標注一個主程序類,說明這是一個Spring Boot應用
 */
@SpringBootApplication
public class HelloWorldMainApplication {
    public static void main(String[] args) {
        // Spring應用啟動起來
        SpringApplication.run(HelloWorldMainApplication.class, args);
    }
}

4键畴、編寫相關的Controller最盅、Service

為了演示突雪,我在這里只創(chuàng)建了 Controller 類,省略了 Service

@Controller
public class HelloController {

    @ResponseBody
    @RequestMapping("/hello")
    public String hello() {
        return "Hello World!";
    }
}

5涡贱、運行主程序測試效果

選中 HelloWorldMainApplication 右鍵單擊選擇 Run ... 咏删,或者打開 HelloWorldMainApplication 按下快捷鍵 Ctrl+Shift+F10 運行程序,可以看到項目在 8080 端口啟動:

1-11

在瀏覽器中訪問 http://localhost:8080/hello 可以看到正常返回了 Hello World 问词。

1-12

至此督函,我們的第一個 Spring Boot 項目算是創(chuàng)建完了。

6激挪、補充:簡化部署

在當前項目辰狡,即 spring-boot-01-helloworldpom 文件中添加下面的配置

<!-- 這個插件,可以將應用打包成一個可執(zhí)行的jar包垄分;-->
<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
        </plugin>
    </plugins>
</build>

然后選中當前 pom 文件搓译,右鍵單擊,選擇 Run Mavenpackage 锋喜,將這個應用打成 jar 包,可以看到 target 文件夾下生成一個名為 spring-boot-01-helloworld-1.0-SNAPSHOT.jarjar 文件豌鸡,我們可以直接在命令行使用 java -jar xxx.jar 命令進行執(zhí)行嘿般,啟動后在瀏覽器中訪問 http://localhost:8080/hello 可以看到正常返回了 Hello World 。若要結束程序涯冠,關閉命令行窗口即可炉奴。

1-13

思考:為什么我們打包后的程序可以直接在命令行使用 java jar 命令就可以部署?

帶著疑問我們來分析一下 spring-boot-01-helloworld-1.0-SNAPSHOT.jar 蛇更,我們使用壓縮文件打開 spring-boot-01-helloworld-1.0-SNAPSHOT.jar瞻赶,可以看到如下所示的目錄結構:

1-14

我們打開 BOOT-INF 文件夾看到有 classeslib 兩個文件夾,我們寫的代碼的二進制字節(jié)碼就在 classes 目錄下派任,而 lib 下可以看到是我們項目依賴的所有 jar 包砸逊,最關鍵的,我們的項目是一個 web 項目掌逛,可以看到所依賴的內嵌的 tomcat jar包师逸,這是我們項目能獨立部署的關鍵:

1-15

其他目錄 META-INF 存放項目的 pom 文件,org 目錄下存放的是 springframework 相關代碼豆混。

5篓像、Hello World 探究

1、POM文件

1皿伺、父項目

依賴路徑入下圖所示:

1-16

spring-boot-01-helloworld 的 pom:

<parent>
    <artifactId>SpringBoot-In-Action</artifactId>
    <groupId>com.demo.springboot</groupId>
    <version>1.0-SNAPSHOT</version>
</parent>

它的父項目是 SpringBoot-In-Action 中的 pom:

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.2.1.RELEASE</version>
</parent>

<packaging>pom</packaging>

<groupId>com.demo.springboot</groupId>
<artifactId>SpringBoot-In-Action</artifactId>
<version>1.0-SNAPSHOT</version>

<modules>
    <module>spring-boot-01-helloworld</module>
</modules>

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.2.1.RELEASE</version>
</parent>

的父 pom 是 spring-boot-starter-parent-2.2.1.RELEASE.pom:

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-dependencies</artifactId>
    <version>2.2.1.RELEASE</version>
    <relativePath>../../spring-boot-dependencies</relativePath>
</parent>
<artifactId>spring-boot-starter-parent</artifactId>

而它的父 pom 是 spring-boot-dependencies-2.2.1.RELEASE.pom:

<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>2.2.1.RELEASE</version>
<packaging>pom</packaging>

在這個pom里邊可以看到员辩,它是用來真正管理Spring Boot應用里面的所有依賴版本,定義了每一個依賴的版本鸵鸥;
1-17

spring-boot-dependencies-2.x.RELEASE.pom 可以成稱為 Spring Boot的版本仲裁中心奠滑;

以后我們導入其他依賴默認是不需要寫版本;(當然沒有在dependencies里面管理的依賴自然需要聲明版本號)

2、導入的其他依賴

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

spring-boot-starter-web :我們可以將其拆分為 spring-boot-starterweb 兩部分

  • spring-boot-starter:spring-boot 場景啟動器养叛;spring-boot-starter-web 幫我們導入了 web 模塊正常運行所依賴的組件种呐。

我們按下 Ctrl 點擊 spring-boot-starter-web 進入 spring-boot-starter-web-2.2.1.RELEASE.pom,可以看到它導入了很多 web 模塊正常運行需要的相關依賴:

1-18

Spring Boot 為我們提供了簡化企業(yè)級開發(fā)的絕大多數(shù)場景的 starter pom(啟動器)弃甥,只要引入了相應場景的 starter pom 爽室,相關技術的絕大部分配置將會消除(即自動配置),從而簡化我們的開發(fā)淆攻。很多業(yè)務場景中我們就會使用到 Spring Boot 為我們自動配置的 bean阔墩,同時 Spring Boot 對這些場景依賴的 jar 也做了嚴格的測試與版本控制,我們可以不必擔心 jar 版本的適配問題瓶珊。

在 Spring Boot 中還有很多這樣的啟動器啸箫,我們打開官方文檔可以看到關于啟動器的描述:

1-19

Spring Boot 將所有的功能場景都抽取出來,做成一個個的 starters(啟動器)伞芹,只需要在項目里面引入這些starter 相關場景的所有依賴都會導入進來忘苛。要用什么功能就導入什么場景的啟動器。而我們一般的開發(fā)也是圍繞著這些 starter 來展開唱较。

2扎唾、主程序類(主入口類)

/**
 *  @SpringBootApplication 來標注一個主程序類,說明這是一個Spring Boot應用南缓,沒有這個注解項目無法啟動
 */
@SpringBootApplication
public class HelloWorldMainApplication {

    public static void main(String[] args) {

        // Spring應用啟動起來
        SpringApplication.run(HelloWorldMainApplication.class, args);
    }
}

1胸遇、@SpringBootApplication

@SpringBootApplication: Spring Boot應用標注在某個類上說明這個類是SpringBoot的主配置類,SpringBoot 就運行這個類的 main 方法來啟動 SpringBoot 應用汉形;

進入 @SpringBootApplication 注解內部纸镊,可以看到它實際上是一個復合注解:

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(
    excludeFilters = {@Filter(
    type = FilterType.CUSTOM,
    classes = {TypeExcludeFilter.class}
), @Filter(
    type = FilterType.CUSTOM,
    classes = {AutoConfigurationExcludeFilter.class}
)}
)
public @interface SpringBootApplication {

2、@SpringBootConfiguration

@SpringBootConfiguration:Spring Boot 的配置類概疆;

作用:標注在某個類上逗威,表示這是一個Spring Boot 的配置類;

進入 @SpringBootConfiguration 內部可以看到届案,它被 Spring 的 @Configuration 注解所注解:

@Configuration
public @interface SpringBootConfiguration {

@Configuration:配置類上來標注這個注解庵楷;配置類 === 配置文件;

進入 @Configuration 內部可以看到楣颠,它被 Spring 的 @Component 注解所注解尽纽;配置類其實也是容器中的一個組件。

@Component
public @interface Configuration {

3童漩、@EnableAutoConfiguration

@EnableAutoConfiguration:開啟自動配置功能

以前在 Spring 中我們需要配置的東西弄贿,現(xiàn)在 Spring Boot 幫我們自動配置;@EnableAutoConfiguration告訴SpringBoot 開啟自動配置功能矫膨,這樣自動配置才能生效差凹;

進入 @EnableAutoConfiguration 內部可以看到下面的代碼:

@AutoConfigurationPackage
@Import({AutoConfigurationImportSelector.class})
public @interface EnableAutoConfiguration {

@AutoConfigurationPackage:自動配置包期奔,將主配置類(@SpringBootApplication 標注的類)的所在包及下面所有子包里面的所有組件掃描到 Spring 容器

進入 @Configuration 內部可以看到它被 @Import 注解所注解。Spring 的底層注解 @Import危尿,給容器中導入一個組件呐萌;導入的組件由 Registrar.class 指定;

@Import({Registrar.class})
public @interface AutoConfigurationPackage {

進入 Registrar 靜態(tài)內部類可以看到如下代碼:

static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports {
    Registrar() {
    }
    // 注冊一些 Bean 定義信息谊娇,進行組件的導入工作肺孤;metadata:注解的元信息
    public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
        AutoConfigurationPackages.register(registry, (new AutoConfigurationPackages.PackageImport(metadata)).getPackageName());
    }

    public Set<Object> determineImports(AnnotationMetadata metadata) {
        return Collections.singleton(new AutoConfigurationPackages.PackageImport(metadata));
    }
}

我們在代碼中打上斷點來看一下:

1-24

@Import({AutoConfigurationImportSelector.class}):給容器中導入組件xxx

AutoConfigurationImportSelector:導入哪些組件的選擇器;

我們進入 AutoConfigurationImportSelector 中可以看到如下代碼:

// 將所有需要導入的組件以全類名的方式返回济欢;這些組件就會被添加到容器中
protected AutoConfigurationImportSelector.AutoConfigurationEntry getAutoConfigurationEntry(AutoConfigurationMetadata autoConfigurationMetadata, AnnotationMetadata annotationMetadata) {
    if (!this.isEnabled(annotationMetadata)) {
        return EMPTY_ENTRY;
    } else {
        AnnotationAttributes attributes = this.getAttributes(annotationMetadata);
        List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes);
        configurations = this.removeDuplicates(configurations);
        Set<String> exclusions = this.getExclusions(annotationMetadata, attributes);
        this.checkExcludedClasses(configurations, exclusions);
        configurations.removeAll(exclusions);
        configurations = this.filter(configurations, autoConfigurationMetadata);
        this.fireAutoConfigurationImportEvents(configurations, exclusions);
        return new AutoConfigurationImportSelector.AutoConfigurationEntry(configurations, exclusions);
    }
}

將所有需要導入的組件以全類名的方式返回赠堵;這些組件就會被添加到容器中。即AutoConfigurationImportSelector會給容器中導入非常多的自動配置類(xxxAutoConfiguration)法褥;就是給容器中導入這個場景需要的所有組件茫叭,并配置好這些組件。

我們在代碼中打斷點可以看到如下的結果:

自動配置類

有了自動配置類半等,就免去了我們手動編寫配置注入功能組件等的工作揍愁。

進入上面代碼中的 getCandidateConfigurations 方法,可以看到如下代碼:

// 獲取候選配置
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
    List<String> configurations = SpringFactoriesLoader.loadFactoryNames(this.getSpringFactoriesLoaderFactoryClass(), this.getBeanClassLoader());
    Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories. If you are using a custom packaging, make sure that file is correct.");
    return configurations;
}

上面代碼中調用了 SpringFactoriesLoader.loadFactoryNames(EnableAutoConfiguration.class, ClassLoader)方法杀饵,我們在這個進入這個方法可以看下面的代碼:

public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {
    // 獲取工廠名
    String factoryTypeName = factoryType.getName();
    return (List)loadSpringFactories(classLoader).getOrDefault(factoryTypeName, Collections.emptyList());
}

private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
    MultiValueMap<String, String> result = (MultiValueMap)cache.get(classLoader);
    if (result != null) {
        return result;
    } else {
        try {
            // 用類加載器從類路徑 "META-INF/spring.factories" 中獲取資源
            Enumeration<URL> urls = classLoader != null ? classLoader.getResources("META-INF/spring.factories") : ClassLoader.getSystemResources("META-INF/spring.factories");
            LinkedMultiValueMap result = new LinkedMultiValueMap();

            while(urls.hasMoreElements()) {
                URL url = (URL)urls.nextElement();
                UrlResource resource = new UrlResource(url);
                // 從獲取的資源中拿出 properties 配置文件吗垮,把獲取的資源當作 properties 配置文件
                Properties properties = PropertiesLoaderUtils.loadProperties(resource);
                Iterator var6 = properties.entrySet().iterator();

                while(var6.hasNext()) {
                    Entry<?, ?> entry = (Entry)var6.next();
                    // 從 properties 文件中拿到 factoryTypeName
                    String factoryTypeName = ((String)entry.getKey()).trim();
                    String[] var9 = StringUtils.commaDelimitedListToStringArray((String)entry.getValue());
                    int var10 = var9.length;

                    for(int var11 = 0; var11 < var10; ++var11) {
                        String factoryImplementationName = var9[var11];
                        result.add(factoryTypeName, factoryImplementationName.trim());
                    }
                }
            }

            cache.put(classLoader, result);
            return result;
        } catch (IOException var13) {
            throw new IllegalArgumentException("Unable to load factories from location [META-INF/spring.factories]", var13);
        }
    }
}

所以根據(jù)上面的分析我的得知:Spring Boot 在啟動的時候從類路徑下的 META-INF/spring.factories 中獲取 EnableAutoConfiguration 指定的值,將這些值作為自動配置類導入到容器中凹髓,自動配置類就生效,幫我們進行自動配置工作怯屉。以前我們在 Spring 中需要自己配置的東西蔚舀,在 Spring Boot 中自動配置類都幫我們配了。

自動配置類

綜上锨络,J2EE 的整體整合解決方案和自動配置都在 spring-boot-autoconfigure-2.2.1.RELEASE.jar (spring-boot-autoconfigure-x.x.x.RELEASE.jar )中:

自動配置解決方案

6赌躺、使用 Spring Initializer 快速創(chuàng)建 Spring Boot項目

1、IDEA:使用 Spring Initializer快速創(chuàng)建項目

所有的 IDE 都支持使用 Spring 的項目創(chuàng)建向導快速創(chuàng)建一個 Spring Boot 項目羡儿,下面我們來看一下如何在 idea 中快速創(chuàng)建一個 Spring Boot 項目礼患。

1、選擇FileNewProject 或是在一個已經存在的工程中選中工程名然后 NewModule

1-28

2掠归、填寫基本信息 GroupID缅叠、ArtifactID

1-29

3、選擇我們需要依賴的模塊

1-30

4虏冻、點擊 Finish肤粱,接下來向導會聯(lián)網創(chuàng)建 Spring Boot 項目

1-31

查看默認生成的 Spring Boot 項目,我們可以看到:

  • 主程序已經生成好了厨相,我們只需要寫我們自己的邏輯
  • resources 文件夾中目錄結構:
    • static:保存所有的靜態(tài)資源: js领曼、css鸥鹉、 images等;
    • templates:保存所有的模板頁面(Spring Boot 默認 jar 包使用嵌入式的 Tomcat庶骄,默認不支持 JSP 頁面)毁渗,可以使用模板引擎(freemarkerthymeleaf等)单刁;
    • application.properties:Spring Boot 應用的配置文件灸异;可以修改一些默認設置,比如端口等

我們在 com.demo.spring.controller 包下新見一個 HelloController 來測試一下我們新建的項目

1-32

HelloController 代碼如下:

//這個類的所有方法返回的數(shù)據(jù)直接寫給瀏覽器幻碱,(如果是對象轉為json數(shù)據(jù))
//@ResponseBody
//@Controller
//  上面兩行一般多用在 Spring 項目中
@RestController // 在 Spring Boot 和 Spring4.2.x 之后使用這個來簡化開發(fā)绎狭,返回 RESTAPI 規(guī)范的接口
public class HelloController {
    @RequestMapping("/hello")
    public String hello(){
        return "hello world quick!";
    }
}

在瀏覽器中訪問 http://localhost:8080/hello 可以得到下面的返回效果:

1-33

2、通過瀏覽器訪問https://start.spring.io/快速創(chuàng)建項目

1-34

執(zhí)行完上面的操作后褥傍,瀏覽器會自動下載一個創(chuàng)建好的項目儡嘶,我們使用idea打開即可。

以上恍风,就是我們 Spring Boot 快速入門的全部內容蹦狂,更多詳細內容請查看源代碼了解。

源代碼:

SpringBoot-In-Action

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末朋贬,一起剝皮案震驚了整個濱河市凯楔,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌锦募,老刑警劉巖摆屯,帶你破解...
    沈念sama閱讀 206,839評論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異糠亩,居然都是意外死亡虐骑,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,543評論 2 382
  • 文/潘曉璐 我一進店門赎线,熙熙樓的掌柜王于貴愁眉苦臉地迎上來廷没,“玉大人,你說我怎么就攤上這事垂寥〉呃瑁” “怎么了?”我有些...
    開封第一講書人閱讀 153,116評論 0 344
  • 文/不壞的土叔 我叫張陵滞项,是天一觀的道長狭归。 經常有香客問我,道長文判,這世上最難降的妖魔是什么唉铜? 我笑而不...
    開封第一講書人閱讀 55,371評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮律杠,結果婚禮上潭流,老公的妹妹穿的比我還像新娘竞惋。我一直安慰自己,他們只是感情好灰嫉,可當我...
    茶點故事閱讀 64,384評論 5 374
  • 文/花漫 我一把揭開白布拆宛。 她就那樣靜靜地躺著,像睡著了一般讼撒。 火紅的嫁衣襯著肌膚如雪浑厚。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,111評論 1 285
  • 那天根盒,我揣著相機與錄音钳幅,去河邊找鬼。 笑死炎滞,一個胖子當著我的面吹牛敢艰,可吹牛的內容都是我干的。 我是一名探鬼主播册赛,決...
    沈念sama閱讀 38,416評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼钠导,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了森瘪?” 一聲冷哼從身側響起牡属,我...
    開封第一講書人閱讀 37,053評論 0 259
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎扼睬,沒想到半個月后逮栅,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經...
    沈念sama閱讀 43,558評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡窗宇,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 36,007評論 2 325
  • 正文 我和宋清朗相戀三年证芭,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片担映。...
    茶點故事閱讀 38,117評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖叫潦,靈堂內的尸體忽然破棺而出蝇完,到底是詐尸還是另有隱情,我是刑警寧澤矗蕊,帶...
    沈念sama閱讀 33,756評論 4 324
  • 正文 年R本政府宣布短蜕,位于F島的核電站,受9級特大地震影響傻咖,放射性物質發(fā)生泄漏朋魔。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,324評論 3 307
  • 文/蒙蒙 一卿操、第九天 我趴在偏房一處隱蔽的房頂上張望警检。 院中可真熱鬧孙援,春花似錦、人聲如沸扇雕。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,315評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽镶奉。三九已至础淤,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間哨苛,已是汗流浹背鸽凶。 一陣腳步聲響...
    開封第一講書人閱讀 31,539評論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留建峭,地道東北人玻侥。 一個月前我還...
    沈念sama閱讀 45,578評論 2 355
  • 正文 我出身青樓,卻偏偏與公主長得像迹缀,于是被迫代替她去往敵國和親使碾。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 42,877評論 2 345

推薦閱讀更多精彩內容