[Next] 一.初見next.js

github => nest-starter

nest 介紹

Nest 是一個用于構(gòu)建高效,可擴展的 Node.js 服務(wù)器端應(yīng)用程序的框架.它使用漸進式 JavaScript,內(nèi)置并完全支持 TypeScript(但仍然允許開發(fā)人員使用純 JavaScript 編寫代碼)并結(jié)合了 OOP(面向?qū)ο缶幊蹋?FP(函數(shù)式編程)和 FRP(函數(shù)式響應(yīng)編程)的元素.

在底層,Nest 使用強大的 HTTP Server 框架,如 Express(默認)和 Fastify.Nest 在這些框架之上提供了一定程度的抽象,同時也將其 API 直接暴露給開發(fā)人員.這樣可以輕松使用每個平臺的無數(shù)第三方模塊.

為什么用 nest

近年來,感謝 Node.js,JavaScript 已成為前端和后端應(yīng)用程序的網(wǎng)絡(luò)“通用語言”.這產(chǎn)生了令人敬畏的項目,如 Angular,React 和 Vue,它們提高了開發(fā)人員的工作效率,并能夠構(gòu)建快速,可測試和可擴展的前端應(yīng)用程序.然而,雖然 Node(和服務(wù)器端 JavaScript )存在大量優(yōu)秀的庫,幫助器和工具,但它們都沒有有效地解決主要問題 - 架構(gòu).

Nest 提供了一個開箱即用的應(yīng)用程序架構(gòu),允許開發(fā)人員和團隊創(chuàng)建高度可測試,可擴展,松散耦合且易于維護的應(yīng)用程序

環(huán)境搭建

您可以使用 Nest CLI 構(gòu)建項目,也可以克隆啟動項目(兩者都會產(chǎn)生相同的結(jié)果).

安裝 cli

npm i -g @nestjs/cli

創(chuàng)建項目目錄

nest new project-name

更簡單些可以直接 clone 官方預設(shè)項目

git clone https://github.com/nestjs/typescript-starter.git project
cd project
npm install
npm run start

新創(chuàng)建的 project-name 目錄結(jié)構(gòu)

├── README.md
├── node_modules
├── nodemon-debug.json
├── nodemon.json
├── package-lock.json
├── package.json
├── src
├── test
├── tsconfig.json
├── tsconfig.spec.json
├── tslint.json
└── webpack.config.js

src 是源碼目錄

├── app.controller.ts # 根控制器
├── app.controller.spec.ts # 根控制器測試文件
├── app.module.ts # 應(yīng)用程序根模塊
├── app.service.ts # 根服務(wù)
└── main.ts # 應(yīng)用程序入口文件

main.ts 代碼

import { NestFactory } from '@nestjs/core';

async function bootstrap() {
  // 創(chuàng)建實例
  const app = await NestFactory.create();

  // 監(jiān)聽6688端口
  await app.listen(6688);
}
bootstrap();

通過 async 和 await 并使用了 NestFactory 核心類創(chuàng)建一個 Nest 應(yīng)用實例.NestFactory 暴露了一些靜態(tài)方法用于創(chuàng)建應(yīng)用實例,create() 方法返回一個實現(xiàn) INestApplication 接口的對象,.并且監(jiān)聽 6688 接口

開啟應(yīng)用

npm start

啟動 HTTP 服務(wù)器,項目會啟動并監(jiān)聽一個接口 6688,此時訪問 localhost:6688 或者 127.0.0.1:6688 可以看到 nest 信息

Nest 可以在創(chuàng)建適配器后使用任何 Node HTTP 框架. 有兩個支持開箱即用的 HTTP 平臺:express 和 fastify. 您可以選擇最適合您需求的產(chǎn)品.

express 和 fastify

當使用 express

npm i --save @nestjs/platform-express colors ip

main.ts

import { NestFactory } from '@nestjs/core';
import { NestExpressApplication } from '@nestjs/platform-express';
import { AppModule } from './app.module';
import { blue } from 'colors';
import { address } from 'ip';

