ps:以爲有幫助的同窗點個贊或者github star 在此謝過react
批量上傳和下載webpack
mongoose數據庫操做ios
增刪查git
webpack4部分優化配置github
jwt登陸控制、路由鑑權web
tips:批量下載須要使用引入archiver第三方包將多個文件打包成一個壓縮文件mongodb
//此處分爲文件和圖片兩個接口 router.get('/downloadFile/:name',//文件 async ctx => { ctx.set('Content-disposition', `attachment;filename=${ctx.params.name}`); const paths = `src/assets/upload/files/${ctx.params.name}` const data = fs.createReadStream(paths) // 發送路徑文件內容的文件 ctx.body = data } ).get('/downloadImg/:name',//圖片 async ctx => { ctx.set('Content-disposition', `attachment;filename=${ctx.params.name}`); const paths = `src/assets/upload/imgs/${ctx.params.name}`; ctx.attachment(paths); await send(ctx, paths); } ) //批量下載 router.get('/batchDownload', async ctx => { const list = [{ name: '1.jpg', path: 'src/assets/upload/imgs/1.jpg' }, { name: '1.csv', path: 'src/assets/upload/files/1.csv' }, { name: '2.png', path: 'src/assets/upload/imgs/2.png' }];//name爲壓縮文件內生成的文件名稱,path爲要下載的文件路徑 const zipName = 'download.zip';//自定義生成的壓縮文件名稱 const zipPath = `src/assets/download/${zipName}`;//自定義生成的壓縮文件路徑 const zipStream = fs.createWriteStream(zipPath); const zip = archiver('zip'); zip.pipe(zipStream); for (let i = 0; i < list.length; i++) { // 添加單個文件到壓縮包 zip.append(fs.createReadStream(list[i].path), { name: list[i].name }) } await zip.finalize(); ctx.attachment(zipPath); await send(ctx, zipPath); } )
//此處同Koa app.get('/downloadFile/:name', (req, res) => { const filePath = `src/assets/upload/files/${req.params.name}` if (fs.existsSync(filePath)) { res.download(filePath) } else { res.json({ err: 'file is not exist', success: false }) } } ).get('/downloadImg/:name', (req, res) => { const filePath = `src/assets/upload/imgs/${req.params.name}` if (fs.existsSync(filePath)) { res.download(filePath) } else { res.json({ err: 'file is not exist', success: false }) } } ).get('/batchDownload', async (req, res) => { const list = [{ name:'1.jpg',path: 'src/assets/upload/imgs/1.jpg' }, { name:'1.csv',path: 'src/assets/upload/files/1.csv' }, { name:'2.png',path: 'src/assets/upload/imgs/2.png' }]; const zipName = 'download.zip'; const zipPath = `src/assets/download/${zipName}`; const zipStream = fs.createWriteStream(zipPath); const zip = archiver('zip'); zip.pipe(zipStream); for (let i = 0; i < list.length; i++) { // 添加單個文件到壓縮包 zip.append(fs.createReadStream(list[i].path), { name: list[i].name }) } await zip.finalize(); setTimeout(() => { res.download(zipPath) }, 0); } )
//接收post請求須要先處理options請求 app.use( async (ctx, next) => { if (ctx.request.method === "OPTIONS") { ctx.response.status = 200 ctx.set('Access-Control-Allow-Origin', ctx.request.headers.origin) ctx.set("Access-Control-Max-Age", 24 * 60 * 60 * 1000); ctx.set("Access-Control-Allow-Methods", 'GET,POST,OPTIONS,DELETE,PUT'); ctx.set("Access-Control-Allow-Headers", 'Origin,Content-Type,Authorization,Accept,X-Custom-Header,anonymous,X-Requested-With') ctx.body = '' } else { await next() } } ) //上傳 router.post('/upload', ctx => { try { const files = ctx.request.files.file files.length ? files.forEach(file => fs .createReadStream(file.path) .pipe(fs.createWriteStream(`${file.type.indexOf('image') >= 0 ? 'src/assets/upload/imgs' : 'src/assets/upload/files'}/${file.name}`)) ) : fs .createReadStream(files.path) .pipe(fs.createWriteStream(`${files.type.indexOf('image') >= 0 ? 'src/assets/upload/imgs' : 'src/assets/upload/files'}/${files.name}`)) ctx.body = '上傳成功' } catch (e) { ctx.body = '上傳失敗' } } )
//處理options app.all('*', (req, res, next) => { if (req.method === "OPTIONS") { res.status(200) res.end() } else { next() } } ).post('/upload', upload.any(), (req, res, next) => { try { const files = req.files console.log(files) files.length ? files.forEach(file => fs .createReadStream(file.path) .pipe(fs.createWriteStream(`${file.mimetype.indexOf('image') >= 0 ? 'src/assets/upload/imgs' : 'src/assets/upload/files'}/${file.originalname}`)) ) : fs .createReadStream(files.path) .pipe(fs.createWriteStream(`${files.mimetype.indexOf('image') >= 0 ? 'src/assets/upload/imgs' : 'src/assets/upload/files'}/${files.originalname}`)) res.json({ err: 'upload success', success: false }) } catch (e) { res.json({ err: 'upload failed', success: false }) } } )
分爲兩個文件 connect.js鏈接數據庫,db.js導出mongodb的自定義數據模型數據庫
const mongoose = require('mongoose') mongoose.Promise = global.Promise mongoose.connect('mongodb://用戶名:密碼@ds145093.mlab.com:45093/用戶名', { useNewUrlParser: true }, (err, info) => { if (err) throw 'mongodb connect failed' console.log('mongodb connect success') } )
require('./connect') const mongoose = require('mongoose'); const Schema = mongoose.Schema; const todoSchema = new Schema({ name: String, isDoing: Boolean, createDate: Date, }, {versionKey: false}) const Todo = mongoose.model('Todo', todoSchema) exports.Todo=Todo;
//須要引入koa-body const koaBody = require('koa-body') //查詢全部記錄 app.get('/todoList', async ctx => { try { let data = await Todo.find({}) ctx.body = { data, success: true } } catch (e) { ctx.body = { data: [], success: false } } }, ).get('/todoList/:name',//模糊查詢單一記錄 async ctx => { const params = { name: { $regex: new RegExp(`${ctx.params.name}`) } } try { let data = await Todo.find(params) ctx.body = { data, success: true } } catch (e) { ctx.body = { data: [], success: false } } } ).post('/todoList', koaBody(),//新增記錄 async ctx => { const todo = new Todo({ ...ctx.request.body }) try { let data = await todo.save() ctx.body = { data, success: true } } catch (err) { ctx.body = { data: { err }, success: false } } } ).del('/todoList/:name',//刪除記錄 async ctx => { const params = { name: ctx.params.name } try { let data = await Todo.findOneAndDelete(params) ctx.body = { data, success: true } } catch (err) { ctx.body = { data: { err }, success: false } } } )
//查詢全部記錄 app.get('/todoList', async (req, res, next) => { try { let data = await Todo.find({}) res.json({ data, success: true }) } catch (e) { res.json({ data: [], success: false }) } }, ).get('/todoList/:name',//模糊查詢記錄 async (req, res, next) => { const params = { name: { $regex: new RegExp(`${req.params.name}`) } } try { let data = await Todo.find(params) res.json({ data, success: true }) } catch (e) { res.json({ data: [], success: false }) } } ).post('/todoList',//新增記錄 async (req, res, next) => { const todo = new Todo({ ...req.body }) try { let data = await todo.save() res.json({ data, success: true }) } catch (err) { res.json({ data: { err }, success: false }) } } ).delete('/todoList/:name',//刪除記錄 async (req, res, next) => { const params = { name: req.params.name } try { let data = await Todo.findOneAndDelete(params) res.json({ data, success: true }) } catch (err) { res.json({ data: { err }, success: false }) } } )
//dll.js const path = require('path') const webpack = require('webpack') module.exports = { entry: { vendor: [ 'react', 'react-dom', 'react-router-dom', 'immutable', 'antd', 'axios', ], }, output: { filename: '[name].dll.js', path: path.resolve(__dirname, '../public'), library: '[name]_library', }, plugins: [ new webpack.DefinePlugin({ 'process.env.NODE_ENV': JSON.stringify('production') }), new webpack.DllPlugin({ path: path.resolve(__dirname, '../public','[name]-manifest.json'), name: '[name]_library', context: __dirname }) ], }
optimization: { splitChunks: { chunks: 'all', name: false, cacheGroups: { commons: { name: 'commons', priority: 10, chunks: 'initial' } }, } }
//引入happypack const HappyPack = require('happypack') new HappyPack({ id: 'jsx', threads: 4, loaders: ['babel-loader?presets[]=react,presets[]=latest&compact=false'], })
//引入react-loadable import Loadable from 'react-loadable' const MyLoadingComponent = ({ isLoading, error }) => { return '' } const Nav = Loadable({ loader: () => import(/* webpackChunkName: "Nav" */'../components/Nav'),//註釋是爲了讓webpack打包出來的文件以路由爲名 loading: MyLoadingComponent })