koa2结合MySQL实现简单的考试系统

news2024/11/24 2:02:39
项目需求:
1. 数据库采用mysql实现, 后台服务Koa2框架, 通过postman调试所有接口
2. 接口功能:
(1)实现对科目表的增删改查
(2)实现对试题表的增删改
(3)实现对试题表的查询操作,要求:<1>显示科目名称和类型名称 <2> 可以按照科目名称、题目进行模糊查询 <3> sql语句中使用占位符

1.建立数据库

2.后台

(1)搭建koa2框架并配置

项目初始化 npm init -y
安装 npm i koa -g
使用脚手架的方式安装 npm install -g koa-generator
创建项目 koa2 koapro[koapro 项目名称]
配置前的项目启动 npm start koapro 或 npm run start

(2)连接数据库

config/sqlconfig.js 配置数据库相关信息

// mysql数据库配置
const sqlconfig = {
  host: 'localhost',  // 连接地址
  user: 'root',    //用户名
  password: '****',  //密码
  port:  3306 ,   //端口号
  database: 'mysql02_exam'   //数据库名
}
module.exports = sqlconfig

utils/mysqlUtils.js 创建连接池,连接数据库 (不要忘记下载 mysql 模块啊~~~)

//  连接数据库
const mysql = require('mysql')
const sqlconfig = require('../config/sqlconfig')
// 创建连接池
const pool = mysql.createPool(sqlconfig)
// 连接
const exec = (sql,values) => {
  return new Promise((resolve, reject) => {
    pool.getConnection((err, conn) => {
      if (err) {
        //连接错误
        reject(err)
      } else {
        //连接成功
        conn.query(sql,values, (err, data) => {
          if (err) {
            //操作失败
            reject(err)
          } else {
            resolve({
              code: 0,
              message: '操作成功!',
              data,
            })
          }
        })
      }
            // 当连接不再使用时,归还到连接池
            conn.release()
    })
  })
}
module.exports = {
  exec
}

(3)创建相关路由

routes/subject.js 科目

const { searchList,delList,updateList,addList } = require('../control/control')
const router = require('koa-router')()
// 设置路由前缀
router.prefix('/subject')
// 查询
router.get('/search', async (ctx, next) => {
  await searchList(ctx,'subject')
})
// 修改
router.post('/update', async (ctx, next) => {
  await updateList(ctx,'subject')
})
//增加
router.post('/add', async (ctx, next) => {
  await addList(ctx,'subject')
})
// 删除
router.post('/delete', async (ctx, next) => {
  await delList(ctx,'subject')
})
module.exports = router

routes/examquestion.js 试题

const { searchList,delList,updateList1,addList, } = require('../control/control')
const router = require('koa-router')()
router.prefix('/examquestion')
// 查询
router.get('/search', async (ctx, next) => {
  await searchList(ctx,'examquestion')
})
// 修改
router.post('/update', async (ctx, next) => {
  await updateList1(ctx,'examquestion')
})
//增加
router.post('/add', async (ctx, next) => {
  await addList(ctx,'examquestion')
})
// 删除
router.post('/delete', async (ctx, next) => {
  await delList(ctx,'examquestion')
})
module.exports = router

别忘啦, 要在app.js中引入和挂载路由喔~~~

const subject = require('./routes/subject')
const examquestion = require('./routes/examquestion')

// routes
app.use(subject.routes(), subject.allowedMethods())
app.use(examquestion.routes(), examquestion.allowedMethods())

(4)封装操作数据库函数

control/control.js

因为很多操作基本一样, 所以大部分我就只写了一个方法, 多处路由调用,根据表名进行相关操作

