【Vue + Koa 前后端分离项目实战4】使用开源框架==>快速搭建后台管理系统 -- part4 后端实现【增删改查】功能

如果你和你想做的事情不在同一个频道,你就会浪费许多精力。等你有机会做你想做的事情时,你可能已经没有力气或时间了。

完整章节回顾

【Vue + Koa 前后端分离项目实战3】使用开源框架==>快速搭建后台管理系统 -- part3 权限控制+行为日志_小白Rachel的博客-CSDN博客

【Vue + Koa 前后端分离项目实战2】使用开源框架==>快速搭建后台管理系统 -- part2 后端新增期刊功能实现_小白Rachel的博客-CSDN博客_koa 开源项目

【Vue + Koa 前后端分离项目实战】使用开源框架==>快速搭建后台管理系统 -- part1 项目搭建_小白Rachel的博客-CSDN博客_vue+koa

后端分层架构的模式和框架中的文件说明 :

分层结构说明对应文件夹对应文件
Model层

实体类层 主要用于定义与数据库对象应的属性

modelsmovies.js  music.js  sentence.js
Dao层

持久层 访问数据库,向数据库发送sql语句,完成数据的增删改查任务

daomovies.js  music.js  sentence.js
Service层

业务逻辑层,完成功能的设计

servicecontents.js
Controller层

控制层,控制请求和响应,负责前后端交互 接口控制具体的业务流程

Validators

api

content.js

content.js

本章节主要完成后端的逻辑实现,并借助接口测试postman工具测试 ,暂无涉及到前端内容。


目录

完整章节回顾

一、基础工作

1.修改配置项文件

2.定义模型层数据

3.测试工具的使用

二、期刊列表查询

1.在dao层定义查询方法

2.在service层合并查询数据

3.在接口层调用接口

4.使用postman接口测试工具测试

三、新增期刊内容

1.添加自定义参数校验器

2.在dao层添加新增方法

3.service层实现新增逻辑

4.接口层调用实现

四、编辑期刊内容

1.添加自定义参数校验器

2.在dao层定义编辑方法

3.在service层中处理数据

4.在接口层编写接口

5.使用postman测试接口

 五、删除期刊内容

1.定义删除校验器

2.在dao层定义删除方法

3.在service层定义删除逻辑

4.在接口层调用删除数据

5.使用测试工具测试


一、基础工作

1.修改配置项文件

// config/secure.js
'use strict';

module.exports = {
  db: {
    database: 'lin-cms',
    host: 'localhost',
    dialect: 'mysql',
    port: 3306,
    username: 'root',
    password: '123456',
    logging: false,
    timezone: '+08:00',
    dialectOptions: {   // 添加配置 修改日期格式
      dateStrings: true,
      typeCast: true
    }
  },
  secret:
    '\x88W\xf09\x91\x07\x98\x89\x87\x96\xa0A\xc68\xf9\xecJJU\x17\xc5V\xbe\x8b\xef\xd7\xd8\xd3\xe6\x95*4'
};

2.定义模型层数据

// models/movie.js
import { Sequelize, Model } from 'sequelize';
import sequelize from '../libs/db';
import { config } from 'lin-mizar';

class Movie extends Model {

}

Movie.init (
  {
    id: {
      type: Sequelize.INTEGER,
      primaryKey: true,
      autoIncrement: true
    },
    image: {
      type: Sequelize.STRING(64)
    },
    content: {
      type: Sequelize.STRING(300),
      allowNull: true
    },
    pubdate: {
      type: Sequelize.INTEGER,
      allowNull: true
    },
    fav_nums: {
      type: Sequelize.INTEGER,
      defaultValue: 0
    },
    title: {
      type: Sequelize.STRING(50)
    },
    type: {
      type: Sequelize.INTEGER
    },
    status: {
      type: Sequelize.INTEGER
    }
  },
  {
    // 定义表名
    tableName: 'movie',
    // 定义模型名
    modelName: 'movie',
    // 删除
    paranoid: true,
    // 自动写入时间
    timestamps: true,
    // 重命名时间字段
    createdAt: 'created_at',
    updatedAt: 'updated_at',
    deletedAt: 'deleted_at',
    sequelize
  }
)

