Node.js学习第四、五天笔记之myAlbums项目实战

MVC

  • 指的是:models views controller;
    • models:用于后台数据的查找;
    • views:视图,用于存储浏览器页面的文件;
    • controller:管理者,控制者;用于二者之间的控制;

myAlbum项目开发

  • 创建文件夹:命令:mkdir
    • models:提供数据;
    • views:模板文件;
    • controller:控制器;
    • uploads:上传的文件
    • public:静态资源
  • 创建文件:命令:touch ; window命令行中使用type nul>
    • app.js:入口文件,创建服务器;
  • package.json文件:记录当前项目依赖;命令npm init -y;
  • 安装项目模块框架:命令npm install --save-dev express ejs formidable
  • controller文件夹下创建router.js文件;作为一个路由的控制器;
    • 知识点:在app.js中引入自定义模块,必须添加相对路径;如:const router=require("./controller/router");
    • 在router.js中设置代码输出参数;
     exports.showIndex=function (req, res) {
         res.render("index")
     };
    
    • 在app.js中直接引入:router.showIndex获取匿名函数;
  • 静态资源文件加载
    • 设置静态资源在public文件下:app.use(express.static("./public"));;即相对路径都在public目录下;
    • 在ejs文件中,通过link引入css文件和通过script引入js文件;都会发送对应的请求;请求地址为href和src中的路径地址;
    • 在通过get请求,打开index.ejs文件后,会在页面中继续发送请求;页面想要有css样式和js动效,必须保证css文件和js文件能够正常引入;如何在页面中渲染打开css文件;css的引入地址是很重要的;
    • 代码:app.use(express.static("./public"));中将静态资源的目录设置在public目录下,即所引入的css文件和js文件必须在此目录下添加相对路径,然后找到文件才能打开;
    • 所以,将css文件和js文件放在public文件夹下,在引入时添加相对路径;如:<link href="/css/bootstrap.css" rel="stylesheet"><script src="/js/bootstrap.js"></script>;注意:css前斜杠最好添加上,若不添加,会被拼接在地址的后面,会出错,所以必须添加;
    • 在地址栏中输入地址localhost:8080/css/bootstrap.css也可以打开引入的css文件;
  • 静态资源设置的含义
    • 代码:app.use(express.static("./public"))
    • 含义:在express中,设置静态资源的请求路径为public目录下;
    • 验证:在地址栏中输入localhost:8080/index.html地址,指的含义是查找到public目录下的index.html,打开并渲染到页面上;
    • 在index.html文件中有link引入的css文件;如:<link href="/css/bootstrap.css">;其中link的href会发送请求;相当于在地址栏中输入localhost:8080/css/bootstrap.css地址;即,在public目录下查找css文件夹下的bootstrap.css文件,打开并渲染到页面中;
    • 结论:
      • 设置了静态资源的路径;则在地址栏中寻找的文件都是在public目录下查找,如果查找到,则渲染,查找不到,则会查看其它的请求是否存在此地址;
      • 打开html或ejs文件中,通过link或script或img中的href或src等引入文件,都会向服务器发送请求;会默认在public目录下查找;
  • 简单的实现index.ejs文件的页面打开渲染:
    • index.ejs文件,通过设置get请求:app.get("/",function(req,res){ res.render("index")};);即:在地址栏中输入"/",后可执行匿名函数;在匿名函数中通过res.render来默认打开views目录下的index.ejs文件;
    • 打开index.ejs文件后,里面引入的href和src再次发送多个请求;在设置的静态资源目录public文件夹下查找文件;然后打开渲染;
    • 代码:
      • index.ejs文件代码:
       <!DOCTYPE html>
       <html lang="zh-CN">
       <head>
           <meta charset="utf-8">
           <title>模板</title>
           <link href="css/bootstrap.css" rel="stylesheet">
       </head>
       <body>
       <h1>你好,世界!</h1>
       <script src="js/jquery.js"></script>
       <script src="js/bootstrap.js"></script>
       </body>
       </html>
      
      • app.js服务器代码:
       const express=require("express");
       const app=express();
       const router=require("./controller/router");//引入自定义模块,必须添加相对路径;
       app.listen(8080);
       
       //发送请求,静态渲染页面
       app.use(express.static("./public"));
       //设置模板引擎
       app.set("view engine","ejs");
       //通过"/"来发送请求,打开views下的index.ejs文件
       app.get("/",router.showIndex);
      
      • router.js管理器代码:
       exports.showIndex=function (req, res) {
           res.render("index")
       };
      

