SpringBoot JPA 代碼自動(dòng)生成 其四

趁著有時(shí)間又對(duì)之前的生成文件做了些調(diào)整扫外,修改了配置項(xiàng),加入了對(duì) swagger 的支持

順便弄了個(gè)demo

生成文件效果

選擇的jpagendemo作為生成目錄生成的文件結(jié)構(gòu)

生成的文件結(jié)構(gòu)
  • entity
package com.marioplus.jpagendemo.entity;

import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import com.marioplus.jpagendemo.common.BaseEntity;
import javax.persistence.*;
import lombok.EqualsAndHashCode;
import lombok.Data;

import java.io.Serializable;


/**
 * 用戶表
 *
 * @author auto generated
 * @date 2020-01-31 01:02:41
 */
@EqualsAndHashCode(callSuper = true)
@Data
@Entity
@Table(name = "user")
@ApiModel(value = "用戶表")
public class User extends BaseEntity implements Serializable {

    /**
     * 姓名
     * nullable : true
     * default  : null
     */
    @ApiModelProperty(value = "姓名")
    @Column(name = "name", nullable = true, length = 20)
    private String name;

    /**
     * 年齡
     * nullable : true
     * default  : null
     */
    @ApiModelProperty(value = "年齡")
    @Column(name = "age", nullable = true, length = 11)
    private Integer age;

    /**
     * 聯(lián)系方式
     * nullable : true
     * default  : null
     */
    @ApiModelProperty(value = "聯(lián)系方式")
    @Column(name = "mobile", nullable = true, length = 11)
    private String mobile;

    /**
     * 性別
     * nullable : true
     * default  : null
     */
    @ApiModelProperty(value = "性別")
    @Column(name = "sex", nullable = true)
    private String sex;
}
  • service
package com.marioplus.jpagendemo.service;

import com.marioplus.jpagendemo.repository.UserRepository;
import com.marioplus.jpagendemo.common.BaseService;
import com.marioplus.jpagendemo.entity.User;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;

/**
 * User service層
 *
 * @author auto generated
 * @date 2020-01-31 01:02:41
 */
@Service
public class UserService extends BaseService<User, Long> {

    @Resource
    private UserRepository rep;
}
  • repository
package com.marioplus.jpagendemo.repository;

import com.marioplus.jpagendemo.entity.User;
import org.springframework.data.jpa.repository.JpaRepository;

/**
 * User Repository層
 *
 * @author auto generated
 * @date 2020-01-31 01:02:41
 */
public interface UserRepository extends JpaRepository<User, Long>, UserRepositoryCustom {

}
  • repositoryCustom
package com.marioplus.jpagendemo.repository;

/**
 * User 自定義Repository層
 *
 * @author auto generated
 * @date 2020-01-31 01:02:41
 */
public interface UserRepositoryCustom {

}
  • repositoryCustomImpl
package com.marioplus.jpagendemo.repository.impl;

import com.marioplus.jpagendemo.repository.UserRepositoryCustom;
import org.springframework.stereotype.Repository;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;

/**
 * User 自定義Repository實(shí)現(xiàn)層
 *
 * @author auto generated
 * @date 2020-01-31 01:02:41
 */
@Repository
public class UserRepositoryCustomImpl implements UserRepositoryCustom {

    @PersistenceContext
    private EntityManager em;
}

如何使用

如果需要使用 lombok 和 swagger 生成配置需要加入相應(yīng)的 maven 依賴

  1. view -> Tool Windows -> Database

    image.png

  2. + -> Data source -> MySQL

    image.png

  3. 配置數(shù)據(jù)庫信息


    image.png
  4. 在database視圖區(qū)域任意地方右鍵瓢喉,然后 Scripted Extensions -> Go to Scripts Directory

    image.png

    image.png

  5. 復(fù)制下面的文件到4中跳轉(zhuǎn)的文件夾schema

  • jpa-auto-generate.groovy
import com.intellij.database.model.DasTable
import com.intellij.database.model.ObjectKind
import com.intellij.database.util.Case
import com.intellij.database.util.DasUtil

import javax.swing.*
import java.awt.Dialog
import java.lang.reflect.Method
import java.time.LocalDateTime
import java.time.format.DateTimeFormatter
import java.util.stream.Collectors

