2017/07/25

Express MVC

ๆœ€่ฟ‘ๅฟƒ่ก€ไพ†ๆฝฎๅˆๆŠŠ express ็Žฉไบ†ไธ€ไธ‹,ๅฏซ็ฏ‡ๆ–‡็ซ ไพ†็ด€้Œ„ไธ€ไธ‹ๆ•ดๅ€‹้Ž็จ‹,ๆœƒ็”จๅˆฐ็š„ๅทฅๅ…ทๅฆ‚ไธ‹:

  1. express 4
  2. node-orm2
  3. nodemon

้ฆ–ๅ…ˆๅฎ‰่ฃ express-generator,้€™ๆ˜ฏไธ€ๅ€‹ๅฏไปฅ่‡ชๅ‹•็”ข็”Ÿ express ้œ€่ฆๅ…งๅฎน็š„ๅทฅๅ…ท

$ sudo npm i -g express-generator

ๅฎ‰่ฃๅฅฝไน‹ๅพŒ,ๆˆ‘ๅ€‘ๅˆ‡ๆ›ๅˆฐๆˆ‘ๅ€‘ๆƒณ่ฆ็š„็›ฎ้Œ„ไพ†็”ข็”Ÿๅฐˆๆกˆ่ณ‡ๆ–™ๅคพ,ๆˆ‘้ธ็”จ twig ็•ถไฝœๆˆ‘็š„ๆจฃๆฟๅผ•ๆ“Ž,ๆˆ‘ๅœจ PHP ไฝฟ็”จ CI ็š„ๆ™‚ๅ€™ไนŸๆ˜ฏ้ธ็”จๅŒไธ€ๅ€‹ๅผ•ๆ“Ž,ๅฏไปฅ็„ก็—›่ฝ‰็งป

/var/www $ sudo express -v twig project

/var/www $ cd project
/var/www/project $ sudo npm i
/var/www/project $ sudo npm i orm mysql --save

ๅฐˆๆกˆ็›ฎ้Œ„็”ข็”ŸๅพŒ,ๆˆ‘ๅ€‘ๅฏไปฅไฝฟ็”จ nodemon ไพ†็›ฃๆŽง็›ฎ้Œ„,ไนŸๅฏไปฅ้”ๅˆฐไฟฎๆ”นๆช”ๆกˆๅพŒ่‡ชๅ‹•้‡่ตท็š„ๆ•ˆๆžœ

/var/www/project $ sudo nodemon bin/www

้€™ๆ™‚ๅ€™ๆ‰“้–‹ http://10.10.10.16:3000 (ๆˆ‘็š„ vm ๆธฌ่ฉฆ IP)ๅฐฑๅฏไปฅ็œ‹ๅˆฐ้ ่จญ็ถฒๅ€,ๅฆ‚ๆžœๅธŒๆœ›ๆ”น port ็š„่ฉฑๅฏไปฅๅœจ env ่จญๅฎš port,ๆˆ–่€…็›ดๆŽฅๅŽปๆ”น bin/www ้€™ๅ€‹ๆช”ๆกˆ

ๆ‰“้–‹ app.js ้€™ๆ˜ฏ้ ่จญ็š„ๅ…งๅฎน

var express = require('express');
var path = require('path');
var favicon = require('serve-favicon');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');

var index = require('./routes/index');
var users = require('./routes/users');

var app = express();

// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'twig');

// uncomment after placing your favicon in /public
//app.use(favicon(path.join(__dirname, 'public', 'favicon.ico')));
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));

app.use('/', index);
app.use('/users', users);

// catch 404 and forward to error handler
app.use(function(req, res, next) {
  var err = new Error('Not Found');
  err.status = 404;
  next(err);
});

// error handler
app.use(function(err, req, res, next) {
  // set locals, only providing error in development
  res.locals.message = err.message;
  res.locals.error = req.app.get('env') === 'development' ? err : {};

  // render the error page
  res.status(err.status || 500);
  res.render('error');
});

module.exports = app;

ๆ‰€ๆœ‰็š„ๅ‹•ไฝœ้ƒฝๅœจ้€™้šป app.js ่จญๅฎš,ๆˆ‘ๅ€‘ไพ†ๅปบ็ซ‹ไธ€ๅ€‹ product routes ๆช”ๆกˆ

routes/product.js
const express = require('express');
const router = express.Router();

router.get('/', function(req, res, next) {
    res.render('product/index');
});

module.exports = router;
view/product/index.twig
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title></title>
</head>
<body>
    <h3>This is product page</h3>
</body>
</html>

ๅฐ‡ app.js ๅŠ ไธŠ้€™ๅ€‹ routes ็š„่จญๅฎš

app.js
var index = require('./routes/index');
var users = require('./routes/users');
var product = require('./routes/product');
var index = require('./routes/index');
var users = require('./routes/users');
var product = require('./routes/product');

app.use('/', index);
app.use('/users', users);
app.use('/product', product);

้€™ๆ™‚็ถฒๅ€ๆ”นๆˆ http://10.10.10.16:3000/product,ๅฐฑๆœƒ็œ‹ๅˆฐ This is product page ้€™ๅนพๅ€‹ๅญ—

