Skip to content

Commit

Permalink
初次提交所有代码
Browse files Browse the repository at this point in the history
  • Loading branch information
Yuki-Nagato committed Feb 18, 2018
0 parents commit c3f5bdb
Show file tree
Hide file tree
Showing 11 changed files with 420 additions and 0 deletions.
6 changes: 6 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
*
!.gitignore
!*/
!*.java
!lib/*
!config/config.example.yaml
23 changes: 23 additions & 0 deletions config/config.example.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# 每轮查询的间隔(秒),建议设置为600以上
interval: 600
# 记录当前成绩的文件(JSON)
record-file: grades-record.json

# 需要查询的学生
students:
- id: 学生1学号
password: 学生1密码
email: 学生1邮箱
- id: 学生2学号
password: 学生2密码
email: 学生2邮箱
# 更多的学生用类似格式添加

# 发件人邮箱设置(默认使用SSL/TLS)
email:
address: [email protected] # 邮箱地址
sender-name: 長門有希 # 发件人显示姓名
username: username # SMTP登录用户名
password: password # SMTP登录密码
server: smtp.example.com # SMTP服务器地址
port: 465 # SMTP服务器端口
Binary file added lib/javax.mail.jar
Binary file not shown.
Binary file added lib/json-20171018.jar
Binary file not shown.
Binary file added lib/yamlbeans-1.13.jar
Binary file not shown.
38 changes: 38 additions & 0 deletions src/com/yuki_nagato/csunotifier/Config.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package com.yuki_nagato.csunotifier;

import com.esotericsoftware.yamlbeans.YamlException;
import com.esotericsoftware.yamlbeans.YamlReader;

import java.io.*;
import java.util.List;
import java.util.Map;

public class Config {
public final int interval;
public final String recordFile;
public final List<Map<String, String>> students;
public final Map<String, String> email;

public Config(File yamlFile) throws IOException {
YamlReader reader;
try {
reader = new YamlReader(new InputStreamReader(new FileInputStream(yamlFile),"utf-8"));
}
catch (FileNotFoundException e) {
System.err.println("配置文件 "+yamlFile.getPath()+" 未找到");
throw e;
}
try {
Map<String, Object> map = (Map)reader.read();
reader.close();
interval = Integer.parseInt((String)map.get("interval"));
recordFile = (String)map.get("record-file");
students = (List)map.get("students");
email = (Map)map.get("email");
}
catch (YamlException | ClassCastException e) {
System.err.println("配置文件 "+yamlFile.getPath()+" 格式错误");
throw e;
}
}
}
57 changes: 57 additions & 0 deletions src/com/yuki_nagato/csunotifier/Grade.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package com.yuki_nagato.csunotifier;

import org.json.JSONObject;

import java.util.Map;

public class Grade {
public final String course,orientationTerm,getTerm,processScore,examScore,mark,credit;
public Grade(String course,String orientationTerm, String getTerm, String processScore, String examScore, String mark, String credit) {
this.course = course;
this.orientationTerm = orientationTerm;
this.getTerm = getTerm;
this.processScore = processScore;
this.examScore = examScore;
this.mark = mark;
this.credit = credit;
}
public Grade(Map<String, String> map) {
course = map.get("course");
orientationTerm = map.get("orientationTerm");
getTerm = map.get("getTerm");
processScore = map.get("processScore");
examScore = map.get("examScore");
mark = map.get("mark");
credit = map.get("credit");
}

public JSONObject toJson() {
JSONObject rst = new JSONObject();
rst.put("course", course);
rst.put("orientationTerm", orientationTerm);
rst.put("getTerm", getTerm);
rst.put("processScore", processScore);
rst.put("examScore", examScore);
rst.put("mark", mark);
rst.put("credit", credit);
return rst;
}

@Override
public boolean equals(Object obj) {
if(obj.getClass()!=Grade.class) return false;
Grade b = (Grade)obj;
return course.equals(b.course) &&
orientationTerm.equals(b.orientationTerm) &&
getTerm.equals(b.getTerm) &&
processScore.equals(b.processScore) &&
examScore.equals(b.examScore) &&
mark.equals(b.mark) &&
credit.equals(b.credit);
}

@Override
public int hashCode() {
return course.hashCode();
}
}
65 changes: 65 additions & 0 deletions src/com/yuki_nagato/csunotifier/MailSender.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package com.yuki_nagato.csunotifier;

import javax.mail.*;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import java.io.UnsupportedEncodingException;
import java.util.Properties;

public class MailSender {
private final InternetAddress from;
private final String server, username, password, port, senderName;

public MailSender(String address, String name, String server, String username, String password, String port) throws UnsupportedEncodingException {
this.from = new InternetAddress(address, name, "utf-8");
this.server = server;
this.username = username;
this.password = password;
this.port = port;
this.senderName = name;
}
public void send(Student student, Diff diff) throws MessagingException, UnsupportedEncodingException {
Properties props = new Properties();
props.put("mail.smtp.host", server);
props.put("mail.smtp.port", port);
props.put("mail.smtp.ssl.enable", "true");
props.put("mail.smtp.auth", "true");
Session session = Session.getInstance(props, new Authenticator() {
@Override
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication(username, password);
}
});
MimeMessage message = new MimeMessage(session);
message.setFrom(from);
message.setRecipient(Message.RecipientType.TO, new InternetAddress(student.email,student.getName(),"utf-8"));
message.setSubject("中南大学新成绩通知","utf-8");
message.setContent(generateContent(student, diff), "text/html;charset=utf-8");
message.saveChanges();
Transport.send(message);
}

String generateContent(Student student, Diff diff) {
StringBuilder rst = new StringBuilder();
rst.append("<p>").append(student.getName()).append("同学:</p>");
rst.append("<p>您有成绩变化:</p>");
if(!diff.additions.isEmpty()) {
rst.append("<p>新增的成绩为</p>");
rst.append("<table border=\"1\"><tr><th>课程</th><th>初修学期</th><th>获得学期</th><th>过程成绩</th><th>期末成绩</th><th>成绩</th><th>学分</th></tr>");
for(Grade grade : diff.additions) {
rst.append(String.format("<tr><td>%s</td><td>%s</td><td>%s</td><td>%s</td><td>%s</td><td>%s</td><td>%s</td></tr>", grade.course, grade.orientationTerm, grade.getTerm, grade.processScore, grade.examScore, grade.mark, grade.credit));
}
rst.append("</table>");
}
if(!diff.deletions.isEmpty()) {
rst.append("<p>消失的成绩为</p>");
rst.append("<table border=\"1\"><tr><th>课程</th><th>初修学期</th><th>获得学期</th><th>过程成绩</th><th>期末成绩</th><th>成绩</th><th>学分</th></tr>");
for(Grade grade : diff.deletions) {
rst.append(String.format("<tr><td>%s</td><td>%s</td><td>%s</td><td>%s</td><td>%s</td><td>%s</td><td>%s</td></tr>", grade.course, grade.orientationTerm, grade.getTerm, grade.processScore, grade.examScore, grade.mark, grade.credit));
}
rst.append("</table>");
}
rst.append("<p>Yours sincerely,<br/>").append(senderName).append("</p>");
return rst.toString();
}
}
45 changes: 45 additions & 0 deletions src/com/yuki_nagato/csunotifier/Main.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package com.yuki_nagato.csunotifier;

import javax.mail.MessagingException;
import java.io.File;
import java.io.IOException;
import java.util.Map;

public class Main {
public static void main(String[] args) throws IOException, InterruptedException {
final Config cfg = new Config(new File("config/config.yaml"));
Student.recordFile = new File(cfg.recordFile);
Student.load();
MailSender sender = new MailSender(cfg.email.get("address"),cfg.email.get("sender-name"),cfg.email.get("server"),cfg.email.get("username"),cfg.email.get("password"),cfg.email.get("port"));
while(true) {
for(Map<String, String> student : cfg.students) {
String id = student.get("id"), password = student.get("password"), email = student.get("email");
try {
System.out.println("开始查询"+id);
Student stu = new Student(id,password,email);
Diff diff = stu.check();
if(diff.additions.isEmpty() && diff.deletions.isEmpty()) {
System.out.println("没有变化");
}
else {
System.out.printf("新增%d个成绩,减少%d个成绩\n", diff.additions.size(), diff.deletions.size());
sender.send(stu,diff);
System.out.println("邮件发送成功");
}
}
catch (MessagingException e) {
System.err.println("邮件发送失败");
e.printStackTrace();
}
catch (AuthenticationException e) {
System.err.println("用户名或密码错误");
}
catch (NullPointerException | IOException e) {
System.err.println("关于"+id+"的配置可能有误");
e.printStackTrace();
}
Thread.sleep(cfg.interval*1000/cfg.students.size());
}
}
}
}
80 changes: 80 additions & 0 deletions src/com/yuki_nagato/csunotifier/ScorePage.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
package com.yuki_nagato.csunotifier;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.*;
import java.util.ArrayList;
import java.util.Base64;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class ScorePage {
private final String content;

public ScorePage(String username, String password) throws IOException, AuthenticationException {
URL url = new URL("http://csujwc.its.csu.edu.cn/jsxsd/xk/LoginToXk");
HttpURLConnection connection = (HttpURLConnection)url.openConnection();
connection.setRequestMethod("POST");
connection.setInstanceFollowRedirects(false);
connection.setDoOutput(true);
connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
String encoded = Base64.getEncoder().encodeToString(username.getBytes("utf-8")) +
"%%%" +
Base64.getEncoder().encodeToString(password.getBytes("utf-8"));
connection.getOutputStream().write(("encoded="+ URLEncoder.encode(encoded,"utf-8")).getBytes("utf-8"));
if(connection.getResponseCode()!=302) {
throw new AuthenticationException();
}
List<String> cookies = connection.getHeaderFields().get("Set-Cookie");

// get page
url = new URL("http://csujwc.its.csu.edu.cn/jsxsd/kscj/yscjcx_list");
connection = (HttpURLConnection)url.openConnection();
for(String cookie : cookies) {
connection.addRequestProperty("Cookie", cookie.substring(0,cookie.indexOf(';')));
}
BufferedReader br = new BufferedReader(new InputStreamReader(connection.getInputStream(), "utf-8"));
StringBuilder body = new StringBuilder();
String line;
while((line = br.readLine())!=null) {
body.append(line);
body.append('\n');
}

//exit
url = new URL("http://csujwc.its.csu.edu.cn/jsxsd/xk/LoginToXk?method=exit");
connection = (HttpURLConnection)url.openConnection();
connection.setInstanceFollowRedirects(false);
for(String cookie : cookies) {
connection.addRequestProperty("Cookie", cookie.substring(0, cookie.indexOf(';')));
}
connection.getResponseCode();

content = body.toString();
}
public ArrayList<Grade> getGrades() {
String pt = "<tr>.*?<td>.*?<td>(.*?)</td>.*?<td>(.*?)</td>.*?<td align=\"left\">(.*?)</td>.*?<td>(.*?)</td>.*?<td>(.*?)</td>.*?,700,500\\)\">(.*?)</a>.*?<td>(.*?)</td>";
Pattern pattern = Pattern.compile(pt, Pattern.DOTALL);
Matcher m = pattern.matcher(content);
ArrayList<Grade> rst = new ArrayList<>();
while(m.find()) {
rst.add(new Grade(m.group(3),m.group(1),m.group(2),m.group(4),m.group(5),m.group(6),m.group(7)));
}
return rst;
}
public String getName() {
String pt = "&nbsp;&nbsp;(.*)\\(";
Pattern pattern = Pattern.compile(pt);
Matcher m = pattern.matcher(content);
m.find();
return m.group(1);
}
}

class AuthenticationException extends Exception {
AuthenticationException() {
super("用户名或密码错误");
}
}
Loading

0 comments on commit c3f5bdb

Please sign in to comment.