config = [
        // 生成開關(guān)
        generate: [
                entity          : true,
                service         : true,
                repository      : true,
                repositoryCustom: true
        ],
        // 實(shí)體生成設(shè)置
        entity  : [
                // 繼承父類設(shè)置
                parent         : [
                        // 是否繼承父類
                        enable    : true,
                        // 父類名稱
                        name      : "BaseEntity",
                        // 父類包名
                        package   : "com.marioplus.jpagendemo.common",
                        // 父類的屬性培他,父類已有屬性不在出現(xiàn)在生成的實(shí)體內(nèi)
                        properties: ["id", "createDate", "lastModifiedDate", "version"],
                ],
                // 是否序列化
                impSerializable: true,
                // 是否生成 jpa 相關(guān)內(nèi)容蜂奸,設(shè)置為 false 可以生成與 jpa 無關(guān)的實(shí)體
                jpa            : true,
                // 是否生成 swagger 文檔相關(guān)注解愉老,相關(guān)說明來數(shù)據(jù)庫注釋
                useSwagger     : true,
                // 是否使用 lombok 注解代替 get、set方法
                useLombok      : true
        ],
        // service 生成設(shè)置
        service : [
                // 參照 entity 部分的 parent
                parent: [
                        enable : true,
                        name   : "BaseService",
                        package: "com.marioplus.jpagendemo.common"
                ]
        ]
]

typeMapping = [
        (~/(?i)bool|boolean|tinyint/)     : "Boolean",
        (~/(?i)bigint/)                   : "Long",
        (~/(?i)int/)                      : "Integer",
        (~/(?i)float|double|decimal|real/): "Double",
        (~/(?i)datetime|timestamp/)       : "java.util.Date",
        (~/(?i)date/)                     : "java.sql.Date",
        (~/(?i)time/)                     : "java.sql.Time",
        (~/(?i)/)                         : "String"
]


FILES.chooseDirectoryAndSave("\u9009\u62e9\u6587\u4ef6\u5939", "\u9009\u62e9\u6587\u4ef6\u751f\u6210\u4f4d\u7f6e") { dir ->
    SELECTION.filter {
        it instanceof DasTable && it.getKind() == ObjectKind.TABLE
    }
            .each { table ->
                def fields = calcFields(table)
                Gen.main(config, table, fields, dir.toString())
            }
}

// 轉(zhuǎn)換類型
def calcFields(table) {
    def pk = Utils.getPK(table)
    DasUtil.getColumns(table).reduce([]) { fields, col ->
//        console(col, i++)
        def spec = Case.LOWER.apply(col.getDataType().getSpecification())
        def typeStr = typeMapping.find { p, t -> p.matcher(spec).find() }.value
        fields += [[
                           name        : Utils.toCamelCase(col.getName().toString()),
                           column      : col.getName(),
                           type        : typeStr,
                           dataType    : Utils.firstMatched(col.getDataType(), /\b\w+\b/, ""),
                           len         : Utils.firstMatched(col.getDataType(), /(?<=\()\d+(?!=\))/, -1),
                           default     : col.getDefault(),
                           comment     : col.getComment(),
                           nullable    : !col.isNotNull(),
                           isPrimaryKey: null != pk && pk == col.getName(),
                   ]]
    }
}

class Gen {

    // 生成對(duì)應(yīng)的文件
    def static main(config, table, fields, dir) {
        def entityName = Utils.toUpperCamelCase(table.getName())
        def basePackage = Utils.firstMatched(dir.toString(), /(?<=src\\main\\java\\).+/, "").replace("\\", ".")
        dir = dir.toString()
        def pkType = fields.find { it.isPrimaryKey }.type
        // entity
        if (config.generate.entity) {
            Utils.createFile("${dir}\\entity", "${entityName}.java").withWriter("utf8") {
                writer -> genEntity(writer, config, config.entity.parent, table, entityName, fields, basePackage)
            }
        }
        // service
        if (config.generate.service) {
            Utils.createFile("${dir}\\service", "${entityName}Service.java").withWriter("utf8") {
                writer -> genService(writer, config, config.service.parent, entityName, pkType, basePackage)
            }
        }

        // rep
        if (config.generate.repository) {
            Utils.createFile("${dir}\\repository", "${entityName}Repository.java").withWriter("utf8") {
                writer -> genRepository(writer, config, entityName, basePackage, pkType)
            }
        }

        // repCustom
        if (config.generate.repositoryCustom) {
            Utils.createFile("${dir}\\repository", "${entityName}RepositoryCustom.java").withWriter("utf8") {
                writer -> genRepositoryCustom(writer, entityName, basePackage)
            }
            Utils.createFile("${dir}\\repository\\impl", "${entityName}RepositoryCustomImpl.java").withWriter("utf8") {
                writer -> genRepositoryCustomImpl(writer, entityName, basePackage)
            }
        }

    }

