文章目录

  • 前端
    • 1. 主页模块
    • 2. 用户管理模块
    • 3. 用户个人中心页面
    • 4. 管理员页面
  • 后端
    • 1. 数据库处理
    • 2. 后台自动发送验证邮箱
    • 3. 用于产生六位随机验证码
    • 4. 管理员路由设置
    • 5. 用户路由设置
    • 6. 程序入口
    • 7. 服务器在运行时会记录相应的日志信息
    • 8. 下载地址

大二课程设计,前端采用了 bootstrap 框架,完成响应式布局,后端用了node平台中的 express 框架,在完成此项目的过程中,虽然遇到了许多问题,但是通过各种途径也一一解决了,在此将此项目以及完成过程的心得分享给大家,希望能给大家带来帮助。本人也是一位正在学习中的程序员,如果遇到什么问题或者建议,也希望大家能够指出。

前端

1. 主页模块

首先此系统参考了其他各大型影院的网上售票系统,再经过小组自身实力的权衡等等,最终达到了如下的效果

抬头是一个巨幕,可以通过点击进行切换,也能自动变换,下面就是正在热映的电影的一个轮播图,用户能够通过点击相关电影图片进入到电影的详细介绍中。

电影详细介绍


通过电影详细介绍能让用户更好的了解这个电影信息,并且能在此界面进行购票操作。

主页的下方是当下比较热门电影的简介,同样,也能点击进去查看详细信息

主页的大题思路就完成了,具体还有许多细节就不在此一一展示了

2. 用户管理模块

展示完主页过后,要完成购票我们首先想到的就是要完成用户的管理,用户首先要拥有自己的账号才能进行买票,才能更好的方便管理。于是就有了售票管理。我们可以通过主页面中的登录按钮来进入登录页面。

注册页面


忘记密码页面


这些页面也都能够完成相应的功能,包括发送邮箱等等,主要采用了 Ajax 从后端接收数据,调用 node 发送邮箱的 API 来完成,整体来讲这部分并不是很难,前端的布局这些都能在一天之内完成。主要考虑的就是后端处理事务的能力、并发度、异步问题等等。此系统运用的是 mysql 数据库,用户数据都存储在数据库中,后期还有用户订单等其他数据也都存储在数据库中。

3. 用户个人中心页面

当我们登录成功以后,之前的登录页面右上角的登录按钮会变成我们用户的个人中心按钮(参考很多网页也是这样来实现的 ),其中的内容也会变成用户的昵称


点击进入个人主页


这就是目前个人主页已经完成的功能,能够看到自己的售票订单,以及对个人账户的管理,退出登录等等。

个人订单

修改密码

用户个人页面目前来讲由于时间有限就只完成了这些功能,后期如果有时间会继续将其完善。但是基本的雏形已经搭建完成。

4. 管理员页面

有了面向用户的应用程序,就有面向管理员的界面,管理员能通过此页面做出更高权限的操作。

管理员登录界面


登录成功后的页面

添加用户或者修改用户


查看电影售票历史

拥有较高权限的管理员界面能够完成许多普通用户完成不了的操作,这里也不一一展示了,如果有疑问,欢迎在评论区指出。

前端几大模块主要页面基本展示完成,还有很多页面就不向大家献丑啦,下面给大家展示下后端的事物处理

后端

1. 数据库处理

const mysql = require('mysql');
//创建数据池
//如果每次都是用createConnect来连接那么每次还需要进行关闭数据库连接的操作,略显繁琐
const pool = mysql.createPool({connectionLimit: 10,host: 'localhost',    //默认情况下的主机名user: 'root',          //默认情况下的用户名password: '111',       //安装时设置的密码database: 'ticketing',      //连接的数据库名字multipleStatements: true,timezone: "SYSTEM"
});
//使用时传入对应参数,sql为相应sql语句,data为插入或修改所需要的数据
module.exports = (sql, data = []) => {//使用Promise解决mysql的命令处理异步问题return new Promise((resolve, reject) => {//在数据池中进行操作pool.query(sql, data, function (error, results, fields) {if (error) {reject(error.message)} else {resolve(results)}})})
}

