本科生:新增缓考申请列表以及学分修读情况的请求;对部分方法重载方便使用;添加部分学校相关信息参数;保留恢复旧版本科生登录方式

lensfrex 2 years ago
parent 0a32c1030c
commit 7af0fbe8f4
Signed by: lensfrex
GPG Key ID: 947ADABD8533C476
  1. 164
      mywust-core/src/main/java/cn/linghang/mywust/core/api/UndergradUrls.java
  2. 2
      mywust-core/src/main/java/cn/linghang/mywust/core/exception/ApiException.java
  3. 7
      mywust-core/src/main/java/cn/linghang/mywust/core/parser/undergraduate/UndergradCourseTableParser.java
  4. 31
      mywust-core/src/main/java/cn/linghang/mywust/core/parser/undergraduate/UndergradCreditStatusIndexParser.java
  5. 4
      mywust-core/src/main/java/cn/linghang/mywust/core/request/RequestFactory.java
  6. 2
      mywust-core/src/main/java/cn/linghang/mywust/core/request/library/response/Map.java
  7. 60
      mywust-core/src/main/java/cn/linghang/mywust/core/request/undergrade/BkjxRequestFactory.java
  8. 5
      mywust-core/src/main/java/cn/linghang/mywust/core/service/auth/LibraryLogin.java
  9. 26
      mywust-core/src/main/java/cn/linghang/mywust/core/service/auth/UndergraduateLogin.java
  10. 4
      mywust-core/src/main/java/cn/linghang/mywust/core/service/graduate/GraduateApiServiceBase.java
  11. 6
      mywust-core/src/main/java/cn/linghang/mywust/core/service/undergraduate/UndergradApiServiceBase.java
  12. 57
      mywust-core/src/main/java/cn/linghang/mywust/core/service/undergraduate/UndergradCreditStatusApiService.java
  13. 83
      mywust-core/src/main/java/cn/linghang/mywust/core/service/undergraduate/UndergradExamDelayApiService.java
  14. 4
      mywust-core/src/main/java/cn/linghang/mywust/core/service/undergraduate/UndergradScoreApiService.java
  15. 4
      mywust-core/src/main/java/cn/linghang/mywust/core/service/undergraduate/UndergradStudentInfoApiService.java
  16. 4
      mywust-core/src/main/java/cn/linghang/mywust/core/service/undergraduate/UndergradTrainingPlanApiService.java
  17. 2
      mywust-core/src/main/java/cn/linghang/mywust/core/util/BkjxUtil.java
  18. 32
      mywust-model/src/main/java/cn/linghang/mywust/model/global/Building.java
  19. 29
      mywust-model/src/main/java/cn/linghang/mywust/model/global/Campus.java
  20. 29
      mywust-model/src/main/java/cn/linghang/mywust/model/global/College.java
  21. 14
      mywust-test/pom.xml
  22. 49
      mywust-test/src/test/java/CourseTableTest.java
  23. 46
      mywust-test/src/test/java/ExamInfoTest.java
  24. 45
      mywust-test/src/test/java/JwcLoginTest.java
  25. 39
      mywust-test/src/test/java/LibraryLoginTest.java
  26. 38
      mywust-test/src/test/java/SchemeTest.java
  27. 39
      mywust-test/src/test/java/StudentInfoPageTest.java
  28. 2
      mywust-test/src/test/java/UnderGraduateTest.java
  29. 58
      mywust-test/src/test/java/WlsyLoginTest.java
  30. 10
      mywust-util/src/main/java/cn/linghang/mywust/util/PasswordEncoder.java
  31. 27
      mywust-util/src/main/java/cn/linghang/mywust/util/StringUtil.java
  32. 3
      pom.xml