    // 生成實(shí)體
    def static genEntity(writer, config, parentConfig, table, entityName, fieldList, basePackage) {

        writer.writeLine "package ${basePackage}.entity;"
        writer.writeLine ""
        if (config.entity.useSwagger) {
            writer.writeLine "import io.swagger.annotations.ApiModel;"
            writer.writeLine "import io.swagger.annotations.ApiModelProperty;"
        }
        if (parentConfig.enable) {
            writer.writeLine "import ${parentConfig.package}.${parentConfig.name};"
        }
        if (config.entity.jpa) {
            writer.writeLine "import javax.persistence.*;"
        }
        if (config.entity.useLombok) {
            if (parentConfig.enable) {
                writer.writeLine "import lombok.EqualsAndHashCode;"
            }
            writer.writeLine "import lombok.Data;"
            writer.writeLine ""
        }
        if (config.entity.impSerializable) {
            writer.writeLine "import java.io.Serializable;"
            writer.writeLine ""
        }

        def tableComment = Utils.getDefaultValIfCurrentValIsBlank(table.getComment(), entityName)
        writer.writeLine ""
        writer.writeLine "/**"
        writer.writeLine " * $tableComment"
        writer.writeLine " *"
        writer.writeLine " * @author auto generated"
        writer.writeLine " * @date ${Utils.localDateTimeStr()}"
        writer.writeLine " */"
        if (config.entity.useLombok) {
            if (parentConfig.enable) {
                writer.writeLine "@EqualsAndHashCode(callSuper = true)"
            }
            writer.writeLine "@Data"
        }
        if (config.entity.jpa) {
            writer.writeLine "@Entity"
            writer.writeLine "@Table(name = \"${table.name}\")"
        }
        if (config.entity.useSwagger) {
            writer.writeLine "@ApiModel(value = \"${tableComment}\")"
        }

        def extendsStr = parentConfig.enable ? " extends $parentConfig.name" : "",
            impStr = config.entity.impSerializable ? " implements Serializable" : ""
        writer.writeLine "public class $entityName$extendsStr$impStr {"

        if (parentConfig.enable) {
            fieldList = fieldList.findAll { field -> !parentConfig.properties.contains(field.name) }
        }

        fieldList.each() { field -> genEntityProperties(writer, config, parentConfig, field) }

        if (!config.entity.useLombok) {
            fieldList.each() { field -> genEntityGetAndSetMethod(writer, field) }
        }
        writer.writeLine "}"
    }

    // 實(shí)體屬性
    def static genEntityProperties(writer, config, parentConfig, field) {
        writer.writeLine ""
        def comment = Utils.getDefaultValIfCurrentValIsBlank(field.comment, field.name)
        writer.writeLine "\t/**"
        writer.writeLine "\t * ${comment}"
        writer.writeLine "\t * nullable : ${field.nullable}"
        writer.writeLine "\t * default  : ${field.default}"
        writer.writeLine "\t */"

        if (field.isPrimaryKey && config.entity.jpa) {
            writer.writeLine "\t@Id"
        }
        if (config.entity.useSwagger) {
            writer.writeLine "\t@ApiModelProperty(value = \"${comment}\")"
        }

        if (config.entity.jpa) {
            def lenStr = ""
            if (field.len.toInteger() >= 0 && !field.type.contains("java")) {
                lenStr = ", length = $field.len"
            }
            writer.writeLine "\t@Column(name = \"${field.column}\", nullable = ${!field.isNotNull}$lenStr)"
        }
        writer.writeLine "\tprivate ${field.type} ${field.name};"
    }

    // 生成get啊犬、get方法
    def static genEntityGetAndSetMethod(writer, field) {

        def methodName = Utils.toUpperCamelCase(field.name)

        // get
        writer.writeLine "\t"
        writer.writeLine "\tpublic ${field.type} get${methodName}() {"
        writer.writeLine "\t\treturn this.${field.name};"
        writer.writeLine "\t}"

        // set
        writer.writeLine "\t"
        writer.writeLine "\tpublic void set${methodName}($field.type $field.name) {"
        writer.writeLine "\t\tthis.${field.name} = ${field.name};"
        writer.writeLine "\t}"
    }

