Students-system开发步骤

发布时间 2023-06-30 11:00:43作者: 堃K

项目初始化

新建文件夹,命名为students-system,注意这里的命名不得为中文或其他特殊字符

npm init -y

安装包

npm i jquery express express-art-template

新建文件夹

新建public,views文件夹,public下新建img,js,css文件夹,目录如下:

student-system
node_modules
public
img
css
js
views
package.json
...

新建服务

在students-system文件夹下新建server.js

const express=require('express')

const app = express()

//配置express-art-template,才可以render html
app.engine('html',require('express-art-template'))

app.get('/',(req,res) =>{
   res.render('login.html')
})

app.listen(3000,() => console.log('app listening on http://localhost:3000 '))

当用户get / 时,就会渲染login.html

开通了3000端口号。

ip地址是链接到网络上的某台计算机

端口号是识别到该计算机上的某个软件

新建页面

views文件夹下,新建login.html

<!DOCTYPE html>
<html>
<head>
   <title>Login</title>
   <style>
       body {
           font-family: Arial, sans-serif;
           background-color: #f4f4f4;
      }

       .container {
           max-width: 400px;
           margin: 0 auto;
           padding: 20px;
           background-color: #ffffff;
           box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
      }

       h1 {
           text-align: center;
           margin-bottom: 20px;
      }

       .form-group {
           margin-bottom: 20px;
      }

       label {
           display: block;
           font-weight: bold;
           margin-bottom: 5px;
      }

       input[type="email"],
       input[type="password"] {
           width: 100%;
           padding: 10px;
           border: 1px solid #ccc;
           border-radius: 4px;
      }

       button {
           display: block;
           width: 100%;
           padding: 10px;
           background-color: #4caf50;
           color: #ffffff;
           border: none;
           border-radius: 4px;
           cursor: pointer;
      }

       button:hover {
           background-color: #45a049;
      }

       .text-center {
           text-align: center;
      }
   </style>
</head>
<body>
<div class="container">
   <h1>Login</h1>
   <form>
       <div class="form-group">
           <label for="email">Email:</label>
           <input type="email" id="email" name="email" required>
       </div>
       <div class="form-group">
           <label for="password">Password:</label>
           <input type="password" id="password" name="password" required>
       </div>
       <div class="text-center">
           <button type="submit">Login</button>
       </div>
   </form>
</div>
</body>
</html>

此时,用户在浏览器进入 Login即可打开我们的登录界面。

登录功能开发

传统的表单登录

表单登录,需要在form表单里,指定action和method,action是路径,method是方法,方法一般分为get和post

get用于保密级别低,长度短的信息(get会把请求写道url里面,受到url长度影响,信息的长度不能无限长)

post用于保密级别高(比如密码等),长度长的信息

表单登录,一定伴随着整个页面的重新跳转或刷新

在login.html,为表单指定路径和方法

 <form action='/login' method='post'>
  ·······
</form>

在后端server.js 里配置相应请求信息

app.post('/login',(req,res) =>{
   console.log(req.body)
   if (req.body.email==='admin@qq.com'&&req.body.password==='admin'){
       res.render('main.html')
  }else{
       res.render('error.html')
  }
})

如果想要在后端使用req.body来获取post来的信息,比如在后端配置body-parser,现在新版本的express已经内置了body-parser,不需要额外安装,直接配置即可

//配置body-parser
app.use(express.urlencoded({ extended:false}))
app.use(express.json())

如此,当用户输入正确账号和密码时,就可以跳转到main.html,如果错误账号或密码,则会跳转到error.html

error.html里可以配置错误信息,并且几秒后跳转回登录界面

ajax局部刷新登录

由于表单登录,伴随着整个页面的刷新,带来白屏问题,等待,跳转等问题,非常不方便,而且提示信息是在错误页面上需要跳转来,跳转去

 <form>
  ·······
</form>

form表单里的action和method此时已经无用,删除掉

引入jQuery

<script src="../node_modules/jquery/dist/jquery.js"></script>

