基于React和Node實(shí)現(xiàn)一個食物熱量參考應(yīng)用

利用業(yè)余時間同廉,自己做了一個食物熱量參考網(wǎng)站苟穆,數(shù)據(jù)參考自一個app食物庫藤肢。技術(shù)棧使用了sass+react+react-router+redux+antd+express+mongoose

node-health

一愧旦、How To Use

下載

首先將代碼clone到本地

git clone https://github.com/mescalchuan/node-health.git

安裝依賴包

cd node-health && npm i

引入數(shù)據(jù)并啟動mongodb服務(wù)

要確保你已經(jīng)安裝了mongodb枢贿,然后在自己電腦上新建數(shù)據(jù)庫文件夾(我的是E:\mongodbData\db)。在mongodb安裝目錄的bin文件夾下啟動mongodb服務(wù):

mongodb --dbpath="E:\mongodbData\db" --port 27017 -journal

啟動成功后举户,數(shù)據(jù)庫是沒有任何數(shù)據(jù)的器联,我們需要將一些默認(rèn)數(shù)據(jù)導(dǎo)入進(jìn)來二汛,我已經(jīng)將這些數(shù)據(jù)導(dǎo)出成json了,你只需要重開一個命令行并輸入:

mongoexport -d db -c category -o "E:node-health\db\category.json" --type json --port 27017
mongoexport -d db -c food -o "E:node-health\db\food.json" --type json --port 27017

這里推薦一個超輕量級數(shù)據(jù)庫操作工具:adminMongo拨拓。

adminMongo

如果數(shù)據(jù)導(dǎo)入成功肴颊,那么在foodcategory表里會看到導(dǎo)入進(jìn)來的數(shù)據(jù),否則渣磷,你需要在adminMongo里自己手動創(chuàng)建這兩張表婿着,然后再導(dǎo)入數(shù)據(jù)就可以了。

啟動前端服務(wù)

cd /e/node-health
webpack --watch

用戶:http://localhost:8888
管理員:http://localhost:8888/admin.html醋界,用戶名和密碼均為admin

啟動后臺服務(wù)

cd /e/node-health
node app

項(xiàng)目截圖

node-health
分類
推薦食物
高熱量食物
食物詳情
搜索結(jié)果頁
管理員登錄頁
后臺管理頁
添加食物
食物詳情
修改食物
刪除食物

二竟宋、說明

該項(xiàng)目適用于有一定前端基礎(chǔ)(包括reactredux)和node.js基礎(chǔ)的同學(xué),如果你正在學(xué)習(xí)node形纺,但又無法將一系列知識體系串起來丘侠,那么本項(xiàng)目同樣適合你~

三、環(huán)境搭建

整體目錄結(jié)構(gòu)

  • controller:后端控制層
  • db:導(dǎo)出的數(shù)據(jù)庫json文件
  • model:后端模型層
  • router:后端路由
  • src:前端代碼
  • admin.ejs:管理員頁面(模板引擎)
  • app.js:后端根文件
  • index.ejs:用戶頁面(模板引擎)
  • webpack.config.js:webpack配置文件

前端

目錄結(jié)構(gòu)如下:

從頭搭建webpack吧逐样,由于用到了后臺模板引擎蜗字,因此我們就不再單獨(dú)用webpack啟動一個服務(wù)了打肝。

var path = require("path");
var webpack = require("webpack");

var OpenBrowserPlugin = require("open-browser-webpack-plugin");
var ExtractTextPlugin = require("extract-text-webpack-plugin");
var OptimizeCSSPlugin = require("optimize-css-assets-webpack-plugin");
//提高loader的解析速度
var HappyPack = require("happypack");
var CommonsChunkPlugin = webpack.optimize.CommonsChunkPlugin;
var NoEmitOnErrorsPlugin = webpack.NoEmitOnErrorsPlugin;
var UglifyJsPlugin = webpack.optimize.UglifyJsPlugin;

//externals配置的對象在生產(chǎn)環(huán)境下會自動引入CDN的對象,不會將node_modules下的文件打包進(jìn)來
var externals = {
    "React": "react",
    "ReactDOM": "react-dom"
}
//配置多入口文件挪捕,包括用戶和管理員
var entry = {
    "index": "./src/index.js",
    "admin": "./src/admin.js"
};