    // 生成Service
    def static genService(writer, config, parentConfig, entityName, pkType, basePackage) {
        writer.writeLine "package ${basePackage}.service;"
        writer.writeLine ""
        writer.writeLine "import ${basePackage}.repository.${entityName}Repository;"
        if (parentConfig.enable) {
            writer.writeLine "import $parentConfig.package.$parentConfig.name;"
            writer.writeLine "import ${basePackage}.entity.$entityName;"
        }
        writer.writeLine "import org.springframework.stereotype.Service;"
        writer.writeLine ""
        writer.writeLine "import javax.annotation.Resource;"
        writer.writeLine ""
        writer.writeLine "/**"
        writer.writeLine " * $entityName service\u5c42"
        writer.writeLine " *"
        writer.writeLine " * @author auto generated"
        writer.writeLine " * @date ${Utils.localDateTimeStr()}"
        writer.writeLine " */"
        writer.writeLine "@Service"

        def extendsStr = parentConfig.enable ? " extends ${parentConfig.name}<$entityName, $pkType>" : ""
        writer.writeLine "public class ${entityName}Service${extendsStr} {"
        writer.writeLine ""
        writer.writeLine "\t@Resource"
        writer.writeLine "\tprivate ${entityName}Repository rep;"
        writer.writeLine "}"
    }

    // 生成rep
    def static genRepository(writer, config, entityName, basePackage, pkType) {
        def customStr = config.generate.repositoryCustom ? ", ${entityName}RepositoryCustom" : ""

        writer.writeLine "package ${basePackage}.repository;"
        writer.writeLine ""
        writer.writeLine "import ${basePackage}.entity.$entityName;"
        writer.writeLine "import org.springframework.data.jpa.repository.JpaRepository;"
        writer.writeLine ""
        writer.writeLine "/**"
        writer.writeLine " * $entityName Repository\u5c42"
        writer.writeLine " *"
        writer.writeLine " * @author auto generated"
        writer.writeLine " * @date ${Utils.localDateTimeStr()}"
        writer.writeLine " */"
        writer.writeLine "public interface ${entityName}Repository extends JpaRepository<$entityName, $pkType>$customStr {"
        writer.writeLine ""
        writer.writeLine "}"
    }

    // 生成repCustom
    def static genRepositoryCustom(writer, entityName, basePackage) {
        writer.writeLine "package ${basePackage}.repository;"
        writer.writeLine ""
        writer.writeLine "/**"
        writer.writeLine " * $entityName \u81ea\u5b9a\u4e49Repository\u5c42"
        writer.writeLine " *"
        writer.writeLine " * @author auto generated"
        writer.writeLine " * @date ${Utils.localDateTimeStr()}"
        writer.writeLine " */"
        writer.writeLine "public interface ${entityName}RepositoryCustom {"
        writer.writeLine ""
        writer.writeLine "}"
    }

    // 生成repCustomImp
    def static genRepositoryCustomImpl(writer, entityName, basePackage) {
        writer.writeLine "package ${basePackage}.repository.impl;"
        writer.writeLine ""
        writer.writeLine "import ${basePackage}.repository.${entityName}RepositoryCustom;"
        writer.writeLine "import org.springframework.stereotype.Repository;"
        writer.writeLine ""
        writer.writeLine "import javax.persistence.EntityManager;"
        writer.writeLine "import javax.persistence.PersistenceContext;"
        writer.writeLine ""
        writer.writeLine "/**"
        writer.writeLine " * $entityName \u81ea\u5b9a\u4e49Repository\u5b9e\u73b0\u5c42"
        writer.writeLine " *"
        writer.writeLine " * @author auto generated"
        writer.writeLine " * @date ${Utils.localDateTimeStr()}"
        writer.writeLine " */"
        writer.writeLine "@Repository"
        writer.writeLine "public class ${entityName}RepositoryCustomImpl implements ${entityName}RepositoryCustom {"
        writer.writeLine ""
        writer.writeLine "\t@PersistenceContext"
        writer.writeLine "\tprivate EntityManager em;"
        writer.writeLine "}"
    }

}

class Utils {

    /**
     * 提示框
     * @param message
     * @return
     */
    static def dialog(message) {
        JOptionPane.showMessageDialog(null, message, "\u6807\u9898", JOptionPane.PLAIN_MESSAGE)
    }

    /**
     * 反射獲取主鍵列名灼擂,
     * @param table
     * @return 若沒有返回null
     */
    static def getPK(table) {
        def method = table.getClass().getMethod("getText")
        method.setAccessible(true)
        def text = method.invoke(table).toString()
        def reg = /(?<=\s{4,})\b[^\s]+\b(?!=.+\n\s+PRIMARY KEY,)/
        firstMatched(text, reg, null)
    }

