Koa商城项目-轮播图模块(后端)

news2024/12/24 8:53:36

前言

通过这次独自做前后端发现有很多需要提升的地方,很多细节处理不到位。下面简单看一下本人自己做的效果吧~~

Git地址

https://gitee.com/ah-ah-bao/koa_system

效果图

后端逻辑分析

首先编写route->banner.router.js

/**
 * @author: zxb
 * @date: 2024-08-06
 * @des : 商品路由
 * @router: /goods/add
 **/

const Router = require('koa-router');

const { upload, addBanner, getBannerList, updateBanner, deleteBanner, getBannerDetail } = require('../controller/banner.controller')
const { validateBanner, PageSizeOrPage } = require('../middleware/banner.middleware')
const { auth, hasAdminPermission } = require('../middleware/auth.middleware')

const router = new Router({ prefix: '/banner' });

router.post('/upload', auth, hasAdminPermission, upload);
router.post('/add', auth, hasAdminPermission, validateBanner, addBanner);
router.post('/update', auth, hasAdminPermission, updateBanner);
router.post('/delete', auth, hasAdminPermission, deleteBanner);
router.post('/detail', getBannerDetail);
router.post('/list', PageSizeOrPage, getBannerList);

module.exports = router; // 导出router

上面的auth、hasAdminPermission和validateBanner是中间件`中间件主要的作用类似于拦截一下,判断符不符合条件,就和去电影院检票一样。一般是用来处理数据、身份校验和是否含有token等操作。中间件的代码放在下面了~

auth等中间件

const jsonwebtoken = require('jsonwebtoken');
const { JWT_SECRET } = require('../config/config.development')
const auth = async (ctx, next) => {
    var { authorization = "" } = ctx.request.header;
    authorization = authorization.replace('Bearer ', '')
    try {
        // user中包含了 jwt加密时的相关信息
        const user = jsonwebtoken.verify(authorization, JWT_SECRET)
        ctx.state.user = user
    } catch (err) {
        if (err.name) {
            switch (err.name) {
                case 'TokenExpiredError':
                    ctx.body = {
                        code: 401,
                        message: 'token过期'
                    }
                    break;
                case 'JsonWebTokenError':
                    ctx.body = {
                        code: 401,
                        message: 'token无效'
                    }
                    break;
                default:
                    ctx.body = {
                        code: 401,
                        message: 'token错误'
                    }
            }
            return
        } else {
            ctx.body = {
                code: 401,
                message: 'token错误'
            }
            return
        }
    }
    await next()
}
const hasAdminPermission = async (ctx, next) => {
    const is_admin = ctx.state.user.is_admin
    if (!is_admin) {
        ctx.body = {
            code: 403,
            message: '您当前没有权限'
        }
        return
    }
    await next()
}
module.exports = {
    auth,
    hasAdminPermission
};
const validateBanner = async (ctx, next) => {
    // 验证商品信息
    try {
        ctx.verifyParams({
            bannername: { type: 'string', required: true },
            url: { type: 'string', required: true },
        })
    } catch (err) {
        ctx.body = {
            code: 500,
            message: '参数错误',
            data: err
        }
        return
    }
    await next()
}

随后到banner.controller.js

const path = require('path')
const { APP_PORT, SYS_LOCATION } = require('../config/config.development');
const { bannerAdd, bannerUpdate, bannerDelete, bannerDetail, bannerList, getBanner } = require('../service/banner.service')
class BannerController {
    // 轮播图图片上传
    async upload(ctx) {
        ctx.body = "图片上传成功"
        const { file } = ctx.request.files
        const fileType = ['image/jpeg', 'image/png', 'image/gif']
        if (file) {
            if (!fileType.includes(file.mimetype)) {
                return ctx.body = {
                    code: 500,
                    message: '图片格式不正确',
                    data: ""
                }
            } else {
                ctx.body = {
                    code: 200,
                    message: '图片上传成功',
                    data: {
                        url: `http://${SYS_LOCATION}:${APP_PORT}/${path.basename(file.filepath)}`
                    }
                }
            }
        } else {
            ctx.body = {
                code: 500,
                message: '图片上传失败',
                data: ""
            }
        }
    }
    // 发布轮播图
    async addBanner(ctx) {
        try {
            const findresult = await getBanner(ctx.request.body.bannername)
            if (findresult) {
                ctx.body = {
                    code: 500,
                    message: '轮播图已存在',
                    data: ""
                }
                return
            } else {
                const res = await bannerAdd(ctx.request.body)
                ctx.body = {
                    code: 200,
                    message: '添加轮播图成功!',
                    data: res
                }
            }
        } catch (err) {
            ctx.body = {
                code: 500,
                message: '添加轮播图失败',
                data: err
            }
            return
        }
    }
    // 修改轮播图信息
    async updateBanner(ctx) {
        try {
            const res = await bannerUpdate(ctx.request.body)
            if (res) {
                ctx.body = {
                    code: 200,
                    message: '更新轮播图成功',
                    data: ''
                }
            } else {
                ctx.body = {
                    code: 500,
                    message: '更新轮播图失败',
                    data: ""
                }
            }
        } catch (err) {
            ctx.body = {
                code: 500,
                message: '更新轮播图失败',
                data: err
            }
            return
        }
    }
    // 删除轮播图
    async deleteBanner(ctx) {
        try {
            const res = await bannerDelete(ctx.request.body.id)
            if (res) {
                ctx.body = {
                    code: 200,
                    message: '删除轮播图成功',
                    data: ''
                }
            } else {
                ctx.body = {
                    code: 500,
                    message: '删除轮播图失败',
                    data: ""
                }
            }
        } catch (err) {
            ctx.body = {
                code: 500,
                message: '删除轮播图失败',
                data: err
            }
        }
    }
    // 获取详情
    async getBannerDetail(ctx) {
        try {
            const res = await bannerDetail(ctx.request.body.id)
            if (res) {
                ctx.body = {
                    code: 200,
                    message: '获取轮播图详情成功',
                    data: res
                }
            } else {
                ctx.body = {
                    code: 500,
                    message: '获取轮播图详情失败',
                    data: ""
                }
            }
        } catch (err) {
            ctx.body = {
                code: 500,
                message: '获取轮播图详情失败',
                data: err
            }
        }
    }
    // 获取轮播图列表
    async getBannerList(ctx) {
        try {
            const { res, total } = await bannerList(ctx.request.body.page, ctx.request.body.pageSize, ctx.request.body)
            if (res) {
                ctx.body = {
                    code: 200,
                    message: '获取轮播图列表成功',
                    data: res,
                    total: total
                }
            } else {
                ctx.body = {
                    code: 500,
                    message: '获取轮播图列表失败',
                    data: ""
                }
            }
        } catch (err) {
            ctx.body = {
                code: 500,
                message: '获取轮播图列表失败',
                data: err
            }
        }
    }
}
module.exports = new BannerController()