//最基本的webpack配置
var webpackConfig = {
    entry: entry,
    output: {
        path: path.resolve(__dirname, "src/build"),
        filename: "[name].bundle.js"
    },
    externals: externals,
    devtool: "source-map",
    module: {
        rules: [
            {
                test: /\.js$/,
                exclude: /node_modules/,
                use: ["happypack/loader?id=babel"]
            },
            {
                test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
                loader: "url-loader",
                options: {
                    limit: 8192,
                    name: "[name].[ext]"
                }
            }, {
                test: /\.css$/,
                exclude: /node_modules/,
                use: ExtractTextPlugin.extract({
                    fallback: "style-loader",
                    use: ["css-loader"]
                })
            }, 
            {
                test: /\.scss$/,
                exclude: /node_modules/,
                use: ExtractTextPlugin.extract({
                    use: ["css-loader", "sass-loader"],
                    fallback: "style-loader"
                })
            }
        ]
    },
    resolve: {
        extensions: [".js", ".json"]
    },
    plugins: [
        new HappyPack({
            id: "babel",
            loaders: [{
                loader: "babel-loader",
                options: {
                    presets: ["es2015", "stage-2", "react"]
                }
            }]
        }),
        new CommonsChunkPlugin({
            name: ["vendor"],
            filename: "vendor.bundle.js",
            minChunks: Infinity
        }),
        new NoEmitOnErrorsPlugin(),
        new OpenBrowserPlugin({
            url: "http://localhost:8888"
        }),
        new ExtractTextPlugin("[name].bundle.css", {
            allChunks: false
        }),
        //為了方便調(diào)試闯睹,暫時屏蔽
        // new UglifyJsPlugin({
        //     minimize: true,
        //     output: {
        //         comments: false,
        //         beautify: false
        //     },
        //     compress: {
        //         warnings: false,
        //         drop_console: true,
        //         collapse_vars: true,
        //         reduce_vars: true
        //     }
        // }),
        new OptimizeCSSPlugin()
    ]
};

module.exports = webpackConfig;

之后,使用webpack --watch既可以完成打包担神。

后端

后端基于expressmongoose,用到了express-sessionbody-parser始花,所以我們先把這些包安裝好:

npm i express mongoose express-session body-parser -S

然后我們看一下app.js

const express = require("express");
const mongoose = require("mongoose");
const cookieParser = require("cookie-parser");
const bodyParser = require("body-parser");
const session = require("express-session");

const app = express();

app.use(cookieParser());
//解析post請求
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
//設(shè)置session
app.use(session({
    secret: 'keyboard cat',
    resave: false,
    saveUninitialized: true
}));

//設(shè)置存放模板文件的目錄
app.set("views", __dirname);
//設(shè)置模板引擎為ejs
app.set("view engine", "ejs");
//訪問靜態(tài)資源文件
app.use(express.static("src"));
app.use(express.static(__dirname));
app.get("/", (req, res) => {
    return res.render("index", {
        userName: "",
        token: "",
        hasLogin: false
    })
})
//連接mongodb妄讯,db為該工程的數(shù)據(jù)庫名
mongoose.connect("mongodb://localhost/db", function(err, db) {
    if(err) {
        console.log("連接失敗");
        process.exit(1);
    }
    else {
        console.log("連接成功")
    }
})

app.listen("8888", () => {
    console.log("server created!");
})

運(yùn)行node app

我們還可以使用supervisor實(shí)現(xiàn)代碼更新功能,只需要npm i supervisor -g然后用supervisor app代替node app即可酷宵。每次代碼有了變更都會自動幫你重啟服務(wù)器亥贸。

環(huán)境搭建結(jié)束

到此步為止,環(huán)境搭建已經(jīng)結(jié)束浇垦,項(xiàng)目也可以成功跑起來了炕置,只不過沒有任何內(nèi)容,剩下的就是一步一步寫業(yè)務(wù)男韧。