export { Movie as MovieModel }

 music音乐,包含url

// models/music.js
import { Sequelize, Model } from 'sequelize';
import sequelize from '../libs/db';
import { config } from 'lin-mizar';

class Music extends Model {

}

Music.init (
  {
    id: {
      type: Sequelize.INTEGER,
      primaryKey: true,
      autoIncrement: true
    },
    image: {
      type: Sequelize.STRING(64)
    },
    content: {
      type: Sequelize.STRING(300),
      allowNull: true
    },
    url: {
      type: Sequelize.STRING(100),
      allowNull: true
    },
    pubdate: {
      type: Sequelize.INTEGER,
      allowNull: true
    },
    fav_nums: {
      type: Sequelize.INTEGER,
      defaultValue: 0
    },
    title: {
      type: Sequelize.STRING(50)
    },
    type: {
      type: Sequelize.INTEGER
    },
    status: {
      type: Sequelize.INTEGER
    }
  },
  {
    // 定义表名
    tableName: 'music',
    // 定义模型名
    modelName: 'music',
    // 删除
    paranoid: true,
    underscored: true,
    // 自动写入时间
    timestamps: true,
    // 重命名时间字段
    createdAt: 'created_at',
    updatedAt: 'updated_at',
    deletedAt: 'deleted_at',
    sequelize
  }
)

export { Music as MusicModel }

 sentence句子

// models/sentence.js
import { Sequelize, Model } from 'sequelize';
import sequelize from '../libs/db';
import { config } from 'lin-mizar';

class Sentence extends Model {

}

Sentence.init (
  {
    id: {
      type: Sequelize.INTEGER,
      primaryKey: true,
      autoIncrement: true
    },
    image: {
      type: Sequelize.STRING(64)
    },
    content: {
      type: Sequelize.STRING(300),
      allowNull: true
    },
    pubdate: {
      type: Sequelize.INTEGER,
      allowNull: true
    },
    fav_nums: {
      type: Sequelize.INTEGER,
      defaultValue: 0
    },
    title: {
      type: Sequelize.STRING(50)
    },
    type: {
      type: Sequelize.INTEGER
    },
    status: {
      type: Sequelize.INTEGER
    }
  },
  {
    // 定义表名
    tableName: 'sentence',
    // 定义模型名
    modelName: 'sentence',
    // 删除
    paranoid: true,
    underscored: true,
    // 自动写入时间
    timestamps: true,
    // 重命名时间字段
    createdAt: 'created_at',
    updatedAt: 'updated_at',
    deletedAt: 'deleted_at',
    sequelize,
  }
)

export { Sentence as SentenceModel }

3.测试工具的使用

 项目添加权限之后,使用postman需要添加权限token

具体方法:运行(npm run serve)前端项目工程(lin-cms-vue),后打开http://localhost:8080/ 登录查看token信息,并复制到postman中

二、期刊列表查询

最终数据包含三张表的数据,即:从三张表中查询返回合并结果数据。

1.在dao层定义查询方法

使用框架已有的findAll()方法,完成dao文件夹下的movie.js  music.js sentence.js文件

// dao/movie.js文件
import { MovieModel } from '../models/movie';
import { NotFound } from 'lin-mizar';

// 在Dao层中调用模型层
class Movie {
    static async getMovieList () {
        return await MovieModel.findAll()
    }
}

export { Movie as MovieDao }
// dao/music.js文件
import { MusicModel } from '../models/music';
import { NotFound } from 'lin-mizar';

// 在Dao层中调用模型层
class Music {
  // 查询音乐列表
  static async getMusicList () {
    return await MusicModel.findAll()
  }
}

export { Music as MusicDao }
// dao/sentence.js文件
import { SentenceModel } from '../models/sentence';
import { NotFound } from 'lin-mizar';

class Sentence {
  static async getSentenceList () {
    return await SentenceModel.findAll()
  }
}

export { Sentence as SentenceDao }

2.在service层合并查询数据

