记录下做项目(在线考试系统)遇到的问题

1.使用post提交url不隐藏参数的问题

注册功能,表单采用ajax提交时。指明post提交还是会出现url参数未隐藏。但是数据成功被提交到了数据库。
排查发现是注册这个按钮的问题。

<button id="register">注册</button>

如果用a链接标签

<a href="javascript:;"  id="register">注册</a>

一切正常
为什么呢?因为button默认是type=sumbit,包括input提交按钮也是。如果类型为submit,那么点击时就会提交表单。所以将button标签或者input添加一个type属性,设置为button即可

ajax提交表单时,按钮类型应该是button,不能是submit。

2.引入bootstrap样式无效果

引入bootstrap路径正确通过127.0.0.1:3000/index.html发现无样式。本地文件打开正常。
查看控制台报错如下
Refused to apply style from 'http://localhost:3000/node_modules/bootstrap/dist/css/bootstrap.min.css' because its MIME type ('text/html') is not a supported stylesheet MIME type, and strict MIME checking is enabled.
是因为通过npm安装的bootstrap安装到了node_modules文件夹下。而我在入口文件中启用静态资源,只是默认的public文件下。所以由于静态资源访问限制导致。
所以可以添加app.use(express.static(path.join(__dirname, 'node_modules')));
或者将bootstrap的文件拷贝到public下

3.mysql多表的同步问题

mysql进行表的同步问题
创建触发器
https://blog.csdn.net/qq_21891743/article/details/85061495
https://www.jb51.net/article/35123.htm

CREATE <触发器名> < BEFORE | AFTER >
<INSERT | UPDATE | DELETE >
ON <表名> FOR EACH Row<触发器主体>

创建插入触发器

create trigger studentInsert after insert
on user for each row
begin
INSERT INTO student(username,password) VALUES(new.username,new.password);
END;

反之亦然

create trigger userInsert after insert
on student for each row
begin
INSERT INTO user(username,password) VALUES(new.username,new.password);
END;

但是出现问题了。修改A表,B表可以同步。但是修改B表,A表不改变。而且还不能相互都加触发器。暂时不知道怎么解决

或者是设置连接字符串的配置时,添加属性multipleStatements: true。默认是关闭,只能执行一条。
今天想起来以前学的细节点的数据库内容。印象中和外键可能有关。有空查

4.文件引入顺序

在做数据列表渲染时。导jquery文件放在了js文件后。导致出错。

5.mysql [Err] 1054

前期使用的json接口。在进行ajax请求时,一直路径不对。网上查,都是使用restful接口的。但是改了后还是不对,最后发现后台返回的设的标志位为2.也就是没影响到行数。去MySQL中查看,数据并未发生改变。将语句单独取出在MySQL中运行。神奇的是,个别能成功。个别不成功,这时候就会返回标志位为2。
报错如下[SQL]delete from student where username=sad [Err] 1054 - Unknown column 'sad' in 'where clause'
猜测是关键字或是字符格式问题,导致。
修改全为数字才成功。
但是又发现有几率出错。未解决

6.request请求的req.body、req.params、req.query区分

关于req.body、req.params、req.query
首先req.params,req.query是用在get请求当中,而req.body是用在post请求中的。
而req.params,req.query的区分粗略查了下没明确说明。有空查官方文档。

7.请求后服务器返回两次或者两次以上的响应

在做文件上传下载有这么个错误。上传成功,但是重定向回上传的页面。服务器就终止报错了。
在这里插入图片描述
Cannot set headers after they are sent to the client
查了资料。
怎么回事呢?
是由于在一次请求后服务器返回两次或者两次以上的响应。
因为我在res.redirect没有return声明的情况下进行调用,所以此后函数也立即被调用。
更详细了解的话可以看此处:https://stackoverflow.com/questions/7042340/error-cant-set-headers-after-they-are-sent-to-the-client

8.(大坑)文件下载的文件

postman插件测试正常。能得到文件。但是在进行前端渲染时。ajax请求会进入error。
通过表单里的按钮,可以第一次ajax请求通过id拿到存储的文件信息。但是在进行二次ajax时,会发现一直进入error。查看后台,发现文件名是拼接正确的。虽然中文会有编码错误导致路径不对而失败。但是纯英文的路径正确仍然是进入erro下载失败。
在这里插入图片描述
在这里插入图片描述
废了不少功夫,解决了。详细另开新篇。

9.(小坑)Failed to lookup view “/login.ejs” in views directory “views”

在这里插入图片描述

10.暂搁 sessionid在火狐的问题。

