目录
写在开头
实验要求
实验过程
后记
写在开头
基于本学期web编程课中对于JavaScript,HTML,CSS语言的学习以及课堂上老师示例的讲解,已经掌握了部分web项目的开发和运用能力,为完成web项目的独立开发和运用以及熟悉基于Linux操作系统的树莓派的项目开发,故此次期末项目实验选择树莓派便携式教学工具开发,完成期末项目。基于本学期web编程课中对于JavaScript,HTML,CSS语言的学习以及课堂上老师示例的讲解,已经掌握了部分web项目的开发和运用能力,为完成web项目的独立开发和运用以及熟悉基于Linux操作系统的树莓派的项目开发,故此次期末项目实验选择树莓派便携式教学工具开发,完成期末项目。
另外,虽然本次实验的项目需要在树莓派上实现但是其实更多的工作在于服务器的搭建和调试,因此我们只需要现在电脑上网成服务器的搭建就行,毕竟在树莓派上再装一个vscode,配置一下环境还是挺麻烦的。
实验要求
- 1、基于树莓派Raspbian操作系统搭建一个Wifi热点(hostapd和udhcpd),电脑和手机客户端可以接入该wifi自动获取到IP地址。(例如树莓派作为网关,IP缺省设为10.1.1.1,其他客户端自动获取到10.1.1.0段的其他地址)。
- 2、电脑和手机客户端可访问树莓派(作为服务器)上架设好的Web网站(例如http://10.1.1.1),两类用户登录,一类是教师用户(管理员),另一类是学生用户,两类用户访问不同的缺省页面。
- 3、教师端可上传任一文件到树莓派,上传完成后下发给所有学生端一个下载链接( WebSocket ),实现文件共享。
- 4、教师用户登录后可上传一道题目(比如json格式的单选题),同时下发给所有学生端(WebSocket),并实时查看该题目的回答情况(比如用Echarts展示)
- 5、学生用户登录后可随时接受教师下发的题目并回答,实时反馈答案回到教师端。
实验过程
- 1、建立HTTP链接;
“http”是js建立TCP连接的一个内置API,我们可以利用这样的API来完成最基本的web服务器搭建的。
// 引入http的api
const http = require('http');
// app.js是完成具体的一些服务处理逻辑的代码,再后面完成
const serverHandler = require("./app");
// 创建端口
const PORT = 8002;
// 开始异步处理连接
const server = http.createServer(serverHandler);
// 建立后端监听
server.listen(PORT,function(){
console.log("listern at port 8002");
});
- 2、完成服务处理
const path = require('path');
const querystring = require('querystring');
// 引入路由
const handleRoute = require('./teachs');
// 处理post请求的信息
const getPostData = function(req){
// console.log("开始了post解析")
const promise = new Promise(function(resolve,rejects){
// 判断请求的方式
if (req.method !== 'POST'){
resolve({});
// console.log("没能解析、方式")
return;
}
// // 判断post对象的格式
// if ((req.headers['content-type'] !== 'application/json')){
// resolve({});
// console.log("没能解析、格式")
// return;
// }
// 一数据流的方式传入
console.log("开始解析了")
let postData = '';
req.on('data',function(chunk){
postData += chunk;
// console.log(chunk);
});
req.on('end',function(){
if (!postData){
resolve({});
return;
}
resolve(
postData
);
});
});
console.log("promise:",promise);
return promise;
}
// 进行相关的路由操作
const serverHandler = function(req,res){
// 获取path
const url = req.url;
req.path = url.split('?')[0];
console.log(url);
// 解析query
req.query = querystring.parse(url.split('?')[1]);
console.log('req.query',req.query);
// 先行获取postData异步处理具体发路由
getPostData(req).then(function(postData){
// 传入postData
req.body=postData;
console.log("postData",postData);
// 异步处理路由
const data = handleRoute(req,res);
});
};
module.exports = serverHandler;
上述的代码段中可以看出,我是把postData先行定义并且再处理具体路由时线性运行再异步处理我们具体的路由操作。
这是因为我搭建的服务器相关的路由操作为异步实现,因此开始的实验中总是无法获取post请求的数据开始时再次碰壁许久,后查阅相关资料后了解到post数据若异步处理是需要在异步操作中实现路由。
- 3、处理具体的路由
const fs = require('fs');
const querystring = require('querystring');
const path = require('path');
// 这一部分是再其他代码段的完成的丽娜姐数据库的操作函数
const {login_check,answer_write,signup_check_stu,signup_check_tea,show_answer,getlist} = require('./src/route/msql');
// 定义路由的处理
const handleRoute = function(req,res){
var count;
// 准备阶段获取method,url,profix
const id = req.query.id;
const pwd = req.query.pwd;
const method = req.method;
const url = req.url;
const profix = req.path.split('.')[1];
const postData = req.body;
const ans = req.query.ans;
// JSON.stringify(req.query);
// JSON.parse(postData);
// console.log('postData.id',postData.id);
// console.log("id",id);
// 访问服务器返回主界面
if (url === '/'){
// console.log("yes");
const returnData = fs.readFileSync(__dirname+'/index.html','utf-8');
console.log(returnData);
res.end(returnData);
return returnData;
}
// 获取html中的css,image
if ((profix === 'css' || profix === 'html' || profix === 'jpg'))
{
// fs.readFile('.'+url,function(err,data){
// // console.log('.'+url);
// if (err){
// // console.log('err');
// }else{
// res.end(data);
// }
// });
const returnData = fs.readFileSync('.'+req.path);
res.end(returnData);
return returnData;
}
// 学生登录
if (method === 'POST' && req.path === '/stu/login'){
// let sql = `select name , pwd from new_table where name = '${id}'`;
login_check(req.query.id).then(function(inform){
JSON.stringify(inform);
console.log('inform',inform);
// const pwds = inform.pwd;
// console.log("pwd",pwd);
// console.log("pwds",pwds);
if (typeof(inform.pwd) == undefined){
res.writeHead(404,{'Content-Type':'text/plain'})
res.write('404 Not Found');
res.end();
return;
}
if (pwd === inform.pwd){
console.log('yes');
returnData = fs.readFileSync('./index.html');
res.end(returnData);
return;
}
res.writeHead(404,{'Content-Type':'text/plain'})
res.write('404 Not Found');
res.end();
});
return;
}
// 学生注册
if (method === 'POST' && req.path === '/stu/signup'){
// if (req.query.id==='123'){
// const returnData = fs.readFileSync('./index.html');
// const returnData ="<script language=javascript'>alert('hello "+req.query.id+"');window.location.href='./view/stupage.html';</script>";
// const a = returnData;
// console.log('returnData',a.toString());
// console.log(returnData);
signup_check_stu(id,pwd).then(function(returnData){
console.log(returnData);
JSON.stringify(returnData);
const Data = fs.readFileSync('./index.html');
res.end(Data);
return;
}
);
return;
// res.end(returnData);
// return returnData;
}
// 教师登录
if (method === 'POST' && req.path === '/tea/login'){
// if (req.query.id='123'){
// const returnData = fs.readFileSync('./index.html');
// // const returnData ="<script language=javascript'>alert('hello "+req.query.id+"');window.location.href='./view/stupage.html';</script>";
// // const a = returnData;
// // console.log('returnData',a.toString());
// console.log(returnData);
// res.end(returnData);
// return returnData;
// }
login_check(req.query.id).then(function(inform){
JSON.stringify(inform);
console.log('inform',inform);
// const pwds = inform.pwd;
// console.log("pwd",pwd);
// console.log("pwds",pwds);
if (typeof(inform.pwd) == undefined){
res.writeHead(404,{'Content-Type':'text/plain'})
res.write('404 Not Found');
res.end();
return;
}
if (pwd === inform.pwd){
console.log('yes');
returnData = fs.readFileSync('./index.html');
res.end(returnData);
return;
}
res.writeHead(404,{'Content-Type':'text/plain'})
res.write('404 Not Found');
res.end();
});
return;
}
// 教师注册
if (method === 'POST' && req.path === '/tea/signup'){
// if (req.query.id='123'){
// const returnData = fs.readFileSync('./index.html');
// // const returnData ="<script language=javascript'>alert('hello "+req.query.id+"');window.location.href='./view/stupage.html';</script>";
// // const a = returnData;
// // console.log('returnData',a.toString());
// console.log(returnData);
// res.end(returnData);
// return returnData;
// }
signup_check_tea(id,pwd).then(function(returnData){
console.log(returnData);
JSON.stringify(returnData);
const Data = fs.readFileSync('./index.html');
res.end(Data);
return;
}
);
return;
}
// 文件上传
if (method === 'POST' && req.path === '/fileupload'){
console.log("yes");
const filename = __dirname+"/public/upfile"+".txt";
fs.writeFileSync(filename,postData);
const returnData = 'success';
console.log(returnData);
res.end(returnData);
return returnData;
}
// 下载文件
if (method === 'GET' &&req.path === '/filedown'){
const filepath = __dirname+"/public/upfile"+".txt";
fs.readFile(filepath, (err, data) => {
console.log('data....');
if (err) {
res.end(err);
return;
}
res.writeHead(200, {
// 'Content-Disposition': 'attachment; filename=' + queryObj[key],
'content-type': 'application/octet-stream',
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Headers': 'X-Requested-With',
'Access-Control-Allow-Methods': 'PUT,POST,GET,DELETE,OPTIONS',
});
console.log("yes");
fs.createReadStream(filepath).pipe(res);
return;
});
}
// 查看问题
if (method === 'GET' &&req.path === '/check_qusetion'){
var returnData=fs.readFileSync(__dirname+"/public/qusetion.json");
console.log(returnData);
res.end(returnData);
return returnData;
}
// 答案写入
if (method === 'POST' && req.path === '/answer'){
filename = __dirname+"/public/qusetion.json";
JSON.parse(postData);
console.log(postData);
console.log("ans",ans);
// const ans = postData.ans;
answer_write(id,ans);
// question = postData.qusetion;
// const A = postData.A;
// const B = postData.B;
// const C = postData.C;
// const D = postData.D;
// console.log(question,A,B,C,D);
// fs.writeFileSync(filename,postData);
res.end();
return;
}
// 问题写入
if (method === 'POST' && req.path === '/question'){
filename = __dirname+"/public/qusetion.json";
fs.writeFileSync(filename,postData);
res.end();
return;
}
// 获取答题情况
if (method === 'GET' && req.path === '/showans'){
// var ansA,ansB,ansC,ansD;
const filenameA = __dirname+"/public/anscountA.json";
const filenameB = __dirname+"/public/anscountB.json";
const filenameC = __dirname+"/public/anscountC.json";
const filenameD = __dirname+"/public/anscountD.json";
const filename = __dirname+"/public/anscount.json";
var ansA;
var ansB;
var ansC;
var ansD;
show_answer('A').then(function(inform){
console.log(inform);
console.log(inform.num);
ansA=inform.num;
// fs.writeFileSync(filenameA,'{"ansA":'+ansA+'}');
show_answer('B').then(function(inform){
console.log(inform);
console.log(inform.num);
ansB=inform.num;
// fs.writeFileSync(filenameB,'{"ansB":'+ansB+'}');
show_answer('C').then(function(inform){
console.log(inform);
console.log(inform.num);
ansC=inform.num;
// fs.writeFileSync(filenameC,'{"ansC":'+ansC+'}');
show_answer('D').then(function(inform){
console.log(inform);
console.log(inform.num);
ansD=inform.num;
fs.writeFileSync(filename,'{"ansA":'+ansA+',"ansB":'+ansB+',"ansC":'+ansC+',"ansD":'+ansD+'}');
const returnData = fs.readFileSync(filename);
res.end(returnData);
return;
});
});
});
});
return;
}
// 获取学生列表
if (method === 'GET' && req.path === '/stulist'){
getlist().then(function(listData){
console.log(listData);
// console.log(listData);
res.setHeader('Content-Type','application/json');
res.end(JSON.stringify(listData));
return;
});
return;
}
}
module.exports = handleRoute
这一部分可以说是完成此次项目饰演的的最难之处,其中也有几点困惑了我许久。
比如HTML和CSS渲染的同步获取。开始连接服务器以及HTML时浏览器只能拿到HTML的框架而不能实现界面的渲染,这是应为CSS文件和其他内置的JS文件没有成功从服务器获取到,即服务器没有设置发送CSS和JS文件的路由,HTML中有引入,依靠引入向服务器发送get请求而服务器没有回应。之后添加相关路由解决。
// 获取html中的css,image
if ((profix === 'css' || profix === 'html' || profix === 'jpg')) {
const returnData = fs.readFileSync('.'+req.path);
res.end(returnData);
return returnData;
又比如说文件的上传和下载实现。这一部分我们通过服务器作为中间转接点,将教师端上传文件保存在服务器然后学生端可以执行下载命令来获取文件。开始时我并不能理解服务器如何保存上传的文件,后了解知道浏览器向服务器以管道的方式发送数据流,而服务器则接收并处理数据流,获取数据流后我利用文件写入的方式将上传的文件写入本地指定的文件中。而在浏览器请求下载文件时服务器指定相应头的方式,建立服务器与客户端的数据管道,再以数据流的方式读取本地指定的文件并传回浏览器,浏览器则接收并下载。
if (method === 'POST' && req.path === '/fileupload'){
console.log("yes");
const filename = __dirname+"/public/upfile"+".txt";
fs.writeFileSync(filename,postData);
const returnData = 'success';
console.log(returnData);
res.end(returnData);
return returnData;
}
if (method === 'GET' &&req.path === '/filedown'){
const filepath = __dirname+"/public/upfile"+".txt";
// res.download(filepath,function(err){
// if (err){
// console.log(err);
// }
// });
// return;
fs.readFile(filepath, (err, data) => {
console.log('data....');
if (err) {
res.end(err);
return;
}
res.writeHead(200, {
'content-type': 'application/octet-stream',
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Headers': 'X-Requested-With',
'Access-Control-Allow-Methods': 'PUT,POST,GET,DELETE,OPTIONS',
});
console.log("yes");
// 创建数据流管道
fs.createReadStream(filepath).pipe(res);
return;
});
}
还有进行答案统计这一步操作。这一步的操作因为答案存在数据库中因此我们需要执行多条sql语句获取出答案的数量,但又由于数据库的操作为异步处理,因此开始时我并不能做到获取到数据库中答案的数量,之后想到可以通过回调的方式来逐层获取,但是看上去有一些回调地狱的感觉,这一部分还有待提高。比如说一种改进的方法就是用另一个数据库来存入我们的答案。
show_answer('A').then(function(inform){
ansA=inform.num;
show_answer('B').then(function(inform){
ansB=inform.num;
show_answer('C').then(function(inform){
ansC=inform.num;
show_answer('D').then(function(inform){
ansD=inform.num;
res.end(ansA,ansB,ansC,ansD);
return;
- 4、数据库操作函数定义和实现
// 这是连接数据库的函数
const { execSQL } = require('../db/mysql');
const login_check = function(id){
let sql = `select name , pwd from new_table where name = '${id}'`;
// return execSQL(sql);
return execSQL(sql).then(function(rows){
// console.log(rows[0]);
return rows[0];
});
}
const signup_check_tea = function(id,pwd){
let sql = `insert into new_table (name , pwd , identity) values ( '${id}' , '${pwd}' , 'tea');`
return execSQL(sql).then(function(insertedResult){
console.log('insertedResult',insertedResult);
return {
id: insertedResult.insertId
}
});
}
const signup_check_stu = function(id,pwd){
let sql = `insert into new_table (name , pwd , identity) values ( '${id}' , '${pwd}' , 'stu');`
return execSQL(sql).then(function(insertedResult){
console.log('insertedResult',insertedResult);
return {
id: insertedResult.insertId
}
});
}
const answer_write = function(id,ans){
let sql = `update new_table set ans = '${ans}' where name = '${id}';`
return execSQL(sql).then(function(insertedResult){
console.log('insertedResult',insertedResult);
return {
id: insertedResult.insertId
}
});
}
const show_answer = function(ans){
let sql = `select count(*) as num from new_table where ans= '${ans}';`;
return execSQL(sql).then(function(rows){
return rows[0];
})
}
const getlist = function(){
let sql = `select name from new_table where identity = 'stu';`
return execSQL(sql);
}
// const signup_check = function(id,pwd){
// let sql = ``;
// return execSQL(sql);
// }
module.exports = {
login_check,
signup_check_tea,
signup_check_stu,
answer_write,
show_answer,
getlist
}
- 5、连接数据库
// 引入数据库的设置
const { MYSQL_CONFIG } = require('../ifconfig/db')
// 引入mysql的api
const mysql = require('mysql');
//创建连接对象
const connection = mysql.createConnection(MYSQL_CONFIG);
// 开始连接
connection.connect();
// 执行sql语句
// const sql = `select name , pwd from new_table where name ='ys'; `;
// connection.query(sql,function(err,result){
// if (err){
// console.log(err);
// return;
// }
// console.log('result',result);
// });
// 执行SQL语句的函数
// function execSQL(sql,callback){
// connection.query(sql,callback);
// };
function execSQL(sql){
const promise = new Promise(function(resolve,reject){
connection.query(sql,function(err,result){
if (err){
reject(err);
return;
}
resolve(result);
});
});
return promise;
}
module.exports = {
execSQL
}
- 6、数据库设置
这一部分需要在cmd中完成,登入数据库,创建如下的数据库;
CREATE TABLE `login_number`.`new_table` (
`id` INT NOT NULL AUTO_INCREMENT,
`name` VARCHAR(10) NOT NULL,
`pwd` VARCHAR(20) NOT NULL,
`ans` VARCHAR(5) NULL,
`identity` VARCHAR(10) NOT NULL,
PRIMARY KEY (`id`));
或者为了方便,其实可以就在MySQL Workbench或者Navicate中创建。貌似微软之前的Access也行,以后慢慢摸索一下。
- 7、设计html界面
初步设计界面如下
成果如下
- 8、
- 具体部分加上请求操作
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title></title>
<link rel="stylesheet" href="./view/css/index.css" />
<script type="text/javascript" src="http://code.jquery.com/jquery-1.11.0.min.js"></script>
</head>
<body>
<body>
<div class="mainbody middle">
<form class="form-box front">
<div>
<h1 id="ways" style="text-align: center;">欢迎来到我的课堂</h1>
</div>
<div>
<p style="font-size: large; text-align: center; margin-top: 50px;">请选择你的登录身份</p>
</div>
<div><input class="btn-submit tea" type="button" value="教师端" style="margin-top: 130px;" onclick="javascript:location.href='./view/tea.html'" />
<input class="btn-submit stu" type="button" value="学生端" style="margin-top: 10px;" onclick="javascript:location.href='./view/stu.html'" />
</div>
</form>
</div>
</body>
<div class="footer">
<p style="float: right;margin-top: 700px;">数据科学与工程学院 2020级 杨舜 10205501415</p>
</div>
</body>
</html>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title></title>
<link rel="stylesheet" href="./css/index.css" />
<!-- <script type="text/javascript" src="http://code.jquery.com/jquery-1.11.0.min.js"></script> -->
<script src="https://cdn.staticfile.org/jquery/1.10.2/jquery.min.js"></script>
<script type="text/javascript">
function login() {
console.log("yes");
const id = document.getElementById("id1").value;
const pwd = document.getElementById("pwd1").value;
console.log("id",id);
console.log("id",pwd);
if (id === ''){
alert("id can not be empty!");
// window.location.href = "./stu.html"
return;
}
if (pwd === ''){
alert("password can not be empty!")
return;
}
console.log("yes");
alert("确认信息无误");
$.ajax({
timeout : 100,
type: "POST",
// dataType: "json",
url: '/stu/login?id='+id+'&pwd='+pwd,
contentType: "application/json",
data:JSON.stringify({
"id": id,
"pwd": pwd
})
,error:function(){alert('密码错误')}
,success: function () {
// console.log("data is :" + result)
// if (data.code == 200) {
// alert("登陆成功");
// window.open('http://www.baidu.com')
// }else {
// alert(result.message)
// }
alert('响应成功')
console.log("123");
// window.open("http://localhost:8002/view/stupage.html")
window.open("./stupage.html?id="+id)
}
});
}
function signup() {
console.log("yes");
const id = document.getElementById("id2").value;
const pwd = document.getElementById("pwd2").value;
console.log("id",id);
console.log("id",pwd);
if (id === ''){
alert("id can not be empty!");
// window.location.href = "./stu.html"
return;
}
if (pwd === ''){
alert("password can not be empty!")
return;
}
console.log("yes");
alert("确认信息无误");
$.ajax({
type: "POST",
// dataType: "json",
url: '/stu/signup?id='+id+'&pwd='+pwd,
contentType: "application/json",
data:JSON.stringify({
"id": id,
"pwd": pwd
})
,error:function(){alert('响应失败')}
,success: function () {
// console.log("data is :" + result)
// if (data.code == 200) {
// alert("登陆成功");
// window.open('http://www.baidu.com')
// }else {
// alert(result.message)
// }
alert('响应成功')
console.log("123");
window.open("./stupage.html?id="+id);
}
});
}
</script>
</head>
<body>
<body>
<div class="mainbody middle">
<form class="form-box front"> <!--</form>method="GET" action="/stu/login">-->
<div>
<h1 id="ways">学生登陆</h1>
<style>
#ways {
text-align: center;
}
</style>
</div>
<div>
<input id="id1" class="input-normal" name="id" type="text" placeholder="UserAccount" />
<input id="pwd1" class="input-normal" name="pwd" type="password" placeholder="PassWord" />
<input class="btn-submit" type="button" onclick="login()">
</div>
<div>
<p style="margin-top: 40px">If you don't have account.Please</p>
<p>Click here to <a id="signup">注册</a></p>
<script type="text/javascript">
// 点击sigup触发翻转样式
$("#signup").click(function () {
$(".middle").toggleClass("middle-flip");
});
</script>
</div>
</form>
<!-- 对的你没看错,上下两个表单基本上没区别,一个front,一个back -->
<form class="form-box back" ><!--</form>method="GET" action="/stu/signup">-->
<div>
<h1 id="ways">学生注册</h1>
<style>
#ways {
text-align: center;
}
</style>
</div>
<div>
<input id="id2" class="input-normal" name=“id” type="text" placeholder="UserAccount" />
<input id="pwd2" class="input-normal" name=“pwd” type="password" placeholder="PassWord" />
<input class="btn-submit" type="button" onclick="signup()">
</div>
<div>
<p style="margin-top: 40px">Have a account ? You can</p>
<p>Click here to <a id="login">登陆</a></p>
<script type="text/javascript">
// 点击login触发翻转样式
$("#login").click(function () {
$(".middle").toggleClass("middle-flip");
});
</script>
</div>
</form>
</div>
</body>
<div class="footer">
<p style="float: right;margin-top: 700px;">数据科学与工程学院 2020级 杨舜 10205501415</p>
</div>
</body>
</html>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title></title>
<link rel="stylesheet" href="./css/index.css" />
<!-- <script type="text/javascript" src="http://code.jquery.com/jquery-1.11.0.min.js"></script> -->
<script src="https://cdn.staticfile.org/jquery/1.10.2/jquery.min.js"></script>
<script type="text/javascript">
function login() {
console.log("yes");
const id = document.getElementById("id1").value;
const pwd = document.getElementById("pwd1").value;
console.log("id",id);
console.log("id",pwd);
if (id === ''){
alert("id can not be empty!");
// window.location.href = "./stu.html"
return;
}
if (pwd === ''){
alert("password can not be empty!")
return;
}
console.log("yes");
alert("确认信息无误");
$.ajax({
type: "POST",
// dataType: "json",
url: '/tea/login?id='+id+'&pwd='+pwd,
contentType: "application/json",
data:JSON.stringify({
"id": id,
"pwd": pwd
})
,error:function(){alert('密码错误')}
,success: function () {
// console.log("data is :" + result)
// if (data.code == 200) {
// alert("登陆成功");
// window.open('http://www.baidu.com')
// }else {
// alert(result.message)
// }
alert('响应成功')
console.log("123");
window.open("./teapage.html?id="+id)
}
});
}
function signup() {
console.log("yes");
const id = document.getElementById("id2").value;
const pwd = document.getElementById("pwd2").value;
console.log("id",id);
console.log("id",pwd);
if (id === ''){
alert("id can not be empty!");
// window.location.href = "./stu.html"
return;
}
if (pwd === ''){
alert("password can not be empty!")
return;
}
console.log("yes");
alert("确认信息无误");
$.ajax({
type: "POST",
// dataType: "json",
url: '/tea/signup?id='+id+'&pwd='+pwd,
contentType: "application/json",
data:JSON.stringify({
"id": id,
"pwd": pwd
})
,error:function(){alert('响应失败')}
,success: function () {
// console.log("data is :" + result)
// if (data.code == 200) {
// alert("登陆成功");
// window.open('http://www.baidu.com')
// }else {
// alert(result.message)
// }
alert('响应成功')
console.log("123");
window.open("./teapage.html?id="+id)
}
});
}
</script>
</head>
<body>
<body>
<div class="mainbody middle">
<form class="form-box front"> <!--</form>method="GET" action="/stu/login">-->
<div>
<h1 id="ways">教师登陆</h1>
<style>
#ways {
text-align: center;
}
</style>
</div>
<div>
<input id="id1" class="input-normal" name="id" type="text" placeholder="UserAccount" />
<input id="pwd1" class="input-normal" name="pwd" type="password" placeholder="PassWord" />
<input class="btn-submit" type="button" onclick="login()">
</div>
<div>
<p style="margin-top: 40px">If you don't have account.Please</p>
<p>Click here to <a id="signup">注册</a></p>
<script type="text/javascript">
// 点击sigup触发翻转样式
$("#signup").click(function () {
$(".middle").toggleClass("middle-flip");
});
</script>
</div>
</form>
<!-- 对的你没看错,上下两个表单基本上没区别,一个front,一个back -->
<form class="form-box back" ><!--</form>method="GET" action="/stu/signup">-->
<div>
<h1 id="ways">教师注册</h1>
<style>
#ways {
text-align: center;
}
</style>
</div>
<div>
<input id="id2" class="input-normal" name=“id” type="text" placeholder="UserAccount" />
<input id="pwd2" class="input-normal" name=“pwd” type="password" placeholder="PassWord" />
<input class="btn-submit" type="button" onclick="signup()">
</div>
<div>
<p style="margin-top: 40px">Have a account ? You can</p>
<p>Click here to <a id="login">登陆</a></p>
<script type="text/javascript">
// 点击login触发翻转样式
$("#login").click(function () {
$(".middle").toggleClass("middle-flip");
});
</script>
</div>
</form>
</div>
</body>
<div class="footer">
<p style="float: right;margin-top: 700px;">数据科学与工程学院 2020级 杨舜 10205501415</p>
</div>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<link rel="stylesheet" href="./css/page.css">
<script src="https://cdn.staticfile.org/jquery/1.10.2/jquery.min.js"></script>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>学生界面</title>
<script type="text/javascript">
function download(){
$.ajax({
type:"get",
url:'/filedown',
responseType: 'blob',
error:function(){
alert("错误");
},
success:function(){
alert("开始下载");
}
}).then(function (response) {
// handle success
console.log(response);
})
.catch(function (error) {
// handle error
console.log(error);
})
.finally(function () {
// always executed
});
};
</script>
<!-- <script>
const btn = document.querySelector('#download');
btn.addEventListener('click', function (e) {
axios({
url: 'http://localhost:8086/getFile?filename=test.txt',
responseType: 'blob',
method: 'get',
}).then(function (response) {
// handle success
console.log(response);
})
.catch(function (error) {
// handle error
console.log(error);
})
.finally(function () {
// always executed
});
});
</script> -->
<script type="text/javascript">
function checkquestion(){
$.ajax({
url:"/check_qusetion",
type:"get",
error: function(){
alert("失败");
},
success: function(data){
alert(data);
alert("ok");
}
})
}
</script>
</head>
<body>
<div class="header">
<h1 style="text-align: center;font-size:xx-large">基于树莓派nodejs的便携式教学工具开发</h1>
<h2 style="text-align: center;font-size: larger;">欢迎来到我的课堂</h2>
</div>
<div class="leftpart_up" id="1">
<!-- <input class="des" onclick="download()" style="text-decoration:none" value="下载文件" type="button"> -->
<a href="/filedown" style="text-decoration:none" class="des" download="/public/upfile.txt">文件下载</a>
</div>
<div class="leftpart_down_left" id="4">
<a class="des" href="./answer.html" style="text-decoration: none;">开始答题</a>
</div>
<div class="leftpart_down_right" id="5">
<button class="des" onclick="checkquestion()" style="background-color: greenyellow;">查看题目</button>
</div>
</div>
<div class="middle" id="6">
<p class="des">开始视频课堂</p>
</div>
<div>
<div class="rightpart_up" id="2">
<p class="des">学生列表</p>
</div>
<div class="rightpart_down" id="3">
<p class="des">签到</p>
</div>
</div>
<script>
$("#1,#2,#3").mouseover(function(){
$(this).animate({
width:'365px',
height:'265px'
},50);
})
$("#1,#2,#3").mouseout(function(){
$(this).animate({
width:'350px',
height:'250px'
},50);
})
$("#4,#5").mouseover(function(){
$(this).animate({
width:'180px',
height:'265px'
},50);
})
$("#4,#5").mouseout(function(){
$(this).animate({
width:'170px',
height:'250px'
},50);
})
$("#6").mouseover(function(){
$(this).animate({
width:'660px',
height:'520px'
},50);
})
$("#6").mouseout(function(){
$(this).animate({
width:'650px',
height:'510px'
},50);
})
</script>
<!-- <script>
$("#1").mousemove(function(){
$(this).stop().animate({
width:'360px',
height:'235px'
},50);
$(this).prev().stop().animate({
width:'360px',
height:'235px'
},50);
$(this).next().stop().animate({
width:'360px',
height:'235px'
},50);
})
$("#1").mouseout(function(){
$(this).stop().animate({
width:'350px',
height:'225px'
},20);
$(this).prev().stop().animate({
width:'350px',
height:'225px'
},20);
$(this).next().stop().animate({
width:'350px',
height:'225px'
},20);
})
</script> -->
<div class="footer">
<p style="float: right;margin-top: 550px;">数据科学与工程学院 2020级 杨舜 10205501415</p>
</div>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<link rel="stylesheet" href="./css/page.css">
<script src="https://cdn.staticfile.org/jquery/1.10.2/jquery.min.js"></script>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>教师界面</title>
<script>
function fileup() {
// 单文件上传
alert("ok");
console.log("yes");
var fileList = $('#singleFile')[0].files;
console.log(fileList);
var formData = new FormData();
//此处文件名必须为 singleFile ,因为后台设置仅接口此文件名
formData.append('singleFile', fileList[0]);
$.ajax({
url: '/fileupload',
type: 'post',
processData: false,
contentType: false, //使用multer配合ajax时无需配置multipart/form-data,multer将自动配置,手动配置将报错,boundary not found
data: formData,
error: function(){
alert("上传失败");
},
success: function (data) {
console.log(data)
alert("上传成功");
}
})
}
</script>
<script type="text/javascript">
console.log(location.toString());
function checkquestion(){
$.ajax({
url:"/check_qusetion",
type:"get",
error: function(){
alert("失败");
},
success: function(data){
alert(data);
alert("ok");
}
})
}
</script>
</head>
<body>
<div class="header">
<h1 style="text-align: center;font-size:xx-large">基于树莓派nodejs的便携式教学工具开发</h1>
<h2 style="text-align: center;font-size: larger;">欢迎来到我的课堂</h2>
</div>
<div class="single leftpart_up" id="1">
<input type="file" style="background-color: coral;" name="singleFile" id="singleFile">
<input type="button" class="single_submit des" style="background-color: coral;" onclick="fileup()" value="上传文件">
</div>
<div class="leftpart_down_left" id="4">
<a class="des" href="./question.html" style="text-decoration: none;">上传题目</a>
</div>
<div class="leftpart_down_right" id="5">
<!-- <button class="des" onclick="checkquestion()" style="background-color: greenyellow;">查看题目</button> -->
<a class="des" href="./1.html" style="text-decoration: none;">查看答题情况</a>
</div>
</div>
<div class="middle" id="6">
<p class="des">开始视频课堂</p>
</div>
<div>
<div class="rightpart_up" id="2">
<a class="des" href="/stulist" style="text-decoration: none;">学生列表</a>
</div>
<div class="rightpart_down" id="3">
<p class="des">签到</p>
</div>
</div>
<script>
$("#1,#2,#3").mouseover(function () {
$(this).animate({
width: '365px',
height: '265px'
}, 50);
})
$("#1,#2,#3").mouseout(function () {
$(this).animate({
width: '350px',
height: '250px'
}, 50);
})
$("#4,#5").mouseover(function () {
$(this).animate({
width: '180px',
height: '265px'
}, 50);
})
$("#4,#5").mouseout(function () {
$(this).animate({
width: '170px',
height: '250px'
}, 50);
})
$("#6").mouseover(function () {
$(this).animate({
width: '660px',
height: '520px'
}, 50);
})
$("#6").mouseout(function () {
$(this).animate({
width: '650px',
height: '510px'
}, 50);
})
</script>
<!-- <script>
$("#1").mousemove(function(){
$(this).stop().animate({
width:'360px',
height:'235px'
},50);
$(this).prev().stop().animate({
width:'360px',
height:'235px'
},50);
$(this).next().stop().animate({
width:'360px',
height:'235px'
},50);
})
$("#1").mouseout(function(){
$(this).stop().animate({
width:'350px',
height:'225px'
},20);
$(this).prev().stop().animate({
width:'350px',
height:'225px'
},20);
$(this).next().stop().animate({
width:'350px',
height:'225px'
},20);
})
</script> -->
<div class="footer">
<p style="float: right;margin-top: 550px;">数据科学与工程学院 2020级 杨舜 10205501415</p>
</div>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<script src="https://cdn.staticfile.org/jquery/1.10.2/jquery.min.js"></script>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Answer</title>
<style>
body{ text-align:center;background-image: url("./image/bg5.jpg");}
.box{margin:0 auto;margin-top: 250px;width:400px; height:80px;border:1px solid black;background-color:whitesmoke;opacity: 0.85;}
</style>
<script type="text/javascript">
function ansubmit(){
const ans = document.getElementById("ans").value;
const id = document.getElementById("id").value;
console.log(ans);
console.log(id);
alert("yes");
$.ajax({
type:'post',
url:'/answer?id='+id+'&ans='+ans,
contentType:"application/json",
data:JSON.stringify({
"id": id,
"ans": ans
})
,error:function(){alert('响应失败')}
,success:function(){alert('提交成功');window.open('./stupage.html')}
})
}
</script>
</head>
<body>
<form>
<fieldset class="box">
<legend>回答</legend>
答案:<input type="text" id="ans"/>
id:<input type="text" id="id"/><br><br>
<input type="button" onclick="ansubmit()" value="submit">
</fieldset>
</form>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<script src="https://cdn.staticfile.org/jquery/1.10.2/jquery.min.js"></script>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Question</title>
<style>
body{ text-align:center;background-image: url("./image/bg5.jpg");}
.box{margin:0 auto;margin-top: 250px;width:400px; height:200px;border:1px solid black;background-color:whitesmoke;opacity: 0.85;}
</style>
<script type="text/javascript">
function qusubmit(){
const que = document.getElementById("que").value;
const A = document.getElementById("A").value;
const B = document.getElementById("B").value;
const C = document.getElementById("C").value;
const D = document.getElementById("D").value;
$.ajax({
type:'post',
url:'/question',
contentType:"application/json",
data:JSON.stringify({
"question": que,
"A": A,
"B": B,
"C": C,
"D": D
})
,error:function(){alert('响应失败')}
,success:function(){alert('提交成功');window.open('./teapage.html')}
})
}
</script>
</head>
<body>
<form>
<fieldset class="box">
<legend>题目设置</legend>
题目描述: <input type="text" id="que"/><br><br>
A: <input type="text" id="A"/>
B: <input type="text" id="B"/><br>
C: <input type="text" id="C"/>
D: <input type="text" id="D"/><br><br>
<input type="button" onclick="qusubmit()" value="submit">
</fieldset>
</form>
</body>
</html>
至此代码部分基本完成接下来就是树莓派的处理了
- 9、树莓派操作
1.下载最新Raspbian系统映像文件buster
建议选择已安装桌面系统和推荐软件的这个映像。
https://www.raspberrypi.org/downloads/raspbian/
2.下载ethcher软件
3.用ethcer将最新Raspbian系统映像文件写入存储卡
4.为了更快的下载安装速度,可以将系统源更改为国内的软件源
sudo nano / etc /apt/ sources.list
保险起见,不推荐直接修改,而是注释掉原来的内容,改成如下内容:
deb https://mirrors.aliyun.com/raspbian/raspbian/ buster main non-free contrib
deb- src https://mirrors.aliyun.com/raspbian/raspbian/ buster main non-free contrib
Nano 中修改保存退出( ctrl+o , ctrl+x )后,可以进行系统更新
sudo apt-get update
sudo apt-get upgrade
5.将树莓派安装成Wifi热点,可参照此链接
https://zhuanlan.zhihu.com/p/102598741
6.在树莓派上创建mysql,参见博客
7.把电脑上的wed服务器文件拷入树莓派,并用终端运行www.js
- 10、测试
电脑连入树莓派的热点,并以树莓派的ip和定义的端口访问网站
后记
本次实验的完成度与自己开始的预想并不完全相同,自己的一些想法因为时间和本人的能力水平而没能实现,但是在屡屡碰壁的学习过程中我慢慢学会了翻阅博客,github等其他的网路资料,作为一门实践性的课程,我已经学会并掌握了web服务器开发的基本知识以及开发的原理和流程,但是对于一些更复杂的操作和功能实现,我还需要更多地去查询资料以及对操作实践。
另外通过与老师的交流汇报,我发现了自己仍还有较大的补充空间,例如多个数据库的创建,回调函数的简化,等等的操作都可以让我继续深入地学习运用。