项目开发

  • 搭建静态页面index.ejs;利用bootstrap模板来创建页面布局;
    • 页面中相册的个数取决于uploads目录下文件夹的个数;
    • 在页面中利用ejs模板创建for循环,在服务器中通过render()传送参数;即在router.js管理器中获取参数;router.js再去models中获取数据;然后最终传送给views中ejs页面;
  • 获取磁盘中uploads目录下文件夹的个数;
    • 在models中files.js中获取数据,导出数据;利用fs文件系统中的readdir()来获取文件夹下所有的文件,再通过fs.stat()获取每个文件的状态stats,判断stats.isDirectory()是否为true;如果文件是文件夹,则返回true;
    • 通过自执行函数和递归函数,将异步强制变成同步;然后待遍历完,输出数组;
    • 在匿名函数中如何输出文件:通过callback参数;注意传出的数据包括err错误信息;
    • 在router.js中引入自定义模块files.js,添加相对路径;通过匿名函数中的参数拿到文件夹信息;然后通过res.render()传送给ejs文件使用;
    • 注意点:
      • 在使用fs.readdir(path,()=>{})时,path路径为"./uploads",其中"./"拿到的是根目录;不是"../"拿到根目录;
      • 数据的输出通过回调函数,将异步操作中的结果输出,但要注意输出不同时刻的err信息;在成功输出数据时,赋值为null,这样在if(err)条件语句中,就不会走语句;
    • 代码:
      • ejs代码:
       <div class="container">
           <div class="row">
               <% for(var i=0; i<albums.length; i++){%>
                   <div class="col-xs-6 col-md-3">
                       <a href="/" class="thumbnail">
                           <img src="/img/01.jpg" alt="文件夹图片">
                       </a>
                       <h5 style="text-align: center;"><%= albums[i]%></h5>
                   </div>
               <% }%>
           </div>
       </div>
      
      • app.js代码:app.get("/",router.showIndex);
      • router.js代码:
       //引入models中的files.js模块;
       const modFiles=require("../models/files");
       //显示首页
       exports.showIndex=function (req, res) {
           modFiles.showAllAlbums(function(err,albums){
               if(err){
                   res.send(err);
                   return;//阻断程序执行;
               }
               res.render("index",{
                   albums
               })
           });
       };
      
      • files.js代码:
       //用于生产数据,然后输给router.js使用;
       const fs=require("fs");
       exports.showAllAlbums=function (callback) {//数据以回调函数的形式输出;
           fs.readdir("./uploads",(err,files)=>{//地址为根目录下的地址;
               if(err){
                   callback(err,null);
                   return;
               }
               var ary=[];
               //把异步操作强制变成了同步操作;
               (function interator(i){
                   if(i>=files.length){
                       callback(null,ary);//null代表不会走if(err)条件;
                       return;//阻断程序执行;
                   }
                   fs.stat("./uploads/"+files[i],(err,stats)=>{
                       if(err){
                           callback(err,null);
                           return;
                       }
                       if(stats.isDirectory()){
                           ary.push(files[i]);
                       }
                       interator(++i);
                   })
               })(0);
           });
       };
      
  • 点击文件夹后发送请求,打开文件夹下的所有文件;
    • 发送请求:在地址栏中输入文件夹名字后,即发送了get请求,使其获的数据并打开渲染;在index.ejs中每一个文件夹都在一个a标签中,设置href为<a href="/<%= albums[i]%>" class="thumbnail">,即根据文件夹的名字不同,发送不同的请求;跟地址栏中输入localhost:8080/大学是一样的效果;从而实现页面的跳转;
    • 打开页面;需要新建一个showImg.ejs文件,里面是新的内容;在发送/:albumsImg请求后,在files.js中打开该文件夹,获取文件夹下所有的文件,通过fs.isFile()筛选出不是文件夹的文件;通过匿名函数传出;然后渲染到页面上,展示出相应个数和名字的图集;
    • 在页面渲染中打开img图片;在files.js中只能拿到文件夹下的文件个数和文件名称;无法打开渲染;res.render的作用是,打开showImg.ejs文件,并且给其传数据;只能渲染页面,不能打开img图片;
    • 呈现img图片在页面中,需要img标签中的src再次发送强求,服务器接受进行响应;所以,需要再设置静态资源到./uploads目录下,指的是,发送来的请求闲杂public目录下找文件,如果找不到,就到uploads目录下查找,找到文件,渲染打开文件;
    • 注意1:img中src的路径需要注意;当showImg.ejs被渲染到页面上的时候,src才开始发送请求;包括css和js也会发送请求;
      • img的src设置时有两种方式;1)<img src="/<%= albumsImg%>/<%= albums[i]%>" alt="文件夹图片">,在地址中添加文件夹路径;2)<img src="<%= albums[i]%>" alt="文件夹图片">,在地址中不添加文件夹路径但是不能添加"/",可能的原因是在地址栏中已经存在http://localhost:8080/大学/;
      • css和js文件src中必须添加"/",不能省略;
    • 注意2:使用req.params.albumsImg获取请求地址时,除了文件夹地址,还会得到favicon.ico,所以需要在获取文件夹下文件的函数中,阻止favicon.ico运行;
    • 代码:
      • showImg.ejs代码:
       <!DOCTYPE html>
       <html lang="zh-CN">
       <head>
           <meta charset="utf-8">
           <title>展示图片</title>
           <link href="/css/bootstrap.css" rel="stylesheet">
       </head>
       <body>
       <% include include/header.ejs%>
       <section class="container">
           <ol class="breadcrumb">
               <li><a href="/">全部相册</a></li>
               <li class="active"><%= albumsImg%></li>
           </ol>
       </section>
       <div class="container">
           <div class="row">
               <% for(var i=0; i<albums.length; i++){%>
                   <div class="col-xs-6 col-md-3">
                       <span class="thumbnail">
                           <img src="/<%= albumsImg%>/<%= albums[i]%>" alt="文件夹图片">
                       </span>
                       <h5 style="text-align: center;"><%= albumsName[i]%></h5>
                   </div>
               <% }%>
           </div>
       </div>
       <script src="/js/jquery.js"></script>
       <script src="/js/bootstrap.js"></script>
       </body>
       </html>
      
      • app.js代码:
       const express=require("express");
       const app=express();
       const router=require("./controller");//引入自定义模块,必须添加相对路径;因为controller创建了package.json文件,在里面设置了main属性,设置默认的入口文件为router.js文件;
       app.listen(8080);
       
       //发送请求,静态渲染页面
       //1.设置静态资源路径在public目录下,用于渲染引入的css文件和js文件;
       app.use(express.static("./public"));
       //2.设置静态资源路径在uploads目录下,用于渲染img图片;
       app.use(express.static("./uploads"));
       
       //设置模板引擎
       app.set("view engine","ejs");
       //通过"/"来发送请求,打开views下的index.ejs文件
       app.get("/",router.showIndex);
       //发送get请求:地址:"/大学",打开views下的showImg.ejs文件;
       app.get("/:albumsImg",router.showImg);
      
      • router.js代码:
       //显示相册文件夹中的图片
       exports.showImg=function (req, res) {
           var albumsImg=req.params.albumsImg;
           modFiles.showAlbumsImgs(albumsImg,function (err,albums,albumsName) {
               //如果有错误,则显示在页面上,并阻断程序执行;
               if(err){
                   res.send(err);//send后面可以写return;
                   return;//必须阻断程序执行;
               }
               res.render("showImg",{
                   albumsImg,
                   albums,
                   albumsName
               })
           });
       };
      
      • files.js代码:
       //获取地址栏中发送的地址文件夹下的所有图片文件;生成数组导出;
       exports.showAlbumsImgs=function (albumsImg, callback) {
           //albumsImg是地址栏中的文件夹名称;callback用来导出数据;
           //读取文件夹下的文件
           fs.readdir("./uploads/"+albumsImg,function (err, files) {
               if(err){
                   callback("读取文件夹失败",null,null);
                   return;
               }
               var albums=[];
               var albumsName=[];
               (function interator(i) {
                   if(i>=files.length){
                       callback(null,albums,albumsName);
                       return;
                   }
                   fs.stat("./uploads/"+albumsImg+"/"+files[i],function (err, stats) {
                       if(err){
                           callback("读取文件夹下的文件失败",null,null);
                           return;
                       }
                       if(stats.isFile()){
                           //成立,则证明不是文件夹
                           albums.push(files[i]);
                           albumsName.push(path.parse(files[i]).name);
                       }
                       interator(++i);
                   })
               })(0);
           })
       };
      
  • 页面的操作:
    • 提炼出两个ejs页面中的公共的代码,放在views下的include文件夹下的header.ejs文件中;这样在文件中引入此文件即可;
    • 优点:当页面公共部分的代码,发生变化,只需在header.ejs文件中修改即可,否则,还需分别再两个文件中修改;
    • 引入include.ejs文件代码:<% include include/header.ejs%>,其中include/header.ejs为相对路径,无需加引号;
  • 图片上传功能
    • 思路:
      • 创建form.ejs表单页面;通过form表单来提交数据;
      • 发送get请求,通过header.ejs中的上传a标签href设置地址,点击发送请求;打开form.ejs页面;传送数据;用于select表单中获取文件夹数据;
      • 发送post请求,通过表单中submit提交按钮,设置form中的action和method;点击发送post请求;
      • 在router.js中通过formidable模块来获取上传的数据;
        • 新建form对象;var form= new formidable.IncomingForm()
        • 设置上传地址;form.uploadDir="./uploads/"
        • 通过form.parse()拿数据;=》fields:表单上传参数组成的对象;files:表单file中name组成的对象;用于获取上传图片的路径名字;以及上传之前的名字;
        • 通过files.tupian.size,拿到上传文件的大小,然后进行判断,如果大于某值,则用fs.unlink()删除已经上传的文件;注意,在条件判断中设置return;阻断程序向下运行;
        • 通过fs.rename()将oldpath改为newpath,修改原来文件名字并移动该文件到新的路径下;
      • 修改成功后,打开对应文件夹的图集;调用modFiles.showAlbumsImgs(albumsImg,function (err,albums,albumsName){})
      • 修改成功后,可以通过 res.redirect("/中学")来进行重定向页面跳转;
    • 注意点:
      • 设置get请求"/upload"时,必须放在app.get("/:albumsImg",router.showImg);前面,否则,不会走该请求;必须将严格的请求放在不严格的请求的前面;
      • form表单中,seclect和file必须设置name值,否则无法获取数据;seclect的name值用来获取放在哪个文件夹下,file的name值是用来作为files对象中属性名来获取上传文件的数据的;
      • form表单中的action设置请求地址,method设置post请求,enctype设置大文件下的类型;
      • 利用formidable模块获取files对象后,path属性拿到的是路径加文件名;作为oldpath;newpath包含相对路径和文件名;相对路径设置为uploads下的对应文件夹中;
      • 在修改名字后,原来上传的文件会被移动到新的路径下;
      • 在设置上传地址时地址后面必须加"/",否则,无法使用;如form.uploadDir="./uploads/";
      • 注意异步和同步问题;
    • 代码:
      • form-upload.ejs代码:
       <!DOCTYPE html>
       <html lang="zh-CN">
       <head>
           <meta charset="utf-8">
           <title>表单上传文件</title>
           <link href="/css/bootstrap.css" rel="stylesheet">
       </head>
       <body>
       <% include include/header.ejs%>
       <section class="container">
           <form action="/doupload" method="post" enctype="multipart/form-data">
               <div class="form-group">
                   <label for="wenjian">相册目录</label>
                   <select class="form-control" name="wenjianjia" id="wenjian">
                       <% for(var i=0; i<albums.length; i++){%>
                           <option><%= albums[i]%></option>
                       <%}%>
                   </select>
               </div>
               <div class="form-group">
                   <label for="InputFile">上传文件路径</label>
                   <input type="file" id="InputFile" name="tupian">
               </div>
               <button type="submit" class="btn btn-primary">上传</button>
           </form>
       </section>
       <script src="/js/jquery.js"></script>
       <script src="/js/bootstrap.js"></script>
       </body>
       </html>
      
      • app.js代码:
       /发送get请求:地址:"/upload",打开views下的form.ejs文件;
       app.get("/upload",router.upload);
       //发送post请求,地址:"/doupload",上传文件;
       app.post("/doupload",router.doUpload);
       //以上代码必须放在下面代码前面;
       //发送get请求:地址:"/大学",打开views下的showImg.ejs文件;
       app.get("/:albumsImg",router.showImg);
      
      • router.js代码:
       //上传文件获取数据
       exports.doUpload=function (req, res) {
           //新建一个form对象
           var form= new formidable.IncomingForm();
           //设置上传地址
           form.uploadDir="./uploads/";
           //解析文件
           form.parse(req,(err,fields,files)=>{
               //修改文件名,放在指定文件夹下
               var oldpath=files.tupian.path;
               var newpath=form.uploadDir+fields.wenjianjia+"/"+files.tupian.name;
               fs.rename(oldpath,newpath,function (err) {
                   if(err){
                       res.send("修改名字失败");
                       return;
                   }else{
                       //res.send("上传成功");//注意异步问题;所以此代码不能写在外面;
                       //当上传成功后,跳转到相应的文件夹中打开;
                       var albumsImg=fields.wenjianjia;
                       modFiles.showAlbumsImgs(albumsImg,function (err,albums,albumsName) {
                           //如果有错误,则显示在页面上,并阻断程序执行;
                           if(err){
                               res.send(err);//send后面可以写return;
                               return;//必须阻断程序执行;
                           }
                           res.render("showImg",{
                               albumsImg,
                               albums,
                               albumsName
                           })
                       });
                   }
               })
           });
       };
      
  • 接盘侠
    • 在最后设置use请求,请求地址为"/",即所有的地址都可以进入请求;渲染打开404.ejs文件,显示404页面;
    • 代码:
     //设置404页面,用来接底
     app.use("/",function (req, res) {
         res.render("404");//打开404.ejs文件;
     });
    
    • 利用middleware中间件来设置错误流,当进入一个请求后,如果出现err,则通过next(),来向下接着请求,最终到达use请求,渲染404页面;
    • 在router.js文件中所有请求的匿名函数;均要设置next,当err情况下,设置next(),并阻断程序执行;
    • files.js文件中err不需要设置next(),因为通过callback已经将err返回到router.js中;
    • 这样设置,也可以解决地址具体地址和广泛地址的影响;
    • 注意:send()后面不能设置任何东西;可以写return;