    /**
     *  轉(zhuǎn)換為大寫駝峰
     * @param content
     * @return
     */
    static def toUpperCamelCase(content) {
        content.toString()
                .split(/_/)
                .toList()
                .stream()
                .filter { s -> s.length() > 0 }
                .map { s -> s.replaceFirst("^.", s.substring(0, 1).toUpperCase()) }
                .collect(Collectors.joining())
    }

    /**
     *  轉(zhuǎn)換為駝峰
     * @param content
     * @return
     */
    static def toCamelCase(content) {
        content = content.toString()
        toUpperCamelCase(content).replaceFirst(/^./, content.substring(0, 1).toLowerCase())
    }

    /**
     * 尋找第一個(gè)匹配的值
     * @param content 匹配內(nèi)容
     * @param reg 正則
     * @param defaultValue 默認(rèn)值
     * @return 根據(jù)正則匹配,能匹配就返回匹配的值觉至,不能則匹配默認(rèn)值
     */
    static def firstMatched(content, reg, defaultValue) {
        if (null == content) {
            return defaultValue
        }
        def m = content =~ reg
        if (m.find()) {
            return m.group()
        }
        return defaultValue
    }

    static def localDateTimeStr() {
        LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))
    }

    static def createFile(filePath, fileName) {
        def file = new File(filePath)

        if (!file.exists()) {
            file.mkdir()
        }

        file = new File(filePath + "/" + fileName)
        if (!file.exists()) {
            file.createNewFile()
        }
        return file
    }

    static def getDefaultValIfCurrentValIsBlank(currentVal, defaultVal) {
        if (null == currentVal || currentVal.isEmpty()) {
            return defaultVal
        }
        return currentVal
    }
}

class Debug {

    // 反射獲取所有方法
    static def console(col) {
        def clazz = col.getClass()
        def desktop = "C:/Users/mario/Desktop/"
        def fileName = "console${col.getName()}.txt"
        def path = desktop + fileName

        def file = new File(path)
        if (!file.exists()) {
            file.createNewFile()
        }

        file.withWriter("utf8") { writer ->
            writer.writeLine "base properties:"
            writer.writeLine "name\t${clazz.name}"
            writer.writeLine "simpleName\t${clazz.simpleName}"
            writer.writeLine ""

            writer.writeLine "public methods:"
            HashSet<Method> objMethodSet = new HashSet<Method>(new Object().getClass().methods as Collection<? extends Method>)
            HashSet<Method> colMethodSet = new HashSet<Method>(clazz.methods as Collection<? extends Method>)

            colMethodSet.stream()
                    .filter { m -> !objMethodSet.contains(m) && m.name.matches("^(get|is).+") && m.parameterCount == 0 }
                    .sorted { m1, m2 -> (m1.name <=> m2.name) }
                    .forEach { m ->
                        m.setAccessible(true)
                        writer.writeLine "method name:\t${m.name}"
                        writer.writeLine "invoke result:\t${m.invoke(col)}"
                        writer.writeLine ""
                    }

            writer.writeLine "all methods:"
            Arrays.stream(clazz.declaredMethods)
                    .sorted { m1, m2 -> (m1.name <=> m2.name) }
                    .forEach {
                        writer.writeLine "#"
                        writer.writeLine "name\t${it.name}"
                        writer.writeLine "accessible\t${it.accessible.toString()}"
                        writer.writeLine "return\t${it.returnType.name}"
                        writer.writeLine "paramCount\t${it.parameterCount}"
                        writer.write "param\t"
                        it.parameterTypes.each { writer.write "${it.name}\t" }
                        writer.write "param\t"
                        it.parameters.each { writer.write "${it.name}\t" }

                        writer.writeLine ""
                    }

            writer.writeLine ""
        }
    }

    // 測(cè)試獲取的字段
    static def consoleFields(fields) {
        def desktop = "C:/Users/mario/Desktop/"
        def fileName = "console-fields.txt"
        def path = desktop + fileName

        def file = new File(path)
        if (!file.exists()) {
            file.createNewFile()
        }

        file.withWriter("utf8") { writer ->
            fields.each {
                it.each { k, v ->
                    writer.writeLine "${k}:\t${v}"
                }
                writer.writeLine "======================================"
            }
        }
    }
}
  1. database視圖區(qū)域選擇你想要生成的表剔应,然后Scripted Extensions -> jpa-auto-generate.groovy
    可以使用ShiftCtrl多選

    image.png

  2. 彈出的文件選擇框中,選擇生成位置


    image.png

