前言

起因

为什么要写这么一个东西呢,主要是因为这学期老师喜欢在课下发布一些作业,可益智教的APP不会推送消息,我们在课下呢也不会没事都去瞅瞅老师发布作业没,而这就导致了发现有作业的时候作业已经截止了,进而导致平时成绩收到影响。

解决办法

所以呢,准备写一个小程序来检测老师发布的作业然后通过QQ、微信、邮箱等进行提醒,毕竟谁也不会一整天都不看微信QQ吧!

开始

分析

首先我们先正常登录,看看需要些什么请求参数

https://www.csgmooc.com/uniplatform/index.html#/login #登录网址
点击登录后可以看到登录的接口
https://www.csgmooc.com/uniBaseApi/portal/login/passwordLogin
请求方式POST
根据上图我们可以看到一共携带了三个参数
1
2
3
password #密码
shcoolNum #应该是学校ID,不会变动
username #账号

登录部分很简单,没什么验证措施,就直接提交参数就行

返回参数

{
"errCode": 200,
"errMsg": "成功",
"data": {
"access_token": "f4cf511b-d553-4b38-85dd-9706808592cc",
"refresh_token": "b6627544-55c1-4549-9099-4d53e7af74e1",
"token_type": "bearer",
"expires_in": 22626,
"scope": "select",
"authtoken": "jXk4xCA8DQdGdWCnmXoCzlYbD3TRtDJj7h+dq0rqegg=",
"teaStuBase": {
"id": 50134,
"schoolNum": "11510",
"number": "2020201308",
"username": "2020201308",
"email": "",
"phone": "",
"headColor": 4,
"peopleType": 1,
"postEntityList": null,
"peopleId": 55319
}
}
}

返回的参数中我们等会要用到的只有**authtoken”: “jXk4xCA8DQdGdWCnmXoCzlYbD3TRtDJj7h+dq0rqegg=”**这个

接着我们进入教学平台

发现新打开了一个标签,这里的请求过程浏览器抓不到了

重新刷新一下,分析下请求,在请求头中可以开到携带了taken,但与之前登录时获取的taken不一样,遂猜测在点击进入应用时获取了一个新的taken。由于请求过程浏览器抓不到,遂使用Fiddler抓包

通过Fiddler进行抓包发现了如下一个请求

请求地址

https://www.csgmooc.com/uni-gateway/jxapi2/auth/getUserDetail
请求方式:GET
参数:authType=0
timeStamap= #时间戳
请求头要携带taken信息:authtoken: jXk4xCA8DQdGdWCnmXoCzlYbD3TRtDJj7h+dq0rqegg=

返回参数

{
"errcode":200,
"errmsg":"SUCCESS",
"data":{
"authtoken":"jXk4xCA8DQdGdWCnmXoCzuas1BA1pJVg",
"appauthtoken":null,
"userId":55319,
"type":0,
"schoolNum":"11510",
"headcolor":4,
"head":null,
"name":"刘国庆",
"registerid":null,
"number":"2020201308",
"role":null,
"flag":null,
"ipAddress":"61.168.4.67",
"roleLogin":1,
"pwd":null,
"schoolName":"河南职业技术学院",
"redirectUrl":"https://www.csgmooc.com/11510/html/stud_historyClass.html"
}
}

这样就获取到了新的authtoken=jXk4xCA8DQdGdWCnmXoCzuas1BA1pJVg,有了新的taken就可以查询课程信息、作业信息了,接下来的每次查询倒要在请求头中携带新的authtoken=jXk4xCA8DQdGdWCnmXoCzuas1BA1pJVg,所以下面的请求我就不在声明了。

继续刷新,可以找到请求作业信息的接口

https://www.csgmooc.com/uni-gateway/jxapi2//student/task/gettaskmodule
请求参数:stuid=55319 #对应这登录时返回的"peopleId": 55319
gid=10 #学期信息
ttid=
sclassid=
key=
taskTypeJson=
sublastType=
type=0
pcFlag=0
timeStamap= #时间戳
请求方式:GET

可以看到,这里需要携带学生id和学期信息,学生id已经有了,接下来就要去获取学期id信息了

返回参数