async function bootstrap() {
  const app = await NestFactory.create<NestExpressApplication>(AppModule);
  const port = 6333;
  await app.listen(port, () => {
    console.log(
      blue(
        `當前服務(wù)運行在 \n http://localhost:${port} \n http://${address()}:${port}`,
      ),
    );
  });
}
bootstrap();

當使用 fastify

npm i --save @nestjs/platform-fastify

main.ts

import { NestFactory } from '@nestjs/core';
import {
  FastifyAdapter,
  NestFastifyApplication,
} from '@nestjs/platform-fastify';
import { AppModule } from './app.module';

async function bootstrap() {
  const app = await NestFactory.create<NestFastifyApplication>(
    AppModule,
    new FastifyAdapter(),
  );
  await app.listen(6688);
}
bootstrap();

不管是使用 express 還是 fastify,它都會暴露自己的應(yīng)用程序界面.它們分別是 NestExpressApplication 和 NestFastifyApplication.將類型傳遞給 NestFactory.create() 方法時,就可以訪問底層平臺 API,app 對象可以調(diào)用 express 或者 fastify 的方法.當然該類型可以不指定.

快速創(chuàng)建模塊

nest 主要有三個核心概念:模塊 Module, 控制器 Controller, 服務(wù)與依賴注入 Provider

  • 模塊 Module: 用于將代碼拆分為獨立的和可重用的模塊,例如用戶信息模塊,然后將該用戶模塊的控制器和服務(wù)集合進來,最后直接將用戶模塊導入到根 Module 就可以使用了.
  • 控制器 Controller: 負責處理客戶端傳入的請求參數(shù)并向客戶端返回響應(yīng)數(shù)據(jù).nest.js 提供許多 http 請求的裝飾器,如例如@Body(),@Post()等.控制器不需要定義任何諸如從客戶端獲取數(shù)據(jù)、驗證用戶輸入等工作,這些都是交給服務(wù) Provider 處理,通過把任務(wù)委托給各種服務(wù),可以讓控制器類更加精簡猎莲、高效.
  • 服務(wù) Provider :在這里處理所有請求執(zhí)行邏輯,在控制器中通過 constructor 函數(shù)以依賴注入的方式實現(xiàn).

直接用命令的方式創(chuàng)建模塊,控制器 , 服務(wù)

// 新建模塊
nest g mo user

// 新建controller
nest g co user

// 新建service
nest g s user

nest 命令全稱和簡稱

  • class (alias: cl) 類
  • controller (alias: co) 控制器
  • decorator (alias: d) 裝飾器
  • exception (alias: e) 異常捕獲
  • filter (alias: f) 過濾器
  • gateway (alias: ga) 網(wǎng)關(guān)
  • guard (alias: gu) 守衛(wèi)
  • interceptor (alias: i) 攔截器
  • middleware (alias: mi) 中間件
  • module (alias: mo) 模塊
  • pipe (alias: pi) 管道
  • provider (alias: pr) 供應(yīng)商
  • service (alias: s) 服務(wù)

cli 還有個好用的命令是nest info用來查詢當前項目的情況

創(chuàng)建路由

修改 user/user.controller.ts

import { Controller, Post, Body, Get } from '@nestjs/common';

@Controller('user')
export class UserController {
  @Get()
  public renderLoginPage(): string {
    return `<div style="color:blue">
        <form action="/collect/create" method="post">
            <div>
                <label for="name">Name:</label>
                <input name="name" type="text" id="name">
            </div>
            <div>
                <label for="mail">E-mail:</label>
                <input name="email" type="email" id="mail">
            </div>
            <div>
                <label for="msg">description:</label>
                <textarea name="description" id="description"></textarea>
            </div>
            <button type="submit">Send your message</button>
        </form>
    </div>`;
  }

  @Post('login')
  public login(
    @Body() loginInfo: { name: string; email: string; description: string },
  ): string {
    return `<div>${loginInfo.name} + ${loginInfo.email} + ${loginInfo.description}</div>`;
  }
}

重新執(zhí)行 start 命令,然后在http://localhost:6333/user進行表單填寫,然后就是進入 login 查看新息

Nest 請求裝飾器

  • @Get()
  • @Post()
  • @Put()
  • @Delete()
  • @Patch()
  • @Options()
  • @Head()
  • @All()