const {exec} = require('../utils/mysqlUtils')
const { randomInt } = require('crypto')
const moment = require('moment')
// 查询  
const searchList = async(ctx, table)=>{
  var params = []
  if(table === 'subject'){
    var sql = ` select * from  ${table} where 1=1`
    // 获取get请求的参数
    const {sid, sname} = ctx.query
    // 如果存在sid
    if(sid && sid.trim() !== ''){
      sql += ` and sid = ? `
      params.push(`${sid}`)
    }
    // 如果存在sname  可模糊查询
    if(sname && sname.trim() !== ''){
      sql += ` and sname like ? `
      params.push(`%${sname}%`)
    }
  }
  if(table === 'examquestion'){
    var sql = ` SELECT ?  FROM  'subject' s ,testtype t ,examquestion  e, exampaper_testquestion et WHERE  et.qid = e.qid AND et.tid = t.tid `
    // 获取get请求的参数
    const { sname, title } = ctx.query
    console.log(ctx.query);
    if(ctx.query === 'undefined'){
      console.log(ctx.query.length);
      sql = ` SELECT s.sname, t.tname   FROM  subject s ,testtype t ,examquestion  e, exampaper_testquestion et WHERE  et.qid = e.qid AND et.tid = t.tid `
    }
    if(ctx.query !== 'undefined'){
      console.log(ctx.query.length);
      sql = ` SELECT s.sname, t.tname   FROM  subject s ,testtype t ,examquestion  e, exampaper_testquestion et WHERE  et.qid = e.qid AND et.tid = t.tid `
          // 如果存在sname  可模糊查询
      if(sname && sname.trim() !== ''){
        sql += ` and sname like ? `
        params.push(`%${sname}%`)
      }
      if(title && title.trim() !== ''){
        sql += ` and title like ? `
        params.push(`%${title}%`)
      }
    }
  }
  
  const result = await exec(sql,params)
  if(result.data.length > 0){
    ctx.body = {
      code : 1,
      message: "查询成功",
      result
    }
  }else{
    ctx.body = {
      code : 0,
      message: "查询失败",
    }
  }
}

// 删除
const delList = async(ctx, table)=>{
  let id = table === 'subject' ? 'sid' : 'qid'
  // 根据id删除数据  一次可删多个
  let sql = ` delete from  ${table}  where ${id} in (?) `
  // 获取post请求的参数  
  const {ids} = ctx.request.body
  console.log(ids);
  // 有删除id
  if(ids && ids.length > 0){  
    // sids本身为数组, 一个?只要一个元素
    const result = await exec(sql,[ids])
    console.log(sql,[ids]);
    console.log(result);
    if(result.data.affectedRows > 0){
      ctx.body = {
        code : 1,
        message: "删除成功",
        result
      }
    }else{
      ctx.body = {
        code : 0,
        message: "删除失败",
      }
    }
  }else{
    ctx.body = {
      code :-1,
      message: "未输入删除id",
    }
  } 
}

//更新
const updateList = async(ctx, table)=>{
  // 获取post请求的参数
  const {sid, sname} = ctx.request.body
  // 根据id修改相关信息
  let sql = ` update  ${table}  set sid = sid `  
  let params = []
  // 如果存在sname  
  if(sname && sname.trim() !== ''){
    sql += ` , sname = ? `
    params.push(sname)
    sql += ` where sid = ${sid} `
    params.push(sid)
    const result = await exec(sql,params)
    console.log(result);
    if(result.data.affectedRows > 0){
      ctx.body = {
        code : 1,
        message: "修改成功",
        result
      }
    }else{
      ctx.body = {
        code : 0,
        message: "修改失败",
      }
    }
  }else{
    ctx.body = {
      code :-1,
      message: "未输入更新的sname",
    }
  }
}

const addObj = (obj,table) => {
    if(table === 'subject'){
        let { sname = ''} = obj;
        // 随机生成 sid   randomInt(x)返回0~x的随机整数
        const sid = moment().get() + (randomInt(999) + 1) + '';
        return Array.of(sid,sname);
    }
  if(table === 'examquestion'){
        let { title,sid,tid,answer,optiona,optionb,optionc,optiond} = obj;
        // 随机生成 qid   randomInt(x)返回0~x的随机整数
        const qid = moment().get()  + (randomInt(999) + 1) + '';
        return Array.of(qid,title,sid,tid,answer,optiona,optionb,optionc,optiond);
    }
}
// 增加
const addList = async(ctx,table)=>{
  let { data } = ctx.request.body
  console.log(data);
  let values  = []
  // 检测data是否为数组
  if(Array.isArray(data)){
    // 是数组, 则对每一项进行操作
    values = data.map(item => addObj(item,table) )
  }else {
    // 对象
    values= addObj(data,table);
  }
  let sql = ''
  if(table === 'subject'){
    // sql语句中 ? 为占位符, 表该处有内容, 具体是什么,后边传值,   所传数据(数组中的元素)的个数必须要和占位符的个数一样, 要以数组的形式进行传递(不论有几个元素)
    sql = ` insert into subject(sid,sname) values (?) `
  }
  if(table === 'examquestion'){
    // sql语句中 ? 为占位符, 表该处有内容, 具体是什么,后边传值,   所传数据(数组中的元素)的个数必须要和占位符的个数一样, 要以数组的形式进行传递(不论有几个元素)
    sql = ` insert into examquestion(qid,title,sid,tid,answer,optiona,optionb,optionc,optiond) values (?) `
  }
   console.log(sql);
    const result = await exec(sql,[values])
    console.log(result);
    if(result.data.affectedRows > 0){
      ctx.body = {
        code : 1,
        message: "添加成功",
        result
      }
    }else{
      ctx.body = {
        code : 0,
        message: "添加失败",
      }
    }
}

