昨天继续在写用jsoup爬取教务系统中学生成绩,在数据爬取后,需要在用户登录的时候,及时爬取该用户在教务系统中的学习成绩,防止学生成绩更新,然后将最新的成绩存储到score表中,这就有如下的几个问题:
1.当用户第一次使用test.jsp进行登录的时候,score表中没有该用户的成绩,需要通过score检索来判断是否存在用户成绩信息 ,然后根据返回值来确定是插入还是更新(其实第一次应该默认为插入数据),
2.当用户曾使用过test.jsp模拟登录(也就是score表中曾在用户的成绩信息),这时候就需要判断score表中的成绩信息和教务系统中爬取出来的成绩信息是否一样,当两者一样的时候,应该不进行任何操作,当两者不一样的时候,我们又需要判断score表中的成绩信息和教务系统成绩信息的差别,我们的目的是做到score中的数据,同步教务系统而不重复.
3.我们知道,当某同学挂科时候,其实是有两个该课程的分数,只是标志不一样,就像这样(这是我昨天做好存入到score表中的数据).
也就是说,我们如果想根据学号+课程名称来联合查找,是否存在该课程成绩(1.成绩更新2.老师上传成绩错误,出现修改(我的成绩曾经就这样过)3.补考),这样最直接的错误就是,当出现补考的 时候,我们的判断思路就出现了明显的问题,存取的数据也会出现遗漏(判断过程中的特殊情况遗漏).
4.我昨天下午一直在 修改这个问题,可能是我的思路太直接,过分的判断操作的if.....else情况,没有想过从反面来操作,这样更好,我昨天最原始的做法,代码如下,记录一哈
private void diffWayByJudge(int i) {
// 由于存在多科目的成绩,所以没有课做做完循环读取后,就应该将score对象写入到score表中,以免数据覆盖
if (i % 14 == 0) {
System.out.println(i);
// 循环一科目,i递加13,等到i++到14时,就往score表中存储对象
ScoreDAO scoreDAO = new ScoreDAO();
score.setSid(student.getSid());
//通过sid查询,课程名称来判断score表中是否有sid学号的成绩记录,是否需要插入 数据,避免重复往数据库中添加数据
try {
if (scoreDAO.findScoreBySid(student.getSid()) != null) {
// 存在socre对象集合,有成绩记录,可尝试更新
System.out.println("!!!!!!!!!-->" + score.getKcmc());// 当i=14的整数倍的时候,其实,是获取上一个score的getkcmc()值,出现错误;
Score jScore = new Score();
jScore = scoreDAO.findScoreBySidAndKcmc(student.getSid(), score.getKcmc());
if (jScore == null) {
// 不存在,需要将该科目写入到数据库中入
scoreDAO.insert(score);
} else {
/**
* 存在,尝试更新(考虑到老师在上传成绩的时候,出现问题,学生申诉,以免二次存储无法刷新)
* 也有可能该科目存在补考
*/
// 判断补考的情况,两次分数不一样,而且两个的考试性质不一样
if (jScore.getZcj() != score.getZcj() && jScore.getKsxz() != score.getKsxz()) {
// 补考
scoreDAO.insert(score);
} else if (jScore.getZcj() == score.getZcj() && jScore.getKsxz() == score.getKsxz()) {
// 数据重合,覆盖;不能进行数据库操作
} else {
// 教师上传成绩错误,及时更正结果
scoreDAO.update(score);
}
}
} else {
// 之前没有该学生的数据集,直接插入数据
scoreDAO.insert(score);
}
} catch (ClassNotFoundException | SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
像这样的分多种情况考虑,到最后,其实混淆了自己的思路 ,相反不能够很好的得到操作的结果.不过昨天在买晚饭回来的路上,我想到的另外一种做法,刚好是我之前用diffWayByJudge(int i)来判断的反面,我的思路是:
当用户用test.jsp登录成功后,我只需要用用户的学号向数据库中查询,是否存在该学生的成绩记录,这样如果存在,我们就直接将所有的记录删除,我们要做的其实就是同步教务系统的成绩信息 ,那么直接将之前有的或没有的信息都做一个判断之后,删除,然后将该学号学生的是所有最新成绩,插入到score表中,将数据及时的更新,这样便不会存在数据遗漏的问题.
代码如下:
/**
* 方法一:直接判断后台的score表中是否有该学号同学的成绩记录,直接将其全部删除,然后重新将从教务系统网页源码上爬取下来的成绩记录存入到是score表中,实现更新;
* 优点:1.可实现更新,且思路清晰
* 2.和判断多种成绩情况(补考,成绩登记错误等情况)相比,这种思路更加直接,且能够在用户进行登录的同时,实时的将成绩存储到score
* 3.代码量小,容易判断 操作 方法二:diffWayByJudge() 功能不完善
*/
ScoreDAO scoreDAO = new ScoreDAO();
try {
if (scoreDAO.findScoreBySid(student.getSid()) != null) {
// 存在记录,直接删除
scoreDAO.deleteBySid(student.getSid());
if (scoreDAO.findScoreBySid(student.getSid()) == null) {
// 删除记录成功
System.out.println("记录删除成功!");
}
}
int i = 1;//循环标记
for (Element element : tr) {
switch (i % 13) {
// 开课学期
case 4:
score.setKkxq(element.text().trim());
System.out.print(element.text() + "\t");
break;
// 课程名称
case 5:
score.setKcmc(element.text().trim());
System.out.print(element.text() + "\t");
break;
// 考试分数
case 6:
score.setZcj(element.text().trim());
System.out.print(element.text() + "\t");
String onclickStr = element.select("a").attr("onclick");
// 截取成绩详情的url链接,写入
score.setCjurl(onclickStr.substring(onclickStr.indexOf("'") + 1, onclickStr.lastIndexOf("'")));
System.out.println(
onclickStr.substring(onclickStr.indexOf("'") + 1, onclickStr.lastIndexOf("'")) + "\t");
break;
// 课程性质
case 8:
score.setKcxz(element.text().trim());
System.out.print(element.text() + "\t");
break;
// 课程类别
case 9:
score.setType(element.text().trim());
System.out.print(element.text() + "\t");
break;
// 学时
case 10:
score.setTime(element.text().trim());
System.out.print(element.text() + "\t");
break;
// 课程学分
case 11:
score.setXf(element.text().trim());
System.out.print(element.text() + "\t");
break;
// 考试性质
case 12:
score.setKsxz(element.text().trim());
System.out.print(element.text() + "\t");
break;
// 补考时间
case 0:
score.setBkxq(element.text().trim());
System.out.print(element.text() + "\t");
System.out.println("-------------------");
break;
default:
break;
}
if (i%13==0) {
// 对score表,直接插入数据
scoreDAO.insert(score);
}
i++;
}
// 尝试更新学习成绩,可记录到record表中;
} catch (ClassNotFoundException | SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
总结一哈:
错误的路上需要我们不断的尝试错误,这样才能在茫然无措的时候,否定之前的做法,向死而生,生活也是一样,不能总是盯着一面看,我们要 学会看事物的背面,这样才能有收获!