【前端】Vue2全家桶案例《看漫画》之番外篇、express上传漫画(可选)
转载请注明出处:http://www.cnblogs.com/shamoyuu/p/vue_vux_app_extra_1.html
项目github地址:https://github.com/shamoyuu/vue-vux-iconan
这一篇属于后台内容,前端小伙伴可以选择阅读。
接口后面都会公开,不会后台的小伙伴可以直接调用。
首先图片存储。图片我会上传到百度的BOS里,是一个支持外链的存储空间,还提供了很多非常方便的功能,后面用到的时候会详细说。
然后数据库用mysql。上传完图片后会把图片的信息都保存起来,方便我们后面调用。
图片处理,会用到gm,因为有些漫画是左右两张放在一张图片上的,我们需要裁切成2份后再上传。
首先我们建表,总共3个表,分别是漫画表(opus)、章节表(chapter)和图片表(picture)
漫画表(opus)

章节表(chapter)

图片表(picture)

然后我们来写一个router吧,它里面有3个接口,分别是添加漫画,重命名文件夹和批处理temp下文件夹。
这个文件是运行在express里的,可以看我以前介绍的在百度BAE搭建node后台的教程:http://www.cnblogs.com/shamoyuu/p/node_bae.html
var express = require("express");
var request = require('request');
var fs = require('fs');
var router = express.Router();
var _ = require("lodash");
var Opus = require("../models/index").Opus;
var Chapter = require("../models/index").Chapter;
var Picture = require("../models/index").Picture;
var gm = require("gm");
var BosClient = require("bce-sdk-js").BosClient;
const config = {
endpoint: "https://bj.bcebos.com", //传入Bucket所在区域域名
credentials: {
ak: "AccessKey", //您的AccessKey
sk: "SecretAccessKey" //您的SecretAccessKey
}
};
var client = new BosClient(config);
/**
* 啥都没有
*/
router.get("/", function (req, res, next) {
res.send({
message: "成功",
stateCode: 0
});
});
/**
* 添加一个漫画
*/
router.get("/add", function (req, res, next) {
Opus.create({
name: "七龙珠",
summary: "很久很久以前,地球上散落着七颗神奇的龙珠,传说只要聚齐它们,神龙就会出现,并可以为人实现一个愿望。为了寻找龙珠,布尔玛和孙悟空踏上了奇妙的寻珠之旅……",
author: "鸟山明",
cover: "http://iconan.bj.bcebos.com/2%2Fcover.jpg",
type: 0,
popularity: 0,
score: 100,
createtime: new Date(),
updatetime: new Date()
}).then(function () {
console.info("插入数据完成");
});
res.send({
message: "成功",
stateCode: 0
});
});
/**
* 重命名temp文件夹下除ok外所有文件夹
*/
router.get("/rename", function (req, res, next) {
fs.readdir("temp", function (err, files) {
for (var key in files) {
var dirname = files[key];
if (dirname != "ok") {
fs.renameSync("temp/" + dirname, "temp/第" + dirname.match(/龍珠完全版Vol_(\d+)/)[1] + "卷");
}
}
});
res.send({
message: "成功",
stateCode: 0
});
});
/**
* 开始处理temp下所有文件夹
*/
router.get("/start", function (req, res, next) {
//需要手动修改为当前漫画id
var opusid = 2;
var chapterid = 1;
var chapterPosition = 0;
fs.readdir("temp", function (err, files) {
console.info(files);
var dirFoo = [];
for (var key in files) {
var chaptername = files[key];
if (chaptername != "ok") {
dirFoo.push(function () {
return new Promise(function (resolve, reject) {
console.info("开始处理章节", chaptername);
Chapter.create({
opusid: opusid,
name: chaptername,
type: 0,
position: chapterPosition++,
createtime: new Date(),
updatetime: new Date()
}).then(function (model) {
console.info("插入数据完成", model.dataValues);
chapterid = model.dataValues.id;
fs.readdir("temp/" + chaptername, function (err, files) {
var pathUrl = "temp/ok/";
var num = 0;
var fooArr = [];
fooArr.push(function () {
return new Promise(function (resolve, reject) {
fs.readdir("temp/ok", function (err, files) {
for (var key in files) {
fs.unlinkSync("temp/ok/" + files[key]);
}
resolve();
});
})
});
for (var key in files) {
var fileName = files[key];
console.info(fileName);
fooArr.push(function () {
return new Promise(function (resolve, reject) {
var img = gm("temp/" + chaptername + "/" + fileName);
//获取图片尺寸
img.size(function (err, size) {
//如果图片是横向长方形,那么就从中间裁切成2张单独的图片
if (size.width / size.height > 1) {
img.crop(Math.floor(size.width / 2), size.height, Math.floor(size.width / 2), 0)
.write(pathUrl + "p" + fill(num++, 4) + ".jpg", function (err) {
err && console.info(err);
//第二张图片在第一张裁切完再进行
img.crop(Math.floor(size.width / 2), size.height, 0, 0)
.write(pathUrl + "p" + fill(num++, 4) + ".jpg", function (err) {
err && console.info(err);
resolve();
});
});
}
else {
img.write(pathUrl + "p" + fill(num++, 4) + ".jpg", function (err) {
err && console.info(err);
resolve();
});
}
});
})
})
}
//顺序同步执行fooArr里的方法
reduce(fooArr).then(function () {
console.info("裁切完成,开始上传");
//清空方法数组
fooArr.length = 0;
var picturePosition = 0;
//完成后上传
fs.readdir("temp/ok", function (err, files) {
for (var key in files) {
var fileName = files[key];
if (/^p\d+.jpg$/.test(fileName)) {
console.info(fileName);
fooArr.push(function () {
return new Promise(function (resolve, reject) {
console.info("开始上传");
//获取图片尺寸
gm(pathUrl + fileName).size(function (err, size) {
var upFileName = opusid + "/" + chapterid + "/" + Date.now() + ".jpg";
console.info(upFileName);
//以文件形式上传
client.putObjectFromFile("iconan", upFileName, pathUrl + fileName)
.then(function () {
Picture.create({
chapterid: chapterid,
url: "http://iconan.bj.bcebos.com/" + upFileName,
width: size.width,
height: size.height,
type: 0,
position: picturePosition++,
createtime: new Date(),
updatetime: new Date()
}).then(function () {
console.info("插入数据完成");
resolve();
});
})
.catch(function () {
console.info("上传失败", arguments);
reject();
});
});
})
});
}
}
reduce(fooArr).then(function () {
console.info("上传完成");
resolve();
});
});
})
});
});
})
});
}
}
reduce(dirFoo).then(function () {
console.info("最终完成");
})
});
res.send({
message: "正在操作中,请在控制台查看进度",
stateCode: 0
});
});
/**
* 将数字补位
* @param num 需要补位的数字
* @param n 需要多少位
* @returns {string}
*/
function fill(num, n) {
return (Array(n).join(0) + num).slice(-n);
}
/**
* 让一个promise的数组顺序执行
*/
function reduce(arr) {
var sequence = Promise.resolve();
arr.forEach(function (item) {
sequence = sequence.then(item)
});
return sequence
}
module.exports = router;
然后把下载好的漫画,以章节为目录复制到temp文件夹下,例如下面的《七龙珠》