//更新 
const updateList1 = async(ctx, table)=>{
    // 获取post请求的参数
    const keys = Object.keys(ctx.request.body)
    const val = Object.values(ctx.request.body)
    let sql = ''
    let items = []
    keys.forEach((item, index) => {
      items.push(`${item} = '${val[index]}'`)
    })
    sql = `update ${table} set  ${items} where qid = '${ctx.request.body.qid}'`
    const result = await exec(sql,'')
    console.log(result);
    if(result.data.affectedRows > 0){
      ctx.body = {
        code : 1,
        message: "修改成功",
        result
      }
    }else{
      ctx.body = {
        code : 0,
        message: "修改失败",
      }
    }
}
module.exports = {
  searchList,
  delList,
  updateList,
  addList,
  updateList1
}

源码我放在资源里啦, npm i就好啦

https://download.csdn.net/download/qq_54379580/87452023

PreviousNotes:

https://blog.csdn.net/qq_54379580/article/details/128995535

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

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

相关文章

第一章 - 对数据库和SQL的简单了解

第一章 - 对数据库和SQL的简单了解1 了解数据库&#xff1a;2 什么是数据库&#xff1a;3 什么是SQL&#xff1a;4 SQL的优点&#xff1a;5 数据库的一些常用术语&#xff1a;6 什么是MySQL&#xff1a;1 了解数据库&#xff1a; 其实你一直都在使用数据库&#xff0c;只是你并…

【观察】从消费级SSD AM6A1,看忆联的优势与胜势

毫无疑问&#xff0c;目前SSD&#xff08;固态硬盘&#xff09;已取代HDD&#xff08;机械硬盘&#xff09;成为电脑中常见的存储设备&#xff0c;特别是在技术创新的持续推动下&#xff0c;如今SSD的速度和效率都在不断地提高&#xff0c;从SATA2 3GB发展到SATA3 6GB&#xff…

四、常用样式讲解二

文章目录一、常用样式讲解二1.1 元素隐藏1.2 二级菜单1.3 相对定位和绝对定位1.4 定位的特殊情况1.5 表格1.6 表格的css属性1.7 表格中新增的标签一、常用样式讲解二 1.1 元素隐藏 如何让一个元素隐藏 1、不定义颜色 占用空间 2、display: none 不占用空间 3、visibility: hi…

在Linux和Windows上安装Nacos-2.1.1

记录&#xff1a;377场景&#xff1a;在CentOS 7.9操作系统安装Nacos-2.1.1。在Windows操作系统上安装Nacos-2.1.1。Nacos&#xff1a;Nacos: Dynamic Naming and Configuration Service。Nacos提供动态配置服务、服务发现及管理、动态DNS服务功能。版本&#xff1a;JDK 1.8 Na…

dva + antd 报错

学习 dva 》 按照dva指南学习、安装 dva-cli、引入antd的报错问题解决 1、在执行命令 npm install antd babel-plugin-import --save时报错 报错类似“A complete log of this run can be fund in : … " 解决&#xff1a;换成cnpm 或者 yarn 进行安装 举例在安装history的…

Java常见问题总结三

一、ArrayList 和 LinkedList的区别 1. 底层数据结构不同。ArrayList底层是基于数组实现的&#xff0c;LinkedList底层是基于链表文现的 2. 由于底层数缺结构不同&#xff0c;他们所适电的场景也不同&#xff0c;Araylist史适合随机查战&#xff0c;LinkedList史适合期余和添…

自动化测试工程师的发展前景怎么样?

根据各大网络招聘平台的数据显示&#xff0c;越来越多的企业在招聘测试工程师的时候&#xff0c;都开始重视自动化测试这一重要技能。早在四年前&#xff0c;自动化测试的人才需求和薪资待遇就开始一路上涨。如果你问&#xff1a;自动化测试工程师的发展前景怎么样&#xff1f;…

基于redis实现分布式锁

前言 我们的系统都是分布式部署的&#xff0c;日常开发中&#xff0c;秒杀下单、抢购商品等等业务场景&#xff0c;为了防⽌库存超卖&#xff0c;都需要用到分布式锁。 分布式锁其实就是&#xff0c;控制分布式系统不同进程共同访问共享资源的一种锁的实现。如果不同的系统或…

ubuntu重启、关机命令