打开localhost:3000发现,jQuery并没有被加载上,因为此时jQuery存在于服务器中的node_modules文件夹中,后端服务器的文件不允许前端随意查看,我们需要开放静态文件权限给前端,public和node_modulse两个文件夹

/开放node_modules,public两个文件夹的权限,允许用户查看
app.use('/public', express.static('public'))
app.use('/bbb', express.static('node_modules'))
//前面的/aaa,/bbb是随便起名,可以对后端文件夹配置有一定的隐藏,防止被黑

此时,前端对于jQuery的引入,也可以改成下面形式,以隐藏真实后端文件夹目录

<script src="/bbb/jquery/dist/jquery.js"></script>

配置前端jQuery ajax,向后端发起请求,如果账号密码正确,则跳转到新页面main.html,如果账号密码错误,则跳出提示

<script>
  $('form').on('submit', function(event){
      event.preventDefault()//取消默认submit提交事件
      $.ajax({
          url:'/login',
          method: 'POST',
          data:{//向后端提交的数据
              email: $('#email').val(),
              password: $('#password').val()
          },
          success: function(data){//提交成功,要执行的函数,data就是后端回来的信息
              console.log(data)
              if (data.success){
                  window.location.href='/main.html'
              }else{
                   alert('账号或密码错误')
              }
          },
          error: function(){//如果受到网络原因或其他不确定因素的影响,导致请求失败执行的函数
              console.log('Something went wrong')
          }
      })
  })

</script>

后端对于post /login的请求修改如下:

app.post('/login',(req,res) =>{
   console.log(req.body)
   if (req.body.email==='admin@qq.com'&&req.body.password==='admin'){
       // res.render('main.html')
       res.send({success:true})
  }else{
       res.send({success:false})
  }
})

image-20230615160632362

新建页面

views文件夹下,新建main.html


<!doctype html>
<html lang="zh-CN">
<head>
   <meta charset="utf-8">
   <meta http-equiv="X-UA-Compatible" content="IE=edge">
   <meta name="viewport" content="width=device-width, initial-scale=1">
   <title>Dashboard Template for Bootstrap</title>

   <!-- Bootstrap core CSS -->
   <link href="/bbb/bootstrap/dist/css/bootstrap.min.css" rel="stylesheet">

   <!-- Custom styles for this template -->
   <link href="../public/css/dashboard.css" rel="stylesheet">
</head>

<body>

<nav class="navbar navbar-inverse navbar-fixed-top">
   <div class="container-fluid">
       <div class="navbar-header">
           <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar">
               <span class="sr-only">Toggle navigation</span>
               <span class="icon-bar"></span>
               <span class="icon-bar"></span>
               <span class="icon-bar"></span>
           </button>
           <a class="navbar-brand" href="#">Project name</a>
       </div>
       <div id="navbar" class="navbar-collapse collapse">
           <ul class="nav navbar-nav navbar-right">
               <li><a href="#">Dashboard</a></li>
               <li><a href="#">Settings</a></li>
               <li><a href="#">Profile</a></li>
               <li><a href="#">Help</a></li>
           </ul>
           <form class="navbar-form navbar-right">
               <input type="text" class="form-control" placeholder="Search...">
           </form>
       </div>
   </div>
</nav>