这里使用了 ES6 重点 promise 关键字,来处理前端发送请求可能带来的异步问题,以及连接 mysql 数据库。创建数据库常量池,减少频繁创建连接带来的资源浪费。将此模块封装起来,其他地方要使用时直接引入就行

2. 后台自动发送验证邮箱

const nodemailer = require("nodemailer");// 创建一个 smtp 服务器
const config = {secureConnection:true,host:'smtp.163.com',service:"163",  //  邮箱secure:true,port:456,auth:{user:'ticketsystem2021@163.com',pass:'IQQZDPQUYWEZJRYU' // 邮箱授权码}
}
const transporter = nodemailer.createTransport(config);module.exports = function(mail,res){transporter.sendMail(mail,function(err,info){if(err){console.log(err);res.json({status:400,msg:"send fail....."})}else{console.log(info);res.json({status:200,msg:"邮件发送成功....."})}})
}

这里运用的是 node 中的 nodemailer 包来达到需求,创建一个163邮箱和 smtp 服务器

3. 用于产生六位随机验证码

module.exports = {createSixNum:function (){var Num="";for(var i=0;i<6;i++){Num+=Math.floor(Math.random()*10);}return Num;}
} 

接下来就是最重要的路由设置,返回请求给前端

4. 管理员路由设置