四朴摊、CSRF防范

在寫業(yè)務(wù)之前,簡單實(shí)現(xiàn)了一下CSRF的防范此虑,我的做法是管理員登錄成功后甚纲,后端直接在頁面中生成一個script標(biāo)簽,標(biāo)簽內(nèi)包含了簡單的登錄信息和token朦前。之后管理員每一次與后端交互都要發(fā)送這個token介杆,由后端校驗(yàn)token,如果不一致韭寸,則直接返回春哨,不再執(zhí)行正常邏輯。

模板引擎

由后端生成script標(biāo)簽恩伺,讓我最先想到了模板引擎赴背,因此我使用了ejs來實(shí)現(xiàn)該功能,這也是為什么用戶頁面和管理員頁面的后綴不是html的原因莫其。我們看一下admin.ejs里面的內(nèi)容吧:

當(dāng)管理員登錄成功后癞尚,就可以全局訪問userInfo了。

下面我們看一下登錄的邏輯:

const login = module.exports = (req, res) => {
    const {userName, password} = req.body;
    const session = req.session;
    //用戶名和密碼正確乱陡,保存session浇揩,并告知前端登錄成功
    if(userName === "admin" && password === "admin") {
        if(session) {
            if(session.user) {
                res.json({
                    retCode: -1,
                    retMsg: "您已登錄過了"
                })
            }
            else {
                session.user = {
                    userName,
                    password
                }
                res.json({
                    retCode: 0,
                    retInfo: {}
                })
            }
        }
        else {
            res.json({
                retCode: -1,
                retMsg: ""
            })
        }
    }
    else {
        res.json({
            retCode: -1,
            retMsg: "用戶名或密碼錯誤"
        })
    }
}

中間件

管理員登錄成功后,session里面保存了登錄信息憨颠,那么下一步就是生成token并將其和用戶登錄信息渲染到頁面中胳徽。在asp.netjava中有一個叫做攔截器的東西积锅,它的作用就是攔截所有請求,包括ajax請求和資源請求养盗,在其中做一些操作然后控制請求是否繼續(xù)往下執(zhí)行缚陷,就像一個管道一樣。在express中往核,中間件的作用和其是一樣的箫爷,我們看一下中間件的代碼:

//app,js
const interceptor = require("./controller/interceptorCtrl");
app.use((req, res, next) => {
    interceptor(req, res, next);
})

//interceptorCtrl.js
const jwt = require('jsonwebtoken');

