前后端分离(蜗牛学苑04)-渲染教师的复选框列表,新增班级时关联教师,polulate嵌套关联查询,实现分页方式的选择及渲染,上一页和下一页的处理,分页其他操作

1、渲染教师的复选框列表

添加新增老师页面代码和getTeachers函数
1、index.html

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>学生管理系统</title>
</head>
<body>
  <div>
    <h2>新增班级</h2>
    <div>
      <div>
          <label>班级名称</label>
          <input type="text" id="addClassName"/>
      </div>
      <div>
        <label>选择教师</label>
        <div id="selectTeacher">
          <!--动态渲染教师列表-->
        </div>
      </div>
      <button id="addClassBtn">确认新增</button>
    </div>
    <div><hr/></div>
  </div>

  <div>
    <h2>新增教师</h2>
    <div>
      <div>
        <label>教师名称</label>
        <input type="text" id="addTeacherName"/>
      </div>
      <button id="addTeacherBtn">确认新增</button>
    </div>
    <div><hr/></div>
  </div>

  <h2>新增学生</h2>
  <div>
    <div><label>学生姓名:</label><input type="text" id="addStudentsName"/> </div>
    <div><label>学生年龄:</label><input type="text" id="addStudentsAge"/> </div>
    <div>
      <label>学生性别:</label>
        <input type="radio" name="addStudentsGender" value="男"><label></label>
        <input type="radio" name="addStudentsGender" value="女"><label></label>
    </div>
    <div>
      <label>所属班级</label>
      <select id="selectClasses">

      </select>
    </div>
    <div>
      <button id="addStudent">确认新增</button>
    </div>
  </div>

  <h2>修改学生</h2>
  <div>
    <input type="hidden" id="updateStudentsId">
    <div><label>学生姓名:</label><input type="text" id="updateStudentsName"/> </div>
    <div><label>学生年龄:</label><input type="text" id="updateStudentsAge"/> </div>
    <div>
      <label>学生性别:</label>
      <input type="radio" name="updateStudentsGender" value="男"><label></label>
      <input type="radio" name="updateStudentsGender" value="女"><label></label>
    </div>
    <div>
      <button id="updateStudent">确认修改</button>
    </div>
  </div>

  <h2>查询学生</h2>
  <div>
    <select id="searchType">
      <option value="name">姓名</option>
      <option value="age">年龄</option>
      <option value="gender">性别</option>
    </select>
    <input type="text" id="searchValue">
    <button id="searchBtn">查询学生</button>
  </div>
  <h2>学生列表</h2>
  <table>
    <thead>
      <tr>
        <th>学生姓名</th>
        <th>学生年龄</th>
        <th>学生性别</th>
        <th>所属班级</th>
        <th>学生操作</th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td>张三</td>
        <td>20</td>
        <td></td>
        <td>
          <button>修改 | 删除</button>
        </td>
      </tr>
    </tbody>
  </table>
<script src="./javascripts/jquery.min.js"></script>
<script>
  //给一个全局变量来做查询
  let data={ }
  //页面刷新就开始做这两个方法
  getStudents()//获取全部学生
  getClassess()//获取全部班级
  getTeachers()//获取全部老师
  //获取全部学生
  function getStudents(){
    $.ajax({
      url:'/students/getStudents',
      data:data,
      type:'GET',
      success({message,status,data }){
        //进入if表示进入学生数据成功
        if(status){
          const str=data.map(function (item,index) {
            return `
            <tr>
              <td>${item.name}</td>
              <td>${item.age}</td>
              <td>${item.gender}</td>
              <td>${item.classId.name}</td>
              <td>
                <button class="updateBtn" data-id="${item._id}">修改</button>
                <button class="removeBtn" data-id="${item._id}">删除</button>
              </td>
            </tr>
            `
          }).join('')//join是拼接
          $('tbody').html(str)
        }
      }
    })
  }

  //获取班级
  function getClassess(){
    $.ajax({
      url:'/classes/getClasses',
      type:'GET',
      data:{},
      success(msg){
        if (msg.status){
          const str=msg.data.map(function(item,index){
            return `<option value="${item._id}">${item.name}</option>`
          }).join('')//遍历出来data的name后,和option一起拼接成一个大字符串
          $('#selectClasses').html(str)
        }
      }
    })
  }

  //获取全部教师
  function getTeachers(){
    $.ajax({
      url:'/teachers/getTeachers',
      type:'GET',
      success(msg){
        if (msg.status){
          const str=msg.data.map(item=>{
            return`
            <input type="checkbox" value="${item._id}"/>
            <label>${item.name}</label>
            `
          }).join('')
          $('#selectTeacher').html(str)
        }
      }
    })
  }

  //新增班级
  $('#addClassBtn').click(function(){
    $.ajax({
      url:'/classes/addClasses',
      type:'POST',
      data:{
        name:$('#addClassName').val()
      },
      success(msg){
        if (msg.status){
          getClassess()
        }
      }
    })
  })

  //删除按钮使用事件委托
  //on做委托,委托给父级的静态元素,第一个参数是事件,第二个参数是真正执行的那个标签(委托人),第三个参数是具体的工作
  $('tbody').on('click','.removeBtn',function(){
    //获取当前点击的这个按钮对应的id,data('id')是获取所有(特定)属性的函数,这里的id实际就是data-id,前面加data-是一种约定俗成
    const _id=$(this).data('id')
    console.log(_id)
    $.ajax({
      url:'/students/deleteStudents',
      type:'post',
      data: { _id },
      success (msg) {
        if (msg.status){
          alert('删除成功')
          //重新发一次ajax请求
          getStudents()

        }
      }
    })

  })

  //修改学生信息
  //获取要修改的一个学生信息
  $('tbody').on('click','.updateBtn',function(){
    const _id=$(this).data('id')
    //console.log(_id)
    $.ajax({
      url:'/students/getStudentsById',
      data:{_id},
      success(msg){
        if (msg.status){
          $('#updateStudentsId').val(msg.data._id)
          $('#updateStudentsName').val(msg.data.name)//设置控件的value值
          $('#updateStudentsAge').val(msg.data.age)//设置控件的value值
          $(`[name=updateStudentsGender][value=${msg.data.gender}]`).prop('checked',true)
        }
      }

    })
  })

  //确认修改学生信息
  $('#updateStudent').click(function(){
    const _id=$('#updateStudentsId').val()
    const name=$('#updateStudentsName').val()
    const age=$('#updateStudentsAge').val()
    const gender=$(`[name=updateStudentsGender]:checked`).val()
    //console.log(name,age,gender)
    $.ajax({
      url:'/students/updateStudents',
      type:'POST',
      data:{
        name,age,gender,_id
      },
      success(msg){
        if(msg.status){
          getStudents()
        }
      }
    })
  })

  //查询
  $('#searchBtn').click(function(){
    //获取下拉列表中选中的option的value值,可以直接获取selected的值
    const searchType=$('#searchType').val()
    //console.log(searchType)

    //获取搜索的值
    const searchValue=$('#searchValue').val()
    data={
      searchType,
      searchValue
    }
    //console.log(data)
    getStudents()
  })
  //新增学生
  $('#addStudent').click(function(){
    const name=$('#addStudentsName').val()
    const age=$('#addStudentsAge').val()
    const gender=$('[name=addStudentsGender]:checked').val()
    const classId=$('#selectClasses').val()
    //console.log(name,age,gender)
    $.ajax({
      url:'/students/addStudents',
      type:'POST',
      data:{
        name,
        age,
        gender,
        classId
      },
      success(msg){
        if (msg.status){
          getStudents()
        }
      }
    })
  })
</script>
</body>
</html>

2、添加以及路由app.js

const teachersRouter=require('./routes/teachers')
app.use('/teachers', teachersRouter)

3、添加二级路由router/teachers.js

var express = require('express');
var router = express.Router();

//引入第二层的getStudents方法
const {getTeachers}=require('../service/teachersService')
//获取所有数据,及查询
router.get('/getTeachers', async function(req, res, next) {
  const data=await getTeachers()
  res.send(data)

});


module.exports = router;

4、添加服务成teacherService.js

const {getTeachers}=require('../dao/teachersDao')
//添加班级
module.exports.getTeachers=async function(){
  const data=await getTeachers()
  return {
    message:'班级新增成功',
    status:1,
    data
  }

}

5、添加服模型teacherModel.js

//数据集合的相关配置
//1、定义数据集合的结构:定义集合中数据有哪些属性,属性的值是什么类型(数据库结构)
//解构出mongoose的Schema方法来,这个方法用来操作集合的
const { Schema,model }=require('mongoose')
//通过构造函数创建集合的结构
const teachersSchema=new Schema({
  name:String,
  phone: {
    type:String,
    default:'18514125625'
  },
},{versionKey:false})

//2、定义数据集合的模型:将schema和数据库中的集合关联起来
//model需要三个参数:模型名称,schema名称,数据库中的集合名称
const teachersModel=model('teachersModel',teachersSchema,'teachers')