HTTP 沒有 All 方法,這是一個快捷方法用來接收任何類型的 HTTP 請求.

nodemon

nodemon 用來監(jiān)視 node.js 應(yīng)用程序中的任何更改并自動重啟服務(wù),非常適合用在開發(fā)環(huán)境中.

npm install --save-dev nodemon

在 nodemon.json 中添加配置

{
  "watch": ["src"],
  "ext": "ts,tsx",
  "ignore": [
    "src/**/*.spec.ts",
    "dist/*",
    "docs/*",
    "node_modules/*",
    "public/*",
    "test/*",
    "static/*"
  ],
  "delay": "2500",
  "exec": "ts-node -r tsconfig-paths/register ./src/main.ts"
}

在 package.json 中 scripts 中添加

"dev": "export NODE_ENV=development && nodemon",

隨便修改內(nèi)容會發(fā)現(xiàn)服務(wù)會自動重啟,適合用于開發(fā)模式

設(shè)置視圖-hbs模板引擎

Nest 默認使用 Express 庫,為了創(chuàng)建一個簡單的 MVC(模型 - 視圖 - 控制器)應(yīng)用程序,我們必須安裝一個模板引擎

npm install --save hbs

然后在 main.ts 文件中進行設(shè)置

  const app = await NestFactory.create<NestExpressApplication>(AppModule);

  // 設(shè)置public文件存放文件夾
  app.useStaticAssets(join(__dirname, '..', 'public'), {
    prefix: '/public/',
  });
  // 設(shè)置靜態(tài)文件存放文件夾
  app.useStaticAssets(join(__dirname, '..', 'static'), {
    prefix: '/static/',
  });
  // 設(shè)置視圖文件夾
  app.setBaseViewsDir(join(__dirname, '..', '/views'));
  // 設(shè)置視圖引擎
  app.setViewEngine('hbs');
  // 設(shè)置視圖部件的文件夾
  registerPartials(join(__dirname, '..', '/views/partials'));

新建 hbs 文件

hbs 的基本使用

  • {{value}}, handlebars 模板會自動匹配相應(yīng)的數(shù)值,對象甚至是函數(shù)
    <h1>{{name}}</h1>
    <p>{{content}}</p>
  • 分離 html 模塊,小模板分離