@ -1,28 +1,188 @@
package cn.linghang.mywust.core.api;
import cn.linghang.mywust.model.global.Building;
import cn.linghang.mywust.model.global.Campus;
import cn.linghang.mywust.model.global.College;
import lombok.Getter;
import java.util.*;
/**
* <p>Bkjx本科教学系统对应的API常量列表拼音咱就别吐槽了吧...</p>
* <p>其实是本科生用的教务处系统</p>
*/
@Getter
public class UndergradUrls {
/**
* 登录cookie获取url
*/
public static final String BKJX_SESSION_COOKIE_API = "http://bkjx.wust.edu.cn/jsxsd/sso.jsp?ticket=%s";
/**
* cookie测试url空白页
*/
public static final String BKJX_TEST_API = "http://bkjx.wust.edu.cn/jsxsd/framework/blankPage.jsp";
/**
* 学生信息url
*/
public static final String BKJX_STUDENT_INFO_API = "http://bkjx.wust.edu.cn/jsxsd/grxx/xsxx";
public static final String BKJX_EXAM_INFO_API = "http://bkjx.wust.edu.cn/jsxsd/kscj/cjcx_list";
/**
* 成绩url
*/
public static final String BKJX_SCORE_API = "http://bkjx.wust.edu.cn/jsxsd/kscj/cjcx_list";
public static final String BKJX_SCHEME_API = "http://bkjx.wust.edu.cn/jsxsd/pyfa/topyfamx";
/**
* 培养计划url
*/
public static final String BKJX_TRAINING_PLAN_API = "http://bkjx.wust.edu.cn/jsxsd/pyfa/topyfamx";
/**
* 课表url
*/
public static final String BKJX_COURSE_TABLE_API = "http://bkjx.wust.edu.cn/jsxsd/xskb/xskb_list.do";
/**
* 学分修读计划首页url
*/
public static final String BKJX_CREDIT_STATUS_INDEX_API = "http://bkjx.wust.edu.cn/jsxsd/xxwcqk/xxwcqk_idxOnzh.do";
/**
* 学分修读计划url
*/
public static final String BKJX_CREDIT_STATUS_API = "http://bkjx.wust.edu.cn/jsxsd/xxwcqk/xxwcqkOnzh.do";
/**
* 考试活动列表url
*/
public static final String BKJX_EXAM_ACTIVITY_LIST_API = "http://bkjx.wust.edu.cn/jsxsd/kscj/hksq_query_ajax?&xnxq01id=%s";
/**
* 缓考申请url
*/
public static final String BKJX_EXAM_DELAY_APPLICATION_LIST_API = "http://bkjx.wust.edu.cn/jsxsd/kscj/hksq_list";
public static class Legacy {
public static final String BKJX_INDEX = "http://bkjx.wust.edu.cn";
public static final String BKJX_DATA_STRING_API = "http://bkjx.wust.edu.cn/Logon.do?method=logon&flag=sess";
public static final String BKJX_SESSION_COOKIE_API = "http://bkjx.wust.edu.cn/Logon.do?method=logon";
}
/**
* 一些需要用到的from参数一般来说是写死固定的
*/
// 别慌,大部分都是脚本自动生成的代码,肯定不会是手写的。
public static class ConstantParams {
/**
* 默认节次模式
*/
public static final String DEFAULT_TIME_MODEL = "9486203B90F3E3CBE0532914A8C03BE2";
private static final List<College> collegesTmp = new ArrayList<>(27);
public static final List<College> COLLEGES = Collections.unmodifiableList(collegesTmp);
static {
collegesTmp.add(new College("00001", "[01]资源与环境工程学院"));
collegesTmp.add(new College("00002", "[02]材料与冶金学院"));
collegesTmp.add(new College("00003", "[03]机械自动化学院"));
collegesTmp.add(new College("00004", "[04]信息科学与工程学院(人工智能学院)"));
collegesTmp.add(new College("00005", "[05]管理学院(恒大管理学院)"));
collegesTmp.add(new College("00006", "[06]法学与经济学院"));
collegesTmp.add(new College("00007", "[07]理学院"));
collegesTmp.add(new College("00008", "[08]城市建设学院"));
collegesTmp.add(new College("00009", "[09]医学院"));
collegesTmp.add(new College("00012", "[12]电子技术学院"));
collegesTmp.add(new College("00013", "[13]计算机科学与技术学院"));
collegesTmp.add(new College("00014", "[14]外国语学院"));
collegesTmp.add(new College("00015", "[15]体育学院(恒大足球学院)"));
collegesTmp.add(new College("0D5444D56D8A46EDB75633181B2042A7", "[16]图书馆"));
collegesTmp.add(new College("26057DF4B9354C6EA85860F1357FE8EB", "[17]工程训练中心"));
collegesTmp.add(new College("00018", "[18]生命科学与健康学院"));
collegesTmp.add(new College("00019", "[19]艺术与设计学院"));
collegesTmp.add(new College("00023", "[21]国际学院"));
collegesTmp.add(new College("00024", "[22]化学与化工学院"));
collegesTmp.add(new College("00025", "[23]汽车与交通工程学院"));
collegesTmp.add(new College("00026", "[24]临床学院"));
collegesTmp.add(new College("0W6z90XTY6", "[25]学生工作处"));
collegesTmp.add(new College("jkwHhwCHLl", "[51]马克思主义学院"));
collegesTmp.add(new College("0C4B597EE18B418B9AA5C52FDAB3EC73", "[52]香涛学院"));
collegesTmp.add(new College("379A57BA53DD4F25BA7582CE3180C077", "[54]公共卫生学院"));
collegesTmp.add(new College("9AA8C9B34EE74DEC8E02F4554B1B5125", "[60]研究生院"));
collegesTmp.add(new College("86AC446406A94EF09DE1F8B7C17F994A", "[98]全校"));
}
private static final List<Campus> campusTmp = new ArrayList<>(3);
public static final List<Campus> CAMPUS = Collections.unmodifiableList(campusTmp);
static {
campusTmp.add(new Campus("00001", "青山校区"));
// tmp.add(new Campus("00002", "洪山校区");
// tmp.add(new Campus("00003", "医学院");
// tmp.add(new Campus("00004", "城市学院");
// tmp.add(new Campus("00005", "东湖教学区");
campusTmp.add(new Campus("00006", "黄家湖校区"));
campusTmp.add(new Campus("00007", "附属医院"));
// tmp.add(new Campus("00008", "武钢医院");
}
/**
* 教室目前只做了黄家湖青山和附属医学院的数据其他校区在制作时相关数据都是空的
* 需要更多信息请请求相关接口获取
*/
private static final Map<Campus, List<Building>> buildingTmp = new HashMap<>(3);
public static final Map<Campus, List<Building>> BUILDINGS = Collections.unmodifiableMap(buildingTmp);
static {
Campus qingshan = CAMPUS.get(0);
List<Building> qingshanBuildings = new ArrayList<>(10);
qingshanBuildings.add(new Building("FE88C3D75F9C4C8CA50B82ACDF83530B", "科大雅苑C栋", qingshan));
qingshanBuildings.add(new Building("3B76302812FD4262B8BD703814D0D8C3", "科大雅苑A栋", qingshan));
qingshanBuildings.add(new Building("90C06D274E254A2CADC88DF1CEBD8396", "教十楼", qingshan));
qingshanBuildings.add(new Building("00001", "主楼", qingshan));
qingshanBuildings.add(new Building("00002", "教一楼", qingshan));
qingshanBuildings.add(new Building("00003", "教二楼", qingshan));
qingshanBuildings.add(new Building("00004", "教三楼", qingshan));
qingshanBuildings.add(new Building("00005", "教四楼", qingshan));
qingshanBuildings.add(new Building("00006", "教五楼", qingshan));
qingshanBuildings.add(new Building("00007", "教六楼", qingshan));
qingshanBuildings.add(new Building("00008", "图书馆", qingshan));
qingshanBuildings.add(new Building("00009", "本部东院体育场", qingshan));
qingshanBuildings.add(new Building("00010", "机械厂", qingshan));
qingshanBuildings.add(new Building("00024", "本部西院体育场", qingshan));
qingshanBuildings.add(new Building("00025", "本部北院体育场", qingshan));
qingshanBuildings.add(new Building("00029", "教七楼", qingshan));
qingshanBuildings.add(new Building("00031", "本部教二楼化学实验区", qingshan));
qingshanBuildings.add(new Building("00032", "学院实验室", qingshan));
qingshanBuildings.add(new Building("00051", "校本部停用教室", qingshan));
buildingTmp.put(qingshan, qingshanBuildings);
Campus huangjiahu = CAMPUS.get(1);
List<Building> huangjiahuBuildings = new ArrayList<>(10);
huangjiahuBuildings.add(new Building("D1521DE0E4CF4641AB4C49CA39EF5E47", "教八楼(管理学院)", huangjiahu));
huangjiahuBuildings.add(new Building("FBD19C52EC3B4A93A6268B815EFA9A5A", "教九楼(汽车学院)", huangjiahu));
huangjiahuBuildings.add(new Building("00034", "恒大楼一区", huangjiahu));
huangjiahuBuildings.add(new Building("00035", "恒大楼二区", huangjiahu));
huangjiahuBuildings.add(new Building("00036", "恒大楼三区", huangjiahu));
huangjiahuBuildings.add(new Building("00037", "黄家湖校区体育场", huangjiahu));
huangjiahuBuildings.add(new Building("00041", "黄家湖校区体育馆", huangjiahu));
huangjiahuBuildings.add(new Building("00042", "教二楼(理学院)", huangjiahu));
huangjiahuBuildings.add(new Building("00043", "教三楼(计算机学院)", huangjiahu));
huangjiahuBuildings.add(new Building("00045", "教四楼二区(外国语学院)", huangjiahu));
huangjiahuBuildings.add(new Building("00046", "教四楼一区(文法学院)", huangjiahu));
huangjiahuBuildings.add(new Building("00048", "教五楼一区", huangjiahu));
huangjiahuBuildings.add(new Building("00049", "教五楼二区", huangjiahu));
huangjiahuBuildings.add(new Building("00050", "教六楼(医学院)", huangjiahu));
huangjiahuBuildings.add(new Building("00052", "黄家湖校区停用教室", huangjiahu));
huangjiahuBuildings.add(new Building("D29468E2AD8241769F47D82913C537EA", "黄家湖校区工程训练中心", huangjiahu));
huangjiahuBuildings.add(new Building("F9A375E92D814DD3BC2EF30E33C4907B", "教七楼(艺术学院)", huangjiahu));
huangjiahuBuildings.add(new Building("DFC73608380C4079A44D4215BD81EB88", "教十一楼", huangjiahu));
buildingTmp.put(huangjiahu, huangjiahuBuildings);
Campus medicineSchool = CAMPUS.get(2);
List<Building> medicineSchoolBuildings = new ArrayList<>(1);
medicineSchoolBuildings.add(new Building("00047", "附属医院教学楼", medicineSchool));
buildingTmp.put(medicineSchool, medicineSchoolBuildings);
}
}
}