{
"errcode": 200,
"errmsg": "SUCCESS",
"data": [
{
"ts_type": 0,
"taskModuleInfos": [
{
"ttid": 15018,
"tcid": 152437,
"tmid": 255853,
"tm_subid": 19679382,
"tm_type": 1,
"tm_name": "用例图绘制",
"tt_name": "计应201班 ",
"tc_name": "第5次 上机实验",
"tm_sumlasttime": 1649087999000,
"tm_residuetime": 125460025,
"is_limit": 0,
"task_setting": 1,
"number": 72,
"g_number": null,
"complete_number": 2,
"g_complete_number": null,
"times": {
"date": "明天",
"time": "23:59"
},
"deadLine": 1649087999000,
"reformFlag": 0,
"deadLineOfGroup": null,
"reformFlagOfGroup": null,
"stuTaskStatu": 1,
"p_type": null,
"t_statu": 1,
"sclassid": 987674,
"classid": 18246,
"homeworkid": 124908,
"task_statu": 1,
"courseId": null
}
]
}
]
}

继续刷新分析接口,可以看到下面这个接口返回了学期信息

https://www.csgmooc.com/uni-gateway/jxapi2//teacher/teachtask/getGradeList
请求参数:tag=0
timeStamap= #时间戳
请求方式:GET

返回参数

{
"errcode": 200,
"errmsg": "SUCCESS",
"data": [
{
"id": 10, #这里就是学期ID
"deleteFlag": 0,
"enddate": 1656432000000,
"name": "2021-2022学年",
"startdate": 1645977600000,
"term": "第2学期",
"weeknum": 18,
"now": true,
"gradeInfo": null,
"formatStartDate": null,
"formatEndDate": null
},
{
"id": 9,
"deleteFlag": 0,
"enddate": 1643904000000,
"name": "2021-2022学年",
"startdate": 1630857600000,
"term": "第1学期",
"weeknum": 22,
"now": false,
"gradeInfo": null,
"formatStartDate": null,
"formatEndDate": null
},
{
"id": 8,
"deleteFlag": 0,
"enddate": 1625760000000,
"name": "2020-2021学年",
"startdate": 1615132800000,
"term": "第2学期",
"weeknum": 18,
"now": false,
"gradeInfo": null,
"formatStartDate": null,
"formatEndDate": null
},
{
"id": 7,
"deleteFlag": 0,
"enddate": 1610640000000,
"name": "2020-2021学年",
"startdate": 1599408000000,
"term": "第1学期",
"weeknum": 19,
"now": false,
"gradeInfo": null,
"formatStartDate": null,
"formatEndDate": null
},
{
"id": 6,
"deleteFlag": 0,
"enddate": 1593705600000,
"name": "2019-2020学年",
"startdate": 1582473600000,
"term": "第2学期",
"weeknum": 19,
"now": false,
"gradeInfo": null,
"formatStartDate": null,
"formatEndDate": null
},
{
"id": 4,
"deleteFlag": 0,
"enddate": 1578585600000,
"name": "2019-2020学年",
"startdate": 1567958400000,
"term": "第1学期",
"weeknum": 18,
"now": false,
"gradeInfo": null,
"formatStartDate": null,
"formatEndDate": null
},
{
"id": 3,
"deleteFlag": 0,
"enddate": 1562256000000,
"name": "2018-2019学年",
"startdate": 1551024000000,
"term": "第2学期",
"weeknum": 19,
"now": false,
"gradeInfo": null,
"formatStartDate": null,
"formatEndDate": null
},
{
"id": 2,
"deleteFlag": 0,
"enddate": 1547136000000,
"name": "2018-2019学年",
"startdate": 1536508800000,
"term": "第1学期",
"weeknum": 18,
"now": false,
"gradeInfo": null,
"formatStartDate": null,
"formatEndDate": null
},
{
"id": 1,
"deleteFlag": 0,
"enddate": 1530806400000,
"name": "2017-2018学年",
"startdate": 1520179200000,
"term": "第2学期",
"weeknum": 18,
"now": false,
"gradeInfo": null,
"formatStartDate": null,
"formatEndDate": null
}
]
}

此时已经获取到了stuidgid,就可以构造参数获取作业信息了。

请求获取作业接口

https://www.csgmooc.com/uni-gateway/jxapi2//student/task/gettaskmodule

得到参数

