nodejs crud功能

地址

https://github.com/unknowSir/nodejs-crud.git

功能

一个页面数据的crud 具有分页 模糊查询 图片上传七牛 前端预览

前端 ajax+formData+html5-require原生验证+FileReader前端图片预览+bootstrap+bootstrap-bootstrap paginator+art-template

文件存储 前端直传七牛云(原生formdata直传)

后台 nodejs+express+xtemplate+mysql+orm2

前言,就是想要做一个crud的demo,把上面的技术都走一走(主要是要走通nodejs+express+orm+xtemplate+FormData+ajax+FileReader)

界面

安装

构建数据库

sql 代码

/*
Navicat MySQL Data TransferSource Server         : localhost_3306
Source Server Version : 50617
Source Host           : localhost:3306
Source Database       : cso2017Target Server Type    : MYSQL
Target Server Version : 50617
File Encoding         : 65001Date: 2017-12-19 22:39:54
*/SET FOREIGN_KEY_CHECKS=0;-- ----------------------------
-- Table structure for `media`
-- ----------------------------
DROP TABLE IF EXISTS `media`;
CREATE TABLE `media` (`id` tinyint(4) NOT NULL AUTO_INCREMENT,`title` varchar(50) DEFAULT '',`src` text,`des` text,`createTime` varchar(50) DEFAULT '',`type` int(11) DEFAULT '-1' COMMENT '媒体类型\r\n-1 默认\r\n0 轮播图\r\n1 优秀标兵\r\n2 状态\r\n3 动态',`isDelete` tinyint(1) unsigned zerofill DEFAULT '0' COMMENT '0 false 1 true',PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=15 DEFAULT CHARSET=latin1;-- ----------------------------
-- Records of media
-- ----------------------------
INSERT INTO `media` VALUES ('1', '11', '1111', '111111', '11111111', '-1', '1');
INSERT INTO `media` VALUES ('2', '2', '22', '222', '22222', '-1', '1');
INSERT INTO `media` VALUES ('3', '1', 'uploads/37094-106.jpg', '3333', '1513678617873', '0', '0');
INSERT INTO `media` VALUES ('4', '2', 'uploads/295727-106.jpg', '333', '1513678633962', '1', '0');
INSERT INTO `media` VALUES ('5', '3', 'uploads/21420-106.jpg', '3333', '1513678676016', '-1', '0');
INSERT INTO `media` VALUES ('6', '4', 'uploads/37094-106.jpg', '111111', '1513678755337', '-1', '0');
INSERT INTO `media` VALUES ('7', '5', 'uploads/41077-106.jpg', '444', '1513678769503', '-1', '0');
INSERT INTO `media` VALUES ('8', '6', 'uploads/37094-106.jpg', '777', '1513679508958', '-1', '0');
INSERT INTO `media` VALUES ('9', '7', 'uploads/21420-106.jpg', '888', '1513679540648', '-1', '0');
INSERT INTO `media` VALUES ('10', '888', 'uploads/350947-106.jpg', '8888', '1513691658007', '2', '0');
INSERT INTO `media` VALUES ('11', '99', 'uploads/127678-106.jpg', '999', '1513691885585', '-1', '0');
INSERT INTO `media` VALUES ('12', '10', 'uploads/129643-106.jpg', '10', '1513691925412', '-1', '0');
INSERT INTO `media` VALUES ('13', '11', 'uploads/268223-106.jpg', '11', '1513691939124', '-1', '0');
INSERT INTO `media` VALUES ('14', '12', 'uploads/37094-106.jpg', '12', '1513692236017', '-1', '0');

安装nodejs后台环境

这里选择的搭配是nodejs+express 4.x + orm +xtemplate

传送门express

通过如下命令安装:

npm install express-generator -g

例如,下面的示例就是在当前工作目录下创建一个命名为 myapp 的应用。

express myapp

然后安装所有依赖包:

cd myapp
npm install

Windows 平台使用如下命令:

> set DEBUG=myapp & npm start

然后在浏览器中打开 http://localhost:3000/ 网址就可以看到这个应用了。

还要安装其他依赖

orm mysql 对象关系模型框架

传送门orm

npm i orm --save

安装 xtemplate

npm i xtemplate --save

项目主要文件目录结构

后台app.js文件

// 引入orm模块
var orm = require('orm');
// 设置静态文件目录
app.use(express.static('public'));
// 修改视图引擎jade改为xtemplate- 不喜欢jade怪异的模样
app.set('view engine', 'xtpl');// 修改上传文件的大小 默认上传太小了 超过1MB都会报错 所以提前修改  报错信息提示:payload 提示太大
app.use(bodyParser.json({limit:'50mb'}));
app.use(bodyParser.urlencoded({limit:'50mb',extended:true}));// 定义数据模型 连接mysql 将模型绑定到 req对象上
app.use(orm.express("mysql://root@localhost/cso2017", {define: function (db, models, next) {var media= db.define("media", {// 字段都是和mysql中对应的id: { type: 'serial', key: true },title: { type: 'text' },src: { type: 'text' },des: { type: 'text' },createTime: { type: 'text' },type: { type: 'number' },isDelete: { type: 'number' }});models.media=media;next();}
}));// 用来指定路由处理的
app.use('/', index);
app.use('/users', users);

后台 七牛 router/qiuniu.js

传送门七牛

var express = require('express');
var qiniu = require('qiniu');
var router = express.Router();// 我的七牛的accessKey-此处修改为自己的即可
var accessKey = 'xxxxxxx';
// 我的七牛的 secretKey - 此处修改为自己的即可
var secretKey = 'xxxxx';
var options = {// 空间名字 buketscope: "xxxx",
};
var putPolicy = new qiniu.rs.PutPolicy(options);
var mac = new qiniu.auth.digest.Mac(accessKey, secretKey);
// 上传凭证
var uploadToken = putPolicy.uploadToken(mac);router.get("/token", function (req, res, next) {console.log(uploadToken);res.send({"uptoken": uploadToken});
})
module.exports = router;

后台 router/user.js

var express = require('express');
var router = express.Router();
// 中间件 某则 req中获取不到上传参数(因为express 4.x 改变了 3.x获取参数的形式)
var multipart = require('connect-multiparty');
var multipartMiddleware = multipart();
var fs = require('fs');
var orm = require('orm');
router.get('/', function (req, res, next) {res.render('user', { title: '我来拉' });
});// 获取分页数据
router.get("/getList", function (req, res, next) {// 获取分页数据var page = +req.query.page;var rows = +req.query.rows;var title = req.query.title;// 注意要传入的类型是数字// limit 限制一共取几条 rows// offset 往后偏移几条   下一页的条数// mysql查询参数var queryObj = { isDelete: "0", title: orm.like('%' + title + '%') };req.models.media.find(queryObj).all().limit(rows).offset((page - 1) * rows).run(function (error0, medias) {if (error0) res.send(error0);// 计算分页后的总数据req.models.media.count(queryObj, function (error1, count) {if (error1) res.send(error1);// medias.total = count;var obj = {data: medias,total: count,page: page,rows: rows};res.send(obj);});})
});// 删除
router.get("/del", function (req, res, next) {var id = req.query.id;req.models.media.get(id, function (err, oldData) {if (err) throw err;oldData.isDelete = 1;oldData.save(function (err1) {if (err1) throw err1;res.send({ status: 0, msg: "删除成功" });})})
})/* post 添加 */
router.post("/add", multipartMiddleware, function (req, res, next) {var file = req.files.src;var formBody = req.body;formBody.src = formBody.src;formBody.createTime = Date.now();formBody.isDelete = 0;req.models.media.create(formBody, function (err) {if (err) throw err;// 正常执行res.send({ status: 0, msg: "新增成功" });})})// 编辑
router.post("/edit", multipartMiddleware, function (req, res, next) {/* 1 有修改了图片文件的 重新保存和提交2 没有修改图片的 只修改字段即可3 改用七牛云 直接存储字段即可*/var formBody = req.body;req.models.media.get(formBody.id, function (err, oldData) {oldData.title = formBody.title;oldData.des = formBody.des;oldData.type = formBody.type;oldData.src = formBody.src;// 保存数据 同步保存数据oldData.save(function (err) {if (err) throw err;res.send({ status: 0, msg: "编F辑成功" });});});})
/*** * @param {*要保存的文件} file * @param {*文件保存的全路径} path  abc/* @param {*回调函数} callback 参数 imgPath 图片全路径*/
function saveFile(file, path, callback) {fs.readFile(file.path, function (err, data) {if (err) {console.log(err);} else {// 存储文件var imgPath = "uploads/" + path + Date.now() + file.originalFilename;fs.writeFile("public/" + imgPath, data, function (err1) {if (err1) {console.log(err1);} else {// 存入数据库callback(imgPath);}});}});
}
module.exports = router;

前端 common.js

$(function () {// 往art-template中注册方法template.helper("toJson", function (str) {return JSON.stringify(str);});// 将数字转为 对应的多媒体类型template.helper("toType", function (num) {var str = "默认";switch (num) {case -1:break;case 0:str = "轮播图";break;case 1:str = "优秀标兵";break;case 2:str = "状态";break;case 3:str = "动态";break;default:break;}return str;})
})

前端 user.xtpl xtpl 是xtemplate特定的文件形式

<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta http-equiv="X-UA-Compatible" content="ie=edge"><title>Document</title><!-- 注意 因为在app.js中设置了 app.use(express.static('public')); 所以路径忽略public文件夹,直接到子层即可 --><link rel="stylesheet" href="lib/bootstrap/css/bootstrap.min.css"><link rel="stylesheet" href="css/user.css">
</head><body><!-- 遮罩层 --><div class="mask"></div><div class="container"><div><button class="btn btn-default" id="add">添加</button><button class="btn btn-default" id="reflash">刷新</button><div class="input-group"><input type="text" class="form-control searchInp" placeholder="Search for..."><span class="input-group-btn"><button class="btn btn-default searchBtn" type="button">搜索</button></span></div></div><div><table class="table table-bordered"></table></div><div><nav aria-label="Page navigation"><ul class="pagination"></ul></nav></div></div><!-- 模态框 --><div id="myModal" class="modal fade" tabindex="-1" role="dialog"><div class="modal-dialog" role="document"><div class="modal-content"><div class="modal-header"><button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button><h4 class="modal-title">操作数据</h4></div><div class="modal-body"><form id="ff" class="form-horizontal" enctype="multipart/form-data"><input type="hidden" name="id"><div class="form-group"><label for="title" class="col-sm-2 control-label">请输入标题</label><div class="col-sm-10"><input required type="text" class="form-control" name="title" id="title" placeholder="Email"></div></div><div class="form-group"><label for="fileInp" class="col-sm-2 control-label">上传文件</label><div class="col-sm-10 " id="upParent"><input required type="file" class="form-control" id="fileInp" placeholder="Email"><input type="hidden" name="src" id="hiddenSrc"></div></div><div class="form-group"><div class="col-sm-10 col-sm-offset-2"><input type="image" width="100" src="data:images/default.png" name="srcImage" id="src"></div></div><div class="form-group"><label for="type" class="col-sm-2 control-label">类型</label><div class="col-sm-10"><select name="type" class="form-control" id="type"><option value="-1">默认</option><option value="0">轮播图</option><option value="1">优秀标兵</option><option value="2">状态</option><option value="3">动态</option></select></div></div><div class="form-group"><label for="inputEmail3" class="col-sm-2 control-label">描述</label><div class="col-sm-10"><textarea placeholder="请输入详细描述" required name="des" id="des" class="form-control"></textarea></div></div></form></div><div class="modal-footer"><button type="button" id="canBtn" class="btn btn-default" data-dismiss="modal">Close</button><button type="submit" form="ff" id="subBtn" class="btn btn-primary">提交</button></div></div></div></div><!-- 删除模态框 --><div class="modal fade" id="deleteModal" tabindex="-1" role="dialog"><div class="modal-dialog" role="document"><div class="modal-content"><div class="modal-header"><button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button><h4 class="modal-title">警告</h4></div><div class="modal-body">你确定要删除吗</div><div class="modal-footer"><button type="button" class="btn btn-default" data-dismiss="modal">取消</button><button type="button" class="btn btn-danger delSubBtn ">删除</button></div></div><!-- /.modal-content --></div><!-- /.modal-dialog --></div><!-- /.modal --><!-- art-template 模板引擎语法 --><script type="text/html" id="tblTpl">{{%<tr><td>序号</td><td>标题</td><td>路径</td><td>描述</td><td>创建时间</td><td>类型</td><td>操作</td></tr>{{each data as value i}}<tr data-value="{{toJson(value)}}" ><td>{{(page-1)*rows+ i+1 }}</td><td>{{ value.title }}</td><td><img src="{{value.src}}" alt=""></td><td>{{  value.des }}</td><td>{{  value.createTime }}</td><td>{{  toType(value.type) }}</td><td><button class="btn btn-warning dataEditBtn " data-id="{{value.id}}" >编辑</button> <button  data-id="{{value.id}}" class="btn btn-danger dataDelBtn" >删除</button> </td></tr>{{/each}}%}}</script><script src="lib/jquery.min.js"></script><script src="lib/bootstrap/js/bootstrap.min.js"></script><!-- 分页插件 --><script src="lib/bootstrap-paginator.min.js"></script><script src="lib/template.js"></script><script src="js/common.js"></script><script src="js/user.js"></script>
</body>
</html>

前端 user.css

table img {width: 100%;max-width: 100px;
}.mask {position: fixed;width: 100%;height: 100%;opacity: .5;background-color: #000;z-index: 100000;
}.mask::after {display: block;content: "";position: absolute;width: 10px;height: 10px;border: 1px solid #fff;background-color: blue;border-radius: 50%;left: 50%;top: 50%;margin-left: -50px;margin-top: -50px;transform-origin: 45px 45px;animation: ani_loading .5s infinite linear;
}@keyframes ani_loading {0% {}100% {transform: rotate(360deg);}
}

前端 user.js


$(function () {// 查询参数var QueryPage = {page: 1,rows: 5,title: ""};// 操作类型// 0 新增 1 编辑 2 删除 默认为0 新增var ManagerType = 0;// 总页数var TotalPages = 1;// 要删除数据的idvar DelID = -1;getList(setPage);function getList(callback) {QueryPage.title = $.trim($(".searchInp").val());$.get("users/getList", QueryPage, function (result) {// 计算总页数TotalPages = Math.ceil(result.total / QueryPage.rows);var html = template("tblTpl", result);$("table").html(html);callback && callback();})}function setPage(params) {// bs 分页插件设置var options = {bootstrapMajorVersion: 3,currentPage: QueryPage.page,//当前页面  numberOfPages: QueryPage.rows,//一页显示几个按钮(在ul里面生成5个li)  totalPages: TotalPages,//总页数  onPageClicked: function (event, originalEvent, type, page) {QueryPage.page = page;getList(setPage);}}$(".pagination").bootstrapPaginator(options);}// 搜索$(".searchBtn").click(function (params) {QueryPage.page = 1;getList(setPage);// 点击搜索后 设置分页插件自动回到第一页$(".pagination").bootstrapPaginator("showFirst");})// 选择图片后,在前端即时预览$("#fileInp").change(function (e) {// console.log(e);var file = e.target.files[0];var fr = new FileReader();fr.readAsDataURL(file);fr.onload = function () {$("#src").attr("src", fr.result);}})// 编辑$("table ").on("click", ".dataEditBtn", function (e) {/* 0 存入当前操作提示 编辑 ManagerType=1 1 弹出对话框2 填充表单3 去除 文件上传按钮 required属性*/ManagerType = 1;$("#myModal").modal("show");// 获取被操作的行上的元数据 data-value//parentsUntil  查找当前元素的所有的父辈元素,直到遇到匹配的那个元素为止。 包含了下面所有找到的父辈元素,但不包括那个选择器匹配到的元素。 var obj = $(e.target).parents("tr").data("value");// 2 填充数据$("input[name='title']").val(obj.title);$("input[name='id']").val(obj.id);// $("input[name='src']").val(obj.src);$("[name='des']").val(obj.des);$("[name='type']").val(obj.type);// 图片按钮$("input[name='srcImage']").attr("src", obj.src);// 3 // $("input[type='src']").removeAttr("required");// 可能存在编辑文件时 没重新提交图片 所以去除验证$("#fileInp").removeAttr("required");})// 新增$("#add").click(function (e) {/* 1 操作类型2 弹出对话框3 清空表单4 添加文件上传按钮 required属性*/ManagerType = 0;$("#myModal").modal("show");$("input[name='src']").attr("required", "");$("#ff")[0].reset();// 清除图片路径的隐藏于$("input[name='src']").val("");// 清除图片按钮$("input[type='image']").attr("src", "");$("input[type='image']").val("");})// 提交$("#ff").submit(function (e) {/* 1 发送了3个ajax a 请求上传图片的token b 上传到七牛 获取图片链接 c 将数据插入到后台*/e.preventDefault();// formData.append("src", $("input[name='src']").val());// 判断操作类型 0 为新增  1 为编辑 2 为删除if (ManagerType == 0) {// 获取最新的token$.get("/qiniu/token", function (token) {var file = $("#fileInp")[0].files[0];// 构造formdata 上传到七牛使用var f = new FormData();f.append("key", Date.now() + file.name);f.append("token", token.uptoken);f.append("file", file);$.ajax({url: "http://upload.qiniup.com/",type: "POST",data: f,cache: false,// 不用jq处理processData: false,contentType: false,success: function (r) {// console.log(r);// 外链名字var namepace = "http://p1935eslc.bkt.clouddn.com/";// 图片的完整名字var imgPath = namepace + r.key;// 构造参数,添加到后台$("input[name='src']").val(imgPath);var formData = new FormData($("#ff")[0]);$.ajax({url: "/users/add",type: "POST",data: formData,cache: false,// 不用jq处理processData: false,contentType: false,success: function (result) {// console.log(e);// 关闭对话框 刷新数据列表$("#myModal").modal("hide");QueryPage = {page: 1,rows: 5};getList(setPage);},error: function (e) {// console.log(e);}});}});});} else if (ManagerType == 1) {// 编辑var formData = new FormData($("#ff")[0]);$.ajax({url: "/users/edit",type: "POST",data: formData,cache: false,// 不用jq处理processData: false,contentType: false,success: function (result) {// console.log(e);// 关闭对话框 刷新数据列表$("#myModal").modal("hide");QueryPage = {page: 1,rows: 5};getList(setPage);},error: function (e) {// console.log(e);}})}});// 删除$("table").on("click", ".dataDelBtn", function (e) {var id = $(e.target).parents("tr").data("value").id;DelID = id;$("#deleteModal").modal("show");});// 提交删除$(".delSubBtn").click(function (e) {/* 1 发送删除请求2 关闭对话框3 刷新数据*/$.get("users/del?id=" + DelID, function (result) {$("#deleteModal").modal("hide");if (result.status == 0) {// 成功QueryPage.page = 1;getList(setPage);}})})
})// 显示进度条
$(window).ajaxStart(function () {$(".mask").show();
})
// 隐藏进度条
$(window).ajaxStop(function () {$(".mask").hide();
})

注意

整个demo download下后,需要修改的地方有

数据库连接代码 在app.js中

七牛的密钥等,在router/qiniu.js 中

环境: nodejs 8.3.0 express 4.x 其他 都是最新版本.

如有错误,联系方式 yeah126139163@163.com

nodejs crud功能(orm 七牛 mysql..)相关推荐

  1. nodejs crud

    nodejs crud功能 地址 https://github.com/unknowSir/nodejs-crud.git 功能 一个页面数据的crud 具有分页 模糊查询 图片上传七牛 前端预览 前 ...

  2. 七牛直播云服务技术揭秘

    以下根据七牛云首席布道师何李石现场演讲内容整理. 直播模型及其实现 一个通用的直播模型一般包括三个模块:主播方.服务器端和播放端. 首先是主播方,它是产生视频流的源头,由一系列流程组成: 第一,通过一 ...

  3. mysql备份七牛云存储_定时备份 Mysql并上传到七牛的方法

    多数应用场景下,我们需要对重要数据进行备份.并放置到一个安全的地方,以备不时之需. 常见的 MySQL 数据备份方式有,直接打包复制对应的数据库或表文件(物理备份).mysqldump 全量逻辑备份. ...

  4. 定时备份 MySQL 并上传到七牛

    定时备份 MySQL 并上传到七牛 多数应用场景下,我们需要对重要数据进行备份.并放置到一个安全的地方,以备不时之需. 常见的 MySQL 数据备份方式有,直接打包复制对应的数据库或表文件(物理备份) ...

  5. nodejs的express实现上传文件到七牛

    本文实现上传文件到七牛,动态切换上传空间,MD5设置key值,点击复制七牛返回的链接. 在七牛中注册开发者,获取key 七牛官网--管理控制台(偏右上角)--个人中心(获取秘钥)--对象存储,新建存储 ...

  6. 七牛首席布道师:Go不是在颠覆,就是在逆袭

    文章来源:http://www.csdn.net/article/2014-07-21/2820743 七牛官网: https://github.com/qiniu http://developer. ...

  7. 七牛服务器入门教程_教程:使用无服务器,StepFunction和StackStorm构建社区的入门应用程序…...

    七牛服务器入门教程 by Dmitri Zimine 由Dmitri Zimine 使用无服务器,StepFunction和StackStorm Exchange构建社区注册应用 (Building ...

  8. 七牛---借助第三方平台实现移动直播

    七牛---借助第三方平台实现移动直播   七牛关于回调流程 直播工作流模型 Client (iOS/Android/PC/Camera) 向 Server (业务逻辑服务器) 请求推流授权 Serve ...

  9. Sequelize 4.43.0 发布,基于 Nodejs 的异步 ORM 框架

    Sequelize 4.43.0 发布了,Sequelize 是一款基于 Nodejs 的异步 ORM 框架,它同时支持 PostgreSQL.MySQL.SQLite 和 MSSQL 多种数据库,很 ...

最新文章

  1. python使用matplotlib可视化使用subplots子图、subplots绘制子图、并为可视化的每个子图添加标题(title for each subplots)
  2. 怎么实现Web系统URL传输(表单提交)参数加密-zhuan
  3. redis的基本使用笔记二
  4. centos7.4二进制安装mysql
  5. sentinel 不显示项目_Sentinel+Nacos实现资源流控、降级、热点、授权
  6. JSON 语法之JSON null
  7. linux查看分区访问权限,linux查看分区是否开启acl权限
  8. VMware虚拟机CentOS7 - VMnet8网络配置及常见问题解决
  9. 最短路径和最小生成树的区别
  10. docker 升级linux内核,docker-machine之升级linux内核
  11. 【Linux】如何在文件中写入感叹号
  12. 数据库银行业务基础知识
  13. OpenGL之纹理过滤(Texture Filtering)、MipMap方法、纹理坐标
  14. SAP 发出商品业务配置
  15. 使用京东云免费云主机搭建CentOS
  16. 纽约州立大学环境与林业学院计算机科学专业,纽约州立大学环境与林业学院研究生专业 如何应对严峻的环境污染问题...
  17. python mql4跟单_MT4多功能本地跟单EA
  18. CTFshow-Web入门writeup
  19. 计算机应用基础高等数学试题,大专高等数学期末试卷(A卷)带答案.doc
  20. 企业网盘是高成本服务,低价网盘很难满足企业需求

热门文章

  1. android p支持三星吗,三星 Note 9 配置曝光,或预装 Android P
  2. 【软件质量】软件安全性
  3. apicloud安卓更新,新版本不能覆盖旧版本的问题及解决方案
  4. java20K之路(番外篇):程序员的技术KPI指标是什么呢
  5. Java读取配置文件中文乱码的问题
  6. Java的基础重要吗?Java入门应该学习那些?
  7. java里面自行车的属性_Java模拟自行车电动车属性调用
  8. 子曾经曰过,我平生第一次讨厌下雨。
  9. openFOAM中时间步长计算参数是怎样读进程序的——初步理解框架
  10. c语言的链表实验总结,链表实现集合实验报告_相关文章专题_写写帮文库