搜索 创建管理员 , 对比这个流程走一遍!

# 一、创建数据库用户留言表 message

用户留言表 message 我们在前面讲课的时候已经带领大家设计和创建了
我们一般创建一个新的栏目板块,第一步就是创建数据库表 ,但在创建之前,先根据业务分析一下表所需字段:

  1. 根据你的客户、老板勾勒出他的需求,然后根据需求设计,比如:
  2. 用户留言表 message 最起码需要有: 留言人(留言用户称呼)、留言用户电话(好联系他)、 留言内容、留言时间字段
  3. 当然还可以增加留言信息是否处理状态字段(已处理,未处理),如果你还想不到这一点,可以先不管这个字段,后期再加上去
  4. message 表字段设计
字段名 数据类型 描述

默认值

字段含义

id int(20) 主键、自增长、UNSIGNED无符号
username varchar(30) 留言用户称呼
tel varchar(64) 留言用户电话加密值
telnumber bigint(11) 0 留言用户电话
message text NULL 用户留言内容
timestamp datetime CURRENT_TIMESTAMP 用户留言时间戳
create_time datetime CURRENT_TIMESTAMP 数据创建时间
update_time datetime CURRENT_TIMESTAMP 数据更新时间

# 二、创建迁移文件、执行迁移命令创建数据表

在数据库创建数据表的方式很多,在上面定义了表字段之后,可以使用phpmyAdmin数据库插件执行sql语句创建等等方式,但是建议大家通过:创建迁移文件、执行迁移命令创建数据表。

涉及的知识点:

  1. 章节2:egg.js基础-五、eggjs项目中sequelize模型创建mysql数据库

创建迁移文件 命令:

npx sequelize migration:generate --name=init-message

创建迁移文件:

'use strict';

/** @type {import('sequelize-cli').Migration} */
module.exports = {
  async up (queryInterface, Sequelize) {
    const { INTEGER, STRING, DATE, ENUM, TEXT, BIGINT} = Sequelize;
    // 创建表 --- 类似我们sql语句定义表结构
    await queryInterface.createTable('message', {
      id: { 
        type: INTEGER(20).UNSIGNED, 
        primaryKey: true, 
        autoIncrement: true,
        comment: '留言板主键id'
      },
      username: { 
        type: STRING(30), 
        allowNull: false, 
        defaultValue: '', 
        comment: '留言板用户称呼'
      },
      tel: { 
        type: STRING(64), 
        allowNull: false, 
        defaultValue: '' , 
        comment: '留言用户的电话号码加密'
      },
      telnumber : { 
        type: BIGINT(11), 
        allowNull: false, 
        defaultValue: 0 , 
        comment: '留言用户的电话号码', 
        unique: true
      },
      message : { 
        type: TEXT, 
        allowNull: true, 
        defaultValue: '', 
        comment: '留言用户的留言信息' 
      },
      // sex: { type: ENUM, values: ['男','女','保密'], allowNull: true, defaultValue: '保密', comment: '留言用户性别'},
      timestamp : {type: DATE, allowNull: false, defaultValue:Sequelize.fn('NOW')},
      create_time: {type: DATE, allowNull: false, defaultValue:Sequelize.fn('NOW')},
      update_time: {type: DATE, allowNull: false, defaultValue:Sequelize.fn('NOW')}
    });
  },

  async down (queryInterface, Sequelize) {
    await queryInterface.dropTable('message')
  }
};

执行迁移文件命令生成数据库表:

// 升级数据库
npx sequelize db:migrate

# 三、创建留言表 message的模型

模型文件主要是用于处理数据库表的增删改查等操作

'use strict';

module.exports = app =>{
    const { INTEGER, STRING, DATE, ENUM, TEXT, BIGINT} = app.Sequelize;

    const Message = app.model.define('message',{
        id: { 
            type: INTEGER(20).UNSIGNED, 
            primaryKey: true, 
            autoIncrement: true,
            comment: '留言板主键id'
          },
          username: { 
            type: STRING(30), 
            allowNull: false, 
            defaultValue: '', 
            comment: '留言板用户称呼',
            // set(val){
            //   let data = val + '(先生/女士)';
            //   this.setDataValue('username', data);
            // }
          },
          tel: { 
            type: STRING(64), 
            allowNull: false, 
            defaultValue: '' , 
            comment: '留言用户的电话号码加密'
          },
          telnumber : { 
            type: BIGINT(11), 
            allowNull: false, 
            defaultValue: 0 , 
            comment: '留言用户的电话号码', 
            unique: true
          },
          message : { 
            type: TEXT, 
            allowNull: true, 
            defaultValue: '', 
            comment: '留言用户的留言信息' 
          },
          // sex: { type: ENUM, values: ['男','女','保密'], allowNull: true, defaultValue: '保密', comment: '留言用户性别'},
          timestamp : {
            type: DATE, 
            allowNull: false, 
            defaultValue:app.Sequelize.fn('NOW'),
            get(){
              let data = this.getDataValue('timestamp') ;
              /*
              //如果想转换成年月日时分秒,可以使用moment.js库等其他时间库
              //我们这里带领大家回忆一下js基础,就手动拼接一下
              let year = data.getFullYear();
              let month = ("0" + (data.getMonth() + 1)).slice(-2);
              let day = ("0" + data.getDate()).slice(-2);
              let hours = ("0" + data.getHours()).slice(-2);
              let minutes = ("0" + data.getMinutes()).slice(-2);
              let seconds = ("0" + data.getSeconds()).slice(-2);
              return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
              */
              //如果想转成时间戳
              return (new Date(data)).getTime();
            }
          },
          create_time: {type: DATE, allowNull: false, defaultValue:app.Sequelize.fn('NOW')},
          update_time: {type: DATE, allowNull: false, defaultValue:app.Sequelize.fn('NOW')}
        //   timestamp : DATE,
        //   create_time: DATE,
        //   update_time: DATE
    },{
        // timestamps: true,//是否自动写入时间戳
        // tableName: 'message',//自定义数据表名称
    });

    return Message;
}

