05-Gradle

Gradle官网:百度搜索“Gradle官网”,可以看到Gradle的基础知识和特性。

一、Gradle是什么

Gradle 是一个用于管理并自动化构建流程的构建工具。(自动化构建工具)

它会帮你下载项目所需的依赖、 将你的项目代码打包并准备编译。

二、Gradle的发行

Gradle安装:

1.下载Gradle:访问Gradle官方网站(https://gradle.org/releases/)并下载最新版本的Gradle。您可以选择二进制分发版(适用于大多数平台)或源码分发版(如果您想查看或修改源代码)。

2.解压

3.配置环境变量:

export GRADLE_HOME=/Users/liangyaru/Downloads/AS_Workspace/gradle/gradle-8.10

export PATH={PATH}:{GRADLE_HOME}/bin

判断Gradle是否安装:在终端中运行 gradle -v 来检查 Gradle 是否已安装

Gradle 支持将 KotlinGroovy 作为主要的构建语言。Gradle 附带了自己的 Kotlin 和 Groovy 库,因此不需要安装它们。

Wrapper 是一个脚本,用于调用声明的 Gradle 版本,是执行 Gradle 构建的推荐方法。它位于项目根目录中,作为 gradlewgradlew.bat 文件

Gradle版本更新:缓存的大小和缓存加载时间进行更新(性能方面)

Gradle 构建,可以看到项目结构、依赖项(常规和项目间依赖项)、正在使用的插件以及构建的控制台输出

Gradle可以:调用任务/添加依赖项

Maven 配置文件在配置 build 中的作用以及 Gradle 中的替代方法

断点调试gradle文件:

Add configuration——Remote——Remote Debug Gradle

查看Gradle配置:View --> Tool Windows --> Gradle,然后点击刷新图标

Gradle 在 Java 虚拟机 (JVM) 上运行

Android studio 如何使用和配置 Gradle?去官网查看

gradlewgradlew.bat :用于调用声明的Gradle版本

三、运行Gradle构建

概念:

插件基础:

核心插件:

为构建 Java 项目提供支持

添加对编译和测试 Groovy 源文件的支持

添加了对为企业应用程序构建 EAR 文件的支持

教程:

1.初始化项目:

.gradle:项目缓存目录

gradlew:macOS 和 Linux 脚本,用于使用 Gradle Wrapper 执行构建。

gradlew.bat:用于使用 Gradle Wrapper 执行构建的 Windows 脚本。

settings.gradle.kts:用于定义子项目列表的项目设置文件

Gradle Wrapper:启动 Gradle 构建

构建文件:

kotlin中定义一个块:

val result = run { val a = 10 val b = 20 a + b } println(result) // 输出:30

2.运行任务:

列出项目中的所有可用任务:./gradlew tasks

任务用途:负责编译、复制和移动文件、创建 JAR 文件、生成 Javadoc、将工件发布到存储库或许多其他离散的工作单元。

Gradle 提供了许多内置任务,开发人员可以使用这些任务来增强构建脚本。

此示例任务使用 Copy 内置任务将 *.war 文件从目录复制到目标目录。

tasks.register<Copy>("copyTask") {

from("source")

into("target")

include("*.war")

}

Copy - 可用于复制文件。

Delete - 可用于删除文件和目录。

Exec - 可用于执行任意 O/S 命令。

Zip - 可用于捆绑文件。

3.了解依赖关系:

Gradle版本目录:gradle/libs.versions.toml

引用版本目录中定义的库,请执行以下操作:

dependencies { implementation(libs.guava) testImplementation(libs.junit.jupiter) }

依赖项管理:

repositories { // Use Maven Central for resolving dependencies. mavenCentral() } dependencies { // Use JUnit Jupiter for testing. testImplementation(libs.junit.jupiter) testRuntimeOnly("org.junit.platform:junit-platform-launcher") // This dependency is used by the application. implementation(libs.guava) }

mavenCentral:依赖项的来源

dependencies:声明依赖项

查看项目依赖项:./gradlew :app:dependencies

传递依赖项:


00.jpg

com.google.code.findbugs:jsr305:3.0.2 传递依赖项来自 com.google.guava:guava:32.1.2-jre 依赖项。

运行Java应用程序:./gradlew run

4.应用Gradle插件

插件是在项目中组织构建逻辑和重用构建逻辑的主要方法。

插件还用于将自定义任务作为打包代码分发。

将插件应用于项目将执行可创建任务、配置属性以及以其他方式扩展项目功能的代码。通常,插件使用 Gradle API 来提供额外的功能并扩展 Gradle 的核心功能。

插件可以:

将任务添加到项目中(例如编译、测试)。

扩展基本的 Gradle 模型(例如,添加可配置的新 DSL 元素)。

根据约定配置项目(例如,添加新任务或配置合理的默认值)。

应用特定配置(例如,添加组织存储库或强制实施标准)。

通过扩展向现有类型添加新属性和方法。

项目目前应用了一个插件,即与 Gradle 捆绑在一起的 Application Plugin:(Groovy)

plugins { // Apply the application plugin to add support for building a CLI application in Java. id 'application' }

有一个插件由 Gradle 维护和分发,称为 Maven Publish Plugin。Maven 发布插件提供了将构建构件发布到 Apache Maven 存储库的功能。它还可以发布到 Maven local,这是位于您计算机上的存储库,位置存放在用户名/.m2下。

通过将 maven-publish 添加到 build.gradle(.kts) 中的 plugins 块来应用插件:

plugins { // Apply the application plugin to add support for building a CLI application in Java. id 'application' id 'maven-publish' }

Maven Publish 插件中的新任务现在可在 IntelliJ 的 Gradle 右侧窗格中使用。

05.jpg

配置插件:将发布信息添加到您的 build.gradle(.kts) 文件中:(Groovy)

publishing { publications { create("maven", MavenPublication) { groupId = "com.gradle.tutorial" artifactId = "tutorial" version = "1.0" from(components["java"]) } } }

Gradle构建:先配置插件再应用插件。

在Gradle构建过程中,应用好插件后还需要进行配置的原因在于,插件本身并不能直接实现所有功能

使用插件:通过运行 publishToMavenLocal 任务来运行 ./gradlew :app:publishToMavenLocal

5.探索增量构建

Gradle 会以多种方式优化您的 build。其中一种优化称为 增量构建。

增量构建是一种构建,它避免运行自上一个构建以来输入未更改的任务,从而无需执行此类任务。

要使增量构建正常工作,任务必须定义其输入和输出。在构建时,Gradle 将确定输入或输出是否已更改。如果它们已更改,Gradle 将执行该任务。否则,它将跳过执行。

查看增量构建的实际效果,我们将控制台输出切换到 verbose。

gradle.properties增加这行代码: org.gradle.console=verbose

6.启用build缓存

gradle.properties添加:

org.gradle.console=verbose

org.gradle.caching=true

FROM-CACHE - 已从本地构建缓存中获取任务。

UP-TO-DATE - 使用增量生成且未重新运行的任务。

四、编写Gradle构建

基础学习:

1.Gradle目录

Gradle 使用两个主要目录来执行和管理其工作:Gradle User Home 目录Project Root 目录

Gradle User Home 目录,即用户主目录:默认情况下,Gradle 用户主目录下(~/.gradleC:\Users\<USERNAME>\.gradle)存储全局配置属性、初始化脚本、缓存和日志文件。

结构大致如下:

01.jpg

1>全局缓存目录(用于非特定于项目的所有内容)。

2>特定于版本的缓存(例如,为了支持增量构建)。

3>共享缓存(例如,用于依赖项的工件)。

4>守护程序的注册表和日志。

5>全局初始化脚本

6>工具链支持下载的 JDK。

7>由 Gradle Wrapper 下载的发行版。

8>Global Gradle 配置属性

项目根目录:包含项目中的所有源文件。

还包含 Gradle 生成的文件和目录,例如 .gradlebuild

02.jpg

1>由 Gradle 生成的特定于项目的缓存目录。

2>特定于版本的缓存(例如,为了支持增量构建)。

3>此项目的 build 目录,Gradle 会将所有 build 工件生成到该目录。

4>包含 Gradle 包装器的 JAR 文件和配置。

5>特定于项目的 Gradle 配置属性

6>用于使用 Gradle Wrapper 执行构建的脚本。

7>用于定义子项目列表的项目设置文件

8>通常,一个项目被组织成一个或多个子项目。

9>每个子项目都有自己的 Gradle 构建脚本。

2.多项目构建

多项目构建由一个根项目和一个或多个子项目组成。

识别项目结构:gradle -q projects

在相对于具有该任务的当前工作目录的任何子项目中执行测试任务:gradle test

如果您从根项目目录运行该命令,您将在子模块 中运行 test

执行特定子项目中的特定:gradle :services:webservice:build

3.Gradle构建生命周期

1>初始化

Gradle 首先评估设置文件 settings.gradle(.kts),然后实例化 Settings 对象。然后,Gradle 会实例化每个项目的 Project 实例。

2>配置

评估参与生成的每个项目的生成脚本 build.gradle(.kts)。

为请求的任务创建任务图。

在配置阶段,Gradle 会将任务和其他属性添加到初始化阶段找到的项目中。

3>执行

计划并执行所选任务。

任务之间的依赖关系决定了执行顺序。

任务的执行可以并行进行。

Gradle 使用配置阶段生成的任务执行图来确定要执行的任务。

4.编写配置文件:(用的是 Gradle API)

设置文件是每个 Gradle 构建的入口点。

找到设置文件 settings.gradle(.kts) 后,Gradle 会实例化一个 Settings 对象。

Settings 对象的用途之一是允许声明 要包含在构建中 的所有项目。

设置脚本可以是 Groovy 中的 settings.gradle 文件,也可以是 Kotlin 中的 settings.gradle.kts 文件。

在 Gradle 组装项目以进行构建之前,它会创建一个 Settings 实例并针对它执行设置文件。

03.jpg

当设置脚本执行时,它会配置此 Settings。因此,设置文件定义 Settings 对象。

Settings 实例和 settings.gradle(.kts) 文件之间存在一一对应的关系。

我们可以使用 Settings.rootProject 属性在设置脚本中设置根项目名称:

settings.rootProject.name = "root"

通常缩写为:rootProject.name = "root"

include() :将给定的项目添加到构建中。

设置 脚本 结构:

设置脚本是对 Gradle API 的一系列方法调用,通常使用 { ... },这是 Groovy 和 Kotlin 语言中的特殊快捷方式。{ } 块在 Kotlin 中称为 lambda,在 Groovy 中称为闭

简单地说,plugins{ } 块是一种方法调用,其中 Kotlin lambda 对象或 Groovy 闭包对象作为参数传递。它是以下各项的简称:方法调用 id(“plugin”) 对象的 this 类型为 PluginDependenciesSpec

plugins(function() { id("plugin") })

具体的配置文件可以看官网。重点看。

注意:include("app") 实际上是:settings.include("app")

5.编写构建脚本:

生成脚本用于配置项目,并与 Project 类型的对象相关联。

04.jpg

在执行生成脚本时,它会配置 Project

Project 对象是 Gradle API 的一部分。

添加依赖项:

dependencies { implementation("com.google.guava:guava:32.1.1-jre") }

使用 Project.getDependencies() 方法返回的 DependencyHandler 来管理依赖项。

使用 Project.getRepositories() 方法返回的 RepositoryHandler 来管理存储库。

设置属性:

application { mainClass = "com.example.Main" }

Project 对象具有关联的 ExtensionContainer 对象,该对象包含已应用于项目的插件的所有设置和属性。

在示例中,应用程序插件添加了一个 application 属性,该属性用于详细说明 Java 应用程序的主类

注册和配置任务:

在项目中注册任务:

tasks.register("zip-reports") { from 'Reports/' include '*' archiveName 'Reports.zip' destinationDir(file('/dir')) }

使用以下 TaskCollection.named(java.lang.String) 方法找到任务以对其进行配置:

tasks.named("test") { useJUnitPlatform() }

Javadoc 任务配置为从 Java 代码自动生成 HTML 文档:

tasks.named("javadoc").configure { exclude 'app/Internal.java' exclude 'app/internal/' exclude 'app/internal/*' }

生成脚本由零个或多个语句和脚本块组成:

println(project.layout.projectDirectory);

语句可以包括方法调用、属性赋值和局部变量定义:

version = '1.0.0.GA'

脚本块是一种方法调用,它以 closure/lambda 作为参数:

configurations { }

closure/lambda 在执行时配置一些委托对象:

repositories { google() }

Extra Properties 额外属性

Gradle 的增强对象(包括项目、任务和源代码集)可以保存用户定义的属性。

通过拥有对象的 ext 属性添加、读取和设置额外的属性。或者,您可以使用 ext 块同时添加多个属性。

ext { springVersion = "3.1.0.RELEASE" emailNotification = "build@master.org" } sourceSets.all { ext.purpose = null }

sourceSets { main { purpose = "production" } test { purpose = "test" } plugin { purpose = "production" } }

具体看官网。

6.使用任务

Gradle 可以在项目中执行的工作由一个或多个任务定义。

任务表示生成执行的某个独立工作单元。可以是编译一些类、创建 JAR、生成 Javadoc 或将一些存档发布到存储库。

当用户在命令行中运行 ./gradlew build 时,Gradle 将执行构建任务以及它所依赖的任何其他任务。

注册任务后,可以通过 TaskProvider API 访问任务以进行进一步配置。

比如:运行时动态地向任务添加依赖项。

或者:向现有任务添加行为

7.编写任务:

Gradle 任务是通过扩展 DefaultTask 创建的。eg:

abstract class HelloTask : DefaultTask() { @TaskAction fun hello() { println("hello from HelloTask") } } // Register the hello Task with type HelloTask tasks.register("hello") { group = "Custom tasks" description = "A lovely greeting task." }

但是,泛型 DefaultTask 没有为 Gradle 提供任何操作。如果用户想要扩展 Gradle 及其构建脚本的功能,则必须使用内置任务或创建自定义任务:

内置任务 - Gradle 提供内置实用程序任务,例如 CopyJarZipDelete 等。

自定义任务 - Gradle 允许用户将 DefaultTask 子类化以创建自己的任务类型。

可以选择使用 TaskCollection.named() 方法在构建脚本中配置任务。

tasks.named("createFileTask") { fileText.set("HELLO FROM THE NAMED METHOD") // Override with custom message }

8.使用插件

Gradle 的大部分功能都是通过插件提供的,包括随 Gradle 分发的核心插件、第三方插件以及构建中定义的脚本插件。

插件引入了新任务(例如 JavaCompile)、域对象(例如 SourceSet)、约定(例如,将 Java 源代码定位在 src/main/java)以及扩展核心或其他插件对象。

插件有三种方式可用:

核心插件 - Gradle 开发并维护一组核心插件

社区插件 - 在远程存储库(如 Maven 或 Gradle 插件门户)中共享的 Gradle 插件。

本地插件 - Gradle 使用户能够使用 API 创建自定义插件。

要使用封装在插件中的构建逻辑,Gradle 需要执行两个步骤。首先,它需要解析插件,然后需要将插件应用于目标,通常是 Project,在项目上执行插件的Plugin.apply(T)

Gradle 在其分发过程中提供了核心插件(例如 JavaPluginGroovyPluginMavenPublishPlugin 等),这意味着它们会自动解析。

plugins { id «plugin id» version «plugin version» }

必须在设置文件中指定插件的位置:settings.gradle pluginManagement { repositories { gradlePluginPortal() maven { url 'https://maven.example.com/plugins' } } }

1>使用 plugins{} 块应用插件:plugins 块配置 PluginDependenciesSpec 的实例

plugins {} 块机制和 “传统” apply() 方法机制之间存在一些关键差异。具体看官网。略着看就可以。

多项目构建中,子项目构建脚本中的plugins{} 块 不带版本

2>应用 buildSrc 目录中的插件:

buildSrc 是 Gradle 项目根目录中的可选目录,其中包含用于构建主项目的构建逻辑(即插件)。您可以应用驻留在项目的 buildSrc 目录中的插件,只要它们具有定义的 ID。

定义一个插件:

gradlePlugin { plugins { myPlugins { id = 'my-plugin' implementationClass = 'my.MyPlugin' } } }

3>使用 buildscript{} 块应用插件

buildscript 块用于:

构建项目所需的全局依赖项存储库(在子项目中应用)。

声明哪些插件可在构建脚本中使用(在 build.gradle(.kts) 文件中)。

当你想在构建脚本本身中使用一个库时,你必须使用 buildScript 在脚本 classpath 上添加这个库:

buildscript { repositories { // this is where the plugins are located mavenCentral() google() } dependencies { // these are the plugins that can be used in subprojects or in the build file itself classpath group: 'commons-codec', name: 'commons-codec', version: '1.2' // used in the task below classpath 'com.android.tools.build:gradle:4.1.0' // used in subproject } }

可以在需要它的子项目中应用全局声明的依赖项:

plugins { id 'com.android.application' }

4>使用旧版 apply() 方法应用脚本插件

插件管理:

pluginManagement{} 块用于配置用于插件解析的存储库,以及定义在构建脚本中应用的插件的版本约束。

pluginManagement{} 块可以在 settings.gradle(.kts) 文件中使用,其中它必须是文件中的第一个块:

自定义插件仓库:请使用 pluginManagement{} 中的 repositories{} 块:

settings.gradle pluginManagement { repositories { maven { url './maven-repo' } gradlePluginPortal() ivy { url './ivy-repo' } } }

9.编写插件

插件是 Plugin 接口的任何类。

编写插件:

abstract class SamplePlugin : Plugin { override fun apply(project: Project) { project.tasks.create("SampleTask") { println("Hello world!") } } }

扩展 org.gradle.api.Plugin 接口。覆盖apply() 方法。

教程:

1.初始化项目:gradle init

Application 插件由 gradle init 自动添加,有助于创建可执行的 JVM 应用程序

4.编写Settings文件,include是一个方法

5.编写构建脚本:

Project 对象的用途是创建 Task 对象的集合、应用插件和检索依赖项。

6.编写任务

Task 是包含操作序列的可执行代码段。

操作通过 doFirst{}doLast{} 闭包添加到 Task 中。

Task 可以依赖于其他 Task。

注册任务:tasks.register

配置任务:tasks.named

构建:

子项目之间的依赖关系:eg:子项目依赖 shared 和 api

dependencies { testImplementation "junit:junit:4.13" implementation project(':shared') implementation project(':api') }

复合构建:通过设置文件定义复合构建,settings.gradle.kts includeBuild("my-utils")

开发任务:

组添加,任务可见;否则,为隐藏任务

tasks.register("helloTask") { group = "Other" description = "Hello task" println 'Hello' }

使用 Gradle 任务时,需要考虑三种状态:

注册任务(register)

配置任务(named)

实施任务(创建自定义任务类,扩展 Gradle 的 DefaultTask 类来完成)

延迟配置任务:lazy属性的一个重要功能是它们可以连接在一起,以便对一个属性的更改会自动反映在其他属性中。

下面是一个示例,其中任务的属性连接到项目扩展的属性:

// A project extension

// MessageExtension 是一个接口,它定义了一个可配置的问候语属性 greeting。 // Property<String> 是Gradle中的一个类型,表示一个可以配置的字符串属性。 interface MessageExtension { // A configurable greeting Property getGreeting() }

// A task that displays a greeting abstract class Greeting extends DefaultTask { // Configurable by the user @Input abstract Property getGreeting() // Read-only property calculated from the greeting @Internal final Provider message = greeting.map { it + ' from Gradle' } @TaskAction void printMessage() { logger.quiet(message.get()) } } // Create the project extension

// 这行代码在项目中创建了一个名为 messages 的 MessageExtension 实例。 project.extensions.create('messages', MessageExtension) // Create the greeting task tasks.register("greeting", Greeting) { // Attach the greeting from the project extension // Note that the values of the project extension have not been configured yet greeting = messages.greeting } messages { // Configure the greeting on the extension // Note that there is no need to reconfigure the task's greeting property. This is automatically updated as the extension property changes greeting = 'Hi' }

此示例调用 Property.set(Provider) 方法将 Provider 附加到 Property 以提供属性的值。在这种情况下,Provider 恰好也是一个 Property,但您可以连接任何 Provider 实现,例如使用 Provider.map() 创建的实现

一段代码:

layout.buildDirectory = layout.projectDirectory.dir('output')

这行代码是在Gradle构建脚本中设置构建输出目录的路径。具体来说,它将构建输出目录设置为项目目录下的 output 文件夹。

以下是代码的详细解释:

  • layout:这是Gradle构建脚本中的一个对象,提供了对构建布局的访问。

  • buildDirectory:这是一个属性,表示构建输出目录的路径。

  • layout.projectDirectory:这是项目根目录的路径。

  • dir('output'):这是一个方法调用,表示在项目根目录下创建一个名为 output 的子目录。

因此,这行代码的作用是将构建输出目录设置为项目根目录下的 output 文件夹。例如,如果项目根目录是 /path/to/project,那么构建输出目录将是 /path/to/project/output

开发并行任务:接下来的篇章自己遇到问题再去查阅。以看会代码,理解代码为主。

开发高级任务:略

插件有三类:脚本插件,预编译的脚本插件,二进制插件。

发布gradle插件

五、依赖关系管理

基础知识:

声明依赖项,依赖项配置,声明仓库,集中依赖关系,依赖关系冲突和冲突解决

六、编写JVM版本

七、优化构建性能

提高gradle构建的性能:腾讯元宝搜索即可得到答案

八、编写 C++/Swift 版本

九、参考

一些命令:

安装Gradle,将Gradle版本更新到8.10:gradle wrapper --gradle-version 8.10

初始化Gradle/初始化项目:gradle init

运行clean任务,然后运行build任务:./gradlew :app:clean :app:build

运行Gradle构建:./gradlew :app:build

仅构建库:./gradlew :lib:build

仅构建 license-plugin:./gradlew :license-plugin:plugin:build

运行Gradle构建/构建应用程序和库:gradle build

删除构建目录:gradle clean

查看项目依赖项:./gradlew :app:dependencies

查看项目结构:gradle projects

识别项目结构:gradle -q projects

打印任务里的值:gradle -q {注册的task任务名称}

列出Gradle默认任务:./gradlew tasks 或 gradle tasks

查看根目录中的任务:./gradlew tasks --all

执行任务:gradle {注册的task任务名称}

查看子项目中的可用任务:/gradlew :app:tasks

查看有关任务的信息:gradle help --task <task-name>

编译和运行gradle/运行应用程序:gradle run

运行应用程序:gradle -q run

再次运行构建任务:gradlew build --scan

编译名为 "api" 的 Gradle 子项目:./gradlew :api:compile

复合构建:./gradlew run --include-build ../my-utils

附加:Kotlin语言与Groovy语言的不同

末尾为.kts就是kotlin语言,否则是Groovy语言(eg:settings.gradle.kts)

eg1:

Kotlin:

repositories { // Use Maven Central for resolving dependencies. mavenCentral() } dependencies { // Use JUnit Jupiter for testing. testImplementation(libs.junit.jupiter) testRuntimeOnly("org.junit.platform:junit-platform-launcher") // This dependency is used by the application. implementation(libs.guava) }

Groovy:

repositories { // Use Maven Central for resolving dependencies. mavenCentral() } dependencies { // Use JUnit Jupiter for testing. testImplementation libs.junit.jupiter testRuntimeOnly 'org.junit.platform:junit-platform-launcher' // This dependency is used by the application. implementation libs.guava }

eg2:

Kotlin:

plugins { // Apply the application plugin to add support for building a CLI application in Java. application }

Groovy:

plugins { // Apply the application plugin to add support for building a CLI application in Java. id 'application' }

附加:问题定位

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 200,841评论 5 472
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,415评论 2 377
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 147,904评论 0 333
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,051评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,055评论 5 363
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,255评论 1 278
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,729评论 3 393
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,377评论 0 255
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,517评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,420评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,467评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,144评论 3 317
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,735评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,812评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,029评论 1 256
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,528评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,126评论 2 341

推荐阅读更多精彩内容