npm init; npm install express moment mysql:我们使用nodejs的express框架,moment是一个日期处理类库,mysql数据库,ejs模板
app.js 中实例化express,设置基本配置,如模板引擎,启动端口号:
var express = require('express'); var path = require('path'); var port = process.env.PORT || 3000; // 设置启动端口 var app = express(); app.set('views', path.join(__dirname, 'views')); // 设置模板引擎 app.set('views', './views'); app.set('view engine', 'ejs'); app.listen(port); console.log('start on port ' + port);
app.js 设置路由,index.ejs设置dom模板,admin.ejs,list.ejs,detail.ejs
<!DOCTYPE> <html> <head> <meta name="viewport" charset="UTF-8" content="width=device-width, initial-scale=1.0" > <title><%= title %></title> </head> <body> </body> </html>
// index page app.get('/', function(req, res) { res.render('index', { title: '电影网首页' }); }); // detail page app.get('/movie/:id', function(req, res) { res.render('detail', { title: '电影网详情页' }); }); // list page app.get('/admin/list', function(req, res) { res.render('list', { title: '电影网列表页' }); }); // admin page app.get('/admin/movie', function(req, res) { res.render('admin', { title: '电影网录入页' }); });
当前目录结构,includes是公共的部分footere.js,footer.ejs; options.js代表前端js逻辑
()
课程中用了bower管理前端的包,但是我觉得没有必要现在来增加学习成本,所以我选择直接引入。安装好jq和bootstrap后,找到node_modules中这两个包的dist目录,把静态资源css和js复制到根目录下的src中,需要在nodejs中,指定我们的静态资源目录 app.js
app.use('/src', express.static(path.join(__dirname, 'src'))); // 指定静态资源目录
/src为虚拟的一个目录,这样就可以在ejs模板中使用了,<link rel="stylesheet" href="/src/css/bootstrap.css" >
ejs模板基本语法
- include 引入其他文件夹下的模板
<%- include('../includes/footer') %>
- for循环
<% for (var i = 0; i < moive.length; i++) { %><div><%= moive[i].title %></div><% } %>
- 拼凑属性
<a href="/moive/<%= moive[i]._id %>">
- include 引入其他文件夹下的模板
数据库 mysql (app.js)
mysql的基本操作都是通过connect.query来实现的,官方文档
连接数据库,关于什么时候连接关闭数据库,我还要研究,文章后面已经添加
var mysql = require('mysql'); var connection = mysql.createConnection({ host: 'localhost', user: 'root', password: '', database: 'moive' }); connection.connect();
查询数据,修改
app.get('/', function(req, res){})
路由app.get('/', function(req, res) { // 查询所有数据内容 connection.query('SELECT * FROM moive_data', function(error, results, fields) { if (error) throw error; else { res.render('index', { title: '电影网首页', moive: results }); } }); });
最开始的时候results可以使用模拟数据
新增一条数据
// 新增一条数据 前端代码逻辑 $('#addOption').on('click', function() { $.ajax({ type: "POST", url: "/admin/add", data: { title: $("#inputTitle").val(), doctor: $("#inputDoctor").val(), country: $("#inputCountry").val(), year: $("#inputYear").val(), poster: $("#inputPoster").val(), language: $("#inputLanguage").val(), flash: $("#inputFlash").val(), summary: $("#inputSummary").val(), }, success: function(res) { console.log("Data Saved: " + res); } }); });
- 删除数据
app.delete('/admin/list', function(req, res) { let id = req.body.id; console.log(id); connection.query(`delete from moive_data where _id = ${id}`, function(error, results, fields) { if (error) { console.log(error); connection.end(); } else { console.log('delete: ', results) } }); }); // 删除一条数据 前端逻辑代码 $('.del').on('click', function() { let del_id = $(this).attr('data-id'); $.ajax({ type: "DELETE", url: "/admin/list", data: { id: del_id }, success: function(res) { console.log("Data Saved: " + res); } }); });
更新修改一条数据
首先只是渲染一界面
app.get('/admin/update/:id', function(req, res) { let id = req.params.id; connection.query(`select * from moive_data where _id = ${id}`, function(error, results, fields) { if (error) { console.log(error); } else { res.render('admin', { title: '电影网列表页', moive: results }); } }); });
由于修改以及录入我们使用的是同一个界面admin界面,所以我们也需要做一个判断,判断即将执行更新还是新增,更改options.js的前端代码
$('#addOption').on('click', function() { let hiddenVal = $('#inputHidden').val(), itype = "PUT"; if (!hiddenVal) { itype = "POST"; } console.log(hiddenVal) // 隐藏域值为null,新增数据 $.ajax({ type: itype, url: "/admin/add", data: { id: hiddenVal, title: $("#inputTitle").val(), doctor: $("#inputDoctor").val(), country: $("#inputCountry").val(), year: $("#inputYear").val(), poster: $("#inputPoster").val(), language: $("#inputLanguage").val(), flash: $("#inputFlash").val(), summary: $("#inputSummary").val(), }, success: function(res) { console.log("Data Saved: " + res); } }); });
新增后端更新接口
app.put('/admin/add', function(req, res) { let id = req.body.id; let [title, doctor, country, year, poster, language, flash, summary] = [req.body.title, req.body.doctor, req.body.country, req.body.year, req.body.poster, req.body.language, req.body.flash, req.body.summary]; connection.query(`update moive_data set title=?,doctor=?,country=?,year=?,poster=?,language=?,flash=?,summary=? where _id = ${id}`, [title, doctor, country, year, poster, language, flash, summary], function(error, results, fields) { if (error) { console.log(error); } else { console.log('update: ' + results); } }); });
因为代码太多,只列出关键代码,详细代码可以查看github
重点
- 存储数据库数据的时候,text,var类型的字段需要添加引号’${xx}’
关于ajax提交后的跳转。我才明白,ajax做的是局部刷新就是为了不跳转所以才使用ajax 如果你需要跳转的那应该使用from表单提交。如果你实在不小心使用了ajax比如我,就应该在后端返回需要跳转的url,在前端进行跳转
res.send({ status: 200, msg: "add success", url: "/" }); //前端逻辑 if (res.status === 200) { window.location.href = res.url; }
但是我目前遇到的问题就是,跳转时而成功时而失败,失败的时候出现:比如我当前的路由是/admin/add 跳转的时候http请求头却会显示referer属性/admin/add?多了一个问号,操作完成后,浏览器不会跳转到目标页面而是刷新当前页面,浏览器会显示/admin/add?,我目前没有解决
连接池,mysql是自己支持了连接池,不同数据库可能不一样。
- 为什么使用连接池
连接池的使用,单独一个js,
// 使用连接池连接数据库 var mysql = require("mysql"); var pool = mysql.createPool({ connectionLimit: 100, host: 'localhost', user: 'root', password: '', database: 'moive' }); var query = function(sql, options, callback) { pool.getConnection(function(err, con) { if (err) { callback(err, null, null); } else { con.query(sql, options, function(err, results, fields) { callback(err, results, fields); }); } con.release(); // 释放资源 }); } module.exports = query;
使用修改connection.query为query
var query = require('./mysql-pool'); // 使用连接池连接数据库 app.get('/', function(req, res) { // 查询所有数据内容 query('select * from moive_data', [], function(error, results, fields) { if (error) { console.log(error); } else { res.render('index', { title: '电影网首页', moive: results }); } }); });
新增录入插入时间。在创建mysql的时候新增一个字段 intime 如图设置
,每次更新也回自动更新时间。获取数据的事后根据时间排序只需要在sql语句中添加order by + 字段 ,比如:select * from moive_data order by intime
就可以啦