使用Node.js+expressjs从零开始搭建博客系列之三:认识Sequelize的CURD及multer实现上传

一、通过用户管理的功能认识Sequelize的CURD

定义用户模型:

  1. const userModel = {};
  2. const db = require('../libs/db.jshttp://openfile.shixinke.com/images/posts/2016/11/span>);
  3. const User = db.db.define('userhttp://openfile.shixinke.com/images/posts/2016/11/span>, {
  4. uid:{type : db.Sequelize.INTEGER, primaryKey : true},
  5. account: db.Sequelize.STRING,
  6. password: db.Sequelize.STRING,
  7. nickname: db.Sequelize.STRING,
  8. email: db.Sequelize.STRING,
  9. avatar: db.Sequelize.STRING,
  10. status: db.Sequelize.STRING,
  11. last_login_time: db.Sequelize.DATE,
  12. last_login_ip: db.Sequelize.STRING,
  13. create_time: db.Sequelize.DATE
  14. }, {
  15. tableName:'blog_userhttp://openfile.shixinke.com/images/posts/2016/11/span>,
  16. timestamps:true,
  17. createdAt : 'create_timehttp://openfile.shixinke.com/images/posts/2016/11/span>,
  18. updatedAt : false,
  19. deletedAt : false
  20. });
1、查询列表并统计查询数目:findAndCountAll
  1. userModel.search = async function(condition, offset, limit){
  2. const where = {};
  3. if (condition.account && condition.account != 'http://openfile.shixinke.com/images/posts/2016/11/span>) {
  4. where.account = condition.account.trim();
  5. }
  6. if (condition.nickname && condition.nickname != 'http://openfile.shixinke.com/images/posts/2016/11/span>) {
  7. where.nickname = condition.nickname.trim();
  8. }
  9. if (condition.email && condition.email != 'http://openfile.shixinke.com/images/posts/2016/11/span>) {
  10. where.email = condition.email.trim();
  11. }
  12. if (condition.status && condition.status != 'http://openfile.shixinke.com/images/posts/2016/11/span>) {
  13. where.status = condition.status;
  14. }
  15. return User.findAndCountAll({where : where, offset : offset, limit : limit});
  16. };
