DAY2-代码优化、验证信息封装和图片上传

代码结构的优化、提交信息校验、文件的上传


一、代码结构的优化

问题:由于现在开发写的代码全部都是在 app.js 文件,这样会导致单个文件非常的大,臃肿。所以在开发的时候,一般我们都是要按照一定的规范去切分我们的代码,形成一定的分层关系,便于后期的维护。

解决方案:
1.对app.js里面的代码需要做切分
2.根据业务的功能然后建立对应的文件或者文件夹进行管理

1.1数据库优化

创建文件夹db,对有个数据库建一个目录,根据数据库的类型,拆分为不同的数据库操作文件,这里使用的是mongoose所以创建mongodb.js(如果使用mysql就创建mysql.js这样)

第一步:

/*1. 根据数据库的类型,拆分为不同的数据库操作文件*/
const mongoose = require('mongoose');
mongoose.connect('mongodb://localhost:27017/dingli', {useNewUrlParser: true, useUnifiedTopology: true});
//定义模型
const WebsiteSchema = mongoose.Schema({
    siteName: String,
    keyword: String,
    description: String,
    copyright: String,
    benanhao: String,
    address: String,
    phoneNumber: String,
    tel: String,
    email: String,
    qrcode: String,
    appcode: String,
});
//引入模型
const WebsiteModel = mongoose.model('Website', WebsiteSchema);

第二步:
对数据库表的处理,在开发的时候,一般我们会操作很多的表。那么我们需要在建立一个models目录,对所有的表的模型进行管理。
models/website.js

/*引入数据库*/
const mongoose = require('../db/mongodb.js');

/*2. 这个是代码对网站配置表的操作,在开发的时候,一般我们会操作很多的表。那么我们需要在建立一个目录,对所有的表的模型进行管理。*/
const WebsiteSchema = mongoose.Schema({
    siteName: String,
    keyword: String,
    description: String,
    copyright: String,
    benanhao: String,
    address: String,
    phoneNumber: String,
    tel: String,
    email: String,
    qrcode: String,
    appcode: String,
});
const WebsiteModel = mongoose.model('Website', WebsiteSchema);

/* 等一下需要操作表的地方,需要使用的到模型,所以模型也要暴露 */
module.exports = WebsiteModel;

db/mongodb.js

/*1. 根据数据库的类型,拆分为不同的数据库操作文件*/
const mongoose = require('mongoose');

mongoose.connect('mongodb://localhost:27017/dingli', {useNewUrlParser: true, useUnifiedTopology: true});

/* 在模型文件夹下的各个模型需要使用的 mongoose ,需要导出 */
module.exports = mongoose;

在app.js里增加

/* 3. 由于业务里面要使用到模型,则我们需要导入模型 */
const WebsiteModel = require('./models/website.js');

第三步:
数据库配置,创建目录condig,db.js定义数据的连接地址

const mgDsn='mongodb://localhost:27017/dingli'
module.exports = {
    mgDsn
}

db/mongodb.js修改为

/*1. 根据数据库的类型,拆分为不同的数据库操作文件*/
const mongoose = require('mongoose');
const dbConfig = require('../config/db.js');

mongoose.connect(dbConfig.mgDsn, {useNewUrlParser: true, useUnifiedTopology: true});

/* 在模型文件夹下的各个模型需要使用的 mongoose ,需要导出 */
module.exports = mongoose;

目录结构:
在这里插入图片描述

nodemon app.js启动
http://localhost:3000/contact
http://localhost:3000/admin/index
都没有问题 都能展示

1.2路由信息优化

通过 app.get 这种定义的urL地址,一般也叫做路由信息。
上网:路由器。在web开发里面里面也有路由的概念,web里面的路由指的是,我们定义好urL地址和业务代码之间的关系,我们称之为路由映射,或者叫做路由规则。
由于一个网站里面的业务非常的那么我们在处理的时候,也需要根据不同的路由规则来划分路由信息﹑例如:后台的路由(1.后台的首页2.后台的新闻中心3.后台的案例中心前台的路由)
新建routes目录创建相关js路由文件

1.2.1引入库

express官网-指南-路由
https://www.expressjs.com.cn/guide/routing.html
翻到差不多最下面express.Router代码复制到routes/index.js进行修改
app.get改成router.get,app.js里的相应代码删除
index.js

const express = require('express');
const router = express.Router(); // 路由器

//使用路由器定义映射规则
/*单独的路由文件,一般称之为:路由外置;路由外置文件里面的 路由url地址:app.use('/admin', indexRouter); + /index*/
router.get('/admin/index',(req,res)=>{
    /*之前使用的 express-art-template 完成静态页面的渲染操作 */
    res.render('index');
});

router.get('/admin/welcome',(req,res)=>{
    res.render('welcome');
});
/* 暴露出去以后,谁需要这个路由信息,导入即可*/
module.exports = router;