//向第三层dao层暴露model数据
module.exports.teachersModel=teachersModel

6、添加持久层teacherDao.js

//引入第三层dao层的model模型,用以操作数据库
const { teachersModel }=require('./models/teachersModel')
//暴露一个获取所有学生方法
module.exports.getTeachers=async function () {
  //find 是异步操作,在model里查找user记录(文档)。返回一个数组
  //populate是做关联查询
  const data=await teachersModel.find()
  return data

}

2、新增班级是关联教师

新增班级部分添加遍历教师的部分
1、index.html

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>学生管理系统</title>
</head>
<body>
  <div>
    <h2>新增班级</h2>
    <div>
      <div>
          <label>班级名称</label>
          <input type="text" id="addClassName"/>
      </div>
      <div>
        <label>选择教师</label>
        <div id="selectTeacher">
          <!--动态渲染教师列表-->
        </div>
      </div>
      <button id="addClassBtn">确认新增</button>
    </div>
    <div><hr/></div>
  </div>

  <div>
    <h2>新增教师</h2>
    <div>
      <div>
        <label>教师名称</label>
        <input type="text" id="addTeacherName"/>
      </div>
      <button id="addTeacherBtn">确认新增</button>
    </div>
    <div><hr/></div>
  </div>

  <h2>新增学生</h2>
  <div>
    <div><label>学生姓名:</label><input type="text" id="addStudentsName"/> </div>
    <div><label>学生年龄:</label><input type="text" id="addStudentsAge"/> </div>
    <div>
      <label>学生性别:</label>
        <input type="radio" name="addStudentsGender" value="男"><label></label>
        <input type="radio" name="addStudentsGender" value="女"><label></label>
    </div>
    <div>
      <label>所属班级</label>
      <select id="selectClasses">

      </select>
    </div>
    <div>
      <button id="addStudent">确认新增</button>
    </div>
  </div>

  <h2>修改学生</h2>
  <div>
    <input type="hidden" id="updateStudentsId">
    <div><label>学生姓名:</label><input type="text" id="updateStudentsName"/> </div>
    <div><label>学生年龄:</label><input type="text" id="updateStudentsAge"/> </div>
    <div>
      <label>学生性别:</label>
      <input type="radio" name="updateStudentsGender" value="男"><label></label>
      <input type="radio" name="updateStudentsGender" value="女"><label></label>
    </div>
    <div>
      <button id="updateStudent">确认修改</button>
    </div>
  </div>

  <h2>查询学生</h2>
  <div>
    <select id="searchType">
      <option value="name">姓名</option>
      <option value="age">年龄</option>
      <option value="gender">性别</option>
    </select>
    <input type="text" id="searchValue">
    <button id="searchBtn">查询学生</button>
  </div>
  <h2>学生列表</h2>
  <table>
    <thead>
      <tr>
        <th>学生姓名</th>
        <th>学生年龄</th>
        <th>学生性别</th>
        <th>所属班级</th>
        <th>学生操作</th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td>张三</td>
        <td>20</td>
        <td></td>
        <td>
          <button>修改 | 删除</button>
        </td>
      </tr>
    </tbody>
  </table>
<script src="./javascripts/jquery.min.js"></script>
<script>
  //给一个全局变量来做查询
  let data={ }
  //页面刷新就开始做这两个方法
  getStudents()//获取全部学生
  getClassess()//获取全部班级
  getTeachers()//获取全部老师
  //获取全部学生
  function getStudents(){
    $.ajax({
      url:'/students/getStudents',
      data:data,
      type:'GET',
      success({message,status,data }){
        //进入if表示进入学生数据成功
        if(status){
          const str=data.map(function (item,index) {
            return `
            <tr>
              <td>${item.name}</td>
              <td>${item.age}</td>
              <td>${item.gender}</td>
              <td>${item.classId.name}</td>
              <td>
                <button class="updateBtn" data-id="${item._id}">修改</button>
                <button class="removeBtn" data-id="${item._id}">删除</button>
              </td>
            </tr>
            `
          }).join('')//join是拼接
          $('tbody').html(str)
        }
      }
    })
  }

  //获取班级
  function getClassess(){
    $.ajax({
      url:'/classes/getClasses',
      type:'GET',
      data:{},
      success(msg){
        if (msg.status){
          const str=msg.data.map(function(item,index){
            return `<option value="${item._id}">${item.name}</option>`
          }).join('')//遍历出来data的name后,和option一起拼接成一个大字符串
          $('#selectClasses').html(str)
        }
      }
    })
  }

  //获取全部教师
  function getTeachers(){
    $.ajax({
      url:'/teachers/getTeachers',
      type:'GET',
      success(msg){
        if (msg.status){
          const str=msg.data.map(item=>{
            return`
            <input type="checkbox" value="${item._id}"/>
            <label>${item.name}</label>
            `
          }).join('')
          $('#selectTeacher').html(str)
        }
      }
    })
  }

  //新增班级
  $('#addClassBtn').click(function(){
    //获取选中教师的id数组,使用扩展运算符转换为真数组
    const teachersId=[...$('#selectTeacher>input[type=checkbox]:checked')].map(function(item,index){
      //return item.value//原生js方法
      return $(item).val()//jquery方法
    })
    //console.log(teachersId)
    $.ajax({
      url:'/classes/addClasses',
      type:'POST',
      data:{
        name:$('#addClassName').val(),
        teachersId
      },
      //当ajax的data传递数组的时候必须要添加选项解决数组格式问题
      traditional:true,
      success(msg){
        if (msg.status){
          getClassess()
        }
      }
    })
  })

  //删除按钮使用事件委托
  //on做委托,委托给父级的静态元素,第一个参数是事件,第二个参数是真正执行的那个标签(委托人),第三个参数是具体的工作
  $('tbody').on('click','.removeBtn',function(){
    //获取当前点击的这个按钮对应的id,data('id')是获取所有(特定)属性的函数,这里的id实际就是data-id,前面加data-是一种约定俗成
    const _id=$(this).data('id')
    console.log(_id)
    $.ajax({
      url:'/students/deleteStudents',
      type:'post',
      data: { _id },
      success (msg) {
        if (msg.status){
          alert('删除成功')
          //重新发一次ajax请求
          getStudents()

        }
      }
    })

  })

  //修改学生信息
  //获取要修改的一个学生信息
  $('tbody').on('click','.updateBtn',function(){
    const _id=$(this).data('id')
    //console.log(_id)
    $.ajax({
      url:'/students/getStudentsById',
      data:{_id},
      success(msg){
        if (msg.status){
          $('#updateStudentsId').val(msg.data._id)
          $('#updateStudentsName').val(msg.data.name)//设置控件的value值
          $('#updateStudentsAge').val(msg.data.age)//设置控件的value值
          $(`[name=updateStudentsGender][value=${msg.data.gender}]`).prop('checked',true)
        }
      }

    })
  })

  //确认修改学生信息
  $('#updateStudent').click(function(){
    const _id=$('#updateStudentsId').val()
    const name=$('#updateStudentsName').val()
    const age=$('#updateStudentsAge').val()
    const gender=$(`[name=updateStudentsGender]:checked`).val()
    //console.log(name,age,gender)
    $.ajax({
      url:'/students/updateStudents',
      type:'POST',
      data:{
        name,age,gender,_id
      },
      success(msg){
        if(msg.status){
          getStudents()
        }
      }
    })
  })

  //查询
  $('#searchBtn').click(function(){
    //获取下拉列表中选中的option的value值,可以直接获取selected的值
    const searchType=$('#searchType').val()
    //console.log(searchType)

    //获取搜索的值
    const searchValue=$('#searchValue').val()
    data={
      searchType,
      searchValue
    }
    //console.log(data)
    getStudents()
  })
  //新增学生
  $('#addStudent').click(function(){
    const name=$('#addStudentsName').val()
    const age=$('#addStudentsAge').val()
    const gender=$('[name=addStudentsGender]:checked').val()
    const classId=$('#selectClasses').val()
    //console.log(name,age,gender)
    $.ajax({
      url:'/students/addStudents',
      type:'POST',
      data:{
        name,
        age,
        gender,
        classId
      },
      success(msg){
        if (msg.status){
          getStudents()
        }
      }
    })
  })
</script>
</body>
</html>

2、修改classessModel.js
由于调整了班级对应教师的模型,一般对多个教师,所以要修改classessModel

//数据集合的相关配置
//1、定义数据集合的结构:定义集合中数据有哪些属性,属性的值是什么类型(数据库结构)
//解构出mongoose的Schema方法来,这个方法用来操作集合的
const { Schema,model }=require('mongoose')
//通过构造函数创建集合的结构
const classesSchema=new Schema({
  name:String,
  //teahersid实际是数组(一对多),所以要加中括号变成数组
  teachersId: [{
    type:Schema.Types.ObjectId,
    ref:'teachersModel'
  }]
},{versionKey:false})