2、只查询列表:findAll
  1. userModel.all = async function(){
  2. const data = await User.findAll({attributes:['uidhttp://openfile.shixinke.com/images/posts/2016/11/span>, 'accounthttp://openfile.shixinke.com/images/posts/2016/11/span>, 'nicknamehttp://openfile.shixinke.com/images/posts/2016/11/span>, 'avatarhttp://openfile.shixinke.com/images/posts/2016/11/span>], where : {status : 'ENABLEhttp://openfile.shixinke.com/images/posts/2016/11/span>}});
  3. let datalist = [];
  4. if (data) {
  5. for(let i=0; i<data.length; i++) {
  6. datalist.push(data[i].dataValues);
  7. }
  8. }
  9. return datalist;
  10. };
3、查询单条数据:findOne或findById
  1. userModel.detail = async function(id){
  2. return await User.findById(id);
  3. };
4、添加数据(添加用户):create
  1. userModel.add = async function(data){
  2. return User.create(data);
  3. };
5、修改数据:update
  1. userModel.update = async function(data){
  2. return await User.update(data, {where : {uid : data.uid}});
  3. };

6、删除数据:destroy

  1. userModel.delete = async function(id){
  2. return await User.destroy({where : {uid : id}});
  3. };

二、通过multer实现上传用户头像的功能

multer是express的一个用于上传的中间件,其github地址为:https://github.com/expressjs/multer

效果如下:

(1)上传组件使用webuploader

webuploader的官方网址:http://fex.baidu.com/webuploader/

定义一个上传的函数:

  1. var webuploader = function(options){
  2. //可以传入的参数列表
  3. var options = options ? options : {};
  4. //加载webuploader和layer
  5. require(['webuploaderhttp://openfile.shixinke.com/images/posts/2016/11/span>, 'layerhttp://openfile.shixinke.com/images/posts/2016/11/span>], function(WebUploader, layer){
  6. //上传区域容器
  7. var $uploadBox = $(options.picker).parents('.upload-boxhttp://openfile.shixinke.com/images/posts/2016/11/span>);
  8. //上传处理的服务端地址
  9. var serverUrl = options.serverUrl;
  10. //上传的文件类型:图片或文件
  11. options.fileType = options.fileType ? options.fileType : 'imagehttp://openfile.shixinke.com/images/posts/2016/11/span>;
  12. if (!serverUrl || serverUrl == 'http://openfile.shixinke.com/images/posts/2016/11/span>) {
  13. serverUrl = options.fileType == 'imagehttp://openfile.shixinke.com/images/posts/2016/11/span> ? '/upload/imageshttp://openfile.shixinke.com/images/posts/2016/11/span> : '/upload/fileshttp://openfile.shixinke.com/images/posts/2016/11/span>;
  14. }
  15. //允许的图片格式
  16. var accept = null;
  17. if (options.fileType == 'imagehttp://openfile.shixinke.com/images/posts/2016/11/span>) {
  18. accept = {title: 'Imageshttp://openfile.shixinke.com/images/posts/2016/11/span>, extensions: 'gif,jpg,jpeg,bmp,pnghttp://openfile.shixinke.com/images/posts/2016/11/span>, mimeTypes: 'image/*http://openfile.shixinke.com/images/posts/2016/11/span>};
  19. } else {
  20. accept = {title: 'fileshttp://openfile.shixinke.com/images/posts/2016/11/span>, extensions: 'pdf,txt,md,csvhttp://openfile.shixinke.com/images/posts/2016/11/span>, mimeTypes: 'application/pdf,text/plain,text/markdown,text/comma-separated-valueshttp://openfile.shixinke.com/images/posts/2016/11/span>};
  21. }
  22. //实例化webuploader
  23. var uploader = WebUploader.create({
  24. //指定用于上传的swf文件
  25. swf:'/js/libs/webuploader/0.1.5/Uploader.swfhttp://openfile.shixinke.com/images/posts/2016/11/span>,
  26. //处理上传的服务端地址
  27. server: serverUrl,
  28. auto:true,
  29. //触发上传的按钮
  30. pick: options.picker ? options.picker : $('#filePickerhttp://openfile.shixinke.com/images/posts/2016/11/span>),
  31. accept:accept,
  32. resize: false
  33. });
  34. //文件域的名称
  35. var name = options.name ? options.name : $uploadBox.attr('data-namehttp://openfile.shixinke.com/images/posts/2016/11/span>);
  36. //上传出错处理函数
  37. uploader.on( 'uploadErrorhttp://openfile.shixinke.com/images/posts/2016/11/span>, function( file ) {
  38. layer.msg('上传失败http://openfile.shixinke.com/images/posts/2016/11/span>, {icon:5});
  39. });
  40. //上传成功回调函数
  41. uploader.on('uploadSuccesshttp://openfile.shixinke.com/images/posts/2016/11/span>, function(file, ret){
  42. if (ret && ret.code && ret.code == 200) {
  43. if (options.fileType == 'imagehttp://openfile.shixinke.com/images/posts/2016/11/span>) {
  44. if (options.showBox) {
  45. //将上传后的文件地址存入到隐藏域中
  46. $('#hidden-img-filehttp://openfile.shixinke.com/images/posts/2016/11/span>).val(ret.data.url);
  47. //并显示图片
  48. $(options.showBox).attr('srchttp://openfile.shixinke.com/images/posts/2016/11/span>, ret.data.url);
  49. } else {
  50. //针对多张图片上传的
  51. $uploadBox.find('ulhttp://openfile.shixinke.com/images/posts/2016/11/span>).append('<li><img src="http://openfile.shixinke.com/images/posts/2016/11/span>+ret.data.url+'"><input type="hidden" class="upload-hidden-path" name="http://openfile.shixinke.com/images/posts/2016/11/span>+name+'" value="http://openfile.shixinke.com/images/posts/2016/11/span>+ret.data.url+'"><a href="javascript:;" class="remove-file iconfont icon-error upload-remove-btn"></a></li>http://openfile.shixinke.com/images/posts/2016/11/span>);
  52. }
  53. } else {
  54. //针对文件上传的,只显示文件名
  55. $uploadBox.find('ulhttp://openfile.shixinke.com/images/posts/2016/11/span>).append('<li><i class="iconfont icon-http://openfile.shixinke.com/images/posts/2016/11/span>+ret.data.extension+'"></i><p class="filename">http://openfile.shixinke.com/images/posts/2016/11/span>+ret.data.basename+'</p><input type="hidden" class="upload-hidden-path" name="http://openfile.shixinke.com/images/posts/2016/11/span>+name+'" value="http://openfile.shixinke.com/images/posts/2016/11/span>+ret.data.url+'"><a href="javascript:;" class="remove-file iconfont icon-error upload-remove-btn"></a></li>http://openfile.shixinke.com/images/posts/2016/11/span>);
  56. }
  57. if (!options.isMulti) {
  58. $(options.picker).parents('.upload-btn-boxhttp://openfile.shixinke.com/images/posts/2016/11/span>).hide();
  59. }
  60. } else {
  61. layer.msg(ret.message, {icon:5});
  62. }
  63. });
  64. });
  65. };

注:这里使用到了requirejs这个模块加载类库,另外使用到layer这个弹框插件

(2)后台上传组件使用multer
  1. //定义控制器名称(这里是上传个人头像)
  2. const profile = {};
  3. //加载multer模块
  4. const multer = require('multerhttp://openfile.shixinke.com/images/posts/2016/11/span>);
  5. //设置上传文件的存储类型(这里指定为磁盘存储,还有内存存储这种)
  6. const storage = multer.diskStorage({
  7. //指定存储的目录
  8. destination:'public/uploads/images/avatarhttp://openfile.shixinke.com/images/posts/2016/11/span>,
  9. //设置文件名(默认上传的文件名是没有后缀的)
  10. filename:function(req, file, cb){
  11. //file.originalname为图片原名称
  12. let fileName = Date.now()+path.extname(file.originalname);
  13. cb(null, fileName);
  14. }
  15. });
  16. //实例化上传中间件(single表示是上传单个文件,多个用array,file表示是文件域的名称)
  17. const upload = multer({storage : storage}).single('filehttp://openfile.shixinke.com/images/posts/2016/11/span>);
  18. //上传头像
  19. profile.avatar = function(req, res){
  20. upload(req, res, function(err){
  21. //获取文件的路径
  22. const filename = req.file.path.replace('publichttp://openfile.shixinke.com/images/posts/2016/11/span>, 'http://openfile.shixinke.com/images/posts/2016/11/span>);
  23. if (err) {
  24. res.json({code : 5003, message : '上传失败:http://openfile.shixinke.com/images/posts/2016/11/span>+err});
  25. } else {
  26. res.json(code : 200 ,message : '上传成功http://openfile.shixinke.com/images/posts/2016/11/span>, data : {url : filename});
  27. }
  28. });
  29. };

注:multer每个版本的用法可能不一样,请查阅使用的版本的使用文档。这里以1.2.0为例