@ -34,7 +34,7 @@ public class ApiException extends BasicException {
@Override
public String toString() {
return "接口调用异常: " + code;
return "Mywust接口调用异常: " + code + ";" + getMessage();
}
public enum Code {

@ -2,6 +2,7 @@ package cn.linghang.mywust.core.parser.undergraduate;
import cn.linghang.mywust.core.exception.ParseException;
import cn.linghang.mywust.core.parser.Parser;
import cn.linghang.mywust.core.util.JsoupUtil;
import cn.linghang.mywust.model.global.ClassRoom;
import cn.linghang.mywust.model.global.Course;
import org.jsoup.Jsoup;
@ -68,11 +69,11 @@ public class UndergradCourseTableParser implements Parser<List<Course>> {
Elements timeElements = courseElement.getElementsByAttributeValue("title", "周次(节次)");
Elements classroomElements = courseElement.getElementsByAttributeValue("title", "教室");
courseBuilder.teachClass(classElements.isEmpty() ? "" : classElements.get(0).text());
courseBuilder.teacher(teacherElements.isEmpty() ? "" : teacherElements.get(0).text());
courseBuilder.teachClass(JsoupUtil.getElementText(classElements));
courseBuilder.teacher(JsoupUtil.getElementText(teacherElements));
ClassRoom classRoom = new ClassRoom();
classRoom.setRoom(classroomElements.isEmpty() ? "" : classroomElements.get(0).text());
classRoom.setRoom(JsoupUtil.getElementText(classroomElements));
courseBuilder.classroom(classRoom);
int weekDay = girdCount % 7;

@ -0,0 +1,31 @@
package cn.linghang.mywust.core.parser.undergraduate;
import cn.linghang.mywust.core.exception.ParseException;
import cn.linghang.mywust.core.parser.Parser;
import cn.linghang.mywust.core.util.JsoupUtil;
import cn.linghang.mywust.core.util.PageFormExtractor;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import java.util.HashMap;
import java.util.Map;
public class UndergradCreditStatusIndexParser implements Parser<Map<String, String>> {
private static final String FROM_PARAM_XPATH = "//*[@id=\"Form1\"]/table/tbody/tr/td[3]";
@Override
public Map<String, String> parse(String html) throws ParseException {
Elements paramElement = Jsoup.parse(html).selectXpath(FROM_PARAM_XPATH);
if (paramElement.isEmpty()) {
throw new ParseException("学分修读情况首页解析失败,关键元素不存在...");
}
Element trimmedElement = paramElement.get(0);
Elements paramElements = trimmedElement.getElementsByAttribute("name");
Map<String, String> targetMap = new HashMap<>(2);
paramElements.forEach(element -> targetMap.put(element.attr("name"), element.attr("value")));
return targetMap;
}
}

@ -38,10 +38,12 @@ public class RequestFactory {
return makeStringDataHttpRequest(url, data, cookies).addHeaders(additionalHeaders);
}
private static final byte[] ZERO_BYTE = {0};
public static HttpRequest makeStringDataHttpRequest(String url, String stringData, String cookies) {
return HttpRequest.builder()
.url(makeUrl(url))
.data(stringData.getBytes(StandardCharsets.UTF_8))
.data(stringData == null ? null : stringData.getBytes(StandardCharsets.UTF_8))
.cookies(cookies)
.build()
.addHeaders(DEFAULT_HTTP_REQUEST.getHeaders());

@ -4,7 +4,7 @@ import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
@Data
public class Map {
public class Map<S, S1> {
@JsonProperty("baseInfo")
private BaseInfo baseInfo;

@ -2,14 +2,13 @@ package cn.linghang.mywust.core.request.undergrade;
import cn.linghang.mywust.core.api.UndergradUrls;
import cn.linghang.mywust.core.request.RequestFactory;
import cn.linghang.mywust.model.global.Campus;
import cn.linghang.mywust.network.entitys.FormBodyBuilder;
import cn.linghang.mywust.network.entitys.HttpRequest;
import cn.linghang.mywust.util.StringUtil;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;
import java.util.TreeMap;
import java.util.*;
public class BkjxRequestFactory extends RequestFactory {
public static HttpRequest sessionCookieRequest(String serviceTicket) {
@ -35,11 +34,39 @@ public class BkjxRequestFactory extends RequestFactory {
formBodyBuilder.add("xsfs", "all");
byte[] postData = formBodyBuilder.buildAndToString().getBytes(StandardCharsets.UTF_8);
return makeHttpRequest(UndergradUrls.BKJX_EXAM_INFO_API, postData, cookies);
return makeHttpRequest(UndergradUrls.BKJX_SCORE_API, postData, cookies);
}
public static HttpRequest trainingPlanPageRequest(String cookies) {
return makeHttpRequest(UndergradUrls.BKJX_SCHEME_API, null, cookies);
return makeHttpRequest(UndergradUrls.BKJX_TRAINING_PLAN_API, null, cookies);
}
public static HttpRequest creditStatusIndexPageRequest(String cookies) {
return makeHttpRequest(UndergradUrls.BKJX_CREDIT_STATUS_INDEX_API, null, cookies);
}
public static HttpRequest creditStatusPageRequest(String cookies, String majorId, String teachPlainId) {
FormBodyBuilder formBodyBuilder = new FormBodyBuilder(2);
// “年度专业代码”(猜的)和“教学0301执行计划id”的参数
formBodyBuilder.add("ndzydm", majorId).add("jx0301zxjhid", teachPlainId);
return makeStringDataHttpRequest(UndergradUrls.BKJX_CREDIT_STATUS_API, formBodyBuilder.buildAndToString(), cookies);
}
public static HttpRequest creditStatusPageRequest(String cookies, Map<String , String> params) {
FormBodyBuilder formBodyBuilder = new FormBodyBuilder(2);
Set<String> keys = params.keySet();
for (String key : keys) {
formBodyBuilder.add(key, params.get(key));
}
return makeStringDataHttpRequest(UndergradUrls.BKJX_CREDIT_STATUS_API, formBodyBuilder.buildAndToString(), cookies);
}
// 不带参数的学分修读情况获取,正常情况下是待带两个参数的(ndzyd和mjx0301zxjhid)
// 但是经过实际测试直接post也是可以的,也就是说post什么都是可以的
public static HttpRequest creditStatusPageRequest(String cookies) {
return makeStringDataHttpRequest(UndergradUrls.BKJX_CREDIT_STATUS_API, "", cookies);
}
public static HttpRequest courseTablePageRequest(String term, String cookies) {
@ -52,6 +79,29 @@ public class BkjxRequestFactory extends RequestFactory {
return makeHttpRequest(UndergradUrls.BKJX_COURSE_TABLE_API, queryData, cookies);
}
public static HttpRequest examActivityListRequest(String term, String cookie) {
String url = String.format(UndergradUrls.BKJX_EXAM_ACTIVITY_LIST_API, term);
return makeHttpRequest(url, null, cookie);
}
public static HttpRequest examDelayApplicationListRequest(String term, String activityId, String cookie) {
FormBodyBuilder formBodyBuilder = new FormBodyBuilder(4);
formBodyBuilder.add("xnxqid", term);
formBodyBuilder.add("cj0701id", activityId);
formBodyBuilder.add("kch", "");
formBodyBuilder.add("iswfmes", "");
return makeStringDataHttpRequest(UndergradUrls.BKJX_EXAM_DELAY_APPLICATION_LIST_API, formBodyBuilder.buildAndToString(), cookie);
}
public static HttpRequest buildingListRequest(String campus, String cookie) {
return null;
}
public static HttpRequest buildingListRequest(Campus campus, String cookie) {
return buildingListRequest(campus.id, cookie);
}
public static class Legacy {
public static HttpRequest dataStringRequest() {
return makeHttpRequest(UndergradUrls.Legacy.BKJX_DATA_STRING_API);

@ -39,7 +39,10 @@ public class LibraryLogin {
}
public boolean checkCookie(String cookies) throws IOException {
RequestClientOption option = RequestClientOption.DEFAULT_OPTION;
return this.checkCookie(cookies, null);
}
public boolean checkCookie(String cookies, RequestClientOption option) throws IOException {
HttpRequest testRequest = LibraryRequestFactory.makeHttpRequest(LibraryUrls.LIBRARY_COOKIE_TEST_URL, null, cookies);
HttpResponse testResponse = requester.get(testRequest, option);

@ -35,14 +35,14 @@ public class UndergraduateLogin {
HttpResponse sessionResponse = requester.get(sessionRequest, requestOption);
String cookies = sessionResponse.getCookies();
if (!roughCheckCookie(cookies)) {
if (roughCheckCookieFail(cookies)) {
log.error("[mywust]: Cookie粗查不通过:{}", cookies);
throw new ApiException(ApiException.Code.UNKNOWN_EXCEPTION, "登录获取的Cookie无效");
}
// 检查Cookie是否真正可用,同时请求一次任意接口使后续接口能够正确响应
// 拿到Cookie后调用的第一个接口会产生302/301跳转,需要再次调用才能正确响应
if (!checkCookies(cookies, requestOption)) {
if (checkCookiesFail(cookies, requestOption)) {
log.warn("[mywust]: Cookie检查不通过:{}", cookies);
}
@ -89,28 +89,38 @@ public class UndergraduateLogin {
HttpResponse sessionResponse = requester.get(sessionRequest, requestOption);
String cookies = sessionResponse.getCookies();
if (checkCookies(cookies, requestOption)) {
log.warn("[mywust]: Cookie检查不通过:{}", cookies);
if (roughCheckCookieFail(cookies)) {
log.error("[mywust]: Cookie粗查不通过:{}", cookies);
throw new ApiException(ApiException.Code.UNKNOWN_EXCEPTION, "登录获取的Cookie无效");
}
// 检查Cookie是否真正可用,同时请求一次任意接口使后续接口能够正确响应
// 拿到Cookie后调用的第一个接口会产生302/301跳转,需要再次调用才能正确响应
if (checkCookiesFail(cookies, requestOption)) {
log.warn("[mywust]: Cookie检查不通过:{}", cookies);
}
return cookies;
}
private boolean roughCheckCookie(String cookies) {
return cookies != null && cookies.contains("JSESSIONID") && cookies.contains("SERVERID");
private boolean roughCheckCookieFail(String cookies) {
return cookies == null || !cookies.contains("JSESSIONID") || !cookies.contains("SERVERID");
}
private static final int COOKIES_ERROR_RESPONSE_LENGTH =
("<script languge='javascript'>window.location.href='https://auth.wust.edu.cn/lyuapServer/login?service=http%3A%2F%2Fbkjx.wust.edu.cn%2Fjsxsd%2Fframework%2FblankPage.jsp'</script>")
.length();
public boolean checkCookies(String cookies, RequestClientOption option) throws IOException {
public boolean checkCookiesFail(String cookies, RequestClientOption option) throws IOException {
HttpRequest testRequest = BkjxRequestFactory.makeHttpRequest(UndergradUrls.BKJX_TEST_API, null, cookies);
HttpResponse testResponse = requester.get(testRequest, option);
// 判断响应长度是否为这么多个字,登录跳转响应长度
// 这种办法虽然在极端情况下可能会出错(而且还挺蠢的),但是是最快的办法中比较准确的了
return Math.abs(COOKIES_ERROR_RESPONSE_LENGTH - testResponse.getBody().length) > 8;
return Math.abs(COOKIES_ERROR_RESPONSE_LENGTH - testResponse.getBody().length) <= 8;
}
public boolean checkCookiesFail(String cookies) throws IOException {
return this.checkCookiesFail(cookies, null);
}
}

@ -33,4 +33,8 @@ public class GraduateApiServiceBase {
this.checkResponse(response);
}
public void checkCookies(String cookie) throws ApiException, IOException {
this.checkCookies(cookie, null);
}
}

@ -23,7 +23,7 @@ public abstract class UndergradApiServiceBase {
// 检查响应是否正确
if (response.getBody() == null ||
response.getStatusCode() != HttpResponse.HTTP_OK ||
BkjxUtil.checkLoginFinger(response.getBody())) {
BkjxUtil.hasLoginFinger(response.getBody())) {
throw new ApiException(ApiException.Code.COOKIE_INVALID);
}
@ -36,6 +36,10 @@ public abstract class UndergradApiServiceBase {
this.checkResponse(response);
}
public void checkCookies(String cookie) throws ApiException, IOException {
this.checkCookies(cookie, null);
}
public abstract String getPage(String cookie, Map<String, String> params, RequestClientOption option) throws ApiException, IOException;
public abstract String getPage(String cookie, Map<String, String> params) throws ApiException, IOException;
}

@ -0,0 +1,57 @@
package cn.linghang.mywust.core.service.undergraduate;
import cn.linghang.mywust.core.exception.ApiException;
import cn.linghang.mywust.core.exception.ParseException;
import cn.linghang.mywust.core.parser.undergraduate.UndergradCreditStatusIndexParser;
import cn.linghang.mywust.core.request.undergrade.BkjxRequestFactory;
import cn.linghang.mywust.network.RequestClientOption;
import cn.linghang.mywust.network.Requester;
import cn.linghang.mywust.network.entitys.HttpRequest;
import cn.linghang.mywust.network.entitys.HttpResponse;
import java.io.IOException;
import java.util.Map;
public class UndergradCreditStatusApiService extends UndergradApiServiceBase {
private static final UndergradCreditStatusIndexParser parser = new UndergradCreditStatusIndexParser();
public UndergradCreditStatusApiService(Requester requester) {
super(requester);
}
@Override
public String getPage(String cookie, Map<String, String> params, RequestClientOption option) throws ApiException, IOException {
return this.getPage(cookie, option, false);
}
@Override
public String getPage(String cookie, Map<String, String> params) throws ApiException, IOException {
return this.getPage(cookie, params, null);
}
public String getPage(String cookie, RequestClientOption option, boolean quick) throws IOException, ApiException {
HttpRequest request;
if (quick) {
request = BkjxRequestFactory.creditStatusPageRequest(cookie);
} else {
HttpRequest indexRequest = BkjxRequestFactory.creditStatusIndexPageRequest(cookie);
HttpResponse indexResponse = requester.get(indexRequest, option);
this.checkResponse(indexResponse);
String indexHtml = indexResponse.getStringBody();
Map<String, String> params;
try {
params = parser.parse(indexHtml);
} catch (ParseException e) {
throw new ApiException(ApiException.Code.COOKIE_INVALID);
}
request = BkjxRequestFactory.creditStatusPageRequest(cookie, params);
}
HttpResponse response = requester.post(request, option);
this.checkResponse(response);
return response.getStringBody();
}
}

@ -0,0 +1,83 @@
package cn.linghang.mywust.core.service.undergraduate;
import cn.linghang.mywust.core.exception.ApiException;
import cn.linghang.mywust.core.request.undergrade.BkjxRequestFactory;
import cn.linghang.mywust.network.RequestClientOption;
import cn.linghang.mywust.network.Requester;
import cn.linghang.mywust.network.entitys.HttpRequest;
import cn.linghang.mywust.network.entitys.HttpResponse;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.IOException;
import java.util.Map;
/**
* 缓考申请查询
*/
public class UndergradExamDelayApiService extends UndergradApiServiceBase {
public UndergradExamDelayApiService(Requester requester) {
super(requester);
}
@Override
public String getPage(String cookie, Map<String, String> params, RequestClientOption option) throws ApiException, IOException {
if (params == null) {
throw new ApiException(ApiException.Code.INTERNAL_EXCEPTION);
}
String term = params.get("term");
String activityId = params.get("activityId");
if (term == null || activityId == null) {
throw new ApiException(ApiException.Code.INTERNAL_EXCEPTION);
}
return this.getPage(term, activityId, cookie, option);
}
@Override
public String getPage(String cookie, Map<String, String> params) throws ApiException, IOException {
return this.getPage(cookie, params, null);
}
public String getPage(String term, String activityId, String cookie, RequestClientOption option) throws ApiException, IOException {
HttpRequest request = BkjxRequestFactory.examDelayApplicationListRequest(term, activityId, cookie);
HttpResponse response = requester.post(request, option);
this.checkResponse(response);
return request.getStringData();
}
public String getPage(String term, String activityId, String cookie) throws ApiException, IOException {
return this.getPage(term, activityId, cookie, null);
}
public ExamActivity[] getActivities(String term, String cookie, RequestClientOption option) throws ApiException, IOException {
HttpRequest request = BkjxRequestFactory.examActivityListRequest(term, cookie);
HttpResponse response = requester.get(request, option);
this.checkResponse(response);
try {
return new ObjectMapper().readValue(response.getBody(), ExamActivity[].class);
} catch (IOException e) {
throw new ApiException(ApiException.Code.UNKNOWN_EXCEPTION, "解析考试活动id列表失败:响应数据:" + response.getStringBody());
}
}
public ExamActivity[] getActivities(String term, String cookie) throws ApiException, IOException {
return this.getActivities(term, cookie, null);
}
public static class ExamActivity {
@JsonProperty("cj0701id")
public final String id;
@JsonProperty("cjlrmc")
public final String name;
public ExamActivity(String id, String name) {
this.id = id;
this.name = name;
}
}
}

@ -34,4 +34,8 @@ public class UndergradScoreApiService extends UndergradApiServiceBase {
return new String(response.getBody());
}
public String getPage(String cookies) throws IOException, ApiException {
return this.getPage(cookies, (RequestClientOption) null);
}
}

@ -34,4 +34,8 @@ public class UndergradStudentInfoApiService extends UndergradApiServiceBase {
return new String(response.getBody());
}
public String getPage(String cookies) throws IOException, ApiException {
return this.getPage(cookies, (RequestClientOption) null);
}
}

@ -34,4 +34,8 @@ public class UndergradTrainingPlanApiService extends UndergradApiServiceBase {
return new String(response.getBody());
}
public String getPage(String cookies) throws IOException, ApiException {
return this.getPage(cookies, (RequestClientOption) null);
}
}

@ -16,7 +16,7 @@ public class BkjxUtil {
* @param response 响应的字节
* @return 是否需要重新登录
*/
public static boolean checkLoginFinger(byte[] response) {
public static boolean hasLoginFinger(byte[] response) {
if (response == null) {
return false;
}

@ -0,0 +1,32 @@
package cn.linghang.mywust.model.global;
import java.util.StringJoiner;
public final class Building {
public final String id;
public final String name;
public final Campus campus;
public Building(String id, String name, Campus campus) {
this.id = id;
this.name = name;
this.campus = campus;
}
public String getId() {
return id;
}
public String getName() {
return name;
}
@Override
public String toString() {
return new StringJoiner(", ", Building.class.getSimpleName() + "[", "]")
.add("id='" + id + "'")
.add("name='" + name + "'")
.add("campus=" + campus)
.toString();
}
}

@ -0,0 +1,29 @@
package cn.linghang.mywust.model.global;
import java.util.StringJoiner;
public final class Campus {
public final String id;
public final String name;
public Campus(String id, String name) {
this.id = id;
this.name = name;
}
public String getId() {
return id;
}
public String getName() {
return name;
}
@Override
public String toString() {
return new StringJoiner(", ", Campus.class.getSimpleName() + "[", "]")
.add("id='" + id + "'")
.add("name='" + name + "'")
.toString();
}
}

@ -0,0 +1,29 @@
package cn.linghang.mywust.model.global;
import java.util.StringJoiner;
public final class College {
public final String id;
public final String name;
public College(String id, String name) {
this.id = id;
this.name = name;
}
public String getId() {
return id;
}
public String getName() {
return name;
}
@Override
public String toString() {
return new StringJoiner(", ", College.class.getSimpleName() + "[", "]")
.add("id='" + id + "'")
.add("name='" + name + "'")
.toString();
}
}

@ -4,20 +4,25 @@
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>cn.linghang</groupId>
<parent>
<groupId>cn.linghang</groupId>
<artifactId>mywust</artifactId>
<version>${revision}</version>
</parent>
<artifactId>mywust-test</artifactId>
<version>1.0-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>cn.linghang</groupId>
<artifactId>mywust-core</artifactId>
<version>0.0.1-SNAPSHOT</version>
<version>${project.parent.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>cn.linghang</groupId>
<artifactId>mywust-network-okhttp</artifactId>
<version>1.0-SNAPSHOT</version>
<version>${project.parent.version}</version>
<scope>test</scope>
</dependency>
@ -57,7 +62,6 @@
<scope>test</scope>
</dependency>
</dependencies>
<properties>

@ -1,49 +0,0 @@
import cn.linghang.mywust.core.exception.BasicException;
import cn.linghang.mywust.core.parser.Parser;
import cn.linghang.mywust.core.parser.undergraduate.CourseTableParser;
import cn.linghang.mywust.core.service.undergraduate.CourseTableApiService;
import cn.linghang.mywust.model.global.Course;
import cn.linghang.mywust.network.RequestClientOption;
import cn.linghang.mywust.network.Requester;
import cn.linghang.mywust.network.okhttp.SimpleOkhttpRequester;
import org.junit.jupiter.api.Test;
import java.io.IOException;
import java.util.List;
import java.util.Scanner;
public class CourseTableTest {
@Test
public void run() throws BasicException, IOException {
System.out.println("课表");
System.out.println("Cookie:");
Scanner scanner = new Scanner(System.in);
String cookie = scanner.nextLine();
System.out.println("使用Cookie:" + cookie);
System.out.println("学期(如2022-2023-1):");
String term = scanner.nextLine();
System.out.println("使用学期:" + term);
Requester requester = new SimpleOkhttpRequester();
CourseTableApiService service = new CourseTableApiService(requester);
RequestClientOption option = new RequestClientOption();
option.setTimeout(5);
RequestClientOption.Proxy proxy = new RequestClientOption.Proxy();
proxy.setPort(6060);
proxy.setAddress("127.0.0.1");
option.setProxy(proxy);
option.setFallowUrlRedirect(false);
Parser<List<Course>> parser = new CourseTableParser();
List<Course> courses = parser.parse(service.getCourseTablePage(term, cookie, option));
for (Course info : courses) {
System.out.println(info);
}
}
}

@ -1,46 +0,0 @@
import cn.linghang.mywust.core.exception.BasicException;
import cn.linghang.mywust.core.parser.Parser;
import cn.linghang.mywust.core.parser.undergraduate.ExamInfoParser;
import cn.linghang.mywust.core.service.undergraduate.ExamInfoApiService;
import cn.linghang.mywust.model.global.ExamInfo;
import cn.linghang.mywust.network.RequestClientOption;
import cn.linghang.mywust.network.Requester;
import cn.linghang.mywust.network.okhttp.SimpleOkhttpRequester;
import org.junit.jupiter.api.Test;
import java.io.IOException;
import java.util.List;
import java.util.Scanner;
public class ExamInfoTest {
@Test
public void run() throws BasicException, IOException {
System.out.println("成绩获取");
System.out.println("Cookie:");
Scanner scanner = new Scanner(System.in);
String cookie = scanner.nextLine();
System.out.println("使用Cookie:" + cookie);
Requester requester = new SimpleOkhttpRequester();
ExamInfoApiService jwcService = new ExamInfoApiService(requester);
RequestClientOption option = new RequestClientOption();
option.setTimeout(5);
RequestClientOption.Proxy proxy = new RequestClientOption.Proxy();
proxy.setPort(8080);
proxy.setAddress("127.0.0.1");
option.setProxy(proxy);
option.setFallowUrlRedirect(false);
Parser<List<ExamInfo>> parser = new ExamInfoParser();
List<ExamInfo> infos = parser.parse(jwcService.getExamInfoPage(cookie, option));
for (ExamInfo info : infos) {
System.out.println(info);
}
}
}

@ -1,45 +0,0 @@
import cn.linghang.mywust.core.exception.BasicException;
import cn.linghang.mywust.core.service.auth.UnionLogin;
import cn.linghang.mywust.core.service.auth.JwcLogin;
import cn.linghang.mywust.network.RequestClientOption;
import cn.linghang.mywust.network.Requester;
import cn.linghang.mywust.network.okhttp.SimpleOkhttpRequester;
import org.junit.jupiter.api.Test;
import java.io.IOException;
import java.util.Scanner;
public class JwcLoginTest {
@Test
public void run() throws BasicException, IOException {
System.out.println("bkjx登录测试(统一身份验证)");
System.out.println("输入账号(学号)和密码,用“ ”(空格)分割");
Scanner scanner = new Scanner(System.in);
String input = scanner.nextLine();
String username = input.split(" ")[0];
String password = input.split(" ")[1];
System.out.println("账号:" + username);
System.out.println("密码:" + password);
Requester requester = new SimpleOkhttpRequester();
JwcLogin jwcLogin = new JwcLogin(requester);
RequestClientOption option = new RequestClientOption();
option.setTimeout(5);
option.setFallowUrlRedirect(false);
RequestClientOption.Proxy proxy = new RequestClientOption.Proxy();
proxy.setPort(6060);
proxy.setAddress("127.0.0.1");
option.setProxy(proxy);
String cookies = jwcLogin.getLoginCookie(username, password, option);
System.out.printf("获取到Cookies: %s \n", cookies);
System.out.printf("检查Cookies: %s", jwcLogin.checkCookies(cookies, RequestClientOption.DEFAULT_OPTION));
}
}

@ -1,39 +0,0 @@
import cn.linghang.mywust.core.exception.BasicException;
import cn.linghang.mywust.core.service.auth.UnionLogin;
import cn.linghang.mywust.core.service.auth.LibraryLogin;
import cn.linghang.mywust.network.RequestClientOption;
import cn.linghang.mywust.network.Requester;
import cn.linghang.mywust.network.okhttp.SimpleOkhttpRequester;
import org.junit.jupiter.api.Test;
import java.io.IOException;
import java.util.Scanner;
public class LibraryLoginTest {
@Test
public void run() throws BasicException, IOException {
System.out.println("图书馆登陆测试");
System.out.println("输入账号(学号)和密码,用“ ”(空格)分割");
Scanner scanner = new Scanner(System.in);
String input = scanner.nextLine();
String username = input.split(" ")[0];
String password = input.split(" ")[1];
System.out.println("账号:" + username);
System.out.println("密码:" + password);
Requester requester = new SimpleOkhttpRequester();
LibraryLogin libraryLogin = new LibraryLogin(requester);
RequestClientOption option = RequestClientOption.DEFAULT_OPTION;
String cookies = libraryLogin.getLibraryLoginCookie(username, password, option);
System.out.printf("获取到的cookies: %s \n", cookies);
System.out.printf("检查Cookies: %s", libraryLogin.checkCookie(cookies));
}
}

@ -1,38 +0,0 @@
import cn.linghang.mywust.core.exception.BasicException;
import cn.linghang.mywust.core.service.undergraduate.TrainingPlanApiService;
import cn.linghang.mywust.network.RequestClientOption;
import cn.linghang.mywust.network.Requester;
import cn.linghang.mywust.network.okhttp.SimpleOkhttpRequester;
import org.junit.jupiter.api.Test;
import java.io.IOException;
import java.util.Scanner;
public class SchemeTest {
@Test
public void run() throws BasicException, IOException {
System.out.println("培养方案获取");
System.out.println("Cookie:");
Scanner scanner = new Scanner(System.in);
String cookie = scanner.nextLine();
System.out.println("使用Cookie:" + cookie);
RequestClientOption option = new RequestClientOption();
option.setTimeout(5);
RequestClientOption.Proxy proxy = new RequestClientOption.Proxy();
proxy.setPort(6060);
proxy.setAddress("127.0.0.1");
option.setProxy(null);
option.setFallowUrlRedirect(false);
Requester requester = new SimpleOkhttpRequester();
TrainingPlanApiService jwcService = new TrainingPlanApiService(requester);
String page = jwcService.getTrainingPlanPage(cookie, option);
System.out.println(page);
}
}

@ -1,39 +0,0 @@
import cn.linghang.mywust.core.exception.BasicException;
import cn.linghang.mywust.core.parser.Parser;
import cn.linghang.mywust.core.parser.undergraduate.StudentInfoPageParser;
import cn.linghang.mywust.core.service.undergraduate.StudentInfoApiService;
import cn.linghang.mywust.model.global.StudentInfo;
import cn.linghang.mywust.network.RequestClientOption;
import cn.linghang.mywust.network.Requester;
import cn.linghang.mywust.network.okhttp.SimpleOkhttpRequester;
import org.junit.jupiter.api.Test;
import java.io.IOException;
import java.util.Scanner;
public class StudentInfoPageTest {
@Test
public void run() throws BasicException, IOException {
System.out.println("学生信息获取");
System.out.println("Cookie:");
Scanner scanner = new Scanner(System.in);
String cookie = scanner.nextLine();
System.out.println("使用Cookie:" + cookie);
Requester requester = new SimpleOkhttpRequester();
StudentInfoApiService jwcService = new StudentInfoApiService(requester);
RequestClientOption option = new RequestClientOption();
option.setTimeout(5);
option.setProxy(null);
option.setFallowUrlRedirect(false);
Parser<StudentInfo> parser = new StudentInfoPageParser();
StudentInfo info = parser.parse(jwcService.getStudentInfoPage(cookie, option));
System.out.println(info);
}
}

@ -1,2 +0,0 @@
public class UnderGraduateTest {
}

@ -1,58 +0,0 @@
import cn.linghang.mywust.core.exception.BasicException;
import cn.linghang.mywust.core.parser.Parser;
import cn.linghang.mywust.core.parser.physics.PhysicsCoursePageParser;
import cn.linghang.mywust.core.service.auth.PhysicsLogin;
import cn.linghang.mywust.core.service.physics.PhysicsApiService;
import cn.linghang.mywust.model.global.Course;
import cn.linghang.mywust.model.physics.PhysicsCourse;
import cn.linghang.mywust.network.RequestClientOption;
import cn.linghang.mywust.network.Requester;
import cn.linghang.mywust.network.okhttp.SimpleOkhttpRequester;
import org.junit.jupiter.api.Test;
import java.io.IOException;
import java.util.List;
import java.util.Scanner;
public class WlsyLoginTest {
@Test
public void run() throws BasicException, IOException {
System.out.println("物理实验登陆测试");
System.out.println("输入账号(学号)和密码,用“ ”(空格)分割");
Scanner scanner = new Scanner(System.in);
String input = scanner.nextLine();
String username = input.split(" ")[0];
String password = input.split(" ")[1];
System.out.println("账号:" + username);
System.out.println("密码:" + password);
Requester requester = new SimpleOkhttpRequester();
PhysicsLogin physicsLogin = new PhysicsLogin(requester);
RequestClientOption option = RequestClientOption.DEFAULT_OPTION;
RequestClientOption.Proxy proxy = new RequestClientOption.Proxy();
proxy.setAddress("127.0.0.1");
proxy.setPort(8080);
option.setProxy(proxy);
String cookies = physicsLogin.getLoginCookie(username, password, option);
System.out.printf("获取到的cookies: %s \n", cookies);
option.setFallowUrlRedirect(false);
PhysicsApiService api = new PhysicsApiService(requester);
String response = api.getCoursePage(cookies, option);
System.out.println(response);
Parser<List<PhysicsCourse>> parser = new PhysicsCoursePageParser();
List<PhysicsCourse> courses = parser.parse(response);
for (Course info : courses) {
System.out.println(info);
}
}
}

@ -115,7 +115,7 @@ public class PasswordEncoder {
*/
public static String legacyPassword(String username, String password, String dataString) {
String[] parts = dataString.split("#");
String scode = parts[0];
StringBuilder scode = new StringBuilder(parts[0]);
String sxh = parts[1];
String code = username + "%%%" + password;
@ -123,11 +123,11 @@ public class PasswordEncoder {
StringBuilder encoded = new StringBuilder();
for (int i = 0, codeLength = code.length(); i < codeLength; i++) {
if (i < 20) {
int endIndex = parseInt(sxh.substring(i, i + 1));
encoded.append(code.charAt(i)).append(scode, 0, endIndex);
scode = scode.substring(endIndex);
int index = sxh.charAt(i) - 48;
encoded.append(code.charAt(i)).append(scode, 0, index);
scode.delete(0, index);
} else {
encoded.append(code.substring(i));
encoded.append(code, i, codeLength);
i = codeLength;
}
}

@ -70,4 +70,31 @@ public class StringUtil {
return Base64.encodeBase64String(rawText.toString().getBytes(StandardCharsets.UTF_8));
}
public static String NoneNullString(String str) {
return str == null ? "" : str;
}
public static String getTermString(Date date, boolean autumn) {
Calendar calendar = new GregorianCalendar();
calendar.setTime(date);
return getTermString(calendar, autumn);
}
public static String getTermString(Calendar calendar, boolean autumn) {
int year = calendar.get(Calendar.YEAR);
int nextYear = year + 1;
// 秋季期,就是第一个学期
return String.format("%d-%d-%s", year, nextYear, autumn ? "1" : "2");
}
public static String getCurrentTermString() {
Calendar now = Calendar.getInstance();
int month = now.get(Calendar.MONTH);
// 一般八月到第二年二月算是是秋季期
return getTermString(now, month >= 8 || month < 2);
}
}

@ -14,6 +14,7 @@
<module>mywust-model</module>
<module>mywust-network</module>
<module>mywust-util</module>
<module>mywust-test</module>
<module>mywust-network-httpclient</module>
<module>mywust-network-okhttp</module>
</modules>
@ -28,7 +29,7 @@
</dependencies>
<properties>
<revision>0.0.1-fixed</revision>
<revision>0.0.2-SNAPSHOT</revision>
<lombok.version>1.18.22</lombok.version>

Loading…
Cancel
Save