Express,Sequelize和MySQL的Node.js Rest API示例

本文翻譯自Node.js Rest APIs example with Express, Sequelize & MySQL

最新修改:2020年9月29號 bezkoder Node.js

Express是Node.js最受歡迎的Web框架之一脉幢,支持路由视粮,中間件帆喇,視圖系統(tǒng)...Sequelize是基于Promise的Node.js ORM杠愧,它支持Postgres,MySQL收班,SQL Server的方言棚赔。在本教程中,我將 向您展示如何使用Express贬芥,Sequelize和MySQL數(shù)據(jù)庫來構(gòu)建Node.js Restful CRUD API。

您應(yīng)該首先在機器上安裝MySQL宣决。 可以在以下位置找到安裝說明:
Official MySQL installation manual

相關(guān)文章:

全棧:

安全性:Node.js – JWT Authentication & Authorization example
部署:Deploying/Hosting Node.js app on Heroku with MySQL database

Node.js Rest CRUD API概述

我們將構(gòu)建Rest Apis蘸劈,它可以創(chuàng)建,檢索尊沸,更新威沫,刪除和按標(biāo)題查找教程。
首先洼专,我們從Express Web服務(wù)器開始棒掠。 接下來,我們?yōu)镸ySQL數(shù)據(jù)庫添加配置屁商,使用Sequelize創(chuàng)建Tutorial模型烟很,編寫控制器。 然后棒假,我們定義用于處理所有CRUD操作(包括自定義查找程序)的路由溯职。

下表概述了將要導(dǎo)出的Rest API:

Methods Urls Actions
GET api/tutorials get all Tutorials
GET api/tutorials/:id get Tutorial by id
POST api/tutorials add new Tutorial
PUT api/tutorials/:id update Tutorial by id
DELETE api/tutorials/:id remove Tutorial by id
DELETE api/tutorials remove all Tutorials
GET api/tutorials/published find all published Tutorials
GET api/tutorials?title=[kw] find all Tutorials which title contains 'kw'

最后,我們將使用Postman測試Rest Apis帽哑。

這是我們的項目結(jié)構(gòu):
[圖片上傳失敗...(image-5f8879-1604969151628)]

示例視頻

這是我們的與MySQL數(shù)據(jù)庫一起運行的Node.js Express Sequelize應(yīng)用程序演示,并通過Postman測試Rest Apis叹俏。

創(chuàng)建Node.js應(yīng)用

首先妻枕,我們創(chuàng)建目錄:

$ mkdir nodejs-express-sequelize-mysql
$ cd nodejs-express-sequelize-mysql

接下來,我們使用package.json文件初始化Node.js App:

npm init

name: (nodejs-express-sequelize-mysql) 
version: (1.0.0) 
description: Node.js Rest Apis with Express, Sequelize & MySQL.
entry point: (index.js) server.js
test command: 
git repository: 
keywords: nodejs, express, sequelize, mysql, rest, api
author: bezkoder
license: (ISC)

Is this ok? (yes) yes

我們需要安裝必要的模塊:express粘驰,sequelize屡谐,mysql2body-parser
運行命令:

npm install express sequelize mysql2 body-parser cors --save

package.json文件應(yīng)如下所示:

{
  "name": "nodejs-express-sequelize-mysql",
  "version": "1.0.0",
  "description": "Node.js Rest Apis with Express, Sequelize & MySQL",
  "main": "server.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [
    "nodejs",
    "express",
    "rest",
    "api",
    "sequelize",
    "mysql"
  ],
  "author": "bezkoder",
  "license": "ISC",
  "dependencies": {
    "body-parser": "^1.19.0",
    "cors": "^2.8.5",
    "express": "^4.17.1",
    "mysql2": "^2.0.2",
    "sequelize": "^5.21.2"
  }
}

建立Express Web服務(wù)器

在根目錄下蝌数,創(chuàng)建一個新的server.js文件:

const express = require("express");
const bodyParser = require("body-parser");
const cors = require("cors");

const app = express();

var corsOptions = {
  origin: "http://localhost:8081"
};

app.use(cors(corsOptions));

// parse requests of content-type - application/json
app.use(bodyParser.json());