website.js

const express = require('express');
const router = express.Router();
const WebsiteModel = require('../models/website.js');

//表单信息收集操作
router.post('/store', (req, res) => {
    /*接受post提交的数据,然后在把数据入库操作 到底是更新还是添加操作 */
    /* 如果是更新,则我们需要知道到底是更新哪条记录信息 */
    console.log(req.body); // 就是post提交的数据 把数据库入库到数据库里面
    //取想要的信息
    let {_id, siteName, keyword, description, copyright, benanhao, address, phoneNumber, tel, email, qrcode, appcode} = req.body;

    if(_id){
        // 如果_id有值是更新操作,否则为添加操作
        WebsiteModel.findById(_id, (error, data) => {
            //找_id是否有错
            if (error) {
                res.send('update failure!');
                return;
            } else {
                //更新 保存到数据库
                data.siteName = siteName;
                data.keyword = keyword;
                data.description = description;
                data.copyright = copyright;
                data.benanhao = benanhao;
                data.address = address;
                data.phoneNumber = phoneNumber;
                data.tel = tel;
                data.email = email;
                data.qrcode = qrcode;
                data.appcode = appcode;

                data.save((error, data) => {
                    if (error) {
                        console.log(error);
                        res.redirect('/admin/website/add');
                    } else {
                        console.log(data);
                        /*redirect翻译过来叫做重定向,也可以理解为跳转。参数就是我们跳转的地址*/
                        res.redirect('/admin/website/add');
                    }
                });
            }
        })
    }else{
        //数据存储用mongoose 定义一个dingli的数据库
        //表的定义
        let webstiteObj = new WebsiteModel({
            siteName,
            keyword,
            description,
            copyright,
            benanhao,
            address,
            phoneNumber,
            tel,
            email,
            qrcode,
            appcode
        });

        webstiteObj.save((error, data) => {
            if (error) {
                console.log(error);
                res.redirect('/admin/website/add');
                // res.send('error');
            } else {
                console.log(data);
                res.redirect('/admin/website/add');
                // res.send('ok');
            }
        });
    }
});

// 网站基本信息模块添加
router.get('/add', async (req, res) => {
    /*添加信息表单*/
    const info = await WebsiteModel.findOne();
    if (info) {
        /* 如果信息是存在,则我们应该把信息给到页面做展示*/
        // res.render('site-add', {info: info}); // {}
        res.render('site-add', {info}); // {}

    } else {
        /* 如果不存在,应该是做信息的添加操作 */
        res.render('site-add', {info: {}});
    }
});
module.exports = router;

front.js

const express = require('express');
const router = express.Router(); // 路由器
const WebsiteModel = require('../models/website.js');
router.get('/', (req, res) => {
    res.render('front/index');
})
router.get('/contact', async (req, res) => {
    const info = await WebsiteModel.findOne();
    res.render('front/contact', {info: info});
})
module.exports = router;

app.js增加

/*路由器引入*/
const indexRouter = require('./routes/index.js');
const websiteRouter = require('./routes/website.js');
const frontRouter = require('./routes/front.js');

app.use('/admin', indexRouter);
app.use('/admin/website', websiteRouter);
app.use(frontRouter);

1.3模板引擎外置

创建templateEngine目录 artTemplate.js

const path = require('path');

module.exports = (app) => {
    app.engine('html', require('express-art-template'));
    app.set('view options', {
        debug: process.env.NODE_ENV !== 'production'
    });

    /* 注意:在使用的模板引擎目录的时候,需要设置为当前目录的上级目录 */
    // console.log(path.join(__dirname, '../views'));

    app.set('views', path.join(__dirname, '../views'));
    app.set('view engine', 'html');
}

app.js增加 相关代码删除

const artTemplate = require('./templateEngine/artTemplate.js');

//定义art-template模板引擎
artTemplate(app);

二、提交信息校验