项目开发中的架构格局

  • 文件分类及作用
    • MVC结构:
      • M:models:用来获取后台的数据库,通过exports输出给controller管理器;
        • 创建files.js文件,作为后台数据的模块;通过exports来传出数据,在router.js管理器中引入此模块,用于获取传出数据;
      • V:views: 目录下存在ejs文件,作为浏览器视图的渲染文件;
        • 存储ejs文件,用于页面的打开渲染;
        • 创建include文件夹,里面创建header.ejs文件,作为ejs文件的公共部分代码;通过<% include include/header.ejs%>引入到其他文件中;
      • C:controller:管理器;用来连接models和views;
        • 作用:作为一个管理者,在views中通过render来打开ejs文件,在数据库或models中拿数据;
        • 创建router.js文件,作为数据的管理器;通过exports来传出数据;在app.js中引入此模块来获取数据;
        • 创建package.json文件,通过设置里面的main属性,来设置默认入口文件router.js;则在app.js服务器文件中引入模块时,可以直接引入controller文件夹,如const router=require("./controller");
      • 三者之间的关系:
        • 当服务器中接受到浏览器发送的请求后,向controller管理器请求;如代码:app.get("/",router.showIndex);;router.js中设置匿名函数;渲染页面;
        • 当浏览器中需要uploads文件夹下的文件夹个数时,向controller管理器要数据;controller再向models后台数据库中查找获取;models数据也通过exports输出数据;
    • public文件夹:用于存储静态文件;如css,js文件;通过在服务器中设置静态渲染来引用文件;
    • app.js:为入口文件,用于创建服务器来前后台交互;
    • package.json:用于记录项目依赖的文件;
    • readme.md:读者读的文档,用于解读项目;
  • 请求及目的
    • get请求,是为了渲染打开页面;
      • get-"/"=>打开index.ejs;即,打开图片首页,根据uploads下文件夹的个数,呈现出相应个数的图集;
      • get-"/:albumsImg" => 打开showImg.ejs;即呈现出每个albumsImg文件夹下的图片;
      • get-"/upload" => 打开form上传文件表单;用于上传图片文件;
    • post请求,是真正做一些功能的,如上传文件;
      • post-"/doupload" => 通过表单中的submit提交按钮,来发送post请求,进行图片文件的上传;
    • use请求:请求地址设置为"/",可以省略,作为接盘侠;
      • use-"/" => 打开404.ejs文件,呈现404页面,配合middleware中间件使用;

项目开发中的知识点

  • 在controller文件夹中创建package.json文件,里面设置main属性,来设置默认的入口文件为router.js,这样在app.js服务器中引入模块时,只引入文件夹controller;即:const router=require("./controller");
  • 在项目开发中如果匿名函数中存在err错误代码,必须设置相应的条件语句,然后传出错误信息;后面一定要加return,阻断程序执行;
  • 使用req.params.albumsImg获取请求地址时,除了文件夹地址,还会得到favicon.ico,所以需要在获取文件夹下文件的函数中,阻止favicon.ico运行;
  • 1M等于1024K,1K等于1024字节,文件上传时,通过files.tupian.size来获取上传文件的大小,单位为字节;
  • 接盘use请求和middleware的设置
    • use请求地址为"/",可以省略;当所有请求都不成立的时候,最后请求use的匿名函数,打开404页面文件;
    • 前提是在每个请求的匿名函数中设置middleware中间件;即next();当err时设置next(),并阻断程序执行;
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,362评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,330评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,247评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,560评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,580评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,569评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,929评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,587评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,840评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,596评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,678评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,366评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,945评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,929评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,165评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,271评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,403评论 2 342

推荐阅读更多精彩内容