<div class="container-fluid">
   <div class="row">
       <div class="col-sm-3 col-md-2 sidebar">
           <ul class="nav nav-sidebar">
               <li class="active"><a href="#">查看学生信息 <span class="sr-only">(current)</span></a></li>
               <li><a href="#">添加学生</a></li>
           </ul>
           <ul class="nav nav-sidebar">
               <li><a href="">Nav item</a></li>
               <li><a href="">Nav item again</a></li>
               <li><a href="">One more nav</a></li>
               <li><a href="">Another nav item</a></li>
               <li><a href="">More navigation</a></li>
           </ul>
           <ul class="nav nav-sidebar">
               <li><a href="">Nav item again</a></li>
               <li><a href="">One more nav</a></li>
               <li><a href="">Another nav item</a></li>
           </ul>
       </div>
       <div class="col-sm-9 col-sm-offset-3 col-md-10 col-md-offset-2 main">
           <h2 class="sub-header">Section title</h2>
           <div class="table-responsive">
               <table class="table table-striped">
                   <thead>
                   <tr>
                       <th>序号</th>
                       <th>姓名</th>
                       <th>性别</th>
                       <th>年龄</th>
                       <th>学号</th>
                       <th>手机</th>
                       <th>操作</th>
                   </tr>
                   </thead>
                   <tbody>
                  {{each students}}
                   <tr>
                       <td>{{$index+1}}</td>
                       <td>{{$value.name}}</td>
                       <td>{{$value.gender}}</td>
                       <td>{{$value.age}}</td>
                       <td>{{$value.studentNumber}}</td>
                       <td>{{$value.phone}}</td>
                       <td></td>
                   </tr>
                  {{/each students}}
                   </tbody>
               </table>
           </div>
       </div>
   </div>
</div>
<!-- Bootstrap core JavaScript
================================================== -->
<!-- Placed at the end of the document so the pages load faster -->
<!--<script src="https://cdn.jsdelivr.net/npm/jquery@1.12.4/dist/jquery.min.js" -->
<!--       integrity="sha384-nvAa0+6Qg9clwYCGGPpDQLVpLNn0fRaROjHqs13t4Ggj3Ez50XnGQqc/r8MhnRDZ" crossorigin="anonymous">-->
<!--</script>-->
<script src="/bbb/jquery/dist/jquery.min.js"></script>
<script src="/bbb/bootstrap/dist/js/bootstrap.min.js"></script>
</body>
</html>

第二个页面 main.html

在views文件夹下新建main.html文件

<!doctype html>
<html lang="zh-CN">
<head>
   <meta charset="utf-8">
   <meta http-equiv="X-UA-Compatible" content="IE=edge">
   <meta name="viewport" content="width=device-width, initial-scale=1">
   <title>Dashboard Template for Bootstrap</title>

   <!-- Bootstrap core CSS -->
   <link href="/aaa/bootstrap/dist/css/bootstrap.min.css" rel="stylesheet">

   <!-- Custom styles for this template -->
   <link href="../public/css/dashboard.css" rel="stylesheet">
</head>

<body>

<nav class="navbar navbar-inverse navbar-fixed-top">
   <div class="container-fluid">
       <div class="navbar-header">
           <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar"
                   aria-expanded="false" aria-controls="navbar">
               <span class="sr-only">Toggle navigation</span>
               <span class="icon-bar"></span>
               <span class="icon-bar"></span>
               <span class="icon-bar"></span>
           </button>
           <a class="navbar-brand" href="#">Project name</a>
       </div>
       <div id="navbar" class="navbar-collapse collapse">
           <ul class="nav navbar-nav navbar-right">
               <li><a href="#">Dashboard</a></li>
               <li><a href="#">Settings</a></li>
               <li><a href="#">Profile</a></li>
               <li><a href="#">Help</a></li>
           </ul>
           <form class="navbar-form navbar-right">
               <input type="text" class="form-control" placeholder="Search...">
           </form>
       </div>
   </div>
</nav>