const express = require('express');
const db = require('./db.js')
const router = express.Router();// 获取 post 请求
router.use(express.json())
router.use(express.urlencoded({ extended: false }));
// 修改默认路径// 返回登陆界面
router.get('/admir',(req,res)=>{console.log('/admir 管理员登陆');res.render('sign-in.html');
})/*** @param user 用户名* @param psw  密码* * ajax 判断账号密码否正确* * @returns yes 账号密码正确* @returns no  账号密码错误 */
router.get('/checkMan',async (req,res)=>{const data = req.query;console.log("/checkMan ajax 验证管理员账号密码")const sql = 'select * from manage where user = ? and psw = ?';try{const result = await db(sql,[data.user,data.psw]);if(result.length == 0){res.send('no');}else{res.send('yes')}}catch(err){// 数据库连接问题res.render('403.html');console.log(err);}
})
// 通过 ajax 如果验证成功,则将管理员主页返回
router.post('/zhu_ye',async (req,res)=>{const sql_users = "select * from user limit 5";const sql_history = "select * from history limit 5"const data_users = await db(sql_users);const data_history = await db(sql_history);let history = JSON.stringify(data_history);let users = JSON.stringify(data_users);console.log("查找到的用户数据为:"+users);console.log('历史数据为:'+history)users = JSON.parse(users);history = JSON.parse(history)res.render('zhu_ye.html',{users:users,history:history,});
})
// 用户列表
router.post("/user_list",async (req,res)=>{const sql = 'select  * from user'const data = await db(sql);let data_str = JSON.stringify(data);let user_list = JSON.parse(data_str);res.render('users.html',{users:user_list})
})
// 用户删改
router.post('/user_change',(req,res)=>{res.render('user_change.html');
})
// 其他
router.post('/more',(req,res)=>{res.render('more.html');
})
// 电影售票统计
router.post('/total',async (req,res)=>{const sql_history = 'select * from history';let data = await db(sql_history);data = JSON.stringify(data);console.log('查询到的历史购票记录为:'+ data);data = JSON.parse(data);res.render('tong_ji.html',{history:data,});
})
// 电影上架
router.post("/shang_jia",(req,res)=>{res.render('shang_jia.html');
})// 用户名修改
router.post('/change_email',(req,res)=>{const email = req.body.email;console.log('需要修改用户信息的账号为:'+email)res.render('user_change.html',{email:email,})
})
// 修改用户信息
router.get('/change_email',async (req,res)=>{let data = req.query;const sql_del = 'delete from user where user = ?';const sql_ins = 'insert into user value(?,?,?)';try{let del_result = await db(sql_del,[data.user]);let ins_result = await db(sql_ins,[data.user,data.psw,data.name])res.render('man_change_success.html')}catch(err){res.send(err);}})
// 删除用户
router.post('/del_email',async (req,res)=>{let data = req.body;const sql_del = 'delete from user where user = ?';try{await db(sql_del,[data.email]);res.redirect(307,'/user_list')}catch(err){res.send(err)}
})
// 添加用户
router.post('/add_user',async (req,res)=>{let data = req.body;const sql_del = 'delete from user where user = ?';const sql_ins = 'insert into user value(?,?,?)';try{let del_result = await db(sql_del,[data.user]);let ins_result = await db(sql_ins,[data.user,data.psw,data.name])res.render('man_change_success.html')}catch(err){res.send(err);}
})
// 错误提示页面
router.post('/403',(req,res)=>{res.render('403.html')
})
router.post('/404',(req,res)=>{res.render('404.html')
})
router.post('/500',(req,res)=>{res.render('500.html')
})
router.post('/503',(req,res)=>{res.render('503.html')
})// 创建路由
module.exports = router;

5. 用户路由设置

const express = require('express');
const db = require('./db.js')
const router = express.Router();
const tools = require('./tools.js')
const nodemail = require('./nodemail.js')
const moment = require('moment')router.use(express.json())
router.use(express.urlencoded({ extended: false }));router.get('/', function (req, res) {console.log("/ 请求主页面")res.render('menu.html', { url: '/user_login', btn_msg: '登录',vaule:'' });
})
// 响应登录页面
router.get('/user_login', function (req, res) {console.log('/user_login 登录页面')res.render('index.html');
})
// 响应忘记密码页面
router.get('/forgot', function (req, res) {console.log('/forgot 忘记密码页面')res.render('forgot.html');
})
// 响应注册页面
router.get('/sign-up', function (req, res) {console.log('/sign-up 注册页面')res.render('sign-up.html');
})
// 接收用户登录
/*** data.user 用户名* data.psw  密码* */
router.post('/form', async (req, res) => {// 获取 post  表单数据const data = req.body;console.log('/form 登录验证账号:'+data.user+'验证的密码为:'+ data.psw)const sql = "select * from user where user = ? and psw = ?";const result = await db(sql, [data.user, data.psw]);let dataString = JSON.stringify(result);dataString = JSON.parse(dataString)if (result.length != 0) {console.log(dataString)res.render('menu.html', {url: "/home?email="+data.user,btn_msg: dataString[0].name,sell:"email="+data.user})}
})
// 用于判断账号和密码是否正确
router.get('/formTest', async (req, res) => {// 获取 get 数据const data = req.query;console.log('/formTest 验证的账号为'+data.user+",密码为:"+data.psw)const sql = "select * from user where user = ? and psw = ?";// 查询到的结果const result = await db(sql, [data.user, data.psw]);if (result.length == 0) res.send("no");else res.send("yes");})
// 购票页面
router.get('/sell_ticket1',(req,res)=>{let data = req.query;if(data.email){res.render("sell_ticket1.html",{sell_btn:data.email,sell_email:"email="+data.email,sell_url:"#",})}else{res.render('sell_ticket1.html',{sell_btn:'登录',sell_url:'/user_login',})}})
router.get('/sell_ticket2',(req,res)=>{let data = req.query;if(data.email){res.render("sell_ticket2.html",{sell_btn:data.email,sell_url:"#",})}else{res.render('sell_ticket2.html',{sell_btn:'登录',sell_url:'/user_login',})}
})
// 购票成功
router.get('/shop_success1',async (req,res)=>{let email = req.query.email;let date = moment(new Date()).format('YYYY-MM-DD HH:mm:ss')console.log("当前时间为:"+date)const sell_sql = "insert into history value(?,?,?,?)"try{await db(sell_sql,[email,'八月未央',60,date])res.render('shop_success.html',{email:email})}catch(err){res.send(err)}})
router.get('/shop_success2',async (req,res)=>{let email = req.query.email;let date = moment(new Date()).format('YYYY-MM-DD HH:mm:ss')console.log("当前时间为:"+date)const sell_sql = "insert into history value(?,?,?,?)"try{await db(sell_sql,[email,'超越',60,date])res.render('shop_success.html',{email:email})}catch(err){res.send(err)}
})
// 接收用户注册
/*** url /sign-up/from* */
router.post('/sign-up/from', async (req, res) => {// 使用 await promise 时会自动转换为 resolve 函数中的参数const data = req.body;console.log('/sign-up/form 注册的账号为'+data.user+",注册密码为:"+data.psw,"用户名为:"+data.name)const sql = "insert into user value(?,?,?);";const result = await db(sql, [data.user, data.psw,data.name]);if (result.affectedRows == 0) res.render('sign_res.html', { result: "注册失败" });else res.render('sign_res.html', { result: '注册成功' });
})
// 判断用户名是否重复 ajax
router.get('/findUser', async (req, res) => {const data = req.query;console.log("/findUser 判断 "+data.email+" 是否重复");const sql = "select * from user where user = ?"const result = await db(sql, [data.email]);if (result.length == 0) res.send('yes');else res.send('no');
})// 发送邮件 ajax
router.get('/email', async (req, res) => {const email = req.query.email;//刚刚从前台传过来的邮箱const code = tools.createSixNum();//生成的随机六位数const delay = 300000;   // 验证码的作用时间const sql = "select * from user where user = ?"try {const result = await db(sql, [email]);console.log(result);if (result.length == 0) {res.json({ status: 400, message: 'no' });} else {req.body = { success: true, message: "账号可行" };//数据传回前台var mail = {// 发件人from: 'ticketsystem2021@163.com',// 主题subject: '票多多 账号验证凭证',//邮箱主题// 收件人to: email,//前台传过来的邮箱// 邮件内容,HTML格式text: `您的验证码为${code} 票多多电影城是四川省电影公司全资影城、属拼多多电影院线旗下影院,创立于2021年5月,距今已2个月历史,累计票房收入2.3亿元,接待观众超过2千余万。影城成立以来先后投资三千余万元,经数次装修改造,使影城始终引领电影时尚潮流。地处最繁华的春熙路商圈核心位置, 拥有18个豪华电影厅,观众座席数2000多座,是全国影厅最多、节目最多、场次最多、人次最多的影城。率先引进数字3D电影,影厅内安装有世界顶级的英国杜比CP650(EX)数字处理器、 美国JBL音响、德国ISCO一体化镜头、美国QSC数字功放(DCA)、 6.1声道杜比数码立体声系统!发送者:ticketsystem2021@qq.com`};let time;const delSql = "delete from checkcode where email = ?;"const inSql = "insert into checkcode value(?,?);"await db(delSql, [email]);await db(inSql, [email, code]);time = setTimeout(() => {const delCode = "delete from checkcode where email = ?";try {db(delCode, [email]);} catch (err) {console.log(err);}}, delay)nodemail(mail, res);//发送邮件clearTimeout(time)console.log("/email 发送邮件 email:" + email, "code:" + code)}} catch (err) {console.log(err)}
})
// 判断是否输入的邮箱与验证码是否符合 ajax
router.get('/findPsw', async (req, res) => {const data = req.query;console.log(data.email, data.code)const sql = "select * from checkcode where email = ? and code = ?"const result = await db(sql, [data.email, data.code]);if (result.length > 0) {console.log(result)res.send("yes")}else res.send("no");
})
// 如果符合就跳转到修改密码界面
// 将邮箱传回
router.post('/findPsw', async (req, res) => {console.log(req.body);res.render('findPsw.html', {email: req.body.email,});
})
// 修改密码
router.post('/change', async (req, res) => {console.log('/change 修改的email与新密码:' + req.body.email, req.body.newPsw)const email = req.body.email;const newPsw = req.body.newPsw;const sql = "update user set psw = ? where user = ?"const result = await db(sql, [newPsw, email]);if (result.affectedRows == 0) {res.send('服务器连接问题,修改失败');} else {res.render('change_success.html');}
})
// 进入个人主页
router.get('/home',(req,res)=>{const data = req.query;res.render('home.html',{email:data.email,})
})
// 返回到菜单
router.get('/form',(req,res)=>{const email = req.query.email;res.render('menu.html', {url: "/home",btn_msg: email})
})
// 用户修改密码
router.get('/changePsw',(req,res)=>{const data = req.query.email;console.log(data)res.render('changePsw.html',{email:data,})
})
// 获取用户信息表单
router.post('/get_form',async (req,res)=>{const email = req.body.email;const sql = 'select * from user where user = ?'let data = await db(sql,[email]);data = JSON.stringify(data);console.log('/get_form'+data);console.log('/get_form:'+email);res.send(data)
})
// 用户获取购票历史
router.get('/order',async (req,res)=>{let email = req.query.email;const sql_his = 'select * from history where email = ?'try{let result = await db(sql_his,[email])result = JSON.stringify(result);console.log('/order :'+result);res.render('order.html',{email:email,history:JSON.parse(result)})}catch(err){res.send(err);}
})
module.exports = router;

6. 程序入口

const express = require('express');
const router_user = require('./source/router_user')
const router_ma = require("./source/router_ma")
const app = express();
// 引入路由
app.use(router_user)
app.use(router_ma)
// express 导入 art-template
app.set('views', [__dirname + '/views/user', __dirname + '/views/manage']);app.engine('html',require('express-art-template'))app.use('/public/',express.static('./public/'))app.listen(3000,function(){console.log('server is running.....');
})

7. 服务器在运行时会记录相应的日志信息

此次项目就展示到这里,可能在很多大佬面前这都不算什么,但是这是我一行一行敲出来的成果,在这个过程中,我学习到了很多东西,也希望能和大家一起学习,一起进步。作为一个上山的人,要多多学习,加倍努力才能登上高峰。

8. 下载地址

原创不易下载地址:https://download.csdn.net/download/Mr_changxin/20486492

大二课设,采用 bootstrap + express + mysql 实现电影售票系统(附带源码)相关推荐

  1. 简易的学生社团管理(大二课设)

    //STUDENT.h//STUDENT.h #ifndef STUDENT_H_INCLUDED #define STUDENT_H_INCLUDED#include<stdio.h> ...

  2. 大二课设-基于Tcp的c/s模式的网络聊天室(c#)

    设计一个网络聊天室,能够显示有关该系统基本信息的描述,如:客户端的实例信息.在线等,具体要求如下: (1)聊天室服务器端的创建 (2)聊天室客户端的创建 (3)实现客户与服务器的连接通讯 (4)实现客 ...

  3. 【飞机票售票系统】山东大学大二暑期数据库课程设计项目SSM+VUE2前后端分离(含源码)

    一.系统概述 二.需求分析 2.1 系统功能分析 2.2 系统数据分析 2.3 系统非功能分析 三.系统设计 3.1 应用程序设计 3.2 数据库设计 3.2.1 概念设计 3.2.2 逻辑设计 四. ...

  4. 毕设课设基于Android的校园订餐APP开发(附源码)

    1.演示视频链接: https://www.bilibili.com/video/BV1N3411c7Pf/?vd_source=48f4d2985ad54326394e2e5947d91c22 2. ...

  5. MySQL长途售票系统_客车网上售票系统(Java源码+sql脚本)

    本实例为Java语言实现的客车网上售票系统, 系统提供了源码, 数据库脚本和相应的文档说明,文档经过修改可以做为论文使用,系统经过修改可以进行商用 点击右侧[下载实例]进行实例下载:下载实例​ 环境配 ...

  6. 基于SpringBoot+Vue+Java+Mysql 的简历招聘系统【源码】

    文章目录 1.效果演示 2. 前言介绍 3.主要技术 4 **系统设计** 4.1 系统体系结构 4.2开发流程设计 4.3 数据库设计原则 4.4 数据表 5 **系统详细设计** 5.1管理员功能 ...

  7. 用java的二维数组做一个简易计算优惠小程序(附带源码)

    要求: 1.单点: 溜肥肠24元 酱肘子32 米饭3元 2.订单满30打八折 3.优惠价: 溜肥肠18元 4.打八折与优惠价不能同时使用,点这三样,最少多少钱? 思路: 首先定义一个 String 类 ...

  8. 单片机多功能电子琴课设_基于51单片机电子琴的设计(附源码及论文)

    单片机最小系统 单片机最小系统 单片机最小系统说明: 时钟信号的产生:在MCS-51芯片内部有一个高增益反相放大器,其输入端为芯片引脚XTAL1,其输出端为引脚XTAL2.而在芯片的外部,XTAL1和 ...

  9. python爬虫课设报告_python爬虫小说设计报告 相关实例(示例源码)下载 - 好例子网...

    开发语言:Python | 大小:0.07M | 发布时间:2020-11-12 | 立即下载 开发语言:Python | 大小:2.24KB | 发布时间:2020-10-23 | 发布人:吴wu ...

最新文章

  1. ACMNO.43 C语言-成绩排序 利用结构体解决,是一个进步啦!
  2. 说说几个 Python 内存分配时的小秘密
  3. 【机器学习】全面解析Kmeans聚类算法(Python)
  4. 模板类的全特化、偏特化
  5. mysql导入数据库某张表_MSSQLServer2005 导出导入数据库中某张表的数据
  6. expect巡检服务器_Shell-批量巡检服务器脚本
  7. 怎么把pdf转换为html,如何将PDF转换成HTML网页格式呢?
  8. 抽象类中不能有private的成员_【java基础】-- java接口和抽象类的异同分析
  9. 开源硬件_如何参与开源硬件协会
  10. Android 系统性能优化(11)---UC性能优化方案
  11. (转载)UI设计还远没有满足客户的需求
  12. STM32F103ZET6 GPIO的使用
  13. Java中的泛型全解析(二)
  14. 《metasploit渗透测试魔鬼训练营》学习笔记第九章--meterpreter
  15. Django视图与模板+vs2019
  16. python 自动化运维小工具——子网掩码计算——随机密码生成
  17. ICLR 2022最佳论文:基于对比消歧的偏标签学习
  18. 如何在TOMCAT上安装Liferay
  19. java中activeThread_java多线程机制中的Thread和Runnable()区别
  20. C语言学习开头以及个人目标

热门文章

  1. CSDN 富文本编辑器和 Markdown 编辑器使用 Word 支持的 LaTx 语法公式
  2. 交通违章 处罚[转]
  3. 电子科大互加数据库课程作业——ER图设计
  4. EWM RF手持设备开发记录
  5. 初中计算机案例交流,初中语文与信息技术整合教学案例——《爱莲说》
  6. 3D游戏建模学习就业会困难吗?10年资深游戏美术大拿分享就职面试心得
  7. 密钥ssh 配置操作
  8. 深度解读低门槛钱包赛道:Web3的用户入口
  9. NOIP练习赛题目1
  10. 有什么编辑图片加文字的软件?今日推荐:图片编辑软件加文字