做完用户的状态后。测试发现。在谷歌以及edge均无问题。而在火狐中出现情况就是登陆成功后,在点击跳转其他页面,就会被打回登陆页面。查看发现火狐不知道为什么访问其他页面先访问了登陆的虚拟路径。由于我设置当回到登陆页面将sessionid销毁,就会导致以上情况。其余浏览器正常。

11.使用jquery时.html()、.text()、.val()的不仔细

都知道这三种各有各的含义。
在做分页跳转时,将前台的点击的页数值获取传到后面。由于错误使用导致整体逻辑写完后驳回。再分一步步回顾时,发现ejs模板也是写错了一点。
应该一步步确保每步都确定得到自己想要的结果后,再往下。这次想一蹴而就就导致了问题。

12.req.query、req.body和req.params的区别

get请求是使用req.params、req.query。 post请求是req.body

而且req.params是用于restful接口的对应路径形式http://localhost:3000/books/book/1
而传统urlhttp://localhost:3000/toEditBook?id=1则是req.query获取

另外req.body是需要用到body-parser第三方中间件。
补充,如果是restful的put请求,也是req.body

经过仔细排查。发现问题。首先是使用ajax传递页数page和每页数量pigeSize时。传递过来的参数。不是整形。没有经过Number.parserInt()处理。使得在插入sql语句时,值不对(NaN)。
还有就是使用了get请求req.params并没有得到传递过来的值。改用req.query才获取到。
大体上,get请求使用req.query和req.params来获取数据。而post请求使用req.body。而像其他的第三方包比如multer获取到文件信息就是req.files。那么req.query和req.params的区别是什么呢?
虽然两者都是get请求。但是不同的是req.query获取到的url是传统的url风格。比如http://localhost:3000/?id=10。而req.params则是restful接口风格的url,比如http://localhost:3000/10
之前写的一些get请求的接口,在路由处理时风格我都是使用的restful接口的url。

router.get('students/student/:id',(req,res)=>{

})

所以是使用req.params正确获取到url参数。而在补充分页时,我写的

router.get('students/count',(req,res)=>{

 })

所以这里应该是req.query。就是这个细节,导致第一次尝试的失败。好在排查也解决了

13.ajax异步文件上传

在开始,这个上传还是很简单的。只需要借助multer中间件就可以完成。使用的表单提交方式,但是问题还是来了。经测试,没有上传成功的提示普遍用户体验不良好。行吧,那就改ajax。
但是ajax表单提交也没那么简单。对于文件上传来说,有一个坑。最后查了许多资料。通过FormDate对象的使用解决了问题。

14.(大坑)数据库操作顺序问题

今天在优化时,想要处理上传文件同步到数据的信息重复问题。做了个判断,先查找已有的,如果重复就删除,然后再插入。但是在写完代码后,进行测试。发现了问题。