// parse requests of content-type - application/x-www-form-urlencoded
app.use(bodyParser.urlencoded({ extended: true }));

// simple route
app.get("/", (req, res) => {
  res.json({ message: "Welcome to bezkoder application." });
});

// set port, listen for requests
const PORT = process.env.PORT || 8080;
app.listen(PORT, () => {
  console.log(`Server is running on port ${PORT}.`);
});

我們要做的是:

  • 導(dǎo)入express愕掏,body-parsercors模塊:

    • Express用于構(gòu)建Rest API
    • body-parser有助于解析請求并創(chuàng)建req.body對象
    • cors提供了Express中間件,以使CORS具有多種選擇顶伞。
  • 創(chuàng)建一個Express應(yīng)用饵撑,然后使用app.use()方法添加body-parsercors中間件剑梳。 請注意,我們設(shè)置了origin:http:// localhost:8081滑潘。

  • 定義一個易于測試的GET路由垢乙。

  • 在端口8080上偵聽傳入請求。

現(xiàn)在语卤,使用以下命令運行該應(yīng)用:node server.js追逮。
使用URL http:// localhost:8080/打開瀏覽器,您將看到:

http://localhost:8080

是的粹舵,第一步已經(jīng)完成钮孵。 在下一節(jié)中,我們將與Sequelize一起協(xié)作眼滤。

配置MySQL數(shù)據(jù)庫并進(jìn)行序列化

在app文件夾中油猫,我們創(chuàng)建一個單獨的config文件夾,然后使用db.config.js文件進(jìn)行配置柠偶,如下所示:

module.exports = {
  HOST: "localhost",
  USER: "root",
  PASSWORD: "123456",
  DB: "testdb",
  dialect: "mysql",
  pool: {
    max: 5,
    min: 0,
    acquire: 30000,
    idle: 10000
  }
};

前面5個參數(shù)用于MySQL連接情妖。

pool是可選的,它將用于Sequelize連接池配置:

- max:池中的最大連接數(shù)
- min:池中的最小連接數(shù)
- idle:連接釋放之前可以空閑的最長時間(以毫秒為單位)
- acquire:該池將在拋出錯誤之前嘗試獲取連接的最長時間(以毫秒為單位)

有關(guān)更多詳細(xì)信息诱担,請訪問API Reference for the Sequelize constructor毡证。

初始化Sequelize

我們將在下一步包含模型的app/models文件夾中初始化Sequelize。

現(xiàn)在蔫仙,使用以下代碼創(chuàng)建app/models/index.js

const dbConfig = require("../config/db.config.js");

const Sequelize = require("sequelize");
const sequelize = new Sequelize(dbConfig.DB, dbConfig.USER, dbConfig.PASSWORD, {
  host: dbConfig.HOST,
  dialect: dbConfig.dialect,
  operatorsAliases: false,

  pool: {
    max: dbConfig.pool.max,
    min: dbConfig.pool.min,
    acquire: dbConfig.pool.acquire,
    idle: dbConfig.pool.idle
  }
});

const db = {};

db.Sequelize = Sequelize;
db.sequelize = sequelize;

db.tutorials = require("./tutorial.model.js")(sequelize, Sequelize);

module.exports = db;

不要忘記在server.js中調(diào)用sync()方法

...
const app = express();
app.use(...);

const db = require("./app/models");
db.sequelize.sync();

...

在開發(fā)中料睛,您可能需要刪除現(xiàn)有表并重新同步數(shù)據(jù)庫。 只需使用force:true即可摇邦,如下代碼:

db.sequelize.sync({ force: true }).then(() => {
  console.log("Drop and re-sync db.");
});

定義Sequelize模型

在models文件夾中恤煞,像這樣創(chuàng)建tutorial.model.js文件:

module.exports = (sequelize, Sequelize) => {
  const Tutorial = sequelize.define("tutorial", {
    title: {
      type: Sequelize.STRING
    },
    description: {
      type: Sequelize.STRING
    },
    published: {
      type: Sequelize.BOOLEAN
    }
  });

  return Tutorial;
};

該Sequelize模型表示MySQL數(shù)據(jù)庫中的tutorials表。 這些列將自動生成:id, title, description, published, createdAt, updatedAt.