新建getContentList 查询列表数据方法
// service/content.js文件
import { MovieDao } from '../dao/movie';
import { MusicDao } from '../dao/music';
import { SentenceDao } from '../dao/sentence';
import { NotFound } from 'lin-mizar';

class Content {
  static async getContentList (v) {
    const movieList = await MovieDao.getMovieList()  // 电影列表数据
    const musicList = await MusicDao.getMusicList()   // 音乐列表数据
    const sentenceList = await SentenceDao.getSentenceList()   // 句子列表数据
    let res = []  // 整合三个资源的数据
    res.push.apply(res, movieList)
    res.push.apply(res, musicList)
    res.push.apply(res, sentenceList)
    res.sort((a, b) => b.created_at.localeCompare(a.created_at))  // 按照创建时间排序
    return res
  }
}

export { Content as ContentService };

3.在接口层调用接口

// api/v1/content.js
contentApi.get("/", async (ctx) => {
  const contentList = await ContentService.getContentList();
  ctx.json(contentList);
});
module.exports = { contentApi };

4.使用postman接口测试工具测试

http://localhost:5000/v1/content

三、新增期刊内容

第二篇文章已经详细讲过新增期刊的逻辑了,这里简单梳理。

【Vue + Koa 前后端分离项目实战】使用开源框架==>快速搭建后台管理系统 -- part2 后端新增期刊功能实现_小白Rachel的博客-CSDN博客_koa 开源项目

1.添加自定义参数校验器

 需要检验的内容有:所有描述信息不为空、id为数字、url合法、日期格式正确等

class AddContentValidator extends LinValidator {
  constructor () {
    super();
    this.image = [
      new Rule('isNotEmpty', '内容封面不能为空')
    ]
    this.type = [
      new Rule('isNotEmpty', '内容类型不能为空'),
      new Rule('isInt', '内容类型id必须是数字')
    ]
    this.title = [
      new Rule('isNotEmpty', '内容标题不能为空')
    ]
    this.content = [
      new Rule('isNotEmpty', '内容介绍不能为空')
    ]
    this.url = [
      new Rule('isOptional'),
      new Rule('isURL', '内容外链必须是合法url地址')
    ]
    this.pubdate = [
      new Rule('isNotEmpty', '发布日期不能为空'),
      new Rule('isISO8601', '发布日期格式不正确')
    ]
    this.status = [
      new Rule('isNotEmpty', '内容有效状态未指定'),
      new Rule('isInt', '内容有效状态标识不正确')
    ]
  }
}

2.在dao层添加新增方法

// dao/movie.js
static async addMovice (v) {
    return await MovieModel.create(v)
  }
// dao/music.js
static async addMusic (v) {
    return await MusicModel.create(v)
  }
// dao/sentence.js
static async addSentence (v) {
    return await SentenceModel.create(v)
  }

3.service层实现新增逻辑

// service/content.js
static async addContent (v) {
    // 根据不同种类判断数据
    switch (v['type']) {
      case 100:
        // 电影
        delete v['url']
        await MovieDao.addMovice(v);
        break;
      case 200:
        // 音乐
        await MusicDao.addMusic(v);
        break;
      case 300:
        // 句子
        delete v['url']
        await SentenceDao.addSentence(v);
        break;
      default:
        throw new NotFound({ msg: '内容类型不存在' });
    }
  }

4.接口层调用实现

// api/v1/content.js
contentApi.linPost(
  "addContent", // 函数唯一标识
  "/",
  {
    permission: "添加期刊内容", // 权限名称
    module: "内容管理", // 权限所属模块
    mount: true,
  },
  groupRequired, // 权限级别
  logger("{user.username}新增了期刊内容"),
  async (ctx) => {
    // 1.参数校验
    const v = await new AddContentValidator().validate(ctx);
    // 2.执行业务逻辑
    // 3.插入数据库-封装在service层
    await ContentService.addContent(v.get("body"));
    // 4.返回成功
    ctx.success({
      msg: "期刊内容新增成功",
    });
  }
);

四、编辑期刊内容

1.添加自定义参数校验器