# 四、提交留言(示例)

# 创建控制器 app/controller/admin/message.js

'use strict';

let crypto = require('crypto');
//自定义IV(16位)、key(密钥(32位的'aes-256-cbc')(24位的'aes-192-cbc'))
const secret = {
  iv: 'IloveYOU@520520!',// 初始化向量(iv)16位
  key: 'a123456789@!*&%bcdef@123456789&&', // 32 位秘钥密钥
}

const Controller = require('egg').Controller;

class MessageController extends Controller {
  //创建留言板---创建页面表单
  async create() {
    const { ctx } = this;
    //渲染公共模版
    await ctx.renderTemplate({
      title: '创建留言板',//现在网页title,面包屑导航title,页面标题
      tempType: 'form', //模板类型:table表格模板 ,form表单模板
      form: {
        //提交地址
        action: "/admin/message/save",
        //  字段
        fields: [
          {
            label: '您的称呼',
            type: 'text',
            name: 'username',
            placeholder: '请输入您的称呼',
            // default:'默认值测试', //新增时候默认值,可选
          },
          {
            label: '您的电话',
            type: 'text',
            name: 'telnumber',
            placeholder: '请输入您的电话',
          },
          {
            label: '您的留言',
            type: 'text',
            name: 'message',
          }
        ],
      },
      //新增成功之后跳转到哪个页面
      successUrl: '/admin/message/index',
    });
  }

  //创建留言板提交数据
  async save() {
    //一般处理流程
    //1.参数验证
    this.ctx.validate({
      username: {
        type: 'string',  //参数类型
        required: true, //是否必须
        // defValue: '', 
        desc: '您的称呼' //字段含义
      },
      telnumber: {
        type: 'phone',
        required: true,
        // defValue: '', 
        desc: '您的电话'
      },
    });
    let { username, telnumber, message } = this.ctx.request.body;
    // 如果一个用户只能提交一次留言,那么可以通过电话判断,多次则拒绝
    if (await this.app.model.Message.findOne({ where: { telnumber } })) {
      return this.ctx.apiFail('您已经提交过留言了,我们会尽快联系您');
    }
    //为了满足数据库设计需要,对电话做一个加密
    let tel = await this.aesEncrypt(telnumber, secret.key, secret.iv);
    //否则不存在则写入数据库
    await this.app.model.Message.create({
      username,
      telnumber,
      tel,
      message
    });
    this.ctx.apiSuccess('留言成功');
  }

  //对称加密
  async aesEncrypt(data, key, iv) {
    // 给定的算法,密钥和初始化向量(iv)创建并返回Cipher对象
    const cipher = crypto.createCipheriv('aes-256-cbc', key, iv)
    // 指定要摘要的原始内容,可以在摘要被输出之前使用多次update方法来添加摘要内容
    // 数据的编码 utf8 返回值的编码 hex
    var crypted = cipher.update(data, 'utf8', 'hex')
    crypted += cipher.final('hex')
    return crypted
  }
  //对称解密
  async aesDecrypt(data, key, iv) {
    // 给定的算法,密钥和初始化向量(iv)创建并返回Cipher对象
    const decipher = crypto.createDecipheriv('aes-256-cbc', key, iv)
    // 数据的编码 hex 返回值的编码 utf8
    var decrypted = decipher.update(data, 'hex', 'utf8')
    decrypted += decipher.final('utf8')
    return decrypted
  }
}

module.exports = MessageController;

# 定义路由

app/router/admin/admin.js

// 创建留言板界面
router.get('/admin/message/create', controller.admin.message.create);
//创建留言板提交数据
router.post('/admin/message/save', controller.admin.message.save);

# 五、留言列表、修改留言、删除留言

# 控制器 app/controller/admin/message.js

'use strict';