这个里面主要做的就是响应和一些逻辑,这一段代码最关键的就是上传这一块,使用的插件,可以看第一个栏目作品的详细介绍。

banner.service.js的相关代码

const Banner = require('../model/banner.model');
class BannerService {
async getBanner(bannername){
  const res = await Banner.findOne({where:{bannername}});
  return res;
}

  async bannerAdd(banner) {
    const res = await Banner.create(banner);
    return res.dataValues;
  }


  async bannerUpdate(banner) {
    const res = await Banner.update(banner, { where: { id: banner.id } });
    return res[0] > 0;
  }

  async bannerDelete(id) {
    const res = await Banner.destroy({ where: { id } });
    return res > 0;
  }

  async bannerDetail(id) {
    const res = await Banner.findByPk(id);
    return res ? res.dataValues : null;
  }

  async bannerList(page = 1, pageSize = 10, otherBannerOptions = {}) {
    const offset = (page - 1) * pageSize
    const options = {
      offset,
      limit: pageSize,
    };
    if (otherBannerOptions.bannername != '' && otherBannerOptions.bannername != null && otherBannerOptions.bannername) {
      options.where = {
        bannername: otherBannerOptions.bannername // 根据 bannername 进行查询
      };
    }
    const res = await Banner.findAll(options);
    const total = await Banner.count();
    return {
      res,total
    };
  }
}
module.exports = new BannerService();

 这个上面主要的功能就是相当于执行sql语句,最后这个就是创建数据库的重要文件//