先调用rename接口,然后调用start接口,就会看到后台在不断处理和上传图片,坐等几小时后,就会按章节分不同文件夹上传的服务器,然后把外链地址保存到数据库的picture表中。
昨晚上传了5小时,就上传完了《柯南》和《七龙珠》,总共10G多的图片,速度还是很不错的。
【前端】Vue2全家桶案例《看漫画》之番外篇、express上传漫画(可选)的更多相关文章
- 【前端】Vue2全家桶案例《看漫画》之六、图片阅读页
转载请注明出处:http://www.cnblogs.com/shamoyuu/p/vue_vux_app_6.html 项目github地址:https://github.com/shamoyuu/ ...
- 【前端】Vue2全家桶案例《看漫画》之一、添加四个导航页
转载请注明出处:http://www.cnblogs.com/shamoyuu/p/vue_vux_app_1.html 项目github地址:https://github.com/shamoyuu/ ...
- 【前端】Vue2全家桶案例《看漫画》之四、漫画页
转载请注明出处:http://www.cnblogs.com/shamoyuu/p/vue_vux_app_4.html 项目github地址:https://github.com/shamoyuu/ ...
- 【前端】Vue2全家桶案例《看漫画》之二、完成首页基本样式
转载请注明出处:http://www.cnblogs.com/shamoyuu/p/vue_vux_app_2.html 项目github地址:https://github.com/shamoyuu/ ...
- 【前端】Vue2全家桶案例《看漫画》之七、webpack插件开发——自动替换服务器API-URL
转载请注明出处:http://www.cnblogs.com/shamoyuu/p/vue_vux_app_7.html 项目github地址:https://github.com/shamoyuu/ ...
- 【前端】Vue2全家桶案例《看漫画》之五、引入axios
转载请注明出处:http://www.cnblogs.com/shamoyuu/p/vue_vux_app_5.html 项目github地址:https://github.com/shamoyuu/ ...
- 【前端】Vue2全家桶案例《看漫画》之三、引入vuex
转载请注明出处:http://www.cnblogs.com/shamoyuu/p/vue_vux_app_3.html 项目github地址:https://github.com/shamoyuu/ ...
- Vue2全家桶+Element搭建的PC端在线音乐网站
目录 1,前言 2,已有功能 3,使用 4,目录结构 5,页面效果 登录页 首页 排行榜 歌单列表 歌单详情 歌手列表 歌手详情 MV列表 MV详情 搜索页 播放器 1,前言 项目基于Vue2全家桶及 ...
- 知识图谱实战开发案例剖析-番外篇(1)- Neo4j是否支持按照边权重加粗和大数量展示
一.前言 本文是<知识图谱实战开发案例完全剖析>系列文章和网易云视频课程的番外篇,主要记录学员在知识图谱等相关内容的学习 过程中,提出的共性问题进行展开讨论.该部分内容原始内容记录在网易云 ...
随机推荐
- PHPUnit使用教程——PHP环境变量+x-debug+composer+phpunit配置安装(超详细!)
注意:Windows系统 一.提前入坑点:要求php5.6,7.0,7.1,不论使用集成版还是非集成版的小伙伴都要好好查看自己的php版本,个人的版本居然是5.5.X的,哭唧唧.不过别担心,爸爸教你升 ...
- gulp压缩文件最简示例
安装gulp-uglify 作为项目的开发依赖即可 $ npm gulp-uglify --save-dev 压缩js文件 gulpfile.js const gulp = require('gulp ...
- echarts中视觉映射器(visualMap)与时间轴(timeline)混用的实现方法
1.简述 echarts中的 timeline 组件,提供了在多个 ECharts option 间进行切换.播放等操作的功能. 与其他组件些不同,它需要操作『多个option』. 所以除了基准的ba ...
- 利用 secureCRT 直接上传下载文件 (sz,rz)
在window下向linux传送文件的方法. 首先在window中安装SecureCRT,然后在快速连接中建立一个到linux的连接,当然,你要先知道你的系统的ip,在终端中键入ifconfig可以查 ...
- SSD trim及4k对齐
trim可以帮助减小SSD的写放大WA问题,删除文件后不仅仅是将文件标记为删除,而是在SSD空闲的时候统一进行删除. Linux下的trim支持叫discard,修改fstab文件,在挂载参数中加上d ...
- 《深入理解Java虚拟机》学习笔记(二)
垃圾回收的前提是判断对象是否存活,对象不再存活时将会被回收,下面是2种判断的方法. 引用计数法: 主流的Java虚拟机并没有使用引用计数法来管理内存,重要的原因就是循环引用的问题难以解决. 可达性分析 ...
- BZOJ 1116: [POI2008]CLO [连通分量]
Byteotia城市有n个 towns m条双向roads. 每条 road 连接 两个不同的 towns ,没有重复的road. 你要把其中一些road变成单向边使得:每个town都有且只有一个入度 ...
- C++ cin.get及getline的用法
1.cin.get() 从指定的输入流中提取一个字符,函数的返回值就是这个字符.文件结束符会返回EOF,一般以-1代表EOF. #include<iostream> using names ...
- C#实现航班查询及预订
using System;using System.Collections.Generic;using System.ComponentModel;using System.Data;using Sy ...
- js作用域的相关知识
众所周知,在ES6之前,JavaScript是没有块级作用域的,如下图所示: 学过其他语言的同学肯定有点诧异,为什么会这样呢?因为js还是不同于其他语言的,在ES5中,只有全局作用域和函数作用域,并没 ...