{
"errcode": 200,
"errmsg": "SUCCESS",
"data": [
{
"ts_type": 0,
"taskModuleInfos": [
{
"ttid": 15018,
"tcid": 152437,
"tmid": 255853,
"tm_subid": 19679382,
"tm_type": 1,
"tm_name": "用例图绘制",
"tt_name": "计应201班 ",
"tc_name": "第5次 上机实验",
"tm_sumlasttime": 1649087999000,
"tm_residuetime": 125049418,
"is_limit": 0,
"task_setting": 1,
"number": 72,
"g_number": null,
"complete_number": 3,
"g_complete_number": null,
"times": {
"date": "明天",
"time": "23:59"
},
"deadLine": 1649087999000,
"reformFlag": 0,
"deadLineOfGroup": null,
"reformFlagOfGroup": null,
"stuTaskStatu": 1,
"p_type": null,
"t_statu": 1,
"sclassid": 987674,
"classid": 18246,
"homeworkid": 124908,
"task_statu": 1,
"courseId": null
}
]
}
]
}

至此,已经得到作业信息,但观察上面返回参数可知

{
"tmid": 255853, #任务ID
"tm_name": "用例图绘制", #任务名称
"tt_name": "计应201班 ", #课程名称
"tc_name": "第5次 上机实验", #课程节次
"deadLine": 1649087999000 #截止时间,时间戳
}

上面就是我们需要的参数了。

总结

至此,我们已经得到我们所需要的所有信息,接下来咱们要做的就是浅写一些代码,通过获取课程信息后使用go-cqhttp进行QQ消息推送,再将任务信息保存到SQLite数据库中。

最后的最后我要提一嘴

ungly but works!

运行结果如下

代码

Tasks.java

/**
* Copyright 2022 json.cn
*/
package pojo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Tasks {
private int ttid;
private long tcid;
private long tmid;
private long tm_subid;
private int tm_type;
private String tm_name;
private String tt_name;
private String tc_name;
private long tm_sumlasttime;
private long tm_residuetime;
private int is_limit;
private int task_setting;
private int number;
private String g_number;
private int complete_number;
private String g_complete_number;
private Times times;
private long deadLine;
private int reformFlag;
private String deadLineOfGroup;
private String reformFlagOfGroup;
private int stuTaskStatu;
private String p_type;
private int t_statu;
private long sclassid;
private int classid;
private long homeworkid;
private int task_statu;
private String courseId;
}

Times.java

/**
* Copyright 2022 json.cn
*/
package pojo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Times {
private String date;
private String time;
}

Login.java

登录及查询任务信息,耦合性有点高,获取token和其他部分拆开比较好,重构有点麻烦并且时间也不多

package service;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.BasicCookieStore;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import pojo.Tasks;

import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.List;