// // // //之前用linux系统&#xff0c; 一键解决也是可以的&#xff0c;反正我每次用命令&#xff08;泪目…&#xff09;&#xff0c;中间崩了好几次&#xff0c;换回win&#xff0c;此篇也做记录 // // // 重启命令 以下所有命令在root根目录下输入&#xff08;普通用户&…

SQL Server 数据批量导出处理

在实际项目环境中&#xff0c;有时会遇到需要将大量数据&#xff08;这里所指百万级别以上的数据量&#xff09;从一台服务器迁移到另外一台数据库服务器的情况。SQL Server有很多方式可以进行数据迁移&#xff1a;备份还原、导入/导出数据、生成脚本&#xff08;包含数据&…

解决console.log打印不出深度链表问题

解决console.log打印不出深度链表问题相信大家在写算法题的时候会遇到这样一个问题&#xff0c;写了一个链表的数据结构&#xff0c;在append几个数据之后&#xff0c;想console.log打印以下看看append正不正确&#xff0c;但是&#xff0c;consolo.log出来成这个样子&#xff…

【算法】差分

作者&#xff1a;指针不指南吗 专栏&#xff1a;算法篇 &#x1f43e;合理规划时间与精力&#x1f43e; 1.什么是差分&#xff1f; 与前缀和是反函数 原数组a a1 , a2 , a3 , a4 , a5 , a6 , a7 构造数组b a1b1; a2b1b2; a3b1b2b3; … aib1b2b3…bi; 构造一个b数组使得&#…

【Linux】信号量

&#x1f387;Linux&#xff1a; 博客主页&#xff1a;一起去看日落吗分享博主的在Linux中学习到的知识和遇到的问题博主的能力有限&#xff0c;出现错误希望大家不吝赐教分享给大家一句我很喜欢的话&#xff1a; 看似不起波澜的日复一日&#xff0c;一定会在某一天让你看见坚持…

Java基础:面向对象进阶

1.static 1.static概念 工具类 2.static内存图 静态变量是随着类的加载而加载的,优于对象出现 3.static的注意事项 1.静态方法中,只能访问静态 : 因为非静态方法一般会传入调用方法的对象的地址this(一般是虚拟机自动调用,不需要手动传入, 如student.study()).但是由于静态方…

MapStruct使用指北

mapstruct官方文档链接&#xff0c;点击跳转 mapstruct是什么&#xff1f; MapStruct 是一个代码生成器&#xff0c;它基于约定优于配置方法极大地简化了 Java bean 类型之间映射的实现。 生成的映射代码使用简单的方法调用&#xff0c;因此速度快、类型安全且易于理解。 为…

介绍一款HCIA、HCIP、HCIE的刷题软件

华为认证考试分为三个等级&#xff0c;分别为工程师HCIA、高级工程师HCIP、专家HCIE&#xff0c;等级越高&#xff0c;考试难度越大。 本篇带大家详细了解华为数通题库刷题工具的详细操作步骤。 操作须知&#xff1a;本款刷题工具为一款刷题小程序&#xff0c;无需安装即可在线…

vue2源码之生命周期篇

vue2源码之生命周期篇vue2源码之生命周期篇生命周期流程图初始化阶段&#xff08;new Vue&#xff09;vue2源码之生命周期篇 生命周期流程图 从图中可以看到&#xff0c;Vue实例的生命周期大致可分为4个阶段&#xff1a; 初始化阶段&#xff1a;为Vue实例上初始化一些属性&am…

YOLOv8 目标检测 | 自定义数据集

本文介绍了使用用于目标检测的自定义数据训练 YOLOv8 模型。我正在使用来自 kaggle 的 yolo 格式的“Face Mask Dataset”&#xff0c;数据集链接如下&#xff1a;https://www.kaggle.com/datasets/maalialharbi/face-mask-dataset?resourcedownloadYOLOv8 是目前最先进的 YOL…

一【 mybatis的工作流程】

目录一.mybatis执行流程二.使用工具类简化项目&#xff08;反射的体现&#xff09;2.1 Sqlsession工厂对像2.2 工具类&#xff08;可直接放在工具类使用&#xff09;一.mybatis执行流程 1.1 读取主配置文件mybatis-config.xml&#xff0c;获得运行环境和数据库连接。 1.2 加载映…

35.网络结构与模型压缩、加速-2

35.1 Depthwise separable convolution Depthwise separable convolution是由depthwise conv和pointwise conv构成depthwise conv(DW)有效减少参数数量并提升运算速度 但是由于每个feature map只被一个卷积核卷积,因此经过DW输出的feature map不能只包含输入特征图的全部信息,…