初始化Sequelize之后施籍,我們無需編寫CRUD函數(shù)居扒,Sequelize支持所有這些功能:

  • 創(chuàng)建一個新的教程:create(object)
  • 通過id查找教程:findByPk(id)
  • 獲取所有教程:findAll()
  • 通過id:update(data, where: { id: id })
  • 刪除教程:destroy(where: { id: id })
  • 刪除所有教程:destroy(where:{})
  • 按標(biāo)題查找所有教程:findAll({ where: { title: ... } })

這些功能將在我們的控制器中使用。

我們可以通過為每個教程添加評論來改進(jìn)示例丑慎。 這是一對多關(guān)系喜喂,我為此編寫了一個教程:
Sequelize Associations: One-to-Many example – Node.js, MySQL

或者,您可以為每個教程添加標(biāo)簽竿裂,并將教程添加到標(biāo)簽(多對多關(guān)系):
Sequelize Many-to-Many Association example with Node.js & MySQL

創(chuàng)建控制器

app/controllers文件夾中玉吁,讓我們使用以下CRUD函數(shù)創(chuàng)建tutorial.controller.js:

  • create
  • findAll
  • findOne
  • update
  • delete
  • deleteAll
  • findAllPublised
const db = require("../models");
const Tutorial = db.tutorials;
const Op = db.Sequelize.Op;

// Create and Save a new Tutorial
exports.create = (req, res) => {
  
};

// Retrieve all Tutorials from the database.
exports.findAll = (req, res) => {
  
};

// Find a single Tutorial with an id
exports.findOne = (req, res) => {
  
};

// Update a Tutorial by the id in the request
exports.update = (req, res) => {
  
};

// Delete a Tutorial with the specified id in the request
exports.delete = (req, res) => {
  
};

// Delete all Tutorials from the database.
exports.deleteAll = (req, res) => {
  
};

// Find all published Tutorials
exports.findAllPublished = (req, res) => {
  
};

讓我們實現(xiàn)這些功能。

創(chuàng)建一個新對象

創(chuàng)建并保存一個新教程:

exports.create = (req, res) => {
  // Validate request
  if (!req.body.title) {
    res.status(400).send({
      message: "Content can not be empty!"
    });
    return;
  }

  // Create a Tutorial
  const tutorial = {
    title: req.body.title,
    description: req.body.description,
    published: req.body.published ? req.body.published : false
  };

  // Save Tutorial in the database
  Tutorial.create(tutorial)
    .then(data => {
      res.send(data);
    })
    .catch(err => {
      res.status(500).send({
        message:
          err.message || "Some error occurred while creating the Tutorial."
      });
    });
};

檢索對象(有條件)

從數(shù)據(jù)庫中檢索所有教程/按標(biāo)題查找:

exports.findAll = (req, res) => {
  const title = req.query.title;
  var condition = title ? { title: { [Op.like]: `%${title}%` } } : null;

  Tutorial.findAll({ where: condition })
    .then(data => {
      res.send(data);
    })
    .catch(err => {
      res.status(500).send({
        message:
          err.message || "Some error occurred while retrieving tutorials."
      });
    });
};

我們使用req.query.title從Request中獲取查詢字符串腻异,并將其作為findAll()方法的條件进副。

檢索單個對象

查找具有ID的單個教程:

exports.findOne = (req, res) => {
  const id = req.params.id;

  Tutorial.findByPk(id)
    .then(data => {
      res.send(data);
    })
    .catch(err => {
      res.status(500).send({
        message: "Error retrieving Tutorial with id=" + id
      });
    });
};

更新對象

更新由請求中的id標(biāo)識的教程:

exports.update = (req, res) => {
  const id = req.params.id;

  Tutorial.update(req.body, {
    where: { id: id }
  })
    .then(num => {
      if (num == 1) {
        res.send({
          message: "Tutorial was updated successfully."
        });
      } else {
        res.send({
          message: `Cannot update Tutorial with id=${id}. Maybe Tutorial was not found or req.body is empty!`
        });
      }
    })
    .catch(err => {
      res.status(500).send({
        message: "Error updating Tutorial with id=" + id
      });
    });
};

刪除對象

刪除具有指定id的教程:

exports.delete = (req, res) => {
  const id = req.params.id;

  Tutorial.destroy({
    where: { id: id }
  })
    .then(num => {
      if (num == 1) {
        res.send({
          message: "Tutorial was deleted successfully!"
        });
      } else {
        res.send({
          message: `Cannot delete Tutorial with id=${id}. Maybe Tutorial was not found!`
        });
      }
    })
    .catch(err => {
      res.status(500).send({
        message: "Could not delete Tutorial with id=" + id
      });
    });
};

刪除所有對象

從數(shù)據(jù)庫中刪除所有教程:

exports.deleteAll = (req, res) => {
  Tutorial.destroy({
    where: {},
    truncate: false
  })
    .then(nums => {
      res.send({ message: `${nums} Tutorials were deleted successfully!` });
    })
    .catch(err => {
      res.status(500).send({
        message:
          err.message || "Some error occurred while removing all tutorials."
      });
    });
};

按條件查找所有對象

查找所有published = true的教程:

exports.findAllPublished = (req, res) => {
  Tutorial.findAll({ where: { published: true } })
    .then(data => {
      res.send(data);
    })
    .catch(err => {
      res.status(500).send({
        message:
          err.message || "Some error occurred while retrieving tutorials."
      });
    });
};

可以對該控制器進(jìn)行一些修改以返回分頁響應(yīng):

{
    "totalItems": 8,
    "tutorials": [...],
    "totalPages": 3,
    "currentPage": 1
}

您可以在以下位置找到更多詳細(xì)信息:
Server side Pagination in Node.js with Sequelize and MySQL

定義路由

當(dāng)客戶端使用HTTP請求(GET,POST悔常,PUT影斑,DELETE)發(fā)送對端點的請求時给赞,我們需要通過設(shè)置路由來確定服務(wù)器的響應(yīng)方式。

這些是我們的路由:

  • /api/tutorials:GET鸥昏,POST塞俱,DELETE
  • /api/tutorials/:id:GET,PUT吏垮,DELETE
  • /api/tutorials/published:GET
    app/routes文件夾中創(chuàng)建一個turorial.routes.js障涯,其內(nèi)容如下:
module.exports = app => {
  const tutorials = require("../controllers/tutorial.controller.js");

  var router = require("express").Router();

  // Create a new Tutorial
  router.post("/", tutorials.create);

  // Retrieve all Tutorials
  router.get("/", tutorials.findAll);

  // Retrieve all published Tutorials
  router.get("/published", tutorials.findAllPublished);

  // Retrieve a single Tutorial with id
  router.get("/:id", tutorials.findOne);

  // Update a Tutorial with id
  router.put("/:id", tutorials.update);

  // Delete a Tutorial with id
  router.delete("/:id", tutorials.delete);

  // Delete all Tutorials
  router.delete("/", tutorials.deleteAll);

  app.use('/api/tutorials', router);
};

您可以看到我們使用了/controllers/tutorial.controller.js中的控制器。

我們還需要在server.js中包含路由(在app.listen()之前):

...

require("./app/routes/turorial.routes")(app);

// set port, listen for requests
const PORT = ...;
app.listen(...);

測試API

使用以下命令運行我們的Node.js應(yīng)用程序:node server.js膳汪。
控制臺顯示:

Server is running on port 8080.
Executing (default): DROP TABLE IF EXISTS `tutorials`;
Executing (default): CREATE TABLE IF NOT EXISTS `tutorials` (`id` INTEGER NOT NULL auto_increment , `title` VARCHAR(255), `description` VARCHAR(255), `published` TINYINT(1), `createdAt` DATETIME NOT NULL, `updatedAt` DATETIME NOT NULL, PRIMARY KEY (`id`)) ENGINE=InnoDB;
Executing (default): SHOW INDEX FROM `tutorials`
Drop and re-sync db.

使用Postman唯蝶,我們將測試以上所有的Apis。

1遗嗽、使用POST/tutorials Api創(chuàng)建一個新教程

Create a new Tutorial

創(chuàng)建一些新教程后粘我,您可以檢查MySQL表:

mysql> select * from tutorials;
+----+-------------------+-------------------+-----------+---------------------+---------------------+
| id | title             | description       | published | createdAt           | updatedAt           |
+----+-------------------+-------------------+-----------+---------------------+---------------------+
|  1 | JS: Node Tut #1   | Tut#1 Description |         0 | 2019-12-13 01:13:57 | 2019-12-13 01:13:57 |
|  2 | JS: Node Tut #2   | Tut#2 Description |         0 | 2019-12-13 01:16:08 | 2019-12-13 01:16:08 |
|  3 | JS: Vue Tut #3    | Tut#3 Description |         0 | 2019-12-13 01:16:24 | 2019-12-13 01:16:24 |
|  4 | Vue Tut #4        | Tut#4 Description |         0 | 2019-12-13 01:16:48 | 2019-12-13 01:16:48 |
|  5 | Node & Vue Tut #5 | Tut#5 Description |         0 | 2019-12-13 01:16:58 | 2019-12-13 01:16:58 |
+----+-------------------+-------------------+-----------+---------------------+---------------------+

2、使用GET /tutorials Api檢索所有的教程

Retrieve all Tutorials

3痹换、使用GET /tutorials/:id Api根據(jù)id查詢單個教程
Retrieve a single Tutorial by id

4征字、使用`PUT /tutorials/:id' Api更新教程
Update a Tutorial

在更新某些行后,請查看tutorials表:

mysql> select * from tutorials;
+----+-------------------+-------------------+-----------+---------------------+---------------------+
| id | title             | description       | published | createdAt           | updatedAt           |
+----+-------------------+-------------------+-----------+---------------------+---------------------+
|  1 | JS: Node Tut #1   | Tut#1 Description |         0 | 2019-12-13 01:13:57 | 2019-12-13 01:13:57 |
|  2 | JS: Node Tut #2   | Tut#2 Description |         0 | 2019-12-13 01:16:08 | 2019-12-13 01:16:08 |
|  3 | JS: Vue Tut #3    | Tut#3 Description |         1 | 2019-12-13 01:16:24 | 2019-12-13 01:22:51 |
|  4 | Vue Tut #4        | Tut#4 Description |         1 | 2019-12-13 01:16:48 | 2019-12-13 01:25:28 |
|  5 | Node & Vue Tut #5 | Tut#5 Description |         1 | 2019-12-13 01:16:58 | 2019-12-13 01:25:30 |
+----+-------------------+-------------------+-----------+---------------------+---------------------+

5娇豫、使用GET /tutorials?title=node查找標(biāo)題包含'node'的所有教程

Find all Tutorials which title contains ‘node’

6匙姜、使用GET /tutorials/published Api查詢所有已發(fā)布的教程
Find all published Tutorials

7、使用'DELETE /tutorials/:idApi刪除一個教程 ![Delete a Tutorial](https://upload-images.jianshu.io/upload_images/15949040-921d6d926ec1ec72?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) id = 2的教程已從tutorials`表中刪除:

mysql> select * from tutorials;
+----+-------------------+-------------------+-----------+---------------------+---------------------+
| id | title             | description       | published | createdAt           | updatedAt           |
+----+-------------------+-------------------+-----------+---------------------+---------------------+
|  1 | JS: Node Tut #1   | Tut#1 Description |         0 | 2019-12-13 01:13:57 | 2019-12-13 01:13:57 |
|  3 | JS: Vue Tut #3    | Tut#3 Description |         1 | 2019-12-13 01:16:24 | 2019-12-13 01:22:51 |
|  4 | Vue Tut #4        | Tut#4 Description |         1 | 2019-12-13 01:16:48 | 2019-12-13 01:25:28 |
|  5 | Node & Vue Tut #5 | Tut#5 Description |         1 | 2019-12-13 01:16:58 | 2019-12-13 01:25:30 |
+----+-------------------+-------------------+-----------+---------------------+---------------------+

8冯痢、使用'DELETE /tutorialsApi刪除所有的教程 ![Delete all Tutorials](https://upload-images.jianshu.io/upload_images/15949040-e3fc6ce85574b9bc?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 現(xiàn)在在tutorials`表中沒有一行數(shù)據(jù)了:

mysql> SELECT * FROM tutorials;
Empty set (0.00 sec)

結(jié)論