banner.model.js

const { DataTypes } = require('sequelize');
const sequelize = require('../db/seq')

const Goods = sequelize.define('node_banner', {
    bannername: {
        type: DataTypes.STRING,
        allowNull: false,
        comment: '轮播图名称',
        unique: true
    },
    url: {
        type: DataTypes.STRING,
        allowNull: false,
        comment: '轮播图名称'
    },
})

// 强制同步数据库(创建数据库表)
// force:ture 如果表存在就强行删除表,然后创建一个新的表
// Goods.sync({force:'ture'})

module.exports = Goods

后端完整代码

可以关注阿宝的git嗷,随时更新,随时不定期上传一些好的代码进行开源,欢迎大家一起交流~

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2051308.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Socket编程TCP 基础

一.什么是Socket(套接字) 定义:就是对网络中不同主机上的应用进程之间进行双向通信的端点的抽象。一个套接字就是网络上进程通信的一端,提供了应用层进程利用网络协议交换数据的机制。从所处的地位来讲,套接字上联应用进程&#x…

【文献阅读】A Comprehensive Review of Multimodal Large Language Models

一、回顾 MLLMs 在语言、图像、视频和音频处理等多模态任务中表现出色。这些模型通过整合多模态信息来增强多模态任务的有效性。 在自然语言处理(NLP)任务中,如文本生成和机器翻译,MLLMs 利用图像、视频和音频提供上下文支持&am…

C#开发实验--卫星星历的计算、空间直角坐标和大地坐标的转换、ArcGIS Engine开发的简单实例

前不久在公众号GIS研发看到了暑假公益C#开发教程,教大家ArcGIS Engine开发。 想到了自己本科阶段也学习了C#开发和AE开发,学习了使用C#添加空间等,进行卫星星历的计算、空间直角坐标和大地坐标的转换、ArcGIS Engine开发的简单实例。 下面的…

数据结构与算法--插入排序与选择排序

文章目录 回顾提要排序基本概念排序的分类排序算法的稳定性排序算法的性能指标内排序 排序方法直接插入排序直接插入排序的要点直接插入排序的实现直接插入排序性能分析直接插入排序的适用情景 简单选择排序简单选择排序的要点简单选择排序的执行过程简单选择排序的实现简单选择…

虚幻5|布料模拟

打开骨骼网格体 1.Mass Prooerties 如果给角色施加风力,密度越大越难飘,相反密度越小飘动浮度也小 2.Material Proerties Edge Stiffness,对衣服的折痕处的调整,其值越大就越能维持原本的折痕,相反折痕就会变小,但…

【Mudo】实战项目之应用层模块

文章目录 前言正文1. Util1.1 File1.2 Url1.3 Str1.4 Infor 2. Http2.1 Request2.2 Response2.3 Context2.4 Server 尾序 前言 在上一篇文章当中,博主从代码的层面介绍了服务器模块的实现,最终封装出了一个传输层的TcpServer模块,那么在本篇…

中国篆刻艺术孙溟㠭凿木《未来之门》

孙溟㠭凿木《未来之门》 每人都有着自己对未来的期盼,未来并不遥远,下一秒就是未来,当下的一切好和一切的恶是暂时的,都会随着时间一秒一秒过去,走向未来,希望每人都能尽早打开未来之门,到达自己…

Arduino开源四足蜘蛛机器人制作教程

视频教程:手把手叫你做四足蜘蛛机器人——1零件介绍_哔哩哔哩_bilibili 一、项目介绍 1.1 项目介绍 Arduino主控,图形化编程,趣味学习 Arduino nano开发板舵机扩展底板 4.8V可充电电池,支持Arduino C语言编程和米思齐图形化编程…

Linux os下借助Qt+libvlc是实现多路拉取摄像头rtsp数据流并实时显示

前言 应客户方的一个实际项目需求,需要在Linux操作系统下拉取多路摄像头的RTSP数据流并实时显示。 该项目的硬件平台基于飞腾2000四核处理器与景嘉微显卡,搭载了Kylin V10操作系统。 当前景嘉微GPU最多支持同时连接16路摄像头,拉取1920x108…

C++中二叉搜索树的底层原理及实现