// 直接引入login_view.hbs
{{> login_view}}
  • hbs 的 foreach 循環(huán)
{{#each items}}
  {{label}}: {{@foo}}
{{/each}}
  • if 判斷
{{#if names.length}}
 <ul>
  {{#each names}}
   <li>{{this}}</li>
  {{/each}}
  </ul>
 {{/if}}

在 views 文件夾中新建 login.hbs

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <title>login</title>
  </head>
  <body>
    {{ login }}
  </body>
</html>

同時修改 user.controller.ts

import { Controller, Post, Get, Render } from '@nestjs/common';

@Controller('')
export class UserController {
  @Get('login')
  @Render('login.hbs')
  public login(): string {
    return '';
  }

  @Get('register')
  @Render('register.hbs')
  public register(): string {
    return '';
  }
}

添加 webpack 進行文件監(jiān)聽

npm i --save-dev webpack webpack-cli webpack-node-externals ts-loader

配置 webpack

然后,我們需要在根目錄創(chuàng)建一個 webpack.config.js.

const webpack = require('webpack');
const path = require('path');
const nodeExternals = require('webpack-node-externals');

module.exports = {
  entry: ['webpack/hot/poll?100', './src/main.ts'],
  watch: true,
  target: 'node',
  externals: [
    nodeExternals({
      whitelist: ['webpack/hot/poll?100'],
    }),
  ],
  module: {
    rules: [
      {
        test: /.tsx?$/,
        use: 'ts-loader',
        exclude: /node_modules/,
      },
    ],
  },
  mode: 'development',
  resolve: {
    extensions: ['.tsx', '.ts', '.js'],
  },
  plugins: [new webpack.HotModuleReplacementPlugin()],
  output: {
    path: path.join(__dirname, 'dist'),
    filename: 'server.js',
  },
};

熱模塊更換

在 main.ts 中添加 webpack 的配置

declare const module: any;

async function bootstrap() {
  const app = await NestFactory.create<NestExpressApplication>(AppModule);
  addEngine(app);

  const port = 6333;
  await app.listen(port, () => {
    console.log(blue(`http server is start at ===> http://localhost:${port}`));
  });

  if (module.hot) {
    module.hot.accept();
    module.hot.dispose(() => app.close());
  }
}
bootstrap();

在 package.json 中添加

"webpack": "webpack --config webpack.config.js"

關(guān)閉 node 進程,重新執(zhí)行 dev 和 webpack 命令

添加 swagger

npm install --save @nestjs/swagger swagger-ui-express

在 main.ts 中添加 swagger

import { DocumentBuilder, SwaggerModule } from '@nestjs/swagger';

......
  const options = new DocumentBuilder()
    .setTitle('平頭哥')
    .setDescription('后端API接口文檔')
    .setVersion('1.0')
    .addTag('nestjs')
    .build();

  const document = SwaggerModule.createDocument(app, options);
  SwaggerModule.setup('swagger', app, document);
......

然后輸入http://localhost:6333/swagger/就可以看到swagger自動生成的文檔

image

常用裝飾器

  • ApiProperty 標注 dto 的字段
  • ApiQuery 發(fā)起查詢的字段
  • ApiBody 請求主體輸入
  • ApiTags 添加指定標簽
  • ApiHeader 添加自定義標頭
  • ApiResponse 添加自定義響應(yīng)

官方文檔 - swagger

添加數(shù)據(jù)庫

為了與 SQL 和 NoSQL 數(shù)據(jù)庫集成,Nest 提供了 @nestjs/typeorm 包.Nest 使用 TypeORM 是因為它是 TypeScript 中最成熟的對象關(guān)系映射器( ORM ).因為它是用 TypeScript 編寫的,所以可以很好地與 Nest 框架集成.

為了開始使用它,我們首先安裝所需的依賴項.在本章中,我們將演示如何使用流行的 Mysql , TypeORM 提供了對許多關(guān)系數(shù)據(jù)庫的支持,比如 PostgreSQL 拼苍、Oracle、Microsoft SQL Server酒奶、SQLite,甚至像 MongoDB 這樣的 NoSQL 數(shù)據(jù)庫.我們在本章中介紹的過程對于 TypeORM 支持的任何數(shù)據(jù)庫都是相同的.您只需為所選數(shù)據(jù)庫安裝相關(guān)的客戶端 API 庫.

npm install --save @nestjs/typeorm typeorm mysql moment

修改 app.module.ts

import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';

@Module({
  imports: [TypeOrmModule.forRoot()],
})
export class AppModule {}

創(chuàng)建 ormconfig.json,可以將 forRoot()配置抽離出來,不傳入沒有任何選項調(diào)用 forRoot()

{
  "type": "mysql",
  "host": "localhost",
  "port": 3306,
  "username": "root",
  "password": "root",
  "database": "test",
  "entities": ["dist/**/*.entity{.ts,.js}"], // 自動加載實體
  "synchronize": true
}

一旦完成,TypeORM 連接和 EntityManager 對象就可以在整個項目中注入(不需要導入任何模塊)

創(chuàng)建 user/entity/user.entity.ts

import { Entity, Column, OneToMany, PrimaryGeneratedColumn } from 'typeorm';
import { ApiProperty } from '@nestjs/swagger';

@Entity({ name: 'user' })
export class User {
  @ApiProperty()
  @PrimaryGeneratedColumn()
  public id: number;

  @ApiProperty()
  @Column({ length: 40 })
  public account: string;

  @ApiProperty()
  @Column({ length: 100 })
  public avatarUrl: string;

  @ApiProperty()
  @Column({ length: 40 })
  public name: string;

  @ApiProperty()
  @Column({ length: 40 })
  public role: string;

  @ApiProperty()
  @Column('int')
  public createdAt: number;

  @ApiProperty()
  @Column('int')
  public updatedAt: number;

  @ApiProperty()
  @Column({ length: 250 })
  public password: string;
}

user 的增刪改查

修改 user/user.controller.ts

import { ApiTags } from '@nestjs/swagger';
import {
  Controller,
  Get,
  Param,
  Post,
  Body,
  Delete,
  Put,
  Render,
} from '@nestjs/common';
import { User } from './entity/user.entity';
import { UserService } from './user.service';

interface IResult {
  code: number;
  message: string;
  data?: any;
}

@Controller('')
export class UserController {
  constructor(private readonly userService: UserService) {}

  @Get('login')
  @Render('login.hbs')
  public renderLogin(): string {
    return '';
  }

  @Get('register')
  @Render('register.hbs')
  public async renderRegister() {
    return '';
  }

  /**
   * 用戶注冊
   * @param user
   */
  @ApiTags('用戶注冊')
  @Post('api/user/register')
  public async register(
    @Body()
    user: {
      account: string;
      password: string;
    },
  ): Promise<IResult> {
    const result = await this.userService.register(user);
    return { code: 200, message: '注冊成功', data: result };
  }

  @ApiTags('刪除用戶')
  @Delete('api/user/:id')
  async remove(@Param() id: number): Promise<IResult> {
    const data = await this.userService.remove(id);
    return { code: 200, message: '刪除用戶成功', data };
  }

  @ApiTags('更新用戶')
  @Put('api/user/:id')
  async update(@Param() id: number, updateInput: User): Promise<IResult> {
    const data = await this.userService.update(id, updateInput);
    return { code: 200, message: '更新用戶成功', data };
  }

  @ApiTags('查找用戶')
  @Get('api/user/:id')
  async findOne(@Param() id: number): Promise<IResult> {
    const data = await this.userService.findOneWithPostsById(id);
    return { code: 200, message: '查詢用戶成功', data };
  }

  @ApiTags('查找全部用戶')
  @Get('api/user/')
  async findAll(): Promise<IResult> {
    const data = await this.userService.findAll();
    return { code: 200, message: '查詢所有用戶成功', data };
  }
}

修改 user/user.service.ts

import { HttpException, Injectable, OnModuleInit } from '@nestjs/common';
import { User } from './entity/user.entity';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import * as moment from 'moment';

@Injectable()
export class UserService implements OnModuleInit {
  async onModuleInit() {
    if (await this.findOneByAccount('admin')) {
      return;
    }
    // 初始化系統(tǒng)管理員
    const admin = this.userRepository.create({
      account: 'admin',
      password: 'admin',
      name: '系統(tǒng)管理員',
      role: 'admin',
      avatarUrl: '',
      createdAt: moment().unix(),
      updatedAt: moment().unix(),
    });
    await this.userRepository.save(admin);
  }
  constructor(
    @InjectRepository(User)
    private readonly userRepository: Repository<User>,
  ) {}

  public async findAll(): Promise<User[]> {
    return await this.userRepository.find();
  }

  public async register(createUserData: any): Promise<User> {
    const user = await this.findOneByAccount(createUserData.account);
    if (user) {
      throw new HttpException('賬號已存在', 409);
    }
    const assign = {
      ...createUserData,
      name: '系統(tǒng)管理員',
      role: 'admin',
      avatarUrl: '',
      createdAt: moment().unix(),
      updatedAt: moment().unix(),
      password: createUserData.password,
    };
    return await this.userRepository.save(assign);
  }

  /**
   * 用戶登錄
   * @param account 登錄賬號
   * @param password 登錄密碼
   */
  public async login(account: string, password: string): Promise<User> {
    const user = await this.findOneByAccount(account);
    if (!user) {
      throw new HttpException('登錄賬號有誤', 406);
    }
    if (!user.password) {
      throw new HttpException('登錄密碼有誤', 409);
    }
    return user;
  }

  /**
   * 刪除用戶
   * @param id 用戶ID
   */
  public async remove(id: number): Promise<void> {
    const existing = await this.userRepository.findOne(id);
    if (!existing) {
      throw new HttpException(`刪除失敗关摇,ID 為 '${id}' 的用戶不存在`, 404);
    }
    await this.userRepository.remove(existing);
  }

  /**
   * 更新用戶
   * @param id 用戶ID
   * @param updateInput updateInput
   */
  public async update(id: number, updateInput: User) {
    const existing = await this.userRepository.findOne(id);
    if (!existing) {
      throw new HttpException(`更新失敗杖小,ID 為 '${id}' 的用戶不存在`, 404);
    }
    if (updateInput.account) {
      existing.account = updateInput.account;
    }
    if (updateInput.password) {
      existing.password = updateInput.password;
    }
    if (updateInput.name) {
      existing.name = updateInput.name;
    }
    return await this.userRepository.save(existing);
  }

  /**
   * 通過登錄賬號查詢用戶
   * @param account 登錄賬號
   */
  public async findOneByAccount(account: string): Promise<User> {
    return await this.userRepository.findOne({ account });
  }

  /**
   * 查詢用戶及其帖子的信息
   * @param id 用戶ID
   */
  public async findOneWithPostsById(id: number): Promise<User> {
    return await this.userRepository.findOne(id, { relations: ['posts'] });
  }
}

輸入http://localhost:6333/register,填寫注冊信息進行注冊,實際只有賬號和密碼兩個字段是有效字段

[圖片上傳失敗...(image-d74cc1-1577760059534)]

這里將 render 和 api 放到了一起,這是為了湊成一個文件

Doc

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末愚墓,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子昂勉,更是在濱河造成了極大的恐慌浪册,老刑警劉巖,帶你破解...
    沈念sama閱讀 212,383評論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件岗照,死亡現(xiàn)場離奇詭異村象,居然都是意外死亡,警方通過查閱死者的電腦和手機攒至,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,522評論 3 385
  • 文/潘曉璐 我一進店門厚者,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人迫吐,你說我怎么就攤上這事库菲。” “怎么了志膀?”我有些...
    開封第一講書人閱讀 157,852評論 0 348
  • 文/不壞的土叔 我叫張陵熙宇,是天一觀的道長。 經(jīng)常有香客問我溉浙,道長烫止,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,621評論 1 284
  • 正文 為了忘掉前任放航,我火速辦了婚禮烈拒,結(jié)果婚禮上圆裕,老公的妹妹穿的比我還像新娘广鳍。我一直安慰自己,他們只是感情好吓妆,可當我...
    茶點故事閱讀 65,741評論 6 386
  • 文/花漫 我一把揭開白布赊时。 她就那樣靜靜地躺著,像睡著了一般行拢。 火紅的嫁衣襯著肌膚如雪祖秒。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,929評論 1 290
  • 那天舟奠,我揣著相機與錄音竭缝,去河邊找鬼。 笑死沼瘫,一個胖子當著我的面吹牛抬纸,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播耿戚,決...
    沈念sama閱讀 39,076評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼湿故,長吁一口氣:“原來是場噩夢啊……” “哼阿趁!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起坛猪,我...
    開封第一講書人閱讀 37,803評論 0 268
  • 序言:老撾萬榮一對情侶失蹤脖阵,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后墅茉,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體命黔,經(jīng)...
    沈念sama閱讀 44,265評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,582評論 2 327
  • 正文 我和宋清朗相戀三年躁锁,在試婚紗的時候發(fā)現(xiàn)自己被綠了纷铣。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,716評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡战转,死狀恐怖搜立,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情槐秧,我是刑警寧澤啄踊,帶...
    沈念sama閱讀 34,395評論 4 333
  • 正文 年R本政府宣布,位于F島的核電站刁标,受9級特大地震影響颠通,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜膀懈,卻給世界環(huán)境...
    茶點故事閱讀 40,039評論 3 316
  • 文/蒙蒙 一顿锰、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧启搂,春花似錦硼控、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,798評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至疑苫,卻和暖如春熏版,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背捍掺。 一陣腳步聲響...
    開封第一講書人閱讀 32,027評論 1 266
  • 我被黑心中介騙來泰國打工撼短, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人挺勿。 一個月前我還...
    沈念sama閱讀 46,488評論 2 361
  • 正文 我出身青樓曲横,卻偏偏與公主長得像,于是被迫代替她去往敵國和親满钟。 傳聞我的和親對象是個殘疾皇子胜榔,可洞房花燭夜當晚...
    茶點故事閱讀 43,612評論 2 350

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