ๆŽฅไธ‹ไพ†ๆˆ‘ๅ€‘้€ฒ่กŒ่ณ‡ๆ–™ๅบซ็š„ไธฒ้€ฃ,ๅœจ MySQL ๅ…งๅปบ็ซ‹ไธ€ๅ€‹ๅซ express ็š„่ณ‡ๆ–™ๅบซ,ๅฆๅค–ๅปบ็ซ‹ไธ€ๅ€‹ products ็š„ table ไธฆไธ”ๅกžๅ…ฅ่ณ‡ๆ–™

CREATE TABLE `products` (
`id` INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
`name` VARCHAR(50) NOT NULL
) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_unicode_ci;

ๆŽฅไธ‹ไพ†ๆˆ‘ๅ€‘ไพ†่จญๅฎš่ณ‡ๆ–™ๅบซ้€ฃๆŽฅ,ๅ› ็‚บๆˆ‘ไธๅ–œๆญกๅ…จ้ƒจ็š„ๆฑ่ฅฟ้ƒฝๅกžๅœจ app.js,ๆ‰€ไปฅๆˆ‘ๅฆๅค–้–‹ไธ€ๅ€‹่ณ‡ๆ–™ๅคพไพ†ๆ”พ่จญ็ฝฎๆช”

config/db.js
module.exports = (app, orm) => {
    app.use(orm.express("mysql://root:123456@127.0.0.1/express", {
        define: function(db, models, next) {
            models.product = db.define('products', {
                id: Number,
                name: String
            });
            next();
        }
    }));
};

ไฟฎๆ”น app.js ๅ•Ÿๅ‹•้€™ๅ€‹่จญๅฎš,ๅช่ฆๆ”พๅœจ app ไปฅๅŠ orm ๅˆๅง‹ๅŒ–ๅพŒๅณๅฏ

app.js
require('./config/db.js')(app, orm);

ๆˆ‘ๅ€‘ๅ…ˆๅฐ‡ routes/product.js ไฟฎๆ”นๆˆไปฅไธ‹ๅ…งๅฎน,่ฎŠๅฏไปฅๅพž็ถฒๅ€ๅ…ˆ็œ‹ๅˆฐ็ตๆžœ

const express = require('express');
const router = express.Router();

router.get('/', function(req, res, next) {
    req.models.product.all((err, data) => {
        res.json(data);
    })
});

module.exports = router;
http://10.10.10.16:3000/product
[{"id":1,"name":"product a"},{"id":2,"name":"product b"}]

้€™ๆ˜ฏๆœ€ๅŸบๆœฌ็š„็”จๆณ•,ไฝ†ๆˆ‘่ฆบๅพ—้€™ๆจฃๅฏ้‡่ค‡ๅˆฉ็”จๆ€งๅคชไฝŽไบ†,ๆ‰€ไปฅๆˆ‘ๅ€‘ไพ†ๅปบ็ซ‹้กžไผผ model ๆฉŸๅˆถๅง

routes/product.js
const express = require('express');
const router = express.Router();
const Product = require('../model/product.js');

router.get('/', async(req, res, next) => {
    try {
        const product = new Product(req.models.product);
        res.json(await product.getAllNews());
    } catch (e) {
        res.send(e);
    }
});

module.exports = router;
model/product.js
class Product {
    constructor(model) {
        this.model = model
    }

    async getAllNews() {
        return new Promise((resolve, reject) => {
            this.model.all((err, data) => {
                if (err) {
                    reject(err);
                }

                resolve(data);
            })
        })
    }
}

module.exports = Product;

้€™ๆจฃ็š„ๅŸท่กŒ็ตๆžœๆœƒไธ€ๆจกไธ€ๆจฃ,ไฝ†ๆŠŠๆฑ่ฅฟๆ‹†ไนพๆทจๆจก็ต„ๅŒ–ไบ†,ๅ†ไฟฎๆ”นไธ€ๆฌกๅœจ view ๅ‘ˆ็พๅง

routes/product.js
const express = require('express');
const router = express.Router();
const Product = require('../model/product.js');

router.get('/', async(req, res, next) => {
    try {
        const product = new Product(req.models.product);
        res.render('product/index', {
            products: await product.getAllNews()
        });
    } catch (e) {
        res.send(e);
    }
});

module.exports = router;
views/product/index.twig
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title></title>
</head>
<body>
    <h3>This is product page</h3>
    {% for product in products %}
    <div>product: {{ product.name }}</div>
    {% endfor %}
</body>
</html>

ไปฅไธŠๅฐฑๆ˜ฏ้€™ๅ…ฉๅคฉ่ฉฆ็Žฉ express ็š„ๆ•ด็†,ๆฒ’ๆœ‰ๅฏฆ็พๆ‰€่ฌ‚็š„ controller ้ƒจไปฝ,ๅฐฑๅ…ˆๆŠŠ routes ็•ถ controller,็•ถ็„ถไธ€ๅฎšๆœƒๆœ‰ๆ›ดๅคšๆ›ดๅฅฝ็š„ๆ–นๆณ•,ๅ†ๆ…ขๆ…ขๆŽข็ดข,ๅœจๆญคไนŸๆ„Ÿ่ฌ้™ณ้ป˜ๅธๅคงๅคง็š„ๆŒ‡ๅฐŽ