编辑时id不能为空,其余属性和【新增编辑器】相同,直接继承复用即可

// validators/content.js
class EditContentValidator extends AddContentValidator {
  // 对于id验证
  constructor () {
    super();
    this.id = [
      new Rule('isNotEmpty', '期刊id不能为空'),
      new Rule('isInt', '期刊id必须是数字且大于0', {min: 1 })
    ]
  }
}
export { AddContentValidator, EditContentValidator}

2.在dao层定义编辑方法

editMovie方法接收两个参数:id params

findBuPK(id)  根据id调用模型的查询方法。返回对象信息

update() 调用模型的更新方法用于更新数据

// dao/movie.js文件
static async editMovie (id, params) {
    const movie = await MovieModel.findByPk(id)  // 根据id查询数据对象
    if (!movie) {
      throw new NotFound()
    }
    return await movie.update({ ...params })  // 修改相应字段数据
}
// dao/music.js文件
static async editMusic (id, params) {
    const music = await MusicModel.findByPk(id)
    if (!music) {
      throw new NotFound()
    }
    return await music.update({ ...params })
}
// dao/sentence.js文件
static async editSentence (id, v) {
    const sentence = await SentenceModel.findByPk(id)
    if (!sentence) {
      throw new NotFound()
    }
    return await sentence.update({ ...v })
}

3.在service层中处理数据

根据数据类型type(100,200,300) 三种类型,使用switch语句,实现三种类型的区分。分别调用dao层的编辑方法。对于电影、句子没有url字段,需要删除。如果类型不对应时抛出异常。

// service/content.js
static async editContent (id, params) {
    switch (params['type']) {
      case 100:
        delete params['url']
        await MovieDao.editMovie(id, params)
        break;
      case 200:
        await MusicDao.editMusic(id, params)
        break;
      case 300:
        delete params['url']
        await SentenceDao.editSentence(id, params)
        break;
      default:
        throw new NotFound({ msg: '内容类型不存在' })
    }
  }

4.在接口层编写接口

使用put方法。上篇文章已讲过【权限问题】和【新增】的接口逻辑详解,不再赘述

// api/v1/content.js
contentApi.linPut(
  "editContent",
  "/:id",
  {
    permission: "编辑期刊内容", // 权限
    module: "内容管理",
    mount: true,
  },
  groupRequired, // 权限级别
  logger("{user.username}编辑了期刊内容"),
  async (ctx) => {
    // 1.参数校验
    const v = await new EditContentValidator().validate(ctx);
    // 2.取值
    const id = v.get("path.id");
    const params = v.get("body");
    // 3.编辑期刊逻辑
    await ContentService.editContent(id, params);
    // 4.返回成功提示
    ctx.success({
      msg: "期刊内容编辑成功",
    });
  }
);

5.使用postman测试接口

修改类型type=100 id=6的数据。

 

 五、删除期刊内容

1.定义删除校验器

需要校验id和type字段,保证能够唯一定义到数据。

class DeleteContentValidator extends LinValidator {
  constructor () {
    super();
    this.id = [
      new Rule('isNotEmpty', '期刊id不能为空'),
      new Rule('isInt', '期刊id必须是数字且大于0', { min: 1 })
    ]
    this.type = [
      new Rule('isNotEmpty', '期刊类型不能为空'),
      new Rule('isInt', '期刊类型必须是数字')
    ]
  }
}

export { AddContentValidator, EditContentValidator, DeleteContentValidator }

2.在dao层定义删除方法

调用模型中的查询方法,按照id查询,并删除对应数据。

// dao/movie.js
static async deleteMovieById (id) {
    return MovieModel.destroy({
      where: { id }
    })
}
// dao/music.js
static async deleteMusicById (id) {
    return MusicModel.destroy({
      where: { id }
    })
  }
// dao/sentence.js
static async deleteSentenceById (id) {
    return SentenceModel.destroy({
      where: { id }
    })
  }

3.在service层定义删除逻辑

使用switch语句,分类删除数据