提交验证的验证操作
mongoose验证
http://www.mongoosejs.net/docs/validation.html

  • 验证定义于 SchemaType
  • 验证是一个中间件。它默认作为 pre(‘save’)` 钩子注册在 schema 上
  • 你可以使用 doc.validate(callback) 或 doc.validateSync() 手动验证验证器不
  • 对未定义的值进行验证,唯一例外是 required 验证器
  • 验证是异步递归的。当你调用 Model#save,子文档验证也会执行,出错
  • 话 Model#save 回调会接收错误
  • 验证是可定制的

找到模板对models/website.js进行对应修改

/*引入数据库*/
const mongoose = require('../db/mongodb.js');

/*2. 这个是代码对网站配置表的操作,在开发的时候,一般我们会操作很多的表。那么我们需要在建立一个目录,对所有的表的模型进行管理。*/
const WebsiteSchema = mongoose.Schema({
    siteName: {
        type: String, // 定义类型
        required: [true, '网站名称不能为空'], // 定义验证规则,这个字段不能为空,必填的
        minlength: [10, '网站名称的最小长度为10个字符'], // 最小长度
        maxlength: [30, '网站名称的最大长度为30个字符'], // 最大长度
    },
    keyword: {
        type: String, // 定义类型
        required: [true, '网站关键字信息不能为空'],
        minlength: [10, '网站关键字信息的最小长度为10个字符'], 
        maxlength: [100, '网站关键字信息最大长度为100个字符'], 
    },
    description: {
        type: String, // 定义类型
        required: [true, '网站描述信息不能为空'],
        minlength: [10, '网站描述信息的最小长度为10个字符'], 
        maxlength: [200, '网站描述信息的最大长度为100个字符'], 
    },
    copyright: String,
    benanhao: String,
    address: String,
    phoneNumber: String,
    tel: String,
    email: String,
    qrcode: String,
    appcode: String,
});

const WebsiteModel = mongoose.model('Website', WebsiteSchema);
WebsiteModel.fields = {
    siteName: '网站名称',
    keyword: '网站关键字',
    description: '网站描述',
    copyright: '版权信息',
    benanhao: '备案号',
    address: '公司地址',
    phoneNumber: '联系方式',
    tel: '传真',
    email: '网站邮箱',
    qrcode: '公众号二维码',
    appcode: '手机App二维码',
};
/* 等一下需要操作表的地方,需要使用的到模型,所以模型也要暴露 */
module.exports = WebsiteModel;

对routes/website.js进行对应修改获取错误信息

const express = require('express');
const router = express.Router();
const WebsiteModel = require('../models/website.js');

//表单信息收集操作
router.post('/store', (req, res) => {

    let {_id, siteName, keyword, description, copyright, benanhao, address, phoneNumber, tel, email, qrcode, appcode} = req.body;

    if(_id){
        WebsiteModel.findById(_id, (error, data) => {
            //找_id是否有错
            if (error) {
                res.send('update failure!');
                return;
            } else {

                //验证信息是否合法
                let error = data.validateSync();

                if(error){
                    //如果有错
                    const errorRs = [];
                    for(let attr in error.errors){
                        errorRs.push(`${WebsiteModel.fields[attr]} 字段:${error.errors[attr]}`);
                    }
                    let url = '/admin/website/add';
                    let time = 3;
                    res.render('error', {errorRs,url, time});
                    return;
                }

                //更新 保存到数据库
                data.siteName = siteName;
                data.keyword = keyword;
                data.description = description;
                data.copyright = copyright;
                data.benanhao = benanhao;
                data.address = address;
                data.phoneNumber = phoneNumber;
                data.tel = tel;
                data.email = email;
                data.qrcode = qrcode;
                data.appcode = appcode;

                data.save((error, data) => {
                    if (error) {
                        console.log(error);
                        res.redirect('/admin/website/add');
                    } else {
                        console.log(data);
                        /*redirect翻译过来叫做重定向,也可以理解为跳转。参数就是我们跳转的地址*/
                        res.redirect('/admin/website/add');
                    }
                });
            }
        })
    }else{

        let webstiteObj = new WebsiteModel({
            siteName,
            keyword,
            description,
            copyright,
            benanhao,
            address,
            phoneNumber,
            tel,
            email,
            qrcode,
            appcode
        });

        let error = webstiteObj.validateSync();
        // console.log('error',error);
        if(error){
            //如果有错
            //     console.log(error.errors);
            const errorRs = [];
            for(let attr in error.errors){
                errorRs.push(`${WebsiteModel.fields[attr]} 字段:${error.errors[attr]}`);
            }
            // console.log(errorRs);
            let url = '/admin/website/add';
            let time = 3;
            res.render('error', {errorRs,url, time});
        }
        else{
            webstiteObj.save((error, data) => {
                if (error) {
                    console.log(error);
                    res.redirect('/admin/website/add');
                    // res.send('error');
                } else {
                    console.log(data);
                    res.redirect('/admin/website/add');
                    // res.send('ok');
                }
            });
        }
    }
});

// 网站基本信息模块添加
router.get('/add', async (req, res) => {

    const info = await WebsiteModel.findOne();
    if (info) {
        /* 如果信息是存在,则我们应该把信息给到页面做展示*/
        // res.render('site-add', {info: info}); // {}
        res.render('site-add', {info}); // {}

    } else {
        /* 如果不存在,应该是做信息的添加操作 */
        res.render('site-add', {info: {}});
    }
});
module.exports = router;

如果提交时出错会跳转到出错页面 3秒后自动跳转回去
在这里插入图片描述

三、提交信息校验

3.1图片上传功能(单个)

第一步:HTML页面的input里的type改成file

 <div class="layui-form-item">
                <label for="qrcode" class="layui-form-label">
                    <span class="x-red">*</span>公众号二维码</label>
                <div class="layui-input-inline">
                    <input type="file" id="qrcode" name="qrcode" autocomplete="off" class="layui-input">
                </div>
            </div>

            <div class="layui-form-item">
                <label for="appcode" class="layui-form-label">
                    <span class="x-red">*</span>手机端二维码</label>
                <div class="layui-input-inline">
                    <input type="file" id="appcode" name="appcode" autocomplete="off" class="layui-input">
                </div>
            </div>

第二步:由于文件要上传 所以表单的编码enctype也需要修改一下

<form class="layui-form" action="/admin/website/store" method="post" enctype="multipart/form-data">

第三步:下载相关文件 查看使用方法
express官网-资源-中间件-Multer
https://github.com/expressjs/multer/blob/master/doc/README-zh-cn.md

npm install --save multer

第四步:使用文件上传
在路由目录的website文件里引入文件上传相关

const path=require('path')
/*完成上传功能*/
const multer  = require('multer')
//上传路径
const upload = multer({ dest: path.join(__dirname,'../public/uploads/' )})

因为是在store里做上传操作所以修改

router.post('/store', (req, res) => {
//改成
router.post('/store', upload.single('qrcode'),(req, res) => {
    //上传文件的信息
    console.log(req.file);

选择文件上传打印信息查看
在这里插入图片描述
在这里插入图片描述
但是这样保存的文件没有后缀名要手动添加、没有保存到数据库。
现在解决该问题:
解决后缀名
还是在之前给的链接里往下翻找到方法进行修改

const upload = multer({ dest: path.join(__dirname,'../public/uploads/' )})
//改成
const storage = multer.diskStorage({
    destination: function (req, file, cb) {
        //上传路径
        cb(null, path.join(__dirname, '../public/uploads/'))
    },
    filename: function (req, file, cb) {
        const uniqueSuffix = Date.now() + '-' + Math.round(Math.random() * 1E9)
        /*path.extname( file.originalname ) 可以获取到文件的扩展名 1.jpg==> .jpg*/
        cb(null, file.fieldname + '-' + uniqueSuffix + path.extname(file.originalname))
    }
})

const upload = multer({ storage: storage })

再次尝试上传
在这里插入图片描述
在这里插入图片描述
保存数据库
外面已经定义了 qrcode 所以后面的 qrcode删除了

let qrcode ='';
    //判断是否上传了图片
    if(req.file){
        //代表用户上传了图片
        qrcode=req.file.filename;
    }
let {_id, siteName, keyword, description, copyright, benanhao, address, phoneNumber, tel, email,  appcode} = req.body;

上传后数据库查看:
在这里插入图片描述

3.2图片上传功能(多个)

router.post('/store', upload.fields([{name: 'qrcode'}, {name: 'appcode'}]), (req, res) => {

    console.log(req.files); // 完成多文件上传功能

    let codePaths = {qrcode: '', appcode: ''};

    if (req.files) {
        /* {qrcode: [{}], appcode: [{}]}*/
        for (let attr in req.files) {
            codePaths[attr] = req.files[attr][0].filename;
        }
    }
    console.log(codePaths);

上传打印尝试,页面出错,但是取到了信息
在这里插入图片描述
信息存入数据库:

let {_id, siteName, keyword, description, copyright, benanhao, address, phoneNumber, tel, email} = req.body;
    //由于我们在文件上传里面已经获取了qrcode和 appcode ,所以不能在从 body 里面获取字段

修改

data.qrcode = qrcode;
data.appcode = appcode;
//改成
data.qrcode = codePaths.qrcode;
data.appcode = codePaths.appcode;
let webstiteObj = new WebsiteModel({
            ...
            qrcode,
            appcode
});
 qrcode,appcode//改成
qrcode: codePaths.qrcode,
appcode: codePaths.appcode,

上传多图
在这里插入图片描述
但是上传完成后,图片没有在后台页面展示,再进行修改:
在这里插入图片描述
在views目录下找到site-add.html进行图片展示修改

<div class="layui-form-item">
    <label for="qrcode" class="layui-form-label">
    <span class="x-red">*</span>公众号二维码</label>
    <div>
        <img src="/uploads/{{ info.qrcode }}" alt="">
    </div>
    <div class="layui-input-inline">
         <input type="file" id="qrcode" name="qrcode" autocomplete="off" class="layui-input">
     </div>
</div>

<div class="layui-form-item">
      <label for="appcode" class="layui-form-label">
      <span class="x-red">*</span>手机端二维码</label>
      <div>
           <img src="/uploads/{{ info.qrcode }}" alt="">
       </div>
       <div class="layui-input-inline">
            <input type="file" id="appcode" name="appcode" autocomplete="off" class="layui-input">
       </div>
</div>

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值