詳細(xì)配置

配置在生成文件的 config

config = [
        // 生成開關(guān)
        generate: [
                entity          : true,
                service         : true,
                repository      : true,
                repositoryCustom: true
        ],
        // 實(shí)體生成設(shè)置
        entity  : [
                // 繼承父類設(shè)置
                parent         : [
                        // 是否繼承父類
                        enable    : true,
                        // 父類名稱
                        name      : "BaseEntity",
                        // 父類包名
                        package   : "com.marioplus.jpagendemo.common",
                        // 父類的屬性,父類已有屬性不在出現(xiàn)在生成的實(shí)體內(nèi)
                        properties: ["id", "createDate", "lastModifiedDate", "version"],
                ],
                // 是否序列化
                impSerializable: true,
                // 是否生成 jpa 相關(guān)內(nèi)容峻贮,設(shè)置為 false 可以生成與 jpa 無關(guān)的實(shí)體
                jpa            : true,
                // 是否生成 swagger 文檔相關(guān)注解席怪,相關(guān)說明來數(shù)據(jù)庫注釋
                useSwagger     : true,
                // 是否使用 lombok 注解代替 get、set方法
                useLombok      : true
        ],
        // service 生成設(shè)置
        service : [
                // 參照 entity 部分的 parent
                parent: [
                        enable : true,
                        name   : "BaseService",
                        package: "com.marioplus.jpagendemo.common"
                ]
        ]
]
  1. 使用 lombok 或者 swagger 需要添加相關(guān) maven 依賴
  2. 重復(fù)生成會(huì)覆蓋之前生成的
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末纤控,一起剝皮案震驚了整個(gè)濱河市挂捻,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌船万,老刑警劉巖细层,帶你破解...
    沈念sama閱讀 207,113評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異唬涧,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)盛撑,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,644評(píng)論 2 381
  • 文/潘曉璐 我一進(jìn)店門碎节,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人抵卫,你說我怎么就攤上這事狮荔。” “怎么了介粘?”我有些...
    開封第一講書人閱讀 153,340評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵殖氏,是天一觀的道長。 經(jīng)常有香客問我姻采,道長雅采,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,449評(píng)論 1 279
  • 正文 為了忘掉前任慨亲,我火速辦了婚禮婚瓜,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘刑棵。我一直安慰自己巴刻,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,445評(píng)論 5 374
  • 文/花漫 我一把揭開白布蛉签。 她就那樣靜靜地躺著胡陪,像睡著了一般。 火紅的嫁衣襯著肌膚如雪碍舍。 梳的紋絲不亂的頭發(fā)上柠座,一...
    開封第一講書人閱讀 49,166評(píng)論 1 284
  • 那天,我揣著相機(jī)與錄音乒验,去河邊找鬼愚隧。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的狂塘。 我是一名探鬼主播录煤,決...
    沈念sama閱讀 38,442評(píng)論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼荞胡!你這毒婦竟也來了妈踊?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,105評(píng)論 0 261
  • 序言:老撾萬榮一對(duì)情侶失蹤泪漂,失蹤者是張志新(化名)和其女友劉穎廊营,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體萝勤,經(jīng)...
    沈念sama閱讀 43,601評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡露筒,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,066評(píng)論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了敌卓。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片慎式。...
    茶點(diǎn)故事閱讀 38,161評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖趟径,靈堂內(nèi)的尸體忽然破棺而出瘪吏,到底是詐尸還是另有隱情,我是刑警寧澤蜗巧,帶...
    沈念sama閱讀 33,792評(píng)論 4 323
  • 正文 年R本政府宣布掌眠,位于F島的核電站,受9級(jí)特大地震影響幕屹,放射性物質(zhì)發(fā)生泄漏蓝丙。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,351評(píng)論 3 307
  • 文/蒙蒙 一望拖、第九天 我趴在偏房一處隱蔽的房頂上張望迅腔。 院中可真熱鬧,春花似錦靠娱、人聲如沸沧烈。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,352評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽锌雀。三九已至,卻和暖如春迅诬,著一層夾襖步出監(jiān)牢的瞬間腋逆,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,584評(píng)論 1 261
  • 我被黑心中介騙來泰國打工侈贷, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留惩歉,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,618評(píng)論 2 355
  • 正文 我出身青樓,卻偏偏與公主長得像撑蚌,于是被迫代替她去往敵國和親上遥。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,916評(píng)論 2 344

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