今天氮昧,我們已經(jīng)學(xué)習(xí)了如何使用Express Web服務(wù)器創(chuàng)建Node.js Rest Apis。 我們還知道添加MySQL數(shù)據(jù)庫和Sequelize配置浦楣,創(chuàng)建Sequelize模型袖肥,編寫控制器以及定義用于處理所有CRUD操作的路由的方法。

您可以在下一個教程中找到更多有趣的東西:

{
    "totalItems": 8,
    "tutorials": [...],
    "totalPages": 3,
    "currentPage": 1
}

學(xué)習(xí)愉快振劳! 再見椎组。

進(jìn)一步閱讀

將教程數(shù)據(jù)從文件上傳到MySQL數(shù)據(jù)庫表:
- Node.js: Upload Excel file data into MySQL Database
- Node.js: Upload CSV file data into MySQL Database

源代碼

您可以在Github上找到此示例的完整源代碼。

如果要為每個教程添加評論澎迎。 它是一對多關(guān)聯(lián)庐杨,有一個有關(guān)該關(guān)系的教程:Sequelize Associations: One-to-Many example – Node.js, MySQL

或者,您可以為每個教程添加標(biāo)簽夹供,并將教程添加到標(biāo)簽(多對多關(guān)系):
Sequelize Many-to-Many Association example with Node.js & MySQL

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市仁堪,隨后出現(xiàn)的幾起案子哮洽,更是在濱河造成了極大的恐慌,老刑警劉巖弦聂,帶你破解...
    沈念sama閱讀 207,113評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件鸟辅,死亡現(xiàn)場離奇詭異氛什,居然都是意外死亡,警方通過查閱死者的電腦和手機匪凉,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,644評論 2 381
  • 文/潘曉璐 我一進(jìn)店門枪眉,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人再层,你說我怎么就攤上這事贸铜。” “怎么了聂受?”我有些...
    開封第一講書人閱讀 153,340評論 0 344
  • 文/不壞的土叔 我叫張陵蒿秦,是天一觀的道長。 經(jīng)常有香客問我蛋济,道長棍鳖,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,449評論 1 279
  • 正文 為了忘掉前任碗旅,我火速辦了婚禮渡处,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘祟辟。我一直安慰自己医瘫,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 64,445評論 5 374
  • 文/花漫 我一把揭開白布川尖。 她就那樣靜靜地躺著登下,像睡著了一般。 火紅的嫁衣襯著肌膚如雪叮喳。 梳的紋絲不亂的頭發(fā)上被芳,一...
    開封第一講書人閱讀 49,166評論 1 284
  • 那天,我揣著相機與錄音馍悟,去河邊找鬼畔濒。 笑死,一個胖子當(dāng)著我的面吹牛锣咒,可吹牛的內(nèi)容都是我干的侵状。 我是一名探鬼主播,決...
    沈念sama閱讀 38,442評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼毅整,長吁一口氣:“原來是場噩夢啊……” “哼趣兄!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起悼嫉,我...
    開封第一講書人閱讀 37,105評論 0 261
  • 序言:老撾萬榮一對情侶失蹤艇潭,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體蹋凝,經(jīng)...
    沈念sama閱讀 43,601評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡鲁纠,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,066評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了鳍寂。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片改含。...
    茶點故事閱讀 38,161評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖迄汛,靈堂內(nèi)的尸體忽然破棺而出捍壤,到底是詐尸還是另有隱情,我是刑警寧澤隔心,帶...
    沈念sama閱讀 33,792評論 4 323
  • 正文 年R本政府宣布白群,位于F島的核電站,受9級特大地震影響硬霍,放射性物質(zhì)發(fā)生泄漏帜慢。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,351評論 3 307
  • 文/蒙蒙 一唯卖、第九天 我趴在偏房一處隱蔽的房頂上張望粱玲。 院中可真熱鬧,春花似錦拜轨、人聲如沸抽减。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,352評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽卵沉。三九已至,卻和暖如春法牲,著一層夾襖步出監(jiān)牢的瞬間史汗,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,584評論 1 261
  • 我被黑心中介騙來泰國打工拒垃, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留停撞,地道東北人。 一個月前我還...
    沈念sama閱讀 45,618評論 2 355
  • 正文 我出身青樓悼瓮,卻偏偏與公主長得像戈毒,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子横堡,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,916評論 2 344

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