//2、定义数据集合的模型:将schema和数据库中的集合关联起来
//model需要三个参数:模型名称,schema名称,数据库中的集合名称
const classesModel=model('classesModel',classesSchema,'classes')

//向第三层dao层暴露model数据
module.exports.classesModel=classesModel

3、populate嵌套关联查询

index页面中添加增加学生、班级、教师关联语句
1、index.html

2、在studentsDao.js中获取学生处理函数中,添加populate设置,注意对于teachersId使用关联语法

const data=await studentsModel.find().populate({
    path:'classId',
    populate:{
      path:'teachersId'
    }
  })

完整studentsDao.js代码

//向第二层服务层暴露getStudents方法,
//在第三层dao层操作数据库
//引入第三层dao层的model模型,用以操作数据库
const { studentsModel }=require('./models/studentsModel')
//暴露一个获取所有学生方法
module.exports.getStudents=async function () {
  //find 是异步操作,在model里查找user记录(文档)。返回一个数组
  //populate是做关联查询
  const data=await studentsModel.find().populate({
    path:'classId',
    populate:{
      path:'teachersId'
    }
  })
  //console.log('第三层的data',data)
  //第三层直接返回数据给第二层,不需要做任何操作,dao层-->服务层-->表现层
  return data
  //做模糊查询
  // return await studentsModel.find({
  //   //$options:'$i'因为不区分大小写
  //   [params.searchType]:{$regex:params.searchValue,$options:'$i'}
  // })
}
//暴露一个获取部分学生方法
module.exports.searchStudents=async function (params) {
  //做模糊查询
  return await studentsModel.find({
    //$options:'$i'因为不区分大小写
  //   [params.searchType]:{$regex:params.searchValue,$options:'$i'}
  // }).populate('classId')
    [params.searchType]:{$regex:params.searchValue,$options:'$i'}
    }).populate( 'classId' )
}

//暴露一个新增方法
module.exports.addStudents=async function (student) {

  const data=await studentsModel.create(student)
  return data
}


//暴露一个删除方法
module.exports.deleteStudents=async function ({ _id }) {//这里把对象中的id解构出来了

  //const data=await studentsModel.deleteOne(_id)//这里id实际是一个对象
  const data=await studentsModel.findByIdAndDelete(_id)

  return data
}



//暴露一个获取学生方法
module.exports.getStudentsById=async function ({ _id }) {//这里把对象中的id解构出来了

  //const data=await studentsModel.deleteOne(_id)//这里id实际是一个对象
  const data=await studentsModel.findById(_id)//返回的事一个对象

  return data
}


//确认修改一个学生方法
module.exports.updateStudents=async function ({_id,name,age,gender }) {//这里把对象中的id解构出来了
  //console.log(student)
  //const data=await studentsModel.deleteOne(_id)//这里id实际是一个对象
  //return await studentsModel.updateOne({_id:student._id},student)//返回的事一个对象
  return await studentsModel.findByIdAndUpdate(_id, { name,age,gender})//返回的事一个对象


}

4、实现分页方式的选择及页面渲染

1、一次渲染,分页显示
2、分页渲染
在页面需要做响应的修改
步骤上
1、给页面ajax传递的参数添加一个pageSize属性和一个currentSize属性

  //获取全部学生
  function getStudents(){
    $.ajax({
      url:'/students/getStudents',
      data: {
        ...data,//先前传递的data对象
        pageSize:5,//每页显示条数
        currentPage:1//当前页
      },
      type:'GET',
      success({message,status,data }){
        //console.log(data)
        //进入if表示进入学生数据成功
        if(status){
          const str=data.map(function (item,index) {
            return `
            <tr>
              <td>${item.name}</td>
              <td>${item.age}</td>
              <td>${item.gender}</td>
              <td>${item.classId.name}</td>
              <td>
                ${
                  item.classId.teachersId.map(item=>`<p>${item.name}</p>`).join('')
                }
              </td>
              <td>
                <button class="updateBtn" data-id="${item._id}">修改</button>
                <button class="removeBtn" data-id="${item._id}">删除</button>
              </td>
            </tr>
            `
          }).join('')//join是拼接
          $('tbody').html(str)
        }
      }
    })
  }

2、在service分别给getstudents函数添加一个参数params
studentsService.js

module.exports.getStudents= async function (params) {
  //console.log('第二层学生数据',params)
  //根据参数情况判断查询什么
  //进入if表示searchValue有值,说明是获取部分学生
  if (params.searchValue){
    const data=await searchStudents(params)
    return {
      message:'学生数据获取成功',
      status:1,
      data
    }
  }else{
    //进入else表示searchValue没有值,说明是获取所有学生
    //调用第三层(dao层)的login,数据从第二次(服务层)传递到了第三层(dao)层
    try{
      const data=await getStudents(params)
      return {
        message:'学生数据获取成功',
        status:1,
        data
      }
      //console.log('第二层的data',data)
    }catch (e) {
      console.log(e)
      return {
        message:'学生数据获取失败',
        status:0
      }
    }

  }
}

3、调整dao层的查询代码使用limit()限制查询条数,使用skip()跳过一定条数

module.exports.getStudents=async function ({pageSize,currentPage }) {
  //console.log('第三层的数据',pageSize,currentPage)
  //find 是异步操作,在model里查找user记录(文档)。返回一个数组
  //populate是做关联查询
  const data=await studentsModel.find()
    .populate({
      path:'classId',
      populate:{
        path:'teachersId'
      }
  }).limit(pageSize-0)//设置请求的数据条数
    .skip((currentPage-1)*pageSize)//跳过数据的条数

完整代码如下:
1、index.html

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>学生管理系统</title>
</head>
<body>
  <div>
    <h2>新增班级</h2>
    <div>
      <div>
          <label>班级名称</label>
          <input type="text" id="addClassName"/>
      </div>
      <div>
        <label>选择教师</label>
        <div id="selectTeacher">
          <!--动态渲染教师列表-->
        </div>
      </div>
      <button id="addClassBtn">确认新增</button>
    </div>
    <div><hr/></div>
  </div>

  <div>
    <h2>新增教师</h2>
    <div>
      <div>
        <label>教师名称</label>
        <input type="text" id="addTeacherName"/>
      </div>
      <button id="addTeacherBtn">确认新增</button>
    </div>
    <div><hr/></div>
  </div>

  <h2>新增学生</h2>
  <div>
    <div><label>学生姓名:</label><input type="text" id="addStudentsName"/> </div>
    <div><label>学生年龄:</label><input type="text" id="addStudentsAge"/> </div>
    <div>
      <label>学生性别:</label>
        <input type="radio" name="addStudentsGender" value="男"><label></label>
        <input type="radio" name="addStudentsGender" value="女"><label></label>
    </div>
    <div>
      <label>所属班级</label>
      <select id="selectClasses">

      </select>
    </div>
    <div>
      <button id="addStudent">确认新增</button>
    </div>
  </div>

  <h2>修改学生</h2>
  <div>
    <input type="hidden" id="updateStudentsId">
    <div><label>学生姓名:</label><input type="text" id="updateStudentsName"/> </div>
    <div><label>学生年龄:</label><input type="text" id="updateStudentsAge"/> </div>
    <div>
      <label>学生性别:</label>
      <input type="radio" name="updateStudentsGender" value="男"><label></label>
      <input type="radio" name="updateStudentsGender" value="女"><label></label>
    </div>
    <div>
      <button id="updateStudent">确认修改</button>
    </div>
  </div>

  <h2>查询学生</h2>
  <div>
    <select id="searchType">
      <option value="name">姓名</option>
      <option value="age">年龄</option>
      <option value="gender">性别</option>
    </select>
    <input type="text" id="searchValue">
    <button id="searchBtn">查询学生</button>
  </div>
  <h2>学生列表</h2>
  <table>
    <thead>
      <tr>
        <th>学生姓名</th>
        <th>学生年龄</th>
        <th>学生性别</th>
        <th>所属班级</th>
        <th>负责教师</th>
        <th>学生操作</th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td>张三</td>
        <td>20</td>
        <td></td>
        <td>
          <button>修改 | 删除</button>
        </td>
      </tr>
    </tbody>
  </table>
  <div>
    <label>每页条数</label>
    <select id="pageSize">
      <option value="2">2</option>
      <option value="3">3</option>
      <option value="5">5</option>
    </select>
  </div>

  <div>
    <button>首页</button>
    <button>下一页</button>
    <button>上一页</button>
    <button>尾页</button>
  </div>
<script src="./javascripts/jquery.min.js"></script>
<script>
  //给一个全局变量来做查询
  let data={ }
  //页面刷新就开始做这两个方法
  getStudents()//获取全部学生
  getClasses()//获取全部班级
  getTeachers()//获取全部老师
  //获取全部学生
  function getStudents(){
    $.ajax({
      url:'/students/getStudents',
      data: {
        ...data,
        pageSize:5,//每页显示条数
        currentPage:1//当前页
      },
      type:'GET',
      success({message,status,data }){
        //console.log(data)
        //进入if表示进入学生数据成功
        if(status){
          const str=data.map(function (item,index) {
            return `
            <tr>
              <td>${item.name}</td>
              <td>${item.age}</td>
              <td>${item.gender}</td>
              <td>${item.classId.name}</td>
              <td>
                ${
                  item.classId.teachersId.map(item=>`<p>${item.name}</p>`).join('')
                }
              </td>
              <td>
                <button class="updateBtn" data-id="${item._id}">修改</button>
                <button class="removeBtn" data-id="${item._id}">删除</button>
              </td>
            </tr>
            `
          }).join('')//join是拼接
          $('tbody').html(str)
        }
      }
    })
  }

  //获取班级
  function getClasses(){
    $.ajax({
      url:'/classes/getClasses',
      type:'GET',
      data:{},
      success(msg){
        if (msg.status){
          const str=msg.data.map(function(item,index){
            return `<option value="${item._id}">${item.name}</option>`
          }).join('')//遍历出来data的name后,和option一起拼接成一个大字符串
          $('#selectClasses').html(str)
        }
      }
    })
  }

  //获取全部教师
  function getTeachers(){
    $.ajax({
      url:'/teachers/getTeachers',
      type:'GET',
      success(msg){
        if (msg.status){
          const str=msg.data.map(item=>{
            return`
            <input type="checkbox" value="${item._id}"/>
            <label>${item.name}</label>
            `
          }).join('')
          $('#selectTeacher').html(str)
        }
      }
    })
  }

  //新增班级
  $('#addClassBtn').click(function(){
    //获取选中教师的id数组,使用扩展运算符转换为真数组
    const teachersId=[...$('#selectTeacher>input[type=checkbox]:checked')].map(function(item,index){
      //return item.value//原生js方法
      return $(item).val()//jquery方法
    })
    //console.log(teachersId)
    $.ajax({
      url:'/classes/addClasses',
      type:'POST',
      data:{
        name:$('#addClassName').val(),
        teachersId
      },
      //当ajax的data传递数组的时候必须要添加选项解决数组格式问题
      traditional:true,
      success(msg){
        if (msg.status){
          getClasses()
        }
      }
    })
  })

  //删除按钮使用事件委托
  //on做委托,委托给父级的静态元素,第一个参数是事件,第二个参数是真正执行的那个标签(委托人),第三个参数是具体的工作
  $('tbody').on('click','.removeBtn',function(){
    //获取当前点击的这个按钮对应的id,data('id')是获取所有(特定)属性的函数,这里的id实际就是data-id,前面加data-是一种约定俗成
    const _id=$(this).data('id')
    console.log(_id)
    $.ajax({
      url:'/students/deleteStudents',
      type:'post',
      data: { _id },
      success (msg) {
        if (msg.status){
          alert('删除成功')
          //重新发一次ajax请求
          getStudents()

        }
      }
    })

  })

  //修改学生信息
  //获取要修改的一个学生信息
  $('tbody').on('click','.updateBtn',function(){
    const _id=$(this).data('id')
    //console.log(_id)
    $.ajax({
      url:'/students/getStudentsById',
      data:{_id},
      success(msg){
        if (msg.status){
          $('#updateStudentsId').val(msg.data._id)
          $('#updateStudentsName').val(msg.data.name)//设置控件的value值
          $('#updateStudentsAge').val(msg.data.age)//设置控件的value值
          $(`[name=updateStudentsGender][value=${msg.data.gender}]`).prop('checked',true)
        }
      }

    })
  })

  //确认修改学生信息
  $('#updateStudent').click(function(){
    const _id=$('#updateStudentsId').val()
    const name=$('#updateStudentsName').val()
    const age=$('#updateStudentsAge').val()
    const gender=$(`[name=updateStudentsGender]:checked`).val()
    //console.log(name,age,gender)
    $.ajax({
      url:'/students/updateStudents',
      type:'POST',
      data:{
        name,age,gender,_id
      },
      success(msg){
        if(msg.status){
          getStudents()
        }
      }
    })
  })

  //查询
  $('#searchBtn').click(function(){
    //获取下拉列表中选中的option的value值,可以直接获取selected的值
    const searchType=$('#searchType').val()
    //console.log(searchType)

    //获取搜索的值
    const searchValue=$('#searchValue').val()
    data={
      searchType,
      searchValue
    }
    //console.log(data)
    getStudents()
  })
  //新增学生
  $('#addStudent').click(function(){
    const name=$('#addStudentsName').val()
    const age=$('#addStudentsAge').val()
    const gender=$('[name=addStudentsGender]:checked').val()
    const classId=$('#selectClasses').val()
    //console.log(name,age,gender)
    $.ajax({
      url:'/students/addStudents',
      type:'POST',
      data:{
        name,
        age,
        gender,
        classId
      },
      success(msg){
        if (msg.status){
          getStudents()
        }
      }
    })
  })
</script>
</body>
</html>

2、studentsService.js

const {getStudents,addStudents,deleteStudents,searchStudents,getStudentsById,updateStudents}=require('../dao/studentsDao')
//在第二层服务层暴露一个属性login给第一层(表现层),并从第一层接收一个数据user到第二层
//获取所有或获取部分学生
module.exports.getStudents= async function (params) {
  //console.log('第二层学生数据',params)
  //根据参数情况判断查询什么
  //进入if表示searchValue有值,说明是获取部分学生
  if (params.searchValue){
    const data=await searchStudents(params)
    return {
      message:'学生数据获取成功',
      status:1,
      data
    }
  }else{
    //进入else表示searchValue没有值,说明是获取所有学生
    //调用第三层(dao层)的login,数据从第二次(服务层)传递到了第三层(dao)层
    try{
      const data=await getStudents(params)
      return {
        message:'学生数据获取成功',
        status:1,
        data
      }
      //console.log('第二层的data',data)
    }catch (e) {
      console.log(e)
      return {
        message:'学生数据获取失败',
        status:0
      }
    }

  }



}

//新增学生
module.exports.addStudents= async function (student) {
  //调用第三层(dao层)的login,数据从第二次(服务层)传递到了第三层(dao)层
  const data= await addStudents(student)
  //console.log('第二层得到的data:',data)
  if (data._id){
    return {
      message:'新增学生成功',
      status:1,
      data
    }
  }else{
    return {
      message:'新增学生失败',
      status:0
    }
  }

}


//删除学生
module.exports.deleteStudents= async function (_id) {
  //调用第三层(dao层)的login,数据从第二次(服务层)传递到了第三层(dao)层
  const data= await deleteStudents(_id)
  //console.log('第二层的data',data)
  if (data){//如果data有值
    return {
      message:'删除成功',
      status:1,
      data
    }
  }else{
    return {
      message:'删除失败',
      status:0,
    }
  }
}


//获取一个学生
module.exports.getStudentsById= async function (_id) {
  //调用第三层(dao层)的login,数据从第二次(服务层)传递到了第三层(dao)层
  const data= await getStudentsById(_id)
  return {
    message:'学生数据获取成功',
    status:1,
    data
  }
}


//确认修改一个学生
module.exports.updateStudents= async function (student) {
  //调用第三层(dao层)的login,数据从第二次(服务层)传递到了第三层(dao)层
  const data= await updateStudents(student)
  //console.log(data)
  if (data){
    return {
      message:'修改学生数据成功',
      status:1,
      data
    }
  }else{
    return {
      message:'修改学生数据成功',
      status:0
    }
  }

}

3、studentsDao.js

//向第二层服务层暴露getStudents方法,
//在第三层dao层操作数据库
//引入第三层dao层的model模型,用以操作数据库
const { studentsModel }=require('./models/studentsModel')
//暴露一个获取所有学生方法
module.exports.getStudents=async function ({pageSize,currentPage }) {
  //console.log('第三层的数据',pageSize,currentPage)
  //find 是异步操作,在model里查找user记录(文档)。返回一个数组
  //populate是做关联查询
  const data=await studentsModel.find()
    .populate({
      path:'classId',
      populate:{
        path:'teachersId'
      }
  }).limit(pageSize-0)//设置请求的数据条数
    .skip((currentPage-1)*pageSize)//跳过数据的条数


  //console.log('第三层的data',data)
  //第三层直接返回数据给第二层,不需要做任何操作,dao层-->服务层-->表现层
  return data
  //做模糊查询
  // return await studentsModel.find({
  //   //$options:'$i'因为不区分大小写
  //   [params.searchType]:{$regex:params.searchValue,$options:'$i'}
  // })
}
//暴露一个获取部分学生方法
module.exports.searchStudents=async function (params) {
  //做模糊查询
  return await studentsModel.find({
    //$options:'$i'因为不区分大小写
  //   [params.searchType]:{$regex:params.searchValue,$options:'$i'}
  // }).populate('classId')
    [params.searchType]:{$regex:params.searchValue,$options:'$i'}
    }).populate( 'classId' )
}

//暴露一个新增方法
module.exports.addStudents=async function (student) {

  const data=await studentsModel.create(student)
  return data
}


//暴露一个删除方法
module.exports.deleteStudents=async function ({ _id }) {//这里把对象中的id解构出来了

  //const data=await studentsModel.deleteOne(_id)//这里id实际是一个对象
  const data=await studentsModel.findByIdAndDelete(_id)

  return data
}



//暴露一个获取学生方法
module.exports.getStudentsById=async function ({ _id }) {//这里把对象中的id解构出来了

  //const data=await studentsModel.deleteOne(_id)//这里id实际是一个对象
  const data=await studentsModel.findById(_id)//返回的事一个对象

  return data
}


//确认修改一个学生方法
module.exports.updateStudents=async function ({_id,name,age,gender }) {//这里把对象中的id解构出来了
  //console.log(student)
  //const data=await studentsModel.deleteOne(_id)//这里id实际是一个对象
  //return await studentsModel.updateOne({_id:student._id},student)//返回的事一个对象
  return await studentsModel.findByIdAndUpdate(_id, { name,age,gender})//返回的事一个对象


}

5、上一页和下一页的处理

使用三个点扩展父还能保留原有的数据(具体原理是什么)

data={
      ...data,//保留原有的data数据
      searchType,
      searchValue
    }

这里重点是需要获取页数
在dao里通过 const total=await studentsModel.countDocuments()
获取总的记录条数并计算出总的页数

//获取查询的总条数
  const total=await studentsModel.countDocuments()
  //计算总页数
  const pages=Math.ceil(total/pageSize)

1、index.html

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>学生管理系统</title>
</head>
<body>
  <div>
    <h2>新增班级</h2>
    <div>
      <div>
          <label>班级名称</label>
          <input type="text" id="addClassName"/>
      </div>
      <div>
        <label>选择教师</label>
        <div id="selectTeacher">
          <!--动态渲染教师列表-->
        </div>
      </div>
      <button id="addClassBtn">确认新增</button>
    </div>
    <div><hr/></div>
  </div>

  <div>
    <h2>新增教师</h2>
    <div>
      <div>
        <label>教师名称</label>
        <input type="text" id="addTeacherName"/>
      </div>
      <button id="addTeacherBtn">确认新增</button>
    </div>
    <div><hr/></div>
  </div>

  <h2>新增学生</h2>
  <div>
    <div><label>学生姓名:</label><input type="text" id="addStudentsName"/> </div>
    <div><label>学生年龄:</label><input type="text" id="addStudentsAge"/> </div>
    <div>
      <label>学生性别:</label>
        <input type="radio" name="addStudentsGender" value="男"><label></label>
        <input type="radio" name="addStudentsGender" value="女"><label></label>
    </div>
    <div>
      <label>所属班级</label>
      <select id="selectClasses">

      </select>
    </div>
    <div>
      <button id="addStudent">确认新增</button>
    </div>
  </div>

  <h2>修改学生</h2>
  <div>
    <input type="hidden" id="updateStudentsId">
    <div><label>学生姓名:</label><input type="text" id="updateStudentsName"/> </div>
    <div><label>学生年龄:</label><input type="text" id="updateStudentsAge"/> </div>
    <div>
      <label>学生性别:</label>
      <input type="radio" name="updateStudentsGender" value="男"><label></label>
      <input type="radio" name="updateStudentsGender" value="女"><label></label>
    </div>
    <div>
      <button id="updateStudent">确认修改</button>
    </div>
  </div>

  <h2>查询学生</h2>
  <div>
    <select id="searchType">
      <option value="name">姓名</option>
      <option value="age">年龄</option>
      <option value="gender">性别</option>
    </select>
    <input type="text" id="searchValue">
    <button id="searchBtn">查询学生</button>
  </div>
  <h2>学生列表</h2>
  <table>
    <thead>
      <tr>
        <th>学生姓名</th>
        <th>学生年龄</th>
        <th>学生性别</th>
        <th>所属班级</th>
        <th>负责教师</th>
        <th>学生操作</th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td>张三</td>
        <td>20</td>
        <td></td>
        <td>
          <button>修改 | 删除</button>
        </td>
      </tr>
    </tbody>
  </table>
  <div>
    <label>每页条数</label>
    <select id="pageSize">
      <option value="2">2</option>
      <option value="3">3</option>
      <option value="5">5</option>
    </select>
  </div>

  <div>
    <button>首页</button>
    <button id="nextPage">下一页</button>
    <button id="lastPage">上一页</button>
    <button>尾页</button>
  </div>
<script src="./javascripts/jquery.min.js"></script>
<script>
  //给一个全局变量来做查询
  let data={
    currentPage: 1,
    pageSize: 5
  }
  //页面刷新就开始做这两个方法
  getStudents()//获取全部学生
  getClasses()//获取全部班级
  getTeachers()//获取全部老师
  //获取全部学生
  function getStudents(){
    $.ajax({
      url:'/students/getStudents',
      data: {
        currentPage: data.currentPage,
        pageSize:data.pageSize,
        searchValue: data.searchValue,
        searchType: data.searchType

      },
      type:'GET',
      success(msg){
        //进入if表示进入学生数据成功
        if(msg.status){
          data={
            ...data,
            ...msg.data

          }
          const str=msg.data.students.map(function (item,index) {
            return `
            <tr>
              <td>${item.name}</td>
              <td>${item.age}</td>
              <td>${item.gender}</td>
              <td>${item.classId.name}</td>
              <td>
                ${
                  item.classId.teachersId.map(item=>`<p>${item.name}</p>`).join('')
                }
              </td>
              <td>
                <button class="updateBtn" data-id="${item._id}">修改</button>
                <button class="removeBtn" data-id="${item._id}">删除</button>
              </td>
            </tr>
            `
          }).join('')//join是拼接
          $('tbody').html(str)
        }
      }
    })
  }

  //获取班级
  function getClasses(){
    $.ajax({
      url:'/classes/getClasses',
      type:'GET',
      data:{},
      success(msg){
        if (msg.status){
          const str=msg.data.map(function(item,index){
            return `<option value="${item._id}">${item.name}</option>`
          }).join('')//遍历出来data的name后,和option一起拼接成一个大字符串
          $('#selectClasses').html(str)
        }
      }
    })
  }

  //获取全部教师
  function getTeachers(){
    $.ajax({
      url:'/teachers/getTeachers',
      type:'GET',
      success(msg){
        if (msg.status){
          const str=msg.data.map(item=>{
            return`
            <input type="checkbox" value="${item._id}"/>
            <label>${item.name}</label>
            `
          }).join('')
          $('#selectTeacher').html(str)
        }
      }
    })
  }

  //新增班级
  $('#addClassBtn').click(function(){
    //获取选中教师的id数组,使用扩展运算符转换为真数组
    const teachersId=[...$('#selectTeacher>input[type=checkbox]:checked')].map(function(item,index){
      //return item.value//原生js方法
      return $(item).val()//jquery方法
    })
    //console.log(teachersId)
    $.ajax({
      url:'/classes/addClasses',
      type:'POST',
      data:{
        name:$('#addClassName').val(),
        teachersId
      },
      //当ajax的data传递数组的时候必须要添加选项解决数组格式问题
      traditional:true,
      success(msg){
        if (msg.status){
          getClasses()
        }
      }
    })
  })

  //查询下一页
  $('#nextPage').click(function(){
    if ( data.currentPage<data.pages){
      //console.log('查看一下全局的data',data)
      data.currentPage++
      getStudents()
    }

  })
  //查询上一页
  $('#lastPage').click(function(){
    if (data.currentPage>1){
      data.currentPage--
      getStudents()
    }


  })

  //删除按钮使用事件委托
  //on做委托,委托给父级的静态元素,第一个参数是事件,第二个参数是真正执行的那个标签(委托人),第三个参数是具体的工作
  $('tbody').on('click','.removeBtn',function(){
    //获取当前点击的这个按钮对应的id,data('id')是获取所有(特定)属性的函数,这里的id实际就是data-id,前面加data-是一种约定俗成
    const _id=$(this).data('id')
    console.log(_id)
    $.ajax({
      url:'/students/deleteStudents',
      type:'post',
      data: { _id },
      success (msg) {
        if (msg.status){
          alert('删除成功')
          //重新发一次ajax请求
          getStudents()

        }
      }
    })

  })

  //修改学生信息
  //获取要修改的一个学生信息
  $('tbody').on('click','.updateBtn',function(){
    const _id=$(this).data('id')
    //console.log(_id)
    $.ajax({
      url:'/students/getStudentsById',
      data:{_id},
      success(msg){
        if (msg.status){
          $('#updateStudentsId').val(msg.data._id)
          $('#updateStudentsName').val(msg.data.name)//设置控件的value值
          $('#updateStudentsAge').val(msg.data.age)//设置控件的value值
          $(`[name=updateStudentsGender][value=${msg.data.gender}]`).prop('checked',true)
        }
      }

    })
  })

  //确认修改学生信息
  $('#updateStudent').click(function(){
    const _id=$('#updateStudentsId').val()
    const name=$('#updateStudentsName').val()
    const age=$('#updateStudentsAge').val()
    const gender=$(`[name=updateStudentsGender]:checked`).val()
    //console.log(name,age,gender)
    $.ajax({
      url:'/students/updateStudents',
      type:'POST',
      data:{
        name,age,gender,_id
      },
      success(msg){
        if(msg.status){
          getStudents()
        }
      }
    })
  })

  //查询
  $('#searchBtn').click(function(){
    //获取下拉列表中选中的option的value值,可以直接获取selected的值
    const searchType=$('#searchType').val()
    //console.log(searchType)

    //获取搜索的值
    const searchValue=$('#searchValue').val()
    data={
      ...data,//保留原有的data数据
      searchType,
      searchValue
    }
    //console.log(data)
    getStudents()
  })
  //新增学生
  $('#addStudent').click(function(){
    const name=$('#addStudentsName').val()
    const age=$('#addStudentsAge').val()
    const gender=$('[name=addStudentsGender]:checked').val()
    const classId=$('#selectClasses').val()
    //console.log(name,age,gender)
    $.ajax({
      url:'/students/addStudents',
      type:'POST',
      data:{
        name,
        age,
        gender,
        classId
      },
      success(msg){
        if (msg.status){
          getStudents()
        }
      }
    })
  })
</script>
</body>
</html>

2、studentsDao.js

//向第二层服务层暴露getStudents方法,
//在第三层dao层操作数据库
//引入第三层dao层的model模型,用以操作数据库
const { studentsModel }=require('./models/studentsModel')
//暴露一个获取所有学生方法
module.exports.getStudents=async function ({pageSize,currentPage }) {
  //获取查询的总条数
  const total=await studentsModel.countDocuments()
  //计算总页数
  const pages=Math.ceil(total/pageSize)
  //console.log('数据总条数',total)
  //console.log('第三层的数据',pageSize,currentPage)
  //find 是异步操作,在model里查找user记录(文档)。返回一个数组
  //populate是做关联查询
  const students=await studentsModel.find()
    .populate({
      path:'classId',
      populate:{
        path:'teachersId'
      }
  }).limit(pageSize-0)//设置请求的数据条数
    .skip((currentPage-1)*pageSize)//跳过数据的条数


  //console.log('第三层的data',data)
  //第三层直接返回数据给第二层,不需要做任何操作,dao层-->服务层-->表现层
  return {
    total,
    pages,
    students
  }
  //做模糊查询
  // return await studentsModel.find({
  //   //$options:'$i'因为不区分大小写
  //   [params.searchType]:{$regex:params.searchValue,$options:'$i'}
  // })
}
//暴露一个获取部分学生方法
module.exports.searchStudents=async function (params) {
  //做模糊查询
  return await studentsModel.find({
    //$options:'$i'因为不区分大小写
  //   [params.searchType]:{$regex:params.searchValue,$options:'$i'}
  // }).populate('classId')
    [params.searchType]:{$regex:params.searchValue,$options:'$i'}
    }).populate( 'classId' )
}

//暴露一个新增方法
module.exports.addStudents=async function (student) {

  const data=await studentsModel.create(student)
  return data
}


//暴露一个删除方法
module.exports.deleteStudents=async function ({ _id }) {//这里把对象中的id解构出来了

  //const data=await studentsModel.deleteOne(_id)//这里id实际是一个对象
  const data=await studentsModel.findByIdAndDelete(_id)

  return data
}



//暴露一个获取学生方法
module.exports.getStudentsById=async function ({ _id }) {//这里把对象中的id解构出来了

  //const data=await studentsModel.deleteOne(_id)//这里id实际是一个对象
  const data=await studentsModel.findById(_id)//返回的事一个对象

  return data
}


//确认修改一个学生方法
module.exports.updateStudents=async function ({_id,name,age,gender }) {//这里把对象中的id解构出来了
  //console.log(student)
  //const data=await studentsModel.deleteOne(_id)//这里id实际是一个对象
  //return await studentsModel.updateOne({_id:student._id},student)//返回的事一个对象
  return await studentsModel.findByIdAndUpdate(_id, { name,age,gender})//返回的事一个对象
}

6、分页其他操作

修改index.html

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>学生管理系统</title>
</head>
<body>
  <div>
    <h2>新增班级</h2>
    <div>
      <div>
          <label>班级名称</label>
          <input type="text" id="addClassName"/>
      </div>
      <div>
        <label>选择教师</label>
        <div id="selectTeacher">
          <!--动态渲染教师列表-->
        </div>
      </div>
      <button id="addClassBtn">确认新增</button>
    </div>
    <div><hr/></div>
  </div>

  <div>
    <h2>新增教师</h2>
    <div>
      <div>
        <label>教师名称</label>
        <input type="text" id="addTeacherName"/>
      </div>
      <button id="addTeacherBtn">确认新增</button>
    </div>
    <div><hr/></div>
  </div>

  <h2>新增学生</h2>
  <div>
    <div><label>学生姓名:</label><input type="text" id="addStudentsName"/> </div>
    <div><label>学生年龄:</label><input type="text" id="addStudentsAge"/> </div>
    <div>
      <label>学生性别:</label>
        <input type="radio" name="addStudentsGender" value="男"><label></label>
        <input type="radio" name="addStudentsGender" value="女"><label></label>
    </div>
    <div>
      <label>所属班级</label>
      <select id="selectClasses">

      </select>
    </div>
    <div>
      <button id="addStudent">确认新增</button>
    </div>
  </div>

  <h2>修改学生</h2>
  <div>
    <input type="hidden" id="updateStudentsId">
    <div><label>学生姓名:</label><input type="text" id="updateStudentsName"/> </div>
    <div><label>学生年龄:</label><input type="text" id="updateStudentsAge"/> </div>
    <div>
      <label>学生性别:</label>
      <input type="radio" name="updateStudentsGender" value="男"><label></label>
      <input type="radio" name="updateStudentsGender" value="女"><label></label>
    </div>
    <div>
      <button id="updateStudent">确认修改</button>
    </div>
  </div>

  <h2>查询学生</h2>
  <div>
    <select id="searchType">
      <option value="name">姓名</option>
      <option value="age">年龄</option>
      <option value="gender">性别</option>
    </select>
    <input type="text" id="searchValue">
    <button id="searchBtn">查询学生</button>
  </div>
  <h2>学生列表</h2>
  <table>
    <thead>
      <tr>
        <th>学生姓名</th>
        <th>学生年龄</th>
        <th>学生性别</th>
        <th>所属班级</th>
        <th>负责教师</th>
        <th>学生操作</th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td>张三</td>
        <td>20</td>
        <td></td>
        <td>
          <button>修改 | 删除</button>
        </td>
      </tr>
    </tbody>
  </table>
  <div>
    <label>每页条数</label>
    <select id="pageSize">
      <option value="2">2</option>
      <option value="3">3</option>
      <option value="5">5</option>
    </select>
    <span><b id="currentPage">1</b>/<b id="pages">4</b></span><span>共计<b id="total"></b>条数据</span>
  </div>

  <div>
    <button id="firstPage">首页</button>
    <button id="nextPage">下一页</button>
    <button id="lastPage">上一页</button>
    <button id="finalPage">尾页</button>
  </div>
<script src="./javascripts/jquery.min.js"></script>
<script>
  //给一个全局变量来做查询,用来存放分页相关数据
  let data={
    currentPage: 1,
    pageSize: 5
  }
  //页面刷新就开始做这两个方法
  getStudents()//获取全部学生
  getClasses()//获取全部班级
  getTeachers()//获取全部老师
  //获取全部学生
  function getStudents(){
    $.ajax({
      url:'/students/getStudents',
      data: {
        currentPage: data.currentPage,
        pageSize:data.pageSize,
        searchValue: data.searchValue,
        searchType: data.searchType

      },
      type:'GET',
      success(msg){
        //进入if表示进入学生数据成功
        if(msg.status){
          data={
            ...data,
            ...msg.data

          }
          //渲染数据
          const str=msg.data.students.map(function (item,index) {
            return `
            <tr>
              <td>${item.name}</td>
              <td>${item.age}</td>
              <td>${item.gender}</td>
              <td>${item.classId.name}</td>
              <td>
                ${
                  item.classId.teachersId.map(item=>`<p>${item.name}</p>`).join('')
                }
              </td>
              <td>
                <button class="updateBtn" data-id="${item._id}">修改</button>
                <button class="removeBtn" data-id="${item._id}">删除</button>
              </td>
            </tr>
            `
          }).join('')//join是拼接
          $('tbody').html(str)

          //渲染下分页指示
          $('#currentPage').text(data.currentPage)
          $('#pages').text(data.pages)
          $('#total').text(data.total)
        }
      }
    })
  }

  //获取班级
  function getClasses(){
    $.ajax({
      url:'/classes/getClasses',
      type:'GET',
      data:{},
      success(msg){
        if (msg.status){
          const str=msg.data.map(function(item,index){
            return `<option value="${item._id}">${item.name}</option>`
          }).join('')//遍历出来data的name后,和option一起拼接成一个大字符串
          $('#selectClasses').html(str)
        }
      }
    })
  }

  //获取全部教师
  function getTeachers(){
    $.ajax({
      url:'/teachers/getTeachers',
      type:'GET',
      success(msg){
        if (msg.status){
          const str=msg.data.map(item=>{
            return`
            <input type="checkbox" value="${item._id}"/>
            <label>${item.name}</label>
            `
          }).join('')
          $('#selectTeacher').html(str)
        }
      }
    })
  }

  //新增班级
  $('#addClassBtn').click(function(){
    //获取选中教师的id数组,使用扩展运算符转换为真数组
    const teachersId=[...$('#selectTeacher>input[type=checkbox]:checked')].map(function(item,index){
      //return item.value//原生js方法
      return $(item).val()//jquery方法
    })
    //console.log(teachersId)
    $.ajax({
      url:'/classes/addClasses',
      type:'POST',
      data:{
        name:$('#addClassName').val(),
        teachersId
      },
      //当ajax的data传递数组的时候必须要添加选项解决数组格式问题
      traditional:true,
      success(msg){
        if (msg.status){
          getClasses()
        }
      }
    })
  })

  //查询下一页
  $('#nextPage').click(function(){
    if ( data.currentPage<data.pages){
      //console.log('查看一下全局的data',data)
      data.currentPage++
      getStudents()
    }

  })
  //查询上一页
  $('#lastPage').click(function(){
    if (data.currentPage>1){
      data.currentPage--
      getStudents()
    }

  })

  //查询首页
  $('#firstPage').click(function(){
    data.currentPage=1
    getStudents()

  })
  //查询尾页
  $('#finalPage').click(function(){
    data.currentPage=data.pages
    getStudents()
  })

  //删除按钮使用事件委托
  //on做委托,委托给父级的静态元素,第一个参数是事件,第二个参数是真正执行的那个标签(委托人),第三个参数是具体的工作
  $('tbody').on('click','.removeBtn',function(){
    //获取当前点击的这个按钮对应的id,data('id')是获取所有(特定)属性的函数,这里的id实际就是data-id,前面加data-是一种约定俗成
    const _id=$(this).data('id')
    console.log(_id)
    $.ajax({
      url:'/students/deleteStudents',
      type:'post',
      data: { _id },
      success (msg) {
        if (msg.status){
          alert('删除成功')
          data.currentPage=1
          //重新发一次ajax请求
          getStudents()

        }
      }
    })

  })

  //修改学生信息
  //获取要修改的一个学生信息
  $('tbody').on('click','.updateBtn',function(){
    const _id=$(this).data('id')
    //console.log(_id)
    $.ajax({
      url:'/students/getStudentsById',
      data:{_id},
      success(msg){
        if (msg.status){
          $('#updateStudentsId').val(msg.data._id)
          $('#updateStudentsName').val(msg.data.name)//设置控件的value值
          $('#updateStudentsAge').val(msg.data.age)//设置控件的value值
          $(`[name=updateStudentsGender][value=${msg.data.gender}]`).prop('checked',true)
        }
      }

    })
  })

  //确认修改学生信息
  $('#updateStudent').click(function(){
    const _id=$('#updateStudentsId').val()
    const name=$('#updateStudentsName').val()
    const age=$('#updateStudentsAge').val()
    const gender=$(`[name=updateStudentsGender]:checked`).val()
    //console.log(name,age,gender)
    $.ajax({
      url:'/students/updateStudents',
      type:'POST',
      data:{
        name,age,gender,_id
      },
      success(msg){
        if(msg.status){
          getStudents()
        }
      }
    })
  })

  //查询
  $('#searchBtn').click(function(){
    //获取下拉列表中选中的option的value值,可以直接获取selected的值
    const searchType=$('#searchType').val()
    //console.log(searchType)

    //获取搜索的值
    const searchValue=$('#searchValue').val()
    data={
      ...data,//保留原有的data数据
      searchType,
      searchValue
    }
    //console.log(data)
    getStudents()
  })
  //新增学生
  $('#addStudent').click(function(){
    const name=$('#addStudentsName').val()
    const age=$('#addStudentsAge').val()
    const gender=$('[name=addStudentsGender]:checked').val()
    const classId=$('#selectClasses').val()
    //console.log(name,age,gender)
    $.ajax({
      url:'/students/addStudents',
      type:'POST',
      data:{
        name,
        age,
        gender,
        classId
      },
      success(msg){
        if (msg.status){
          getStudents()
        }
      }
    })
  })
</script>
</body>
</html>

7、分页后的搜索功能优化

调整太多……主要是分页上的几个按钮及对应是事件处理函数
1、index.html

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <link rel="stylesheet" href="stylesheets/index.css">
  <title>学生管理系统</title>
</head>
<body>
  <div>
    <h2>新增班级</h2>
    <div>
      <div>
          <label>班级名称</label>
          <input type="text" id="addClassName"/>
      </div>
      <div>
        <label>选择教师</label>
        <div id="selectTeacher">
          <!--动态渲染教师列表-->
        </div>
      </div>
      <button id="addClassBtn">确认新增</button>
    </div>
    <div><hr/></div>
  </div>

  <div>
    <h2>新增教师</h2>
    <div>
      <div>
        <label>教师名称</label>
        <input type="text" id="addTeacherName"/>
      </div>
      <button id="addTeacherBtn">确认新增</button>
    </div>
    <div><hr/></div>
  </div>

  <h2>新增学生</h2>
  <div>
    <div><label>学生姓名:</label><input type="text" id="addStudentsName"/> </div>
    <div><label>学生年龄:</label><input type="text" id="addStudentsAge"/> </div>
    <div>
      <label>学生性别:</label>
        <input type="radio" name="addStudentsGender" value="男"><label></label>
        <input type="radio" name="addStudentsGender" value="女"><label></label>
    </div>
    <div>
      <label>所属班级</label>
      <select id="selectClasses">

      </select>
    </div>
    <div>
      <label>上传头像</label>
      <input type="file">
    </div>
    <div class="imag-box">
      <!-- 显示图片预览 -->
      <img src="" alt=""/>
    </div>
    <div>
      <button id="addStudent">确认新增</button>
    </div>
  </div>

  <h2>修改学生</h2>
  <div>
    <input type="hidden" id="updateStudentsId">
    <div><label>学生姓名:</label><input type="text" id="updateStudentsName"/> </div>
    <div><label>学生年龄:</label><input type="text" id="updateStudentsAge"/> </div>
    <div>
      <label>学生性别:</label>
      <input type="radio" name="updateStudentsGender" value="男"><label></label>
      <input type="radio" name="updateStudentsGender" value="女"><label></label>
    </div>
    <div>
      <button id="updateStudent">确认修改</button>
    </div>
  </div>

  <h2>查询学生</h2>
  <div>
    <select id="searchType">
      <option value="name">姓名</option>
      <option value="age">年龄</option>
      <option value="gender">性别</option>
    </select>
    <input type="text" id="searchValue">
    <button id="searchBtn">查询学生</button>
  </div>
  <h2>学生列表</h2>
  <table>
    <thead>
      <tr>
        <th>学生姓名</th>
        <th>学生年龄</th>
        <th>学生性别</th>
        <th>所属班级</th>
        <th>负责教师</th>
        <th>学生操作</th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td>张三</td>
        <td>20</td>
        <td></td>
        <td>
          <button>修改 | 删除</button>
        </td>
      </tr>
    </tbody>
  </table>
  <div>
    <label>每页条数</label>
    <select id="pageSize">
      <option value="2">2</option>
      <option value="3">3</option>
      <option value="5">5</option>
    </select>
    <span><b id="currentPage">1</b>/<b id="pages">4</b></span><span>共计<b id="total"></b>条数据</span>
  </div>

  <div>
    <button id="firstPage">首页</button>
    <button id="nextPage">下一页</button>
    <button id="lastPage">上一页</button>
    <button id="finalPage">尾页</button>
  </div>
<script src="./javascripts/jquery.min.js"></script>
<script>
  //给一个全局变量来做查询,用来存放分页相关数据
  let data={
    currentPage: 1,
    pageSize: 5
  }
  //页面刷新就开始做这两个方法
  getStudents()//获取全部学生
  getClasses()//获取全部班级
  getTeachers()//获取全部老师
  //获取全部学生
  function getStudents(){
    $.ajax({
      url:'/students/getStudents',
      data: {
        currentPage: data.currentPage,
        pageSize:data.pageSize,
        searchValue: data.searchValue,
        searchType: data.searchType

      },
      type:'GET',
      success(msg){
        //进入if表示进入学生数据成功
        if(msg.status){
          data={
            ...data,
            ...msg.data

          }
          console.log(msg.data)
          //渲染数据
          const str=msg.data.students.map(function (item,index) {
            return `
            <tr>
              <td>${item.name}</td>
              <td>${item.age}</td>
              <td>${item.gender}</td>
              <td>${item.classId.name}</td>
              <td>
                ${
                  item.classId.teachersId.map(item=>`<p>${item.name}</p>`).join('')
                }
              </td>
              <td>
                <button class="updateBtn" data-id="${item._id}">修改</button>
                <button class="removeBtn" data-id="${item._id}">删除</button>
              </td>
            </tr>
            `
          }).join('')//join是拼接
          $('tbody').html(str)

          //渲染下分页指示
          $('#currentPage').text(data.currentPage)
          $('#pages').text(data.pages)
          $('#total').text(data.total)
        }
      }
    })
  }

  //获取班级
  function getClasses(){
    $.ajax({
      url:'/classes/getClasses',
      type:'GET',
      data:{},
      success(msg){
        if (msg.status){
          const str=msg.data.map(function(item,index){
            return `<option value="${item._id}">${item.name}</option>`
          }).join('')//遍历出来data的name后,和option一起拼接成一个大字符串
          $('#selectClasses').html(str)
        }
      }
    })
  }

  //获取全部教师
  function getTeachers(){
    $.ajax({
      url:'/teachers/getTeachers',
      type:'GET',
      success(msg){
        if (msg.status){
          const str=msg.data.map(item=>{
            return`
            <input type="checkbox" value="${item._id}"/>
            <label>${item.name}</label>
            `
          }).join('')
          $('#selectTeacher').html(str)
        }
      }
    })
  }

  //新增班级
  $('#addClassBtn').click(function(){
    //获取选中教师的id数组,使用扩展运算符转换为真数组
    const teachersId=[...$('#selectTeacher>input[type=checkbox]:checked')].map(function(item,index){
      //return item.value//原生js方法
      return $(item).val()//jquery方法
    })
    //console.log(teachersId)
    $.ajax({
      url:'/classes/addClasses',
      type:'POST',
      data:{
        name:$('#addClassName').val(),
        teachersId
      },
      //当ajax的data传递数组的时候必须要添加选项解决数组格式问题
      traditional:true,
      success(msg){
        if (msg.status){
          getClasses()
        }
      }
    })
  })

  //查询下一页
  $('#nextPage').click(function(){
    if ( data.currentPage<data.pages){
      //console.log('查看一下全局的data',data)
      data.currentPage++
      getStudents()
    }

  })
  //查询上一页
  $('#lastPage').click(function(){
    if (data.currentPage>1){
      data.currentPage--
      getStudents()
    }

  })

  //查询首页
  $('#firstPage').click(function(){
    data.currentPage=1
    getStudents()

  })
  //查询尾页
  $('#finalPage').click(function(){
    data.currentPage=data.pages
    getStudents()
  })

  //设置每页条数
  $('#pageSize').change(function(){
    data.pageSize=$('#pageSize').val()
    data.currentPage=1
    getStudents()
  })

  //删除按钮使用事件委托
  //on做委托,委托给父级的静态元素,第一个参数是事件,第二个参数是真正执行的那个标签(委托人),第三个参数是具体的工作
  $('tbody').on('click','.removeBtn',function(){
    //获取当前点击的这个按钮对应的id,data('id')是获取所有(特定)属性的函数,这里的id实际就是data-id,前面加data-是一种约定俗成
    const _id=$(this).data('id')
    console.log(_id)
    $.ajax({
      url:'/students/deleteStudents',
      type:'post',
      data: { _id },
      success (msg) {
        if (msg.status){
          alert('删除成功')
          data.currentPage=1
          //重新发一次ajax请求
          getStudents()

        }
      }
    })

  })

  //修改学生信息
  //获取要修改的一个学生信息
  $('tbody').on('click','.updateBtn',function(){
    const _id=$(this).data('id')
    //console.log(_id)
    $.ajax({
      url:'/students/getStudentsById',
      data:{_id},
      success(msg){
        if (msg.status){
          $('#updateStudentsId').val(msg.data._id)
          $('#updateStudentsName').val(msg.data.name)//设置控件的value值
          $('#updateStudentsAge').val(msg.data.age)//设置控件的value值
          $(`[name=updateStudentsGender][value=${msg.data.gender}]`).prop('checked',true)
        }
      }

    })
  })

  //确认修改学生信息
  $('#updateStudent').click(function(){
    const _id=$('#updateStudentsId').val()
    const name=$('#updateStudentsName').val()
    const age=$('#updateStudentsAge').val()
    const gender=$(`[name=updateStudentsGender]:checked`).val()
    //console.log(name,age,gender)
    $.ajax({
      url:'/students/updateStudents',
      type:'POST',
      data:{
        name,age,gender,_id
      },
      success(msg){
        if(msg.status){
          getStudents()
        }
      }
    })
  })

  //查询
  $('#searchBtn').click(function(){
    //获取下拉列表中选中的option的value值,可以直接获取selected的值
    const searchType=$('#searchType').val()
    //console.log(searchType)

    //获取搜索的值
    const searchValue=$('#searchValue').val()
    data={
      ...data,//保留原有的data数据
      currentPage: 1,
      searchType,
      searchValue
    }
    //console.log(data)
    getStudents()
  })
  //新增学生
  $('#addStudent').click(function(){
    const name=$('#addStudentsName').val()
    const age=$('#addStudentsAge').val()
    const gender=$('[name=addStudentsGender]:checked').val()
    const classId=$('#selectClasses').val()
    //console.log(name,age,gender)
    $.ajax({
      url:'/students/addStudents',
      type:'POST',
      data:{
        name,
        age,
        gender,
        classId
      },
      success(msg){
        if (msg.status){
          getStudents()
        }
      }
    })
  })
</script>
</body>
</html>

2、studentsDao.js
主要是接个页数,条数,查询到的条数和页数的计算

//向第二层服务层暴露getStudents方法,
//在第三层dao层操作数据库
//引入第三层dao层的model模型,用以操作数据库
const { studentsModel }=require('./models/studentsModel')
//暴露一个获取所有学生方法
module.exports.getStudents=async function ({pageSize,currentPage }) {
  //获取查询的总条数
  const total=await studentsModel.countDocuments()
  //计算总页数
  const pages=Math.ceil(total/pageSize)
  //console.log('数据总条数',total)
  //console.log('第三层的数据',pageSize,currentPage)
  //find 是异步操作,在model里查找user记录(文档)。返回一个数组
  //populate是做关联查询
  const students=await studentsModel.find()
    .populate({
      path:'classId',
      populate:{
        path:'teachersId'
      }
  }).limit(pageSize-0)//设置请求的数据条数
    .skip((currentPage-1)*pageSize)//跳过数据的条数


  //console.log('第三层的data',data)
  //第三层直接返回数据给第二层,不需要做任何操作,dao层-->服务层-->表现层
  return {
    total,
    pages,
    students
  }
  //做模糊查询
  // return await studentsModel.find({
  //   //$options:'$i'因为不区分大小写
  //   [params.searchType]:{$regex:params.searchValue,$options:'$i'}
  // })
}
//暴露一个获取部分学生方法
module.exports.searchStudents=async function (params) {
  //获取查询到的数据总条数
  const total=await studentsModel.find({
    [params.searchType]:{$regex:params.searchValue,$options:'$i'}
  }).countDocuments(true)
  console.log('查询出来的总条数',total)

  //获取查询到的总页数
  const pages=Math.ceil(total/params.pageSize)

  //做模糊查询
  const students= await studentsModel.find({
    //$options:'$i'因为不区分大小写
  //   [params.searchType]:{$regex:params.searchValue,$options:'$i'}
  // }).populate('classId')
    [params.searchType]:{$regex:params.searchValue,$options:'$i'}
    }).populate({
      path:'classId',
      populate:{
        path:'teachersId'
      }
    }).limit(params.pageSize-0)
    .skip((params.currentPage-1)*params.pageSize)

  return {
    students,
    pages,
    total
  }
}

//暴露一个新增方法
module.exports.addStudents=async function (student) {

  const data=await studentsModel.create(student)
  return data
}


//暴露一个删除方法
module.exports.deleteStudents=async function ({ _id }) {//这里把对象中的id解构出来了

  //const data=await studentsModel.deleteOne(_id)//这里id实际是一个对象
  const data=await studentsModel.findByIdAndDelete(_id)

  return data
}



//暴露一个获取学生方法
module.exports.getStudentsById=async function ({ _id }) {//这里把对象中的id解构出来了

  //const data=await studentsModel.deleteOne(_id)//这里id实际是一个对象
  const data=await studentsModel.findById(_id)//返回的事一个对象

  return data
}


//确认修改一个学生方法
module.exports.updateStudents=async function ({_id,name,age,gender }) {//这里把对象中的id解构出来了
  //console.log(student)
  //const data=await studentsModel.deleteOne(_id)//这里id实际是一个对象
  //return await studentsModel.updateOne({_id:student._id},student)//返回的事一个对象
  return await studentsModel.findByIdAndUpdate(_id, { name,age,gender})//返回的事一个对象


}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值