let crypto = require('crypto');
//自定义IV(16位)、key(密钥(32位的'aes-256-cbc')(24位的'aes-192-cbc'))
const secret = {
  iv: 'IloveYOU@520520!',// 初始化向量(iv)16位
  key: 'a123456789@!*&%bcdef@123456789&&', // 32 位秘钥密钥
}

const Controller = require('egg').Controller;

class MessageController extends Controller {

  //创建留言板列表页面
  async index() {
    const { ctx, app } = this;
    let data = await ctx.page('Message');
    //渲染公共模版
    await ctx.renderTemplate({
      title: '留言板列表',//现在网页title,面包屑导航title,页面标题
      data,
      tempType: 'table', //模板类型:table表格模板 ,form表单模板
      table: {
        //表格上方按钮,没有不要填buttons
        buttons: [
          {
            url: '/admin/message/create',//新增路径
            desc: '提交留言',//新增 //按钮名称
            // icon: 'fa fa-plus fa-lg',//按钮图标
          }
        ],
        //表头
        columns: [
          {
            title: '留言用户称呼',
            key: 'username',
          },
          {
            title: '留言用户电话',
            key: 'telnumber',
          },
          {
            title: '留言内容',
            key: 'message',
          },
          {
            title: '留言时间',
            key: 'create_time',
            width: 200,//可选
            class: 'text-center',//可选
          },
          {
            title: '操作',
            class: 'text-right',//可选
            action: {
              //修改
              edit: function (id) {
                return `/admin/message/edit/${id}`;
              },
              //删除
              delete: function (id) {
                return `/admin/message/delete/${id}`;
              }
            }
          },
        ],
      },
    });
  }

  //删除留言功能
  async delete() {
    const { ctx, app } = this;
    const id = ctx.params.id;
    await app.model.Message.destroy({
      where: {
        id
      }
    });
    //提示
    ctx.toast('留言删除成功', 'success');
    //跳转
    ctx.redirect('/admin/message/index');
  }

  //修改留言界面
  async edit() {
    const { ctx, app } = this;
    const id = ctx.params.id;
    let data = await app.model.Message.findOne({
      where: {
        id
      }
    });
    if (!data) {
      return ctx.pageFail('该留言不存在', 404);
    }
    data = JSON.parse(JSON.stringify(data));
    //渲染公共模版
    await ctx.renderTemplate({
      id,
      title: '修改留言',//现在网页title,面包屑导航title,页面标题
      tempType: 'form', //模板类型:table表格模板 ,form表单模板
      form: {
        //修改留言提交地址
        action: '/admin/message/update/' + id,
        //  字段
        fields: [
          {
            label: '您的称呼',
            type: 'text',
            name: 'username',
            placeholder: '请输入您的称呼',
          },
          {
            label: '您的电话',
            type: 'text',
            name: 'telnumber',
            placeholder: '请输入您的电话',
          },
          {
            label: '您的留言',
            type: 'text',
            name: 'message',
            placeholder: '请输入您的留言',
          },
        ],
        //修改内容默认值
        data,
      },
      //修改成功之后跳转到哪个页面
      successUrl: '/admin/message/index',
    });

  }

  //修改留言数据功能
  async update() {
    const { ctx, app } = this;
    //1.参数验证
    this.ctx.validate({
      id:{
        type: 'int',
        required: true,
        desc: '留言id'
      },
      username: {
        type: 'string',  //参数类型
        required: true, //是否必须
        // defValue: '', 
        desc: '您的称呼' //字段含义
      },
      telnumber: {
        type: 'phone',
        required: true,
        // defValue: '', 
        desc: '您的电话'
      },
      message: {
        type: 'string',
        required: false,
        // defValue: '', 
        desc: '您的留言'
      },
    });

    // 参数
    const id = ctx.params.id;
    const { username, telnumber, message } = ctx.request.body;
    // 查一下是否存在这个留言记录
    const data = await app.model.Message.findOne({where: { id } });
    if (!data) {
      return ctx.pageFail('该留言记录不存在');
    }
    //存在,由于电话号码具有唯一性,你不能修改留言的时候,修改成存在的电话
    const Op = this.app.Sequelize.Op;//拿Op,固定写法
    if(await app.model.Message.findOne({
      where: { 
        telnumber,
        id:{
          [Op.ne]:id
        }
      } 
    })){
      return ctx.apiFail('您已经提交过留言了,我们会尽快联系您');
    }
    // 修改数据
    data.username = username;
    data.telnumber = telnumber;
    if(message){
      data.message = message;
    }
    await data.save();
    // 给一个反馈
    ctx.apiSuccess('修改成功');
  }

}

module.exports = MessageController;

# 定义路由

app/router/admin/admin.js

//创建留言板列表页面
router.get('/admin/message/index', controller.admin.message.index);
//删除留言功能
router.get('/admin/message/delete/:id', controller.admin.message.delete);
//修改留言界面
router.get('/admin/message/edit/:id', controller.admin.message.edit);
//修改留言数据功能
router.post('/admin/message/update/:id', controller.admin.message.update);
更新时间: 2024年3月8日星期五下午2点06分