小编在学习完二叉搜索树(SearchBinaryTree)之后觉得虽然二叉搜索树不是很难,但是它对于后面学习C中的AVL树和红黑树及map和set的封装都有重要的作用,因此小编今天带给大家二叉搜索树的原理及实现,话不多说,开始学习!~~…

<Linux> git

在使用git之前,要先在linux中安装git yum list | grep git yum install -y 文件名 在第一次安装git时,需要进行下面的操作 git config --global user.email "你的邮箱名" git config --global user.name "你想要的名字" 1. git clon…

LeetCode 热题 HOT 100 (038/100)【宇宙最简单版】

【动态规划】No. 0337 打家劫舍III【中等】👉力扣对应题目指路 希望对你有帮助呀!!💜💜 如有更好理解的思路,欢迎大家留言补充 ~ 一起加油叭 💦 欢迎关注、订阅专栏 【力扣详解】谢谢你的支持&a…

NGINX 常用内置变量

目录 $remote_addr 变量 $args 变量 $is_args 变量 $document_root 变量 $document_uri 变量 $host 变量 $limit_rate 变量 $remote_port 变量 $remote_port --显示客户端端口 $request_method 变量 --返回请求方式 $request_filename 变量 --返回请求实际路径 $request_uri…

eNSP 华为ACL配置

华为ACL配置 需求&#xff1a;公司保证财务部数据安全&#xff0c;禁止研发部门和互联网访问财务服务器&#xff0c;但总裁办不受影响 R1&#xff1a; <Huawei>sys [Huawei]sys Router1 [Router1]undo info-center enable [Router1]int g1/0/0 [Router1-GigabitEthern…

AI 工程应用 建筑表面检测及修复

文章目录 1 项目概述&#xff08;必写&#xff09;&#xff1a;2 技术方案与实施步骤2.1 模型选择&#xff08;必写&#xff09;&#xff1a;2.2 数据的构建&#xff1a;2.3 功能整合&#xff08;进阶&#xff09;&#xff1a; 3 实施步骤&#xff1a;3.1 环境搭建&#xff08;…

【Nginx】nginx的核心配置

1.nginx的文件启动 [rootNginx ~]# vim /lib/systemd/system/nginx.service [Unit] DescriptionThe NGINX HTTP and reverse proxy server Aftersyslog.target network-online.target remote-fs.target nss-lookup.target Wantsnetwork-online.target [Service] Typeforking P…

Python -- GUI图形界面编程—GUI编程实例 博主也在持续学习中[ 持续更新中!!! 欢迎白嫖 也求粉啊啊啊~ ]

本文介绍了GUI的图形界面编程&#xff08;相关视频是哔站上的应该搜这个题目就能找到&#xff09;&#xff0c;文章还是很基础的&#xff0c;反正我是小白从0开始&#xff0c;主要的结构tinkter库、重要组件简介&#xff08;这个不用死记硬背 用的时候再说&#xff09;、Label&…

诊断知识:DTC Status中pending位的使用

文章目录 前言OCC6的定义pending位的定义pending位的使用总结 前言 上一篇文章介绍了ConfirmedDTCLimit的使用&#xff0c;诊断知识&#xff1a;ConfirmedDTCLimit的使用&#xff0c;后面发现理解还是有问题的&#xff0c;其实原来的图画的没有问题&#xff0c;之前对OCC6理解…

【业余玩儿AI】Day 1

【业余玩儿AI】Day 1 实际是昨天的事儿了&#xff0c;记录以下 魔法 不管三七二十一&#xff0c;重新启用魔法&#xff0c;没有魔法这些事情肯定是不行滴 种子任务 把收藏了两个星期的短视频都看了一遍&#xff0c;挑了个种子任务&#xff0c;《本地部署Llama3.1》&#x…

【Web IDE】WebContainer容器在浏览器中启动运行nodejs并使用vite启动项目

参考了文章WebContainer/api 基础&#xff08;Web IDE 技术探索 一&#xff09; 在浏览器中运行vite的vue3项目 示例站点 最终效果 主要流程 加载WebContainer》加载代码压缩包>解压代码压缩包》生成文件树》挂载文件树》pnpm安装依赖》启动项目 代码 <script setup…