前言
通过这次独自做前后端发现有很多需要提升的地方,很多细节处理不到位。下面简单看一下本人自己做的效果吧~~
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嗷,随时更新,随时不定期上传一些好的代码进行开源,欢迎大家一起交流~