let filename = fileList[i].originalname
                // console.log(filename);
                let checksql = 'select * from homework where filename=? and username=?';
                let checkdata = [filename,username];
                db.base(checksql,checkdata,(result)=>{
                    //有就删除  注意这里之所以写重复是因为会将if条件外的先执行,再执行if里面的。也就是说先插入再删除。应该说是删除相应的db函数里的代码最后执行
                    if(result.length != 0){
                        // console.log('查到'+result.length+'条'+filename);
                        let deletesql = 'delete from homework where filename=? and username=?';
                        let deletedata = [filename,username];
                        db.base(deletesql,deletedata,(result)=>{
                            //删除同username同filename数据
                            let sql = 'insert ignore into homework set username=?,name=?,description=?,filename=?';
                            let data = [username,info.name,info.description,filename];
                            db.base(sql,data,(result)=>{
                                // console.log('删完了已有的'+filename+ '-----'+ filename +"插入数据库成功"+i);
                            })
                        })
                        let sql = 'insert ignore into homework set username=?,name=?,description=?,filename=?';
                        let data = [username,info.name,info.description,filename];
                        db.base(sql,data,(result)=>{
                            // console.log(filename+ "插入数据库成功"+i);
                        })
 }) 
                   

一开始大概是这样的。查到了,如果查到数量不为0,进行删除。然后插入。但是
在这里插入图片描述
问题来了,先插入再删除。他的执行顺序,调用删除的封装好的操作数据库的函数里的语句是最后执行。

15.textarea的基线对齐

遇到这么个情况,下面的input和前面的文字都是正常。设置相同的样式。而第一个textare文本域发现他前方的文字与文本域不对齐。导致无法居中效果。在这里插入图片描述
而且查看下面input标签与textare标签的距离发现。除了自身的高度和margin,还有一层不知出处的空白区域。而控制台看到的元素盒子也并无此区域。
在这里插入图片描述
再查看正常的input标签。自身的高度和margin上就是上一个input标签而无空白区域。而且已经清除了默认的margin和padding在这里插入图片描述
想到一种可能,和图片容易遇到的问题一样,垂直对齐是基线对齐了。而前方的文字也是因此掉了下去。设置vertical-align:bottom;
解决。

16.twbs-pagination 条件查询的分页问题

主要遇到两个问题。
第一个是由于我是点击后获取到查询的依据类别type。而由于它定义在函数中,是个局部变量。虽然可以成功获取到当前类别的分页总数。但是,点击后,无法分页渲染列表。经过一段段的调试,发现时渲染时的type是undefined。需要定义为全局变量,才可以在加载页面数据的initTypeList(page)中得到type值。

$('#page2').twbsPagination({
        totalPages: Math.ceil(data.result/pageSize),   
        visiblePages: 5,        //可见页码
        first: '首页',
        next: '下一页',
        prev: '上一页',
        last: '尾页',
        onPageClick: function (event, page) {
            initTypeList(page);
        }
});

第二个,当点击后,第一次成功。第二次点击其他条件页面无变化。控制台发现第二次并没有进入到上面的代码段中。其实是涉及到动态设置页数以及页面初始化,分页插件的总页数更改。需要先将原来的destory。才可以实现刷新或重绘。否则加载页面数据onPageClick的函数并没有进入,也就没有initTypeList(page);

可以通过两个简单的步骤来完成。
先调用destroy方法,然后使用新选项对其进行初始化。

$('#page2').twbsPagination('destroy');
$('#page2').twbsPagination({
        totalPages: Math.ceil(data.result/pageSize),   
        visiblePages: 5,        //可见页码
        first: '首页',
        next: '下一页',
        prev: '上一页',
        last: '尾页',
        onPageClick: function (event, page) {
            initTypeList(page);
        }
});

更完整的代码以及说明可以看这篇博文。

17.使用ejs模板渲染题目时,单选按钮出现点击混乱。

原因是遍历的时候,使用的循环遍历。开始没对每个题目进行区分。
他们的name属性和label属性所绑定的id都是一样的。
就会导致判断题,所有的题,只能有一题可以选。而选择题,点击第一题的A选项,可能勾选的是其他的题目,或者点其他的题目选项,把之前的一题答案给更改了。

对于单选radio来说,name的属性值是标榜是否同一个单选项的参考。所以对于一题来说,他们的name 属性必须一致 ,而不同题的name应该不同,此外label标签的for属性绑定的id也是同理。

解决方法,id或者name后增加了遍历的专属题目号<%= data[i].question_id%>

18.ajax往后台传递对象数据的问题

一开始没注意,直接将对象写在了数据头中。

data: {
	'username': username,
	'titleObj': titleObj
}

因为dataType是json。传到后台就会发现,对象被拆开成json数据中去了。然后你不能按你所想的获取。

要注意的是,传递对象数据时,要首先将对象转为json形式字符串,

data: {
	'username': username,
	'titleObj': JSON.stringify(titleObj),
}

然后在后台我们再通过JSON.parse()进行将json形式字符串转为对象的操作。
let titleObj = JSON.parse(req.body.titleObj);

19.批阅试卷时从数据库中获取到的不是按题号顺序的,通过对象数组的每个对象的题号属性进行排序

从数据库获取到考生题目信息是一个对象数组,每一题我都是存在一个对象数组的对象中。这个题目对象有个题号属性,我们可以通过对对象属性进行排序解决由于数据库存储的不按顺序所导致的获取渲染时题目的紊乱。

function compare(property) {
	return function (a, b) {
		return a[property] - b[property];
	}
};
answerData.sort(compare('question_id'));

题目数组调用sort()排序方法,里面传入我们写好的排序规则的函数

20.操作数据库封装的函数改进:将错误交给用户进行流程控制

在之前实现业务逻辑时,封装的操作数据库的函数是出错就抛出

connection.query(sql,data, function(error, results, fields) {
	if (error) throw error;
	callback(results);
});

整体完成逻辑后优化发现并不良好。比如当主键重复插入冲突,抛出了错误,但是我们无法进行控制。
在这里插入图片描述

connection.query(sql,data, function(error, results, fields) {
	if (error) return callback(error);
	callback(results);
});

然后我们在进行调用这个封装好的函数后,就可以错误时进行异常捕获

 db.base(sql,data,(result)=>{
        if(result.errno) {
            console.log(result.errno);
            res.json({
                flag : 2,
                errno : result.errno
            })
        }else if(result.affectedRows == 1){
            res.json({flag : 1});           //反回一个标记 falg=1成功
        }
})
相关推荐
简介 笔者当初为了学习JAVA,收集了很多经典源码,源码难易程度分为初级、中级、高级等,详情看源码列表,需要可以直接载! 这些源码反映了那时那景笔者对未来盲目,对代码热情、执着,对IT憧憬、向往!此时此景,笔者只专注Android、Iphone等移动平台开发,看着这些源码心中有万分感慨,写此文章纪念那时那景! Java 源码包 Applet钢琴模拟程序java源码 2个目标文件,提供基本音乐编辑功能。编辑音乐软件朋友,这款实例会对你有所帮助。 Calendar万年历 1个目标文件 EJB 模拟银行ATM流程及操作源代码 6个目标文件,EJB来模拟银行ATM机流程及操作:获取系统属性,初始化JNDI,取得Home对象引用,创建EJB对象,并将当前计数器初始化,调用每一个EJB对象count()方法,保证Bean正常被激活和钝化,EJB对象是用完毕,从内存中清除,从账户中取出amt,如果amt>账户余额抛出异常,一个实体Bean可以表示不同数据实例,我们应该通过主键来判断删除哪个数据实例…… ejbCreate函数用于初始化一个EJB实例 5个目标文件,演示Address EJB实现 ,创建一个EJB测试客户端,得到名字上文,查询jndi名,通过强制转型得到Home接口,getInitialContext()函数返回一个经过初始化文,用clientgetHome()函数调用Home接口函数得到远程接口引用,用远程接口引用访问EJB。 EJB中JNDI使用源码例子 1个目标文件,JNDI使用例子,有源代码,可以载参考,JNDI使用,初始化Context,它是连接JNDI树起始点,查找你要对象,打印找到对象,关闭Context…… ftp文件传输 2个目标文件,FTP目标是:(1)提高文件共享性(计算机程序和/或数据),(2)鼓励间接地(通过程序)使用远程计算机,(3)保护用户因主机之间文件存储系统导致变化,(4)为了可靠和高效地传输,虽然用户可以在终端上直接地使用它,但是它主要作用是供程序使用。本规范尝试满足大型主机、微型主机、个人工作站、和TACs 不同需求。例如,容易实现协议设计。 Java EJB中有、无状态SessionBean两个例子 两个例子,无状态SessionBean可会话Bean必须实现SessionBean,获取系统属性,初始化JNDI,取得Home对象引用,创建EJB对象,计算利息等;在有状态SessionBean中,用累加器,以对话状态存储起来,创建EJB对象,并将当前计数器初始化,调用每一个EJB对象count()方法,保证Bean正常被激活和钝化,EJB对象是用完毕,从内存中清除…… Java Socket 聊天通信演示代码 2个目标文件,一个服务器,一个客户端。 Java Telnet客户端实例源码 一个目标文件,演示Socket使用。 Java 组播组中发送和接受数据实例 3个目标文件。 Java读写文本文件示例代码 1个目标文件。 java俄罗斯方块 一个目标文件。 Java非对称加密源码实例 1个目标文件 摘要:Java源码,算法相关,非对称加密   Java非对称加密源程序代码实例,本例中使用RSA加密技术,定义加密算法可用 DES,DESede,Blowfish等。   设定字符串为“张三,你好,我是李四”   产生张三密钥对(keyPairZhang)   张三生成公钥(publicKeyZhang)并发送给李四,这里发送是公钥数组字节   通过网络或磁盘等方式,把公钥编码传送给李四,李四接收到张三编码后公钥,将其解码,李四用张三公钥加密信息,并发送给李四,张三用自己私钥解密从李四处收到信息…… Java利用DES私钥对称加密代码实例 同上 java聊天室 2个目标文件,简单。 java模拟掷骰子2个 1个目标文件,输出演示。 java凭图游戏 一个目标文件,简单。 java求一个整数因子 如题。 Java生成密钥实例 1个目标文件 摘要:Java源码,算法相关,密钥   Java生成密钥、保存密钥实例源码,通过本源码可以了解到Java如何产生单钥加密密钥(myKey)、产生双钥密钥对(keyPair)、如何保存公钥字节数组、保存私钥到文件privateKey.dat、如何用Java对象序列化保存私钥,通常应对私钥加密后再保存、如何从文件中得到公钥编码字节数组、如何从字节数组解码公钥。 Java数据压缩与传输实例 1个目标文件 摘要:Java源码,文件操作,数据压缩,文件传输   Java数据压缩与传输实例,可以学习一实例化套按字、得到文件输入流、压缩输入流、文件输出流、实例化缓冲
©️2020 CSDN 皮肤主题: 游动-白 设计师:白松林 返回首页