/**
* @author Administrator
*/
public class Login {
public List<Tasks> login(){
//登录接口
final String loginUri="https://www.csgmooc.com/uniBaseApi/portal/login/passwordLogin";
//获取新taken接口
final String getUserDetail="https://www.csgmooc.com/uni-gateway/jxapi2/auth/getUserDetail";
//获取学期信息接口
final String getGradeList="https://www.csgmooc.com/uni-gateway/jxapi2//teacher/teachtask/getGradeList";
//获取作业信息接口
final String getTasks="https://www.csgmooc.com/uni-gateway/jxapi2//student/task/gettaskmodule";
//authtoken
String authtoken=null;
//学生ID
String stuid=null;
//学期ID
String gid=null;
//任务实体对象列表
List<Tasks> tasks =null;
BasicCookieStore cookieStore = new BasicCookieStore();
CloseableHttpClient httpClient = HttpClients.custom().setDefaultCookieStore(cookieStore).build();
//创建请求体
HttpPost httpPost = new HttpPost();
HttpGet httpGet = new HttpGet();
CloseableHttpResponse response;
httpPost.setURI(URI.create(loginUri));
//构造请求参数
JSONObject params = new JSONObject();
params.put("username","学号");
params.put("password","密码");
params.put("schoolNum","GWNH9iO0ts0=");
try {
//设置请求参数
httpPost.setEntity(new StringEntity(params.toString()));
//设置请求头
httpPost.setHeader("Content-Type", ContentType.APPLICATION_JSON.toString());
//发送请求
response = httpClient.execute(httpPost);
if (response.getStatusLine().getStatusCode()==200){
System.out.println("登录成功");
//获取authtoken
authtoken = JSONObject.parseObject(EntityUtils.toString(response.getEntity(), "UTF-8")).getJSONObject("data").getString("authtoken");
}else {
System.out.println("登录失败!状态码:"+response.getStatusLine().getStatusCode());
}
} catch (IOException e) {
e.printStackTrace();
}
try {
URIBuilder uriBuilder=new URIBuilder(getUserDetail);
uriBuilder.addParameter("authType","0");
uriBuilder.addParameter("timeStamap",String.valueOf(System.currentTimeMillis()));
httpGet.setURI(uriBuilder.build());
//设置请求头将authtoken参数信息携带
httpGet.setHeader("authtoken",authtoken);
httpGet.setHeader("Content-Type", ContentType.APPLICATION_JSON.toString());
response = httpClient.execute(httpGet);
if (response.getStatusLine().getStatusCode()==200){
String responseData = EntityUtils.toString(response.getEntity(), "UTF-8");
authtoken = JSONObject.parseObject(responseData).getJSONObject("data").getString("authtoken");
stuid = JSONObject.parseObject(responseData).getJSONObject("data").getString("userId");
System.out.println("获取成功!新的token: "+authtoken);
System.out.println("获取学生ID:"+stuid);
}else {
System.out.println("获取新token时失败");
}
} catch (URISyntaxException | IOException e) {
e.printStackTrace();
}

try {
URIBuilder uriBuilder=new URIBuilder(getGradeList);
uriBuilder.addParameter("tag","0");
uriBuilder.addParameter("timeStamap",String.valueOf(System.currentTimeMillis()));
httpGet.setURI(uriBuilder.build());
//设置请求头将authtoken参数信息携带
httpGet.setHeader("authtoken",authtoken);
httpGet.setHeader("Content-Type", ContentType.APPLICATION_JSON.toString());
response = httpClient.execute(httpGet);
if (response.getStatusLine().getStatusCode()==200){
gid = JSONObject.parseObject(EntityUtils.toString(response.getEntity(), "UTF-8")).getJSONArray("data").getJSONObject(0).getString("id");
System.out.println("最新学期ID:"+gid);
}else {
System.out.println("获取学期ID时失败");
}
} catch (URISyntaxException | IOException e) {
e.printStackTrace();
}


try {
URIBuilder uriBuilder=new URIBuilder(getTasks);
uriBuilder.addParameter("stuid",stuid);
uriBuilder.addParameter("gid",gid);
uriBuilder.addParameter("ttid","");
uriBuilder.addParameter("sclassid","");
uriBuilder.addParameter("key","");
uriBuilder.addParameter("taskTypeJson","");
uriBuilder.addParameter("sublastType","");
uriBuilder.addParameter("type","0");
uriBuilder.addParameter("pcFlag","0");
uriBuilder.addParameter("timeStamap",String.valueOf(System.currentTimeMillis()));
httpGet.setURI(uriBuilder.build());
//设置请求头将authtoken参数信息携带
httpGet.setHeader("authtoken",authtoken);
httpGet.setHeader("Content-Type", ContentType.APPLICATION_JSON.toString());
response = httpClient.execute(httpGet);
if (response.getStatusLine().getStatusCode()==200){
String responseData = EntityUtils.toString(response.getEntity(), "UTF-8");
JSONObject jsonObject = JSONObject.parseObject(responseData);
JSONArray jsonArray = jsonObject.getJSONArray("data").getJSONObject(0).getJSONArray("taskModuleInfos");
tasks = JSON.parseArray(jsonArray.toString(), Tasks.class);
}else {
System.out.println("获取作业信息时失败");
}
} catch (URISyntaxException | IOException e) {
e.printStackTrace();
} finally {
try {
httpClient.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return tasks;
}
}

SendMessage.java

消息发送,通过go-cqhttp推送QQ消息

package service;


import com.alibaba.fastjson.JSONObject;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;

import java.io.IOException;
import java.nio.charset.StandardCharsets;

public class SendMessage {
public int send(String message) {
int statusCode=1;
CloseableHttpClient client = HttpClients.createDefault();
HttpPost httpPost = new HttpPost("http://IP:端口/send_private_msg");
//构造请求参数
JSONObject params = new JSONObject();
params.put("user_id", "85605964");
params.put("message", message);
try {
//设置请求参数,设置Charset.forName("UTF-8")避免中文请求乱码
httpPost.setEntity(new StringEntity(params.toString(), StandardCharsets.UTF_8));
//设置请求头
httpPost.setHeader("Content-Type", "application/json");
CloseableHttpResponse response = client.execute(httpPost);
String responseData = EntityUtils.toString(response.getEntity(), "UTF-8");
JSONObject responseJSON = JSONObject.parseObject(responseData);
statusCode=responseJSON.getInteger("retcode");
} catch (IOException e) {
e.printStackTrace();
}
if (statusCode==0){
return 0;
}else {
return 1;
}
}
}

Job.java

用于整理信息推送消息及将数据插入数据库

package service;

import pojo.Tasks;
import utils.SQLiteUtil;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;

public class Job {
public void job() {
Login login = new Login();
List<Tasks> tasks = login.login();
SendMessage sendMessage = new SendMessage();
Connection connection = null;
PreparedStatement preInsert = null;
PreparedStatement preQuery = null;
String insertSql = "INSERT INTO TASKS(TMID, TT_NAME, TM_NAME, TC_NAME, DEADLINE, SEND)" +
"VALUES(?,?,?,?,?,?) ";
String querySql = "SELECT COUNT(*) AS NUM FROM TASKS WHERE TMID=?";
try {
connection = SQLiteUtil.getConnection();
preInsert = connection.prepareStatement(insertSql);
preQuery = connection.prepareStatement(querySql);
for (Tasks task : tasks) {
preQuery.setLong(1, task.getTmid());
ResultSet resultSet = preQuery.executeQuery();
resultSet.next();
if (resultSet.getInt("NUM") == 0) {
preInsert.setLong(1, task.getTmid());
preInsert.setString(2, task.getTt_name());
preInsert.setString(3, task.getTm_name());
preInsert.setString(4, task.getTc_name());
preInsert.setString(5, new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date(task.getDeadLine())));
String message = "课程名称:" + task.getTt_name() + "\r"
+ "作业名称:" + task.getTm_name() + "\r"
+ "课程节次:" + task.getTc_name() + "\r"
+ "截止时间:" + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date(task.getDeadLine()));
int statusCode = sendMessage.send(message);
if (statusCode == 0) {
System.out.println("提醒推送成功!");
}
preInsert.setInt(6, statusCode);
int i = preInsert.executeUpdate();
if (i > 0) {
System.out.println("作业信息插入成功!");
}
}
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
if (connection != null) {
try {
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (preInsert != null) {
try {
preInsert.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (preQuery != null) {
try {
preQuery.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
}

SQLiteUtil.java

用于获取SQLite数据库连接

package utils;

import java.sql.Connection;
import java.sql.DriverManager;

public class SQLiteUtil {
public static Connection getConnection() {
Connection c = null;
try {
Class.forName("org.sqlite.JDBC");
c = DriverManager.getConnection("jdbc:sqlite:identifier.sqlite");
} catch (Exception e) {
System.err.println(e.getClass().getName() + ": " + e.getMessage());
System.exit(0);
}
return c;
}
}

Go.java

启动类,每隔十分钟查询一下任务

import service.Job;


public class Go {
public static void main(String[] args) throws InterruptedException {
Job job = new Job();
while (true){
job.job();
Thread.sleep(600000);
}
}
}

pom.xml

<dependencies>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.13</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.80</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.22</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
<dependency>
<groupId>org.xerial</groupId>
<artifactId>sqlite-jdbc</artifactId>
<version>3.36.0.3</version>
</dependency>
</dependencies>

数据库

CREATE TABLE "tasks"
(
tmid integer not null
constraint tasks_pk
primary key,
tt_name text not null,
tm_name text,
tc_name text,
deadLine text,
send integer default 0
)

发表回复

后才能评论

本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。

最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。 若排除这种情况,可在对应资源底部留言,或联络我们。

对于会员专享、整站源码、程序插件、网站模板、网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。

如果您已经成功付款但是网站没有弹出成功提示,请联系站长提供付款信息为您处理

源码素材属于虚拟商品,具有可复制性,可传播性,一旦授予,不接受任何形式的退款、换货要求。请您在购买获取之前确认好 是您所需要的资源