// service/content.js
static async deleteContent (id, type) {
    switch (type) {
      case 100:
        await MovieDao.deleteMovieById(id)
        break;
      case 200:
        await MusicDao.deleteMusicById(id)
        break;
      case 300:
        await SentenceDao.deleteSentenceById(id)
        break;
      default:
        throw new NotFound({ msg: '内容类型不存在' })
    }
  }

4.在接口层调用删除数据

定义delete方法,传递参数为id

contentApi.linDelete(
  "deleteContent",
  "/:id",
  {
    permission: "删除期刊内容", // 权限
    module: "内容管理",
    mount: true,
  },
  groupRequired, // 权限级别
  logger("{user.username}删除了期刊内容"),
  async (ctx) => {
    const v = await new DeleteContentValidator().validate(ctx);
    const id = v.get("path.id");
    const type = v.get("query.type");
    await ContentService.deleteContent(id, type);
    ctx.success({
      msg: "期刊删除成功",
    });
  }
);

5.使用测试工具测试

http://localhost:5000/v1/content/1?type=100

 至此,期刊模块的增删查改功能全部完成。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
### 回答1: Python+Vue+Django前后端分离项目实战,涉及到使用Python语言编写后端服务,使用Vue框架构建前端界面,并通过Django框架作为API接口实现后端数据交互的方式。在实战项目中也会涉及到数据库设计和调用、权限控制、文件上传等问题的解决。 ### 回答2: Python、Vue和Django是现在非常流行的前后端开发技术。如果你想学习这些技术,那么前后端分离是一个很好的选择。在这个项目中使用Python作为后端编程语言,Django作为Web框架Vue作为前端框架。我们可以在这个项目中学习到很多关于前后端分离的经验。 首先,前后端分离可以让我们更好地组织我们的代码。在一个分离的项目中,我们可以通过明确的接口来分离前端和后端。这样一来,我们可以专注于开发代码,而不必担心前后端之间的交互问题。 其次,前后端分离可以使我们更好地实现可重用性。在这个项目中,我们可以编写可重用的Vue组件,并在不同的前端页面中使用它们。同样地,我们也可以编写可重用的Django应用程序,并在不同的后端端点中使用它们。这会使我们的代码更加清晰简洁,也可以提高我们的开发效率。 最后,前后端分离可以让我们更好地实现可维护性。在一个分离的项目中,我们可以更轻松地进行单元测试和端到端测试。这可以帮助我们保持代码的质量,并尽早发现和解决潜在的问题。 总之,Python、Vue和Django前后端分离项目是一个非常好的学习项目。通过这个项目,我们可以从实践中学习如何使用这些技术,并在以后的项目中更好地应用它们。 ### 回答3: Python、Vue和Django是目前非常流行的技术栈之一,其中Python和Django主要用于后端开发Vue则是一款流行的前端框架。Python和Django的优点在于它们易于学习、可扩展性强、社区活跃,并且可以用于构建各种类型的Web应用程序。而Vue的优点在于它简洁、高效、组件化,并且可以很好地配合其他框架和库使用前后端分离是一种可以将前端和后端分别开发的方法,这种方法具有很多优点。首先,可以使开发人员更加专注于各自的领域,减少互相干扰和影响。其次,这种方法可以提高应用程序的可维护性和可扩展性。最后,这种方法还可以提高开发效率,使开发人员能够更加高效地开发应用程序。 在前后端分离项目实战中,需要注意以下几点。首先,需要确定应用程序的需求,确定前端和后端的接口规范。其次,需要使用合适的工具和框架来完成前后端开发任务。对于后端开发,可以使用Django的REST框架,这个框架可以很快地构建RESTful API,并且配合数据库使用。而对于前端开发,则可以使用Vue框架开发Vue可以很好地处理数据和UI逻辑。最后,需要着重测试和调试应用程序,确保应用程序的正确性和可用性。 总的来说,Python、Vue和Django是一组非常流行的技术栈,非常适合用于前后端分离项目的开发。在开发前需要确定好需求,选择好工具和框架开发期间需要注重测试和调试,这样才能开发出高质量的应用程序。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小白Rachel

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值