const interceptor = module.exports = (req, res, next) => {
    let url = req.path;
    //頁面請求,判斷session是否有值聂儒,如果有的話則生成token并將userName虎锚、token、hasLogin渲染到頁面上
    if(!!(~url.indexOf(".html"))) {
        url = url.replace(/\//g, "");
        const page = url.split(".")[0];
        //將用戶登錄信息和token返回給前臺
        if(req.session.user) {
            const token = jwt.sign({name: "token"}, "node-health", {expiresIn: 600});
            const { userName } = req.session.user;
            res.render(page, {
                userName,
                token,
                hasLogin: true
            })
        }
        else {
            res.render(page, {
                userName: "",
                token: "",
                hasLogin: false
            })
        }
        next();
    }
    //如果是ajax請求并且請求接口來自管理員衩婚,那么校驗(yàn)請求參數(shù)中的token是否正確窜护,不正確的話則直接返回retCode 500
    else if(!!(~url.indexOf("/api/admin"))) {
        let token = "";
        const method = req.method.toLowerCase();
        if(method == "get") {
            token = req.query.token;
        }
        else {
            token = req.body.token;
        }
        jwt.verify(token, "node-health", function (err, decoded) {
            if (!err) {
                if(decoded.name !== "token") {
                    return res.json({
                        retCode: 500,
                        retMsg: "csrf"
                    })
                }
                else {
                    next();
                }
            }
            else {
                return res.json({
                    retCode: 500,
                    retMsg: "csrf"
                })
            }
        })
    }
    else {
        next();
    }
}

功能很簡單:如果是頁面請求,則判斷session是否有用戶信息:如果有的話說明登錄成功了非春,生成token并將其和登錄信息渲染到頁面上柱徙;如果沒有登錄信息,則渲染空值即可奇昙,執(zhí)行next()讓請求繼續(xù)往下執(zhí)行护侮。如果是ajax請求,獲取請求參數(shù)中的token并解密储耐,校驗(yàn)值的正確性:如果不正確概行,則直接返回錯誤信息,請求不再往下執(zhí)行弧岳;如果正確凳忙,執(zhí)行next()讓請求繼續(xù)往下執(zhí)行。

五禽炬、寫一個Ajax吧

我們以管理員獲取所有分類為例涧卵,看一下前后端分別是如何實(shí)現(xiàn)的。

前端

組件在componentDidMount階段發(fā)起server的請求 --> 等待后端返回數(shù)據(jù) --> 發(fā)起action --> reducer中保存數(shù)據(jù) --> 更新視圖

由于用戶和管理員都需要獲取分類列表腹尖,因此我將分類的serveraction都劃分到了用戶模塊柳恐。

src/components/admin/center.js
import { bindActionCreators } from "redux";
import { connect } from "react-redux";
import * as server from "../../server/adminServer";
...
componentDidMount() {
    this.props.actions.getCategory({token: userInfo.token}, null, res => message.error(res.retMsg));
}
render() {
    return (
        <div>
            ...
            {/*渲染分類列表*/}
            {this.props.category.map((item, index) => (<div>...</div>)}
        </div>
    )
}
...
// 將actions綁定到props上
const mapDispatchToProps = (dispatch) => ({
    actions: bindActionCreators(server, dispatch)
});
//將state綁定到props上
const mapStateToProps = (state) => ({
    category: state.adminReducer.category
});

export default connect(mapStateToProps, mapDispatchToProps)(AdminCenter);
src/server/adminServer.js

這里使用到了redux-thunk

...
import * as action from "../action/userAction";
export function getCategory(successBK, errorBK) {
    return (dispatch, getState) => {
        return getData(url.SERVER_ADMIN + url.GET_CATEGORY).then(res => {
            if(res.retCode == 0) {
                dispatch(action.getCategory(res.retInfo));
                successBK && successBK(res.retInfo);
            }
            else {
                errorBK && errorBK(res);
            }
        }, e => console.log(e))
        .catch(e => console.log(e))
    }
}
src/actionType/userAction.js
...
export function getCategory(category) {
    return {
        type: types.GET_CATEGORY,
        category
    }
}
src/reducer/adminReducer.js
...
const defaultState = {
    category: []
}
const adminReducer = (state = defaultState, action) => {
    switch(action.type) {
        case types.GET_CATEGORY: 
            return Object.assign({}, state, {
                category: action.category
            })
        default:
            return state;
    }
}
export default adminReducer;

后端

中間件攔截請求热幔,校驗(yàn)token并繼續(xù)執(zhí)行 --> 路由映射 --> 轉(zhuǎn)發(fā)給控制層 --> 處理并返回數(shù)據(jù)

app.js
...
const adminRouter = require("./router/adminRouter");

app.use("/api/admin", adminRouter);
...
router/adminRouter.js
const express = require("express");
const category= require("../controller/user/category");
const router = express.Router();
...
//調(diào)用控制層
router.get("/getCategory", (req, res) => {
    category.getCategory(req, res);
})

module.exports = router;
controller/user/category
const models = require("../../model/index");
//從數(shù)據(jù)庫中讀取分類并返回給前端
const getCategory = (req, res) => {
    models.Category.find((err, result) => {
        if(err) {
            res.json({
                retCode: -1,
                retMsg: "mongoose error"
            })
        }
        res.json({
            retCode: 0,
            retInfo: result
        })
    })
}

module.exports = {
    getCategory
}

六乐设、圖片上傳

管理員添加和修改食物信息時需要上傳圖片。如果只是練習(xí)的話绎巨,可以將圖片保存到本地并將圖片絕對路徑保存到數(shù)據(jù)庫中近尚。但是,我們來個更加貼切真實(shí)項(xiàng)目的吧场勤,將圖片保存到圖片服務(wù)器中~

我們將圖片保存到七牛云存儲系統(tǒng)中戈锻,你需要先注冊個賬號歼跟,官網(wǎng)地址在這里
七牛云取消了測試賬號格遭,現(xiàn)已將圖片全部存儲在阿里云中哈街,官網(wǎng)地址在這里

在管理控制臺 --> 對象存儲 --> 內(nèi)容管理中可以看到已經(jīng)存儲的圖片:
在控制臺 --> 對象存儲 OSS --> 文件管理中可以看到已經(jīng)存儲的圖片:

下一步要做的就是前端上傳圖片發(fā)送給后端拒迅,后端上傳到七牛云阿里云并將圖片鏈接保存到數(shù)據(jù)庫骚秦。

前端上傳圖片

使用<input type="file" />實(shí)現(xiàn)圖片選擇。默認(rèn)樣式比較丑璧微,因此我自己重寫了樣式:

然后要做的就是使用formData對象將圖片信息發(fā)送給后端骤竹。

const fileEle = this.refs.file;
const file = fileEle.files[0];
let formData = new FormData();
formData.append("imgUrl", file);
formData.append("name", this.state.name);
...
this.props.actions.addFood(formData);

后端接收圖片

后端接收圖片需要用到multiparty插件,你只需要npm i multiparty -S即可往毡。

//controller/admin/foodHandler.js
const multiparty = require("multiparty");

const addFood = (req, res) => {
    const form = new multiparty.Form();
    form.parse(req, (err, fields, files) => {
        console.log(fields);
        console.log(files);
    })
}

上傳到七牛云阿里云

我們需要使用到七牛云的node sdknpm i qiniu -Snpm i ali-oss靶溜。使用文檔請訪問Node.js SDK开瞭。

我們首先要做一些配置:

const domain = "http://mescal-chuan.oss-cn-beijing.aliyuncs.com/";

const OSS = require('ali-oss');
const client = new OSS({
    region: 'oss-cn-beijing',
    //云賬號AccessKey有所有API訪問權(quán)限,建議遵循阿里云安全最佳實(shí)踐罩息,部署在服務(wù)端使用RAM子賬號或STS嗤详,部署在客戶端使用STS。
    accessKeyId: 'LTAIa2EaQxqPMBfb',
    accessKeySecret: 'WjKeNw8gAdU1y80SpO1JYnWfzq9Pbe',
    bucket: 'mescal-chuan'
 });

接下來要做的就是將圖片信息上傳到七牛云阿里云:

const file = files.imgUrl[0];
const localFile = file.path//"/Users/jemy/Documents/qiniu.mp4";
let temp = file.path.split("\\");
if(temp.length <= 1) {
    temp = file.path.split("/")
}
const key = temp[temp.length - 1]//'test.mp4';
// 文件上傳
client.put('/' + key, localFile).then((respBody, reject) => {
    if (reject) {
        res.json({
            retCode: -1,
            retMsg: "ali yun upload error"
        })
        throw reject;
    }
    if(respBody.res.statusCode == 200) {
        const imgUrl = domain + respBody.name;
        //保存到數(shù)據(jù)庫即可
    }
}

我們可以在七牛云阿里云上看到已經(jīng)上傳的圖片:

結(jié)束語

本項(xiàng)目從功能上來說只是簡單的CRUD瓷炮,但用到的技術(shù)比較多葱色,也是為了給自己做一個整體技術(shù)棧的實(shí)戰(zhàn),后期還可以考慮添加分頁和排序功能娘香。

如果你覺得對你有幫助苍狰,歡迎star~,如果有任何疑問或bug烘绽,也歡迎提供issue淋昭。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市安接,隨后出現(xiàn)的幾起案子翔忽,更是在濱河造成了極大的恐慌,老刑警劉巖盏檐,帶你破解...
    沈念sama閱讀 218,755評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件歇式,死亡現(xiàn)場離奇詭異,居然都是意外死亡胡野,警方通過查閱死者的電腦和手機(jī)材失,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,305評論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來硫豆,“玉大人豺憔,你說我怎么就攤上這事额获。” “怎么了恭应?”我有些...
    開封第一講書人閱讀 165,138評論 0 355
  • 文/不壞的土叔 我叫張陵抄邀,是天一觀的道長。 經(jīng)常有香客問我昼榛,道長境肾,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,791評論 1 295
  • 正文 為了忘掉前任胆屿,我火速辦了婚禮奥喻,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘非迹。我一直安慰自己环鲤,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,794評論 6 392
  • 文/花漫 我一把揭開白布憎兽。 她就那樣靜靜地躺著冷离,像睡著了一般。 火紅的嫁衣襯著肌膚如雪纯命。 梳的紋絲不亂的頭發(fā)上西剥,一...
    開封第一講書人閱讀 51,631評論 1 305
  • 那天,我揣著相機(jī)與錄音亿汞,去河邊找鬼瞭空。 笑死,一個胖子當(dāng)著我的面吹牛疗我,可吹牛的內(nèi)容都是我干的咆畏。 我是一名探鬼主播,決...
    沈念sama閱讀 40,362評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼吴裤,長吁一口氣:“原來是場噩夢啊……” “哼鳖眼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起嚼摩,我...
    開封第一講書人閱讀 39,264評論 0 276
  • 序言:老撾萬榮一對情侶失蹤钦讳,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后枕面,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體愿卒,經(jīng)...
    沈念sama閱讀 45,724評論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,900評論 3 336
  • 正文 我和宋清朗相戀三年潮秘,在試婚紗的時候發(fā)現(xiàn)自己被綠了琼开。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,040評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡枕荞,死狀恐怖柜候,靈堂內(nèi)的尸體忽然破棺而出搞动,到底是詐尸還是另有隱情,我是刑警寧澤渣刷,帶...
    沈念sama閱讀 35,742評論 5 346
  • 正文 年R本政府宣布鹦肿,位于F島的核電站,受9級特大地震影響辅柴,放射性物質(zhì)發(fā)生泄漏箩溃。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,364評論 3 330
  • 文/蒙蒙 一碌嘀、第九天 我趴在偏房一處隱蔽的房頂上張望涣旨。 院中可真熱鬧,春花似錦股冗、人聲如沸霹陡。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,944評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽烹棉。三九已至,卻和暖如春导俘,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背剔蹋。 一陣腳步聲響...
    開封第一講書人閱讀 33,060評論 1 270
  • 我被黑心中介騙來泰國打工旅薄, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人泣崩。 一個月前我還...
    沈念sama閱讀 48,247評論 3 371
  • 正文 我出身青樓少梁,卻偏偏與公主長得像,于是被迫代替她去往敵國和親矫付。 傳聞我的和親對象是個殘疾皇子凯沪,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,979評論 2 355

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

  • 前端開發(fā)者丨h(huán)ttp請求 https:www.rokub.com 前言見解有限, 如有描述不當(dāng)之處买优, 請幫忙指出妨马,...
    麋鹿_720a閱讀 10,920評論 11 31
  • 小轉(zhuǎn)中雨 昨天頹廢了一天,本來今天想看看書的,結(jié)果依然頹廢了一天,傷心,,,, 今天就看了一下抓取豆瓣電影排行前1...
    eagleli閱讀 208評論 0 1
  • 首先慶祝自己,從負(fù)四位數(shù)的資產(chǎn)到萬元戶*?(?′?`?)?*之前都沒有想過自己會去星巴克坐一坐杀赢,總感覺自己不適合那...
    小腦虎的牢騷閱讀 1,409評論 5 2
  • 忙碌的一天烘跺,來到公司就開始寫早宣,一件件事具體詳細(xì)的表現(xiàn)在紙上脂崔,一下子非常清晰具體到可操作滤淳,崔總的管理風(fēng)格非常人性...
    Hi_張閱讀 203評論 0 0
  • 居延海位于內(nèi)蒙古自治區(qū)阿拉善盟額濟(jì)納旗北部,形狀狹長彎曲砌左,有如新月脖咐,額濟(jì)納河匯入湖中铺敌,是居延海最主要的補(bǔ)給水源。居...
    干涸的海閱讀 777評論 0 5