<div class="container-fluid">
   <div class="row">
       <div class="col-sm-3 col-md-2 sidebar">
           <ul class="nav nav-sidebar">
               <li class="active"><a href="#">查看学生信息</a></li>
               <li><a href="#">添加学生</a></li>
           </ul>
           <ul class="nav nav-sidebar">
               <li><a href="">Nav item</a></li>
               <li><a href="">Nav item again</a></li>
               <li><a href="">One more nav</a></li>
               <li><a href="">Another nav item</a></li>
               <li><a href="">More navigation</a></li>
           </ul>
           <ul class="nav nav-sidebar">
               <li><a href="">Nav item again</a></li>
               <li><a href="">One more nav</a></li>
               <li><a href="">Another nav item</a></li>
           </ul>
       </div>
       <div class="col-sm-9 col-sm-offset-3 col-md-10 col-md-offset-2 main">
           <h2 class="sub-header">Section title</h2>
           <div class="table-responsive">
               <table class="table table-striped">
                   <thead>
                   <tr>
                       <th>序号</th>
                       <th>姓名</th>
                       <th>性别</th>
                       <th>年龄</th>
                       <th>学号</th>
                       <th>手机</th>
                       <th>操作</th>
                   </tr>
                   </thead>
                   <tbody>
                  {{each students}}
                   <tr>
                       <td>{{$index+1}}</td>
                       <td>{{$value.name}}</td>
                       <td>{{$value.gender}}</td>
                       <td>{{$value.age}}</td>
                       <td>{{$value.studentNumber}}</td>
                       <td>{{$value.phone}}</td>
                       <td></td>
                   </tr>
                  {{/each students}}
                   </tbody>
               </table>
           </div>
       </div>
   </div>
</div>

<!-- Bootstrap core JavaScript
================================================== -->
<!-- Placed at the end of the document so the pages load faster -->
<!--<script src="https://cdn.jsdelivr.net/npm/jquery@1.12.4/dist/jquery.min.js"
       integrity="sha384-nvAa0+6Qg9clwYCGGPpDQLVpLNn0fRaROjHqs13t4Ggj3Ez50XnGQqc/r8MhnRDZ" crossorigin="anonymous">
</script>-->
<script src="/aaa/jquery/dist/jquery.min.js"></script>
<script src="/aaa/bootstrap/dist/js/bootstrap.min.js"></script>

</body>
</html>

对于main.html在服务器端的渲染

app.get('/main.html', (req, res) => {
   res.render('main.html',{students})
})

注意:这里的数据应该从数据库中获取,但是现在没有数据库,暂时用{student}里的内容代替

在main.html页面中出现的数据是来自server.js中我们提前写好的一个数组

const students = [
  {
       id: 0,
       name: 'zzh',
       gender: 'male',
       age: 21,
       studentNumber: 202104101234,
       phone: 17865931234
  }, {
       id: 1,
       name: 'zzg',
       gender: 'male',
       age: 21,
       studentNumber: 202104101235,
       phone: 17865931235
  }
]

在main.html页面中,

{{each students}}
                   <tr>
                       <td>{{$index+1}}</td>
                       <td>{{$value.name}}</td>
                       <td>{{$value.gender}}</td>
                       <td>{{$value.age}}</td>
                       <td>{{$value.studentNumber}}</td>
                       <td>{{$value.phone}}</td>
                       <td></td>
                   </tr>
{{/each students}}

这种写法属于js语言,但这是express-art-template所扩展的写法,js中并不存在这种写法

第三个页面 add-student.html

在完成了login.html和main.html后,我们已经实现了登陆后进入main页面的功能,接下来我们要实现增删查改功能,在main页面上我们已经可以查看学生信息,接下来我们要完成增加学生信息的功能

在views文件夹下新建add-student.html页面

<!doctype html>
<html lang="zh-CN">
<head>
   <meta charset="utf-8">
   <meta http-equiv="X-UA-Compatible" content="IE=edge">
   <meta name="viewport" content="width=device-width, initial-scale=1">
   <title>Dashboard Template for Bootstrap</title>

   <!-- Bootstrap core CSS -->
   <link href="/aaa/bootstrap/dist/css/bootstrap.min.css" rel="stylesheet">

   <!-- Custom styles for this template -->
   <link href="../public/css/dashboard.css" rel="stylesheet">
   <script src="/aaa/jquery/dist/jquery.min.js"></script>
   <script src="/aaa/bootstrap/dist/js/bootstrap.min.js"></script>
</head>

<body>

<nav class="navbar navbar-inverse navbar-fixed-top">
   <div class="container-fluid">
       <div class="navbar-header">
           <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar"
                   aria-expanded="false" aria-controls="navbar">
               <span class="sr-only">Toggle navigation</span>
               <span class="icon-bar"></span>
               <span class="icon-bar"></span>
               <span class="icon-bar"></span>
           </button>
           <a class="navbar-brand" href="#">Project name</a>
       </div>
       <div id="navbar" class="navbar-collapse collapse">
           <ul class="nav navbar-nav navbar-right">
               <li><a href="#">Dashboard</a></li>
               <li><a href="#">Settings</a></li>
               <li><a href="#">Profile</a></li>
               <li><a href="#">Help</a></li>
           </ul>
           <form class="navbar-form navbar-right">
               <input type="text" class="form-control" placeholder="Search...">
           </form>
       </div>
   </div>
</nav>

<div class="container-fluid">
   <div class="row">
       <div class="col-sm-3 col-md-2 sidebar">
           <ul class="nav nav-sidebar">
               <li><a href="/main.html">查看学生信息</a></li>
               <li class="active"><a href="/add-student.html">添加学生</a></li>
           </ul>
           <ul class="nav nav-sidebar">
               <li><a href="">Nav item</a></li>
               <li><a href="">Nav item again</a></li>
               <li><a href="">One more nav</a></li>
               <li><a href="">Another nav item</a></li>
               <li><a href="">More navigation</a></li>
           </ul>
           <ul class="nav nav-sidebar">
               <li><a href="">Nav item again</a></li>
               <li><a href="">One more nav</a></li>
               <li><a href="">Another nav item</a></li>
           </ul>
       </div>
       <div class="col-sm-9 col-sm-offset-3 col-md-10 col-md-offset-2 main">
           <h2 class="sub-header">添加学生</h2>
           <form id="newStudentForm">
               <div class="form-group">
                   <label for="name" class="control-label">姓名</label>
                   <input type="text" class="form-control" id="name" placeholder="请输入学生姓名">
               </div>
               <div class="form-group">
                   <label for="age" class="control-label">年龄</label>
                   <input type="number" class="form-control" id="age" placeholder="请输入年龄">
               </div>
               <div class="form-group">
                   <strong>性别</strong>
                   <div class="radio">
                       <label>
                           <input type="radio" name="gender" checked value="男"> 男
                       </label>
                       <label>
                           <input type="radio" name="gender" value="女"> 女
                       </label>
                   </div>
               </div>
               <div class="form-group">
                   <label for="studentNumber" class="control-label">学号</label>
                   <input type="text" class="form-control" id="studentNumber" placeholder="请输入学号">
               </div>
               <div class="form-group">
                   <label for="phone" class="control-label">手机号</label>
                   <input type="text" class="form-control" id="phone" placeholder="请输入手机号">
               </div>
               <div class="form-group">
                   <button type="submit" class="btn btn-primary btn-lg">保存</button>
               </div>
           </form>
           <script>
               //将学生信息作为查询参数传递给后端,根据成功与否的响应结果,显示相应的提示信息,并清空输入框
               $(() => {  //当前页面加载完毕后执行的函数
                   $('#newStudentForm').on('submit', function (event) {
                       event.preventDefault()  //阻止默认事件
                       const newStudent = {  //从表单中获取学生信息
                           name: $('#name').val(),  //获取姓名输入框的值
                           age: $('#age').val(),  //获取年龄输入框的值
                           studentNumber: $('#studentNumber').val(),  //获取学号输入框的值
                           phone: $('#phone').val(),  //获取手机号输入框的值
                           gender: $('input[name="gender"]:checked').val()  //获取选中的性别单选框的值
                      }
                       $.ajax({  //发生ajax请求
                           url: '/add-student',  //后端接口的url
                           method: 'get',  //使用get方法发送请求
                           data: newStudent,  //发送的数据为获取到的学生信息
                           success(data) {
                               if (data.success) {
                                   alert('Student added successfully')  //显示成功提示
                                   $('#newStudentForm input[type!="radio"]').val('')  //清空除了单选框之外的输入框的值
                              }
                          },
                           error() {
                               console.log('Something went wrong')
                          }
                      })
                  })
              })
           </script>
       </div>
   </div>
</div>

<!-- Bootstrap core JavaScript
================================================== -->
<!-- Placed at the end of the document so the pages load faster -->
<!--<script src="https://cdn.jsdelivr.net/npm/jquery@1.12.4/dist/jquery.min.js"
       integrity="sha384-nvAa0+6Qg9clwYCGGPpDQLVpLNn0fRaROjHqs13t4Ggj3Ez50XnGQqc/r8MhnRDZ" crossorigin="anonymous">
</script>-->


</body>
</html>

在这个页面中,我们需要六个input,可以让用户输入学生信息然后完成提交。其中,在性别的input中,我们要加入

<input type="radio" name="gender">

其中还需要添加checked属性,在页面打开时就默认选择一个男或女。

在add-student.html上进行的前后端交互

当用户输入完信息后,需要将数据提交到后端。 在这里前端向后端提交数据然后后端返回值我们使用的是ajax,此处不需要页面的整体刷新或跳转,所以使用ajax。

$(() => {  //当前页面加载完毕后执行的函数
                   $('#newStudentForm').on('submit', function (event) {
                       event.preventDefault()  //阻止默认事件
                       const newStudent = {  //从表单中获取学生信息
                           name: $('#name').val(),  //获取姓名输入框的值
                           age: $('#age').val(),  //获取年龄输入框的值
                           studentNumber: $('#studentNumber').val(),  //获取学号输入框的值
                           phone: $('#phone').val(),  //获取手机号输入框的值
                           gender: $('input[name="gender"]:checked').val()  //获取选中的性别单选框的值
                      }
                       $.ajax({  //发生ajax请求
                           url: '/add-student',  //后端接口的url
                           method: 'get',  //使用get方法发送请求
                           data: newStudent,  //发送的数据为获取到的学生信息
                           success(data) {
                               if (data.success) {
                                   alert('Student added successfully')  //显示成功提示
                                   $('#newStudentForm input[type!="radio"]').val('')  //清空除了单选框之外的输入框的值
                              }
                          },
                           error() {
                               console.log('Something went wrong')
                          }
                      })
                  })
              })

$(()=>{})这是使用的是jquery的文档就绪函数,当页面全部加载完毕后执行此函数。 我们首先利用表单的提交事件,这里依然使用jquery的on事件,先阻止原本的表单默认提交事件。然后获取表单中的学生信息,即用户输入的数据。然后和后端进行交互,我们用ajax向后端发出请求,这里使用get即可。因为这里的数据都是用户输入的内容,可以直接在url中显示出来,所以不需要考虑安全性。

在接收到前端提交的请求后,后端做出回应

app.get('/add-student', (req, res) => {
   const newStudent = {...req.query}  //对象的解构赋值来给newStudent添加属性
   //给新学生对象添加唯一的id,取最后一个学生的id加1
   newStudent.id = students[students.length - 1].id + 1
   //将新学生对象添加到学生数组里
   students.push(newStudent)
   //发送成功的相应
   res.send({success: true})
})

我们在这里声明一个newStudent对象,利用这个newStudent来给前端输入的学生数据添加一个唯一的id,然后将这个对象添加到学生数组当中。添加成功后,后端发送添加成功的回复。

前端收到后端发出的回复后,我们要做出相对应的反应,当回复成功时做出一个反应,回复失败时做出一个反应。

success(data)
{
   if (data.success) {
       alert('Student added successfully')  //显示成功提示
       $('#newStudentForm input[type!="radio"]').val('')  //清空除了单选框之外的输入框的值
  }
}
error()
{
   console.log('Something went wrong')
}

当后端回复成功时,我们弹出添加成功的对话框,然后清空除了单选框之外的输入框;当后端回复失败时,我们直接输出错误。 此时,我们的add-student页面也基本完成。已经具备我们的增加学生功能;接下来还需要完成删除和修改功能。