更新太多了,主要是代码结构的一些调整,一方面是service包下只保留请求部分,解析由调用方自行调用(因为存在部分只需要请求而不需要解析的情况),将本科教学系统的功能api拆分成不同的类,调用者可按需生成实例,api接口异常改用通用的业务异常

old-package
lensfrex 2 years ago
parent 3bc1df9836
commit f3aa0d4be0
Signed by: lensfrex
GPG Key ID: 0F69A0A2FBEE98A0
  1. 12
      mywust-core/pom.xml
  2. 2
      mywust-core/src/main/java/cn/linghang/mywust/core/api/Graduate.java
  3. 6
      mywust-core/src/main/java/cn/linghang/mywust/core/api/Library.java
  4. 5
      mywust-core/src/main/java/cn/linghang/mywust/core/api/PhysicsSystem.java
  5. 3
      mywust-core/src/main/java/cn/linghang/mywust/core/api/UnionAuth.java
  6. 95
      mywust-core/src/main/java/cn/linghang/mywust/core/exception/ApiException.java
  7. 14
      mywust-core/src/main/java/cn/linghang/mywust/core/exception/CookieInvalidException.java
  8. 14
      mywust-core/src/main/java/cn/linghang/mywust/core/exception/PasswordWornException.java
  9. 2
      mywust-core/src/main/java/cn/linghang/mywust/core/parser/graduate/GraduateCourseTableParser.java
  10. 2
      mywust-core/src/main/java/cn/linghang/mywust/core/parser/graduate/GraduateExamInfoParser.java
  11. 2
      mywust-core/src/main/java/cn/linghang/mywust/core/parser/graduate/GraduateStudentInfoPageParser.java
  12. 2
      mywust-core/src/main/java/cn/linghang/mywust/core/parser/graduate/GraduateTrainingPlanPageParser.java
  13. 16
      mywust-core/src/main/java/cn/linghang/mywust/core/parser/physics/PhysicsCoursePageParser.java
  14. 6
      mywust-core/src/main/java/cn/linghang/mywust/core/parser/physics/PhysicsIndexPageParser.java
  15. 13
      mywust-core/src/main/java/cn/linghang/mywust/core/parser/physics/xpath/PhysicsCourseXpath.java
  16. 5
      mywust-core/src/main/java/cn/linghang/mywust/core/parser/physics/xpath/PhysicsIndexXpath.java
  17. 5
      mywust-core/src/main/java/cn/linghang/mywust/core/parser/undergraduate/ExamInfoParser.java
  18. 32
      mywust-core/src/main/java/cn/linghang/mywust/core/parser/undergraduate/StudentInfoPageParser.java
  19. 1
      mywust-core/src/main/java/cn/linghang/mywust/core/parser/undergraduate/TrainingPlanPageParser.java
  20. 5
      mywust-core/src/main/java/cn/linghang/mywust/core/parser/undergraduate/xpath/ExamInfoXpath.java
  21. 31
      mywust-core/src/main/java/cn/linghang/mywust/core/parser/undergraduate/xpath/StudentInfoXpath.java
  22. 14
      mywust-core/src/main/java/cn/linghang/mywust/core/request/graduate/GraduateRequestFactory.java
  23. 12
      mywust-core/src/main/java/cn/linghang/mywust/core/request/library/LibraryRequestFactory.java
  24. 30
      mywust-core/src/main/java/cn/linghang/mywust/core/request/library/response/BaseInfo.java
  25. 30
      mywust-core/src/main/java/cn/linghang/mywust/core/request/library/response/DetailInfo.java
  26. 30
      mywust-core/src/main/java/cn/linghang/mywust/core/request/library/response/ExtraInfo.java
  27. 49
      mywust-core/src/main/java/cn/linghang/mywust/core/request/library/response/LoanResultItem.java
  28. 64
      mywust-core/src/main/java/cn/linghang/mywust/core/request/library/response/Map.java
  29. 17
      mywust-core/src/main/java/cn/linghang/mywust/core/request/library/response/Response.java
  30. 150
      mywust-core/src/main/java/cn/linghang/mywust/core/request/library/response/SearchResultItem.java
  31. 19
      mywust-core/src/main/java/cn/linghang/mywust/core/request/physics/PhysicsSystemRequestFactory.java
  32. 14
      mywust-core/src/main/java/cn/linghang/mywust/core/service/auth/JwcLogin.java
  33. 8
      mywust-core/src/main/java/cn/linghang/mywust/core/service/auth/LibraryLogin.java
  34. 17
      mywust-core/src/main/java/cn/linghang/mywust/core/service/auth/PhysicsLogin.java
  35. 30
      mywust-core/src/main/java/cn/linghang/mywust/core/service/auth/UnionLogin.java
  36. 36
      mywust-core/src/main/java/cn/linghang/mywust/core/service/graduate/GraduateApiService.java
  37. 25
      mywust-core/src/main/java/cn/linghang/mywust/core/service/graduate/GraduateCourseTableApiService.java
  38. 25
      mywust-core/src/main/java/cn/linghang/mywust/core/service/graduate/GraduateScoreApiService.java
  39. 25
      mywust-core/src/main/java/cn/linghang/mywust/core/service/graduate/GraduateStudentInfoApiService.java
  40. 25
      mywust-core/src/main/java/cn/linghang/mywust/core/service/graduate/GraduateTrainingPlanApiService.java
  41. 2
      mywust-core/src/main/java/cn/linghang/mywust/core/service/library/LibraryApiService.java
  42. 31
      mywust-core/src/main/java/cn/linghang/mywust/core/service/physics/PhysicsApiService.java
  43. 22
      mywust-core/src/main/java/cn/linghang/mywust/core/service/undergraduate/CourseTableApiService.java
  44. 23
      mywust-core/src/main/java/cn/linghang/mywust/core/service/undergraduate/ExamInfoApiService.java
  45. 38
      mywust-core/src/main/java/cn/linghang/mywust/core/service/undergraduate/StudentInfoApi.java
  46. 26
      mywust-core/src/main/java/cn/linghang/mywust/core/service/undergraduate/StudentInfoApiService.java
  47. 36
      mywust-core/src/main/java/cn/linghang/mywust/core/service/undergraduate/TrainingPlanApi.java
  48. 26
      mywust-core/src/main/java/cn/linghang/mywust/core/service/undergraduate/TrainingPlanApiService.java
  49. 17
      mywust-core/src/main/java/cn/linghang/mywust/core/service/undergraduate/UndergraduateApi.java
  50. 38
      mywust-core/src/main/java/cn/linghang/mywust/core/service/undergraduate/UndergraduateApiService.java
  51. 4
      mywust-core/src/main/java/cn/linghang/mywust/core/util/BkjxUtil.java
  52. 27
      mywust-core/src/main/java/cn/linghang/mywust/core/util/PageFormExtractor.java
  53. 6
      mywust-test/pom.xml
  54. 17
      mywust-test/src/test/java/CourseTableTest.java
  55. 19
      mywust-test/src/test/java/ExamInfoTest.java
  56. 10
      mywust-test/src/test/java/JwcLoginTest.java
  57. 10
      mywust-test/src/test/java/LibraryLoginTest.java
  58. 14
      mywust-test/src/test/java/SchemeTest.java
  59. 17
      mywust-test/src/test/java/StudentInfoPageTest.java
  60. 2
      mywust-test/src/test/java/UnderGraduateTest.java
  61. 28
      mywust-test/src/test/java/WlsyLoginTest.java

@ -55,6 +55,18 @@
<version>0.0.1-dev</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.14.0-rc1</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.14.0-rc1</version>
<scope>compile</scope>
</dependency>
</dependencies>
<properties>

@ -4,6 +4,8 @@ public class Graduate {
public static final String GRADUATE_CAPTCHA_API = "http://59.68.177.189/pyxx/PageTemplate/NsoftPage/yzm/createyzm.aspx";
public static final String GRADUATE_LOGIN_API = "http://59.68.177.189/pyxx/login.aspx";
public static final String GRADUATE_INDEX_TEST_API = "http://59.68.177.189/pyxx/Default.aspx";
public static final String GRADUATE_STUDENT_INFO_API = "http://59.68.177.189/pyxx/grgl/student_info1.aspx";
public static final String GRADUATE_COURSE_TABLE_API = "http://59.68.177.189/pyxx/pygl/kbcx_xs.aspx";
public static final String GRADUATE_SCORE_API = "http://59.68.177.189/pyxx/grgl/xskccjcx.aspx";

@ -6,4 +6,10 @@ public class Library {
public static final String LIBRARY_INDEX_URL = "https://libsys.wust.edu.cn/meta-local/opac/cas/rosetta";
public static final String LIBRARY_COOKIE_TEST_URL = "https://libsys.wust.edu.cn/meta-local/opac/users/info";
public static final String LIBRARY_CURRENT_LOAN_API = "https://libsys.wust.edu.cn/meta-local/opac/users/loans";
public static final String LIBRARY_LOAN_HISTORY_API = "https://libsys.wust.edu.cn/meta-local/opac/users/loan_hists";
public static final String LIBRARY_OVERDUE_SOON_API = "https://libsys.wust.edu.cn/meta-local/opac/users/overdue_soon";
public static final String LIBRARY_SEARCH_API = "https://libsys.wust.edu.cn/meta-local/opac/search/";
}

@ -6,4 +6,9 @@ public class PhysicsSystem {
public static final String PHYSICS_LOGIN_COOKIES_API = "http://wlsy.wust.edu.cn/Page/BI/BI000.aspx";
public static final String PHYSICS_MAIN_INDEX_URL = "http://wlsy.wust.edu.cn/Page/BI/BI0000.aspx";
public static final String PHYSICS_SYSTEM_INDEX_URL = "http://wlsy.wust.edu.cn:7101/Page/PEE/PEECM/PEECM0001.aspx";
public static final String PHYSICS_COURSE_INDEX_URL = "http://wlsy.wust.edu.cn:7101/Page/PEE/PEECM/PEECM0001.aspx?flag=1&&action=PEE110101&&moduleId=PEE11";
public static final String PHYSICS_COURSE_API = "http://wlsy.wust.edu.cn:7101/Page/PEE/PEECM/PEECM0001.aspx?action=PEE110301&&parentId=PEE11";
}

@ -7,9 +7,10 @@ public class UnionAuth {
public static final String UNION_AUTH_API = "https://auth.wust.edu.cn/lyuapServer/v1/tickets";
public static class Service {
public static final String LIBRARY_SSO_SERVICE = "https://libsys.wust.edu.cn:443/meta-local/opac/cas/rosetta";
public static final String BKJX_SSO_SERVICE = "http://bkjx.wust.edu.cn/jsxsd/sso.jsp";
public static final String PORTAL_SSO_SERVICE = "https://portal.wust.edu.cn/c/portal/login?redirect=%2F&p_l_id=121585";
}
}

@ -1,38 +1,105 @@
package cn.linghang.mywust.core.exception;
public class ApiException extends BasicException {
private final int code;
private final Code code;
public ApiException(int code) {
public ApiException(Code code) {
this.code = code;
}
public ApiException(int code, String message) {
public ApiException(Code code, String message) {
super(message);
this.code = code;
}
public int getCode() {
public Code getCode() {
return code;
}
public int getCodeValue() {
return code.value;
}
public String getCodeDescribe() {
return code.describe;
}
@Override
public String toString() {
return "接口调用异常: " + code;
}
public static class ApiExceptionCode {
// 统一认证的异常
public static final int UNI_LOGIN_PASSWORD_WRONG = 100101;
public static final int UNI_LOGIN_USER_NOT_EXISTS = 100102;
public static final int UNI_LOGIN_USER_BANNED = 100103;
public enum Code {
/**
* 未知的API异常
*/
UNKNOWN_EXCEPTION(-1, "未知错误(开发又有活干啦)"),
// --------------------------------
// 统一认证的异常(本科生、图书馆)
/**
* 密码错误
*/
UNI_LOGIN_PASSWORD_WRONG(100100, "统一认证登录: 密码错误"),
/**
* 用户不存在
*/
UNI_LOGIN_USER_NOT_EXISTS(100101, "统一认证登录: 用户不存在"),
/**
* 用户登录被封禁
*/
UNI_LOGIN_USER_BANNED(100102, "统一认证登录: 用户被封禁"),
// --------------------------------
// 共有异常码:cookie无效
// 放一起了
public static final int BKJX_COOKIE_INVALID = 110101;
public static final int LIBRARY_COOKIE_INVALID = 12101;
public static final int PHYSICS_COOKIE_INVALID = 130101;
public static final int GRADE_COOKIE_INVALID = 140101;
/**
* Cookie无效
*/
COOKIE_INVALID(100101, "Cookie无效"),
// --------------------------------
// 本科生API异常代码
/**
* 需要评教
*/
BKJX_COURSE_NEED_EVALUATE(110102, "需要评教"),
// --------------------------------
// 物理实验系统API异常代码
/**
* 物理实验系统密码错误
*/
PHYSICS_PASSWORD_WRONG(130100, "物理实验系统登录: 密码错误"),
// --------------------------------
// 研究生API异常代码
/**
* 研究生密码错误
*/
GRADUATE_PASSWORD_WRONG(140100, "研究生登录: 密码错误"),
;
// --------------------------------
// 图书馆API异常代码
private final int value;
private final String describe;
Code(int value, String describe) {
this.value = value;
this.describe = describe;
}
@Override
public String toString() {
return String.format("%s(%d)", describe, value);
}
}
}

@ -1,14 +0,0 @@
package cn.linghang.mywust.core.exception;
public class CookieInvalidException extends BasicException {
public CookieInvalidException() {
}
public CookieInvalidException(String message) {
super(message);
}
public CookieInvalidException(String message, Throwable cause) {
super(message, cause);
}
}

@ -1,14 +0,0 @@
package cn.linghang.mywust.core.exception;
public class PasswordWornException extends BasicException {
public PasswordWornException() {
}
public PasswordWornException(String message) {
super(message);
}
public PasswordWornException(String message, Throwable cause) {
super(message, cause);
}
}

@ -1,4 +1,4 @@
package cn.linghang.mywust.core.parser.postgraduate;
package cn.linghang.mywust.core.parser.graduate;
import cn.linghang.mywust.core.exception.ParseException;
import cn.linghang.mywust.core.parser.Parser;

@ -1,4 +1,4 @@
package cn.linghang.mywust.core.parser.postgraduate;
package cn.linghang.mywust.core.parser.graduate;
import cn.linghang.mywust.core.exception.ParseException;
import cn.linghang.mywust.core.parser.Parser;

@ -1,4 +1,4 @@
package cn.linghang.mywust.core.parser.postgraduate;
package cn.linghang.mywust.core.parser.graduate;
import cn.linghang.mywust.core.exception.ParseException;
import cn.linghang.mywust.core.parser.Parser;

@ -1,4 +1,4 @@
package cn.linghang.mywust.core.parser.postgraduate;
package cn.linghang.mywust.core.parser.graduate;
import cn.linghang.mywust.core.exception.ParseException;
import cn.linghang.mywust.core.parser.Parser;

@ -3,10 +3,8 @@ package cn.linghang.mywust.core.parser.physics;
import cn.linghang.mywust.core.exception.ParseException;
import cn.linghang.mywust.core.parser.HuangjiahuClassroomNameParser;
import cn.linghang.mywust.core.parser.Parser;
import cn.linghang.mywust.core.parser.physics.xpath.PhysicsCourseXpath;
import cn.linghang.mywust.model.physics.PhysicsCourse;
import cn.linghang.mywust.model.global.ClassRoom;
import cn.linghang.mywust.model.global.Course;
import cn.linghang.mywust.model.physics.PhysicsCourse;
import org.jsoup.Jsoup;
import org.jsoup.select.Elements;
@ -83,3 +81,15 @@ public class PhysicsCoursePageParser implements Parser<List<PhysicsCourse>> {
return courses;
}
}
final class PhysicsCourseXpath {
/**
* 用于获取表格中所有行的xpath
* */
public static final String COURSE_ROWS_XPATH = "//*[@id=\"ID_PEE110301_gvpee120101\"]/tbody/tr";
public static final String COURSE_ROW_NAME_XPATH = "";
public static final String COURSE_ROW_TEACHER_XPATH = "";
public static final String COURSE_ROW_TIME_XPATH = "";
public static final String COURSE_ROW_CLASSROOM_XPATH = "";
}

@ -2,7 +2,6 @@ package cn.linghang.mywust.core.parser.physics;
import cn.linghang.mywust.core.exception.ParseException;
import cn.linghang.mywust.core.parser.Parser;
import cn.linghang.mywust.core.parser.physics.xpath.PhysicsIndexXpath;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.select.Elements;
@ -18,3 +17,8 @@ public class PhysicsIndexPageParser implements Parser<String> {
return linkElements.get(0).attr("href");
}
}
final class PhysicsIndexXpath {
public static final String PHYSICS_LINK_XPATH = "//*[@id=\"rolemenu\"]/tbody/tr[1]/td[1]/a[2]";
}

@ -1,13 +0,0 @@
package cn.linghang.mywust.core.parser.physics.xpath;
public class PhysicsCourseXpath {
/**
* 用于获取表格中所有行的xpath
* */
public static final String COURSE_ROWS_XPATH = "//*[@id=\"ID_PEE110301_gvpee120101\"]/tbody/tr";
public static final String COURSE_ROW_NAME_XPATH = "";
public static final String COURSE_ROW_TEACHER_XPATH = "";
public static final String COURSE_ROW_TIME_XPATH = "";
public static final String COURSE_ROW_CLASSROOM_XPATH = "";
}

@ -1,5 +0,0 @@
package cn.linghang.mywust.core.parser.physics.xpath;
public class PhysicsIndexXpath {
public static final String PHYSICS_LINK_XPATH = "//*[@id=\"rolemenu\"]/tbody/tr[1]/td[1]/a[2]";
}

@ -2,7 +2,6 @@ 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.parser.undergraduate.xpath.ExamInfoXpath;
import cn.linghang.mywust.core.util.JsoupUtil;
import cn.linghang.mywust.model.global.ExamInfo;
import org.jsoup.Jsoup;
@ -67,3 +66,7 @@ public class ExamInfoParser implements Parser<List<ExamInfo>> {
return examInfos;
}
}
final class ExamInfoXpath {
public static final String EXAM_INFO_ROWS_XPATH = "//*[@id=\"dataList\"]/tbody/tr";
}

@ -2,7 +2,6 @@ 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.parser.undergraduate.xpath.StudentInfoXpath;
import cn.linghang.mywust.model.global.StudentInfo;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
@ -61,4 +60,35 @@ public class StudentInfoPageParser implements Parser<StudentInfo> {
.idNumber(idNumber)
.build();
}
}
/**
* <p>本科生学生信息接口用到的xpath</p>
* <p>看着挺唬人的其实直接浏览器选择元素复制xpath就行了</p>
* <p>这里的xpath只要网站UI不整什么花活就不会出问题</p>
*
* @author lensfrex
* @create 2022-10-22 22:16
*/
final class StudentInfoXpath {
public static final String STUDENT_NUMBER = "//*[@id=\"xjkpTable\"]/tbody/tr[3]/td[5]";
public static final String COLLEGE = "//*[@id=\"xjkpTable\"]/tbody/tr[3]/td[1]";
public static final String MAJOR = "//*[@id=\"xjkpTable\"]/tbody/tr[3]/td[2]";
public static final String CLASS = "//*[@id=\"xjkpTable\"]/tbody/tr[3]/td[4]";
public static final String NAME = "//*[@id=\"xjkpTable\"]/tbody/tr[4]/td[2]";
public static final String SEX = "//*[@id=\"xjkpTable\"]/tbody/tr[4]/td[4]";
public static final String BIRTHDAY = "//*[@id=\"xjkpTable\"]/tbody/tr[5]/td[2]";
public static final String HOMETOWN = "//*[@id=\"xjkpTable\"]/tbody/tr[7]/td[2]";
public static final String NATIONALITY = "//*[@id=\"xjkpTable\"]/tbody/tr[8]/td[4]";
public static final String ID_NUMBER = "//*[@id=\"xjkpTable\"]/tbody/tr[50]/td[4]";
}

@ -3,7 +3,6 @@ package cn.linghang.mywust.core.parser.undergraduate;
import cn.linghang.mywust.core.exception.ParseException;
import cn.linghang.mywust.core.parser.Parser;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
public class TrainingPlanPageParser implements Parser<String> {

@ -1,5 +0,0 @@
package cn.linghang.mywust.core.parser.undergraduate.xpath;
public class ExamInfoXpath {
public static final String EXAM_INFO_ROWS_XPATH = "//*[@id=\"dataList\"]/tbody/tr";
}

@ -1,31 +0,0 @@
package cn.linghang.mywust.core.parser.undergraduate.xpath;
/**
* <p>本科生学生信息接口用到的xpath</p>
* <p>看着挺唬人的其实直接浏览器选择元素复制xpath就行了</p>
* <p>这里的xpath只要网站UI不整什么花活就不会出问题</p>
*
* @author lensfrex
* @create 2022-10-22 22:16
*/
public class StudentInfoXpath {
public static final String STUDENT_NUMBER = "//*[@id=\"xjkpTable\"]/tbody/tr[3]/td[5]";
public static final String COLLEGE = "//*[@id=\"xjkpTable\"]/tbody/tr[3]/td[1]";
public static final String MAJOR = "//*[@id=\"xjkpTable\"]/tbody/tr[3]/td[2]";
public static final String CLASS = "//*[@id=\"xjkpTable\"]/tbody/tr[3]/td[4]";
public static final String NAME = "//*[@id=\"xjkpTable\"]/tbody/tr[4]/td[2]";
public static final String SEX = "//*[@id=\"xjkpTable\"]/tbody/tr[4]/td[4]";
public static final String BIRTHDAY = "//*[@id=\"xjkpTable\"]/tbody/tr[5]/td[2]";
public static final String HOMETOWN = "//*[@id=\"xjkpTable\"]/tbody/tr[7]/td[2]";
public static final String NATIONALITY = "//*[@id=\"xjkpTable\"]/tbody/tr[8]/td[4]";
public static final String ID_NUMBER = "//*[@id=\"xjkpTable\"]/tbody/tr[50]/td[4]";
}

@ -15,18 +15,18 @@ public class GraduateRequestFactory extends RequestFactory {
return makeHttpRequest(Graduate.GRADUATE_CAPTCHA_API);
}
private static final Map<String,String> CONST_PARAMS = new HashMap<>(5);
private static final Map<String,String> LOGIN_CONST_PARAMS = new HashMap<>(5);
static {
CONST_PARAMS.put("__VIEWSTATE", "/wEPDwUENTM4MWQYAQUeX19Db250cm9sc1JlcXVpcmVQb3N0QmFja0tleV9fFgIFEl9jdGwwOkltYWdlQnV0dG9uMQUSX2N0bDA6SW1hZ2VCdXR0b24yXnZLY54iSWFQ6B2yKH0EisNqU3/eKWEJPibQUElowzU=");
CONST_PARAMS.put("__EVENTVALIDATION", "/wEdAAYVkBquZFuFxLpraDgB64v+UDagjadrq+xukJizXKfuf485DjYUnSc4B1y8D5WGXeCaN+cQ7B52HzGj0ueO5HRlbdfASR9MjKgO1uRUmJC5kWf476Bpzok4CsBoBh+4Dc7vLkoP0tXUghu7H8qg++pYHeGok+i2xPFtG5oj0qB2dw==");
CONST_PARAMS.put("__VIEWSTATEGENERATOR", "496CE0B8");
CONST_PARAMS.put("_ctl0:ImageButton1.x", "39");
CONST_PARAMS.put("_ctl0:ImageButton1.y", "10");
LOGIN_CONST_PARAMS.put("__VIEWSTATE", "/wEPDwUENTM4MWQYAQUeX19Db250cm9sc1JlcXVpcmVQb3N0QmFja0tleV9fFgIFEl9jdGwwOkltYWdlQnV0dG9uMQUSX2N0bDA6SW1hZ2VCdXR0b24yXnZLY54iSWFQ6B2yKH0EisNqU3/eKWEJPibQUElowzU=");
LOGIN_CONST_PARAMS.put("__EVENTVALIDATION", "/wEdAAYVkBquZFuFxLpraDgB64v+UDagjadrq+xukJizXKfuf485DjYUnSc4B1y8D5WGXeCaN+cQ7B52HzGj0ueO5HRlbdfASR9MjKgO1uRUmJC5kWf476Bpzok4CsBoBh+4Dc7vLkoP0tXUghu7H8qg++pYHeGok+i2xPFtG5oj0qB2dw==");
LOGIN_CONST_PARAMS.put("__VIEWSTATEGENERATOR", "496CE0B8");
LOGIN_CONST_PARAMS.put("_ctl0:ImageButton1.x", "39");
LOGIN_CONST_PARAMS.put("_ctl0:ImageButton1.y", "10");
}
public static HttpRequest loginRequest(String username, String password, SolvedImageCaptcha captcha) {
Map<String, String> params = new HashMap<>(7);
params.putAll(CONST_PARAMS);
params.putAll(LOGIN_CONST_PARAMS);
params.put("_ctl0:txtusername", username);
params.put("_ctl0:txtpassword", password);
params.put("_ctl0:txtyzm", captcha.getResult());

@ -12,4 +12,16 @@ public class LibraryRequestFactory extends RequestFactory {
public static HttpRequest indexRequest() {
return makeHttpRequest(Library.LIBRARY_INDEX_URL);
}
public static HttpRequest currentLoanRequest(String cookie) {
return makeHttpRequest(Library.LIBRARY_CURRENT_LOAN_API, null, cookie);
}
public static HttpRequest loanHistoryRequest(String cookie) {
return makeHttpRequest(Library.LIBRARY_LOAN_HISTORY_API, null, cookie);
}
public static HttpRequest overdueSoonRequest(String cookie) {
return makeHttpRequest(Library.LIBRARY_OVERDUE_SOON_API, null, cookie);
}
}

@ -0,0 +1,30 @@
package cn.linghang.mywust.core.request.library.response;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
@Data
public class BaseInfo {
@JsonProperty("map")
private Map map;
@JsonProperty("empty")
private boolean empty;
public void setMap(Map map) {
this.map = map;
}
public Map getMap() {
return map;
}
public void setEmpty(boolean empty) {
this.empty = empty;
}
public boolean isEmpty() {
return empty;
}
}

@ -0,0 +1,30 @@
package cn.linghang.mywust.core.request.library.response;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
@Data
public class DetailInfo {
@JsonProperty("map")
private Map map;
@JsonProperty("empty")
private boolean empty;
public void setMap(Map map) {
this.map = map;
}
public Map getMap() {
return map;
}
public void setEmpty(boolean empty) {
this.empty = empty;
}
public boolean isEmpty() {
return empty;
}
}

@ -0,0 +1,30 @@
package cn.linghang.mywust.core.request.library.response;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
@Data
public class ExtraInfo {
@JsonProperty("map")
private Map map;
@JsonProperty("empty")
private boolean empty;
public void setMap(Map map) {
this.map = map;
}
public Map getMap() {
return map;
}
public void setEmpty(boolean empty) {
this.empty = empty;
}
public boolean isEmpty() {
return empty;
}
}

@ -0,0 +1,49 @@
package cn.linghang.mywust.core.request.library.response;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
@Data
public class LoanResultItem {
@JsonProperty("bibId")
private String bookId;
@JsonProperty("bibAttrs")
private BookAttribute bookAttribute;
@JsonProperty("returnDate")
private String returnDate;
@JsonProperty("loanDate")
private String loanDate;
@JsonProperty("location")
private String location;
@JsonProperty("barCode")
private String barCode;
@Data
public static class BookAttribute {
@JsonProperty("pub_year")
private String publishYear;
@JsonProperty("author")
private String author;
@JsonProperty("callno")
private String callNumber;
@JsonProperty("isbn")
private String isbn;
@JsonProperty("classno")
private String classNumber;
@JsonProperty("publisher")
private String publisher;
@JsonProperty("title")
private String title;
}
}

@ -0,0 +1,64 @@
package cn.linghang.mywust.core.request.library.response;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
@Data
public class Map {
@JsonProperty("baseInfo")
private BaseInfo baseInfo;
@JsonProperty("detailInfo")
private DetailInfo detailInfo;
@JsonProperty("extraInfo")
private ExtraInfo extraInfo;
@JsonProperty("score")
private int score;
@JsonProperty("_clickCount")
private int clickCount;
@JsonProperty("collected")
private boolean collected;
@JsonProperty("出版发行项")
private String publisher;
@JsonProperty("个人责任者")
private String author;
@JsonProperty("提要文摘附注")
private String describe;
@JsonProperty("ISBN及定价")
private String isbn;
@JsonProperty("载体形态项")
private String size;
@JsonProperty("学科主题")
private String category;
@JsonProperty("使用对象附注")
private String reader;
@JsonProperty("责任者附注")
private String authorDescribe;
@JsonProperty("中图法分类号")
private String clcNumber;
@JsonProperty("著录信息附注")
private String publishNotes;
@JsonProperty("丛编项")
private String series;
@JsonProperty("题名/责任者")
private String fullTitle;
@JsonProperty("title")
private String title;
}

@ -0,0 +1,17 @@
package cn.linghang.mywust.core.request.library.response;
import com.fasterxml.jackson.annotation.JsonProperty;
public class Response{
@JsonProperty("map")
private Map map;
public void setMap(Map map){
this.map = map;
}
public Map getMap(){
return map;
}
}

@ -0,0 +1,150 @@
package cn.linghang.mywust.core.request.library.response;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
import java.util.List;
@Data
public class SearchResultItem {
/**
* 图书id
*/
@JsonProperty("bibId")
private String bookId;
/**
* 作者
*/
@JsonProperty("author")
private String author;
/**
* 索书号
*/
@JsonProperty("callno")
private List<String> callNumber;
/**
* doc类型
*/
@JsonProperty("docType")
private String docType;
/**
* 分组id
*/
@JsonProperty("groupId")
private String groupId;
/**
* ISBN号
*/
@JsonProperty("isbn")
private String isbn;
@JsonProperty("bibNo")
private String bibNo;
/**
* 标题
*/
@JsonProperty("title")
private String title;
/**
* 图书总数
*/
@JsonProperty("itemCount")
private int itemCount;
/**
* 可借数
*/
@JsonProperty("circCount")
private int circCount;
/**
* 出版年
*/
@JsonProperty("pub_year")
private String publishYear;
/**
* 分类号
*/
@JsonProperty("classno")
private String classNumber;
/**
* 出版商
*/
@JsonProperty("publisher")
private String publisher;
/**
* 馆藏信息原始数据为json字符串
*/
@JsonProperty("holdings")
private String collectionInfo;
/**
* 馆藏信息
*/
@Data
public static class CollectionInfo {
/**
* 索书号
*/
@JsonProperty("callNo")
private String callNumber;
/**
* 馆藏总数
*/
@JsonProperty("itemsCount")
private int itemsCount;
/**
* 图书条码
*/
@JsonProperty("barCode")
private String barCode;
/**
* 可借状态
*/
@JsonProperty("circStatus")
private int circStatus;
/**
* 书籍分卷信息
*/
@JsonProperty("vol")
private String vol;
/**
* 图书可借状态
*/
@JsonProperty("itemsAvailable")
private int itemsAvailable;
/**
* 所属馆藏地
*/
@JsonProperty("location")
private String location;
/**
* 捐赠者id
*/
@JsonProperty("donatorId")
private Object donatorId;
/**
* 状态信息
*/
@JsonProperty("status")
private String status;
}
}

@ -27,11 +27,30 @@ public class PhysicsSystemRequestFactory extends RequestFactory {
return makeHttpRequest(redirect, null, cookies);
}
public static HttpRequest physicsCourseIndexRequest(Map<String, String> indexParam, String cookies) {
// 补上“动态”生成的参数
indexParam.put("smLabManage", "upnMenu|lnk_2");
indexParam.put("__EVENTTARGET", "lnk_2");
indexParam.put("ID_PEE01$NoticeType", "-999");
indexParam.put("ID_PEE01$txtCreater", "");
indexParam.put("ID_PEE01$IsRead", "-999");
indexParam.put("ID_PEE01$ObjPager_input", "1");
indexParam.put("__ASYNCPOST", "true");
byte[] fromData = StringUtil.generateQueryString(indexParam).getBytes(StandardCharsets.UTF_8);
return makeHttpRequest(PhysicsSystem.PHYSICS_COURSE_INDEX_URL, fromData, cookies);
}
public static HttpRequest physicsCourseRequest(String cookies) {
return makeHttpRequest(PhysicsSystem.PHYSICS_COURSE_API, null, cookies);
}
private static Map<String, String> makeLoginQueryParam(String username, String password) {
// 这几个算是是写死了的,也能用
// 但其实最好还是从首页动态获取某些关键字段("__VIEWSTATE")
// 这种办法等后面有时间了再实现
Map<String, String> queryParams = new HashMap<>(12);
queryParams.put("__EVENTTARGET", "");
queryParams.put("__EVENTARGUMENT", "");
queryParams.put("__VIEWSTATE", VIEW_STATE);

@ -4,10 +4,10 @@ import cn.linghang.mywust.core.api.Bkjx;
import cn.linghang.mywust.core.api.UnionAuth;
import cn.linghang.mywust.core.exception.BasicException;
import cn.linghang.mywust.core.request.undergrade.BkjxRequestFactory;
import cn.linghang.mywust.network.entitys.HttpRequest;
import cn.linghang.mywust.network.entitys.HttpResponse;
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 org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -25,11 +25,6 @@ public class JwcLogin {
this.unionLogin = new UnionLogin(requester);
}
public JwcLogin(Requester requester, UnionLogin unionLogin) {
this.requester = requester;
this.unionLogin = unionLogin;
}
public String getLoginCookie(String username, String password, RequestClientOption requestOption) throws IOException, BasicException {
// 获取service ticket以进行进一步的登录
String serviceTicket = unionLogin.getServiceTicket(username, password, UnionAuth.Service.BKJX_SSO_SERVICE, requestOption);
@ -51,9 +46,8 @@ public class JwcLogin {
}
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();
("<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 {
HttpRequest testRequest = BkjxRequestFactory.makeHttpRequest(Bkjx.BKJX_TEST_API, null, cookies);

@ -4,10 +4,10 @@ import cn.linghang.mywust.core.api.Library;
import cn.linghang.mywust.core.api.UnionAuth;
import cn.linghang.mywust.core.exception.BasicException;
import cn.linghang.mywust.core.request.library.LibraryRequestFactory;
import cn.linghang.mywust.network.entitys.HttpRequest;
import cn.linghang.mywust.network.entitys.HttpResponse;
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;
@ -16,9 +16,9 @@ public class LibraryLogin {
private final UnionLogin unionLogin;
public LibraryLogin(Requester requester, UnionLogin unionLogin) {
public LibraryLogin(Requester requester) {
this.requester = requester;
this.unionLogin = unionLogin;
this.unionLogin = new UnionLogin(requester);
}
public String getLibraryLoginCookie(String username, String password, RequestClientOption requestOption) throws BasicException, IOException {

@ -1,13 +1,13 @@
package cn.linghang.mywust.core.service.auth;
import cn.linghang.mywust.core.exception.ApiException;
import cn.linghang.mywust.core.exception.BasicException;
import cn.linghang.mywust.core.exception.PasswordWornException;
import cn.linghang.mywust.core.parser.physics.PhysicsIndexPageParser;
import cn.linghang.mywust.core.request.physics.PhysicsSystemRequestFactory;
import cn.linghang.mywust.network.entitys.HttpRequest;
import cn.linghang.mywust.network.entitys.HttpResponse;
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 org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -29,19 +29,19 @@ public class PhysicsLogin {
HttpRequest loginCookieRequest = PhysicsSystemRequestFactory.loginCookiesRequest(username, password, null);
HttpResponse loginCookieResponse = requester.post(loginCookieRequest, requestClientOption);
if (loginCookieResponse.getStatusCode() != HttpResponse.HTTP_REDIRECT_302) {
throw new PasswordWornException();
throw new ApiException(ApiException.Code.PHYSICS_PASSWORD_WRONG);
}
String loginCookies = loginCookieResponse.getCookies();
if (loginCookies == null) {
throw new PasswordWornException();
throw new ApiException(ApiException.Code.UNKNOWN_EXCEPTION);
}
// 请求主页,获取实验选课系统的链接,顺便测试获取到的cookie是否有效,主页能否正常访问
HttpRequest indexRequest = PhysicsSystemRequestFactory.mainIndexRequest(loginCookies);
HttpResponse indexResponse = requester.get(indexRequest, requestClientOption);
if (indexResponse.getStatusCode() != HttpResponse.HTTP_OK || indexResponse.getBody() == null) {
throw new BasicException();
throw new ApiException(ApiException.Code.UNKNOWN_EXCEPTION);
}
// 登录实验选课系统,因为之前使用的登录接口和真正的物理实验选课系统是两个不一样的系统,
@ -51,7 +51,10 @@ public class PhysicsLogin {
HttpRequest systemIndexRequest = PhysicsSystemRequestFactory.physicsSystemIndexRequest(redirect, loginCookies);
requestClientOption.setFallowUrlRedirect(true);
requester.get(systemIndexRequest, requestClientOption);
HttpResponse response = requester.get(systemIndexRequest, requestClientOption);
if (response.getStatusCode() != HttpResponse.HTTP_OK) {
throw new ApiException(ApiException.Code.COOKIE_INVALID);
}
return loginCookies;
}

@ -1,13 +1,15 @@
package cn.linghang.mywust.core.service.auth;
import cn.linghang.mywust.core.exception.ApiException;
import cn.linghang.mywust.core.exception.BasicException;
import cn.linghang.mywust.core.exception.PasswordWornException;
import cn.linghang.mywust.core.request.auth.UnionAuthRequestFactory;
import cn.linghang.mywust.network.entitys.HttpRequest;
import cn.linghang.mywust.network.entitys.HttpResponse;
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 cn.linghang.mywust.util.PasswordEncoder;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -34,7 +36,7 @@ public class UnionLogin {
String redirectAddress = unionAuthResponse.getHeaders().get("Location");
if (redirectAddress == null) {
throw new PasswordWornException();
throw new ApiException(this.analyzeFailReason(unionAuthResponse.getBody()));
}
// 获取服务ticket(service ticket,ST)
@ -45,9 +47,27 @@ public class UnionLogin {
if (serviceTicketResponseData == null) {
log.warn("获取服务st出错,serviceTicketResponseData == null");
throw new BasicException();
throw new ApiException(ApiException.Code.UNKNOWN_EXCEPTION);
}
return new String(serviceTicketResponseData);
}
private ApiException.Code analyzeFailReason(byte[] response) {
try {
JsonNode dataNode = new ObjectMapper().readTree(response).get("data");
switch (dataNode.get("code").asText()) {
case "PASSERROR":
return ApiException.Code.UNI_LOGIN_PASSWORD_WRONG;
case "NOUSER":
return ApiException.Code.UNI_LOGIN_USER_NOT_EXISTS;
case "USERLOCK":
return ApiException.Code.UNI_LOGIN_USER_BANNED;
default:
return ApiException.Code.UNKNOWN_EXCEPTION;
}
} catch (Exception e) {
return ApiException.Code.UNKNOWN_EXCEPTION;
}
}
}

@ -0,0 +1,36 @@
package cn.linghang.mywust.core.service.graduate;
import cn.linghang.mywust.core.api.Graduate;
import cn.linghang.mywust.core.exception.ApiException;
import cn.linghang.mywust.core.request.RequestFactory;
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;
public class GraduateApiService {
protected final Requester requester;
public GraduateApiService(Requester requester) {
this.requester = requester;
}
public void checkResponse(HttpResponse response) throws ApiException {
// 检查响应是否正确
if (response.getBody() == null ||
response.getStatusCode() != HttpResponse.HTTP_OK ||
new String(response.getBody()).contains("name=\"_ctl0:txtpassword\"")) {
throw new ApiException(ApiException.Code.COOKIE_INVALID);
}
}
public void checkCookies(String cookie, RequestClientOption option) throws ApiException, IOException {
HttpRequest request = RequestFactory.makeHttpRequest(Graduate.GRADUATE_INDEX_TEST_API, null, cookie);
HttpResponse response = requester.get(request, option);
this.checkResponse(response);
}
}

@ -0,0 +1,25 @@
package cn.linghang.mywust.core.service.graduate;
import cn.linghang.mywust.core.exception.ApiException;
import cn.linghang.mywust.core.request.graduate.GraduateRequestFactory;
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;
public class GraduateCourseTableApiService extends GraduateApiService{
public GraduateCourseTableApiService(Requester requester) {
super(requester);
}
public String getCourseTablePage(String cookie, RequestClientOption option) throws IOException, ApiException {
HttpRequest request = GraduateRequestFactory.courseTableRequest(cookie);
HttpResponse response = requester.get(request, option);
super.checkResponse(response);
return new String(response.getBody());
}
}

@ -0,0 +1,25 @@
package cn.linghang.mywust.core.service.graduate;
import cn.linghang.mywust.core.exception.ApiException;
import cn.linghang.mywust.core.request.graduate.GraduateRequestFactory;
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;
public class GraduateScoreApiService extends GraduateApiService{
public GraduateScoreApiService(Requester requester) {
super(requester);
}
public String getCourseTablePage(String cookie, RequestClientOption option) throws IOException, ApiException {
HttpRequest request = GraduateRequestFactory.examScoreInfoRequest(cookie);
HttpResponse response = requester.get(request, option);
super.checkResponse(response);
return new String(response.getBody());
}
}

@ -0,0 +1,25 @@
package cn.linghang.mywust.core.service.graduate;
import cn.linghang.mywust.core.exception.ApiException;
import cn.linghang.mywust.core.request.graduate.GraduateRequestFactory;
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;
public class GraduateStudentInfoApiService extends GraduateApiService {
public GraduateStudentInfoApiService(Requester requester) {
super(requester);
}
public String getStudentInfoPage(String cookie, RequestClientOption option) throws ApiException, IOException {
HttpRequest request = GraduateRequestFactory.studentInfoRequest(cookie);
HttpResponse response = requester.get(request, option);
super.checkResponse(response);
return new String(response.getBody());
}
}

@ -0,0 +1,25 @@
package cn.linghang.mywust.core.service.graduate;
import cn.linghang.mywust.core.exception.ApiException;
import cn.linghang.mywust.core.request.graduate.GraduateRequestFactory;
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;
public class GraduateTrainingPlanApiService extends GraduateApiService{
public GraduateTrainingPlanApiService(Requester requester) {
super(requester);
}
public String getCourseTablePage(String cookie, RequestClientOption option) throws IOException, ApiException {
HttpRequest request = GraduateRequestFactory.trainingPlanPageRequest(cookie);
HttpResponse response = requester.get(request, option);
super.checkResponse(response);
return new String(response.getBody());
}
}

@ -1,4 +1,4 @@
package cn.linghang.mywust.core.service.library;
public class LibraryService {
public class LibraryApiService {
}

@ -0,0 +1,31 @@
package cn.linghang.mywust.core.service.physics;
import cn.linghang.mywust.core.exception.ApiException;
import cn.linghang.mywust.core.request.physics.PhysicsSystemRequestFactory;
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;
public class PhysicsApiService {
private final Requester requester;
public PhysicsApiService(Requester requester) {
this.requester = requester;
}
public String getCoursePage(String cookie, RequestClientOption requestClientOption) throws IOException, ApiException {
requestClientOption.setFallowUrlRedirect(false);
// 请求真正的课表页
HttpRequest coursePageRequest = PhysicsSystemRequestFactory.physicsCourseRequest(cookie);
HttpResponse courseResponse = requester.get(coursePageRequest, requestClientOption);
if (courseResponse.getStatusCode() != HttpResponse.HTTP_OK) {
throw new ApiException(ApiException.Code.COOKIE_INVALID);
}
return new String(courseResponse.getBody());
}
}

@ -1,10 +1,9 @@
package cn.linghang.mywust.core.service.undergraduate;
import cn.linghang.mywust.core.exception.CookieInvalidException;
import cn.linghang.mywust.core.exception.ApiException;
import cn.linghang.mywust.core.exception.ParseException;
import cn.linghang.mywust.core.parser.undergraduate.CourseTableParser;
import cn.linghang.mywust.core.request.undergrade.BkjxRequestFactory;
import cn.linghang.mywust.core.util.BkjxUtil;
import cn.linghang.mywust.model.global.Course;
import cn.linghang.mywust.network.RequestClientOption;
import cn.linghang.mywust.network.Requester;
@ -16,28 +15,19 @@ import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.util.List;
public class CourseTableApi extends UndergraduateApi {
private static final Logger log = LoggerFactory.getLogger(CourseTableApi.class);
public class CourseTableApiService extends UndergraduateApiService {
private static final CourseTableParser parser = new CourseTableParser();
private final Requester requester;
public CourseTableApi(Requester requester) {
this.requester = requester;
public CourseTableApiService(Requester requester) {
super(requester);
}
public String getCourseTablePage(String term, String cookies, RequestClientOption requestClientOption) throws IOException, CookieInvalidException {
public String getCourseTablePage(String term, String cookies, RequestClientOption requestClientOption) throws IOException, ApiException {
HttpRequest request = BkjxRequestFactory.courseTablePageRequest(term, cookies);
HttpResponse response = requester.post(request, requestClientOption);
checkResponse(response, cookies);
super.checkResponse(response);
return new String(response.getBody());
}
public List<Course> getCourseTable(String term, String cookies, RequestClientOption requestClientOption) throws IOException, CookieInvalidException, ParseException {
String page = this.getCourseTablePage(term, cookies, requestClientOption);
return parser.parse(page);
}
}

@ -1,6 +1,6 @@
package cn.linghang.mywust.core.service.undergraduate;
import cn.linghang.mywust.core.exception.CookieInvalidException;
import cn.linghang.mywust.core.exception.ApiException;
import cn.linghang.mywust.core.exception.ParseException;
import cn.linghang.mywust.core.parser.undergraduate.ExamInfoParser;
import cn.linghang.mywust.core.request.undergrade.BkjxRequestFactory;
@ -15,29 +15,18 @@ import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.util.List;
public class ExamInfoApi extends UndergraduateApi {
private static final Logger log = LoggerFactory.getLogger(ExamInfoApi.class);
public class ExamInfoApiService extends UndergraduateApiService {
private final Requester requester;
private static final ExamInfoParser parser = new ExamInfoParser();
public ExamInfoApi(Requester requester) {
this.requester = requester;
public ExamInfoApiService(Requester requester) {
super(requester);
}
public String getExamInfoPage(String cookies, RequestClientOption requestClientOption) throws IOException, CookieInvalidException {
public String getExamInfoPage(String cookies, RequestClientOption requestClientOption) throws IOException, ApiException {
HttpRequest request = BkjxRequestFactory.examScoreInfoRequest(cookies, "", "", "");
HttpResponse response = requester.post(request, requestClientOption);
checkResponse(response, cookies);
super.checkResponse(response);
return new String(response.getBody());
}
public List<ExamInfo> getExamInfo(String cookies, RequestClientOption requestClientOption) throws IOException, CookieInvalidException, ParseException {
String examInfoPage = this.getExamInfoPage(cookies, requestClientOption);
return parser.parse(examInfoPage);
}
}

@ -1,38 +0,0 @@
package cn.linghang.mywust.core.service.undergraduate;
import cn.linghang.mywust.core.exception.CookieInvalidException;
import cn.linghang.mywust.core.exception.ParseException;
import cn.linghang.mywust.core.parser.undergraduate.StudentInfoPageParser;
import cn.linghang.mywust.core.request.undergrade.BkjxRequestFactory;
import cn.linghang.mywust.model.global.StudentInfo;
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;
public class StudentInfoApi extends UndergraduateApi {
private final Requester requester;
private static final StudentInfoPageParser parser = new StudentInfoPageParser();
public StudentInfoApi(Requester requester) {
this.requester = requester;
}
public String getStudentInfoPage(String cookies, RequestClientOption requestOption) throws IOException, CookieInvalidException {
HttpRequest request = BkjxRequestFactory.studentInfoRequest(cookies);
HttpResponse response = requester.get(request, requestOption);
checkResponse(response, cookies);
return new String(response.getBody());
}
public StudentInfo getStudentInfo(String cookies, RequestClientOption requestOption) throws IOException, CookieInvalidException, ParseException {
String studentInfoPage = this.getStudentInfoPage(cookies, requestOption);
return parser.parse(studentInfoPage);
}
}

@ -0,0 +1,26 @@
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 java.io.IOException;
public class StudentInfoApiService extends UndergraduateApiService {
public StudentInfoApiService(Requester requester) {
super(requester);
}
public String getStudentInfoPage(String cookies, RequestClientOption requestOption) throws IOException, ApiException {
HttpRequest request = BkjxRequestFactory.studentInfoRequest(cookies);
HttpResponse response = requester.get(request, requestOption);
super.checkResponse(response);
return new String(response.getBody());
}
}

@ -1,36 +0,0 @@
package cn.linghang.mywust.core.service.undergraduate;
import cn.linghang.mywust.core.exception.CookieInvalidException;
import cn.linghang.mywust.core.exception.ParseException;
import cn.linghang.mywust.core.parser.undergraduate.TrainingPlanPageParser;
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;
public class TrainingPlanApi extends UndergraduateApi {
private final Requester requester;
private static final TrainingPlanPageParser parser = new TrainingPlanPageParser();
public TrainingPlanApi(Requester requester) {
this.requester = requester;
}
public String getTrainingPlanPage(String cookies, RequestClientOption requestClientOption) throws CookieInvalidException, IOException {
HttpRequest request = BkjxRequestFactory.trainingPlanPageRequest(cookies);
HttpResponse response = requester.get(request, requestClientOption);
checkResponse(response, cookies);
return new String(response.getBody());
}
public String getPrueSchemePage(String cookies, RequestClientOption requestClientOption) throws IOException, CookieInvalidException, ParseException {
String fullPage = this.getTrainingPlanPage(cookies, requestClientOption);
return parser.parse(fullPage);
}
}

@ -0,0 +1,26 @@
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 java.io.IOException;
public class TrainingPlanApiService extends UndergraduateApiService {
public TrainingPlanApiService(Requester requester) {
super(requester);
}
public String getTrainingPlanPage(String cookies, RequestClientOption requestClientOption) throws IOException, ApiException {
HttpRequest request = BkjxRequestFactory.trainingPlanPageRequest(cookies);
HttpResponse response = requester.get(request, requestClientOption);
super.checkResponse(response);
return new String(response.getBody());
}
}

@ -1,17 +0,0 @@
package cn.linghang.mywust.core.service.undergraduate;
import cn.linghang.mywust.core.exception.CookieInvalidException;
import cn.linghang.mywust.core.util.BkjxUtil;
import cn.linghang.mywust.network.entitys.HttpResponse;
public class UndergraduateApi {
public void checkResponse(HttpResponse response, String cookies) throws CookieInvalidException {
// 检查响应是否正确
if (response.getBody() == null ||
response.getStatusCode() != HttpResponse.HTTP_OK ||
BkjxUtil.checkLoginFinger(response.getBody())) {
throw new CookieInvalidException("响应无效,cookie可能过期:" + cookies);
}
}
}

@ -0,0 +1,38 @@
package cn.linghang.mywust.core.service.undergraduate;
import cn.linghang.mywust.core.api.Bkjx;
import cn.linghang.mywust.core.exception.ApiException;
import cn.linghang.mywust.core.request.RequestFactory;
import cn.linghang.mywust.core.request.undergrade.BkjxRequestFactory;
import cn.linghang.mywust.core.util.BkjxUtil;
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;
public class UndergraduateApiService {
protected final Requester requester;
public UndergraduateApiService(Requester requester) {
this.requester = requester;
}
public void checkResponse(HttpResponse response) throws ApiException {
// 检查响应是否正确
if (response.getBody() == null ||
response.getStatusCode() != HttpResponse.HTTP_OK ||
BkjxUtil.checkLoginFinger(response.getBody())) {
throw new ApiException(ApiException.Code.COOKIE_INVALID);
}
}
public void checkCookies(String cookie, RequestClientOption option) throws ApiException, IOException {
HttpRequest request = RequestFactory.makeHttpRequest(Bkjx.BKJX_TEST_API, null, cookie);
HttpResponse response = requester.get(request, option);
this.checkResponse(response);
}
}

@ -1,5 +1,7 @@
package cn.linghang.mywust.core.util;
import cn.linghang.mywust.core.api.Bkjx;
import java.nio.charset.StandardCharsets;
/**
@ -7,7 +9,7 @@ import java.nio.charset.StandardCharsets;
*/
public class BkjxUtil {
// 在“Bkjx”系统里边如果收到的响应开头是这个的话多半是cookie无效了,需要重新登录获取cookie
private static final byte[] LOGIN_MESSAGE_RESPONSE_FINGER = "<script languge='javascript'>".getBytes(StandardCharsets.UTF_8);
private static final byte[] LOGIN_MESSAGE_RESPONSE_FINGER = "<script".getBytes(StandardCharsets.UTF_8);
/**
* <p>通过粗暴地比较响应字节前几个字符是否为登录跳转特征字符判断是否需要重新登录</p>

@ -0,0 +1,27 @@
package cn.linghang.mywust.core.util;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import java.util.Map;
/**
* html页面表单参数提取用于简化部分繁琐的表单数据生成模拟网页表单数据的请求参数
*/
public class PageFormExtractor {
public static void extractToMap(String html, String formId, Map<String, String> targetMap) {
Document page = Jsoup.parse(html);
Element form = page.getElementById(formId);
if (form == null) {
throw new NullPointerException("The Form Doesn't exist.");
}
Elements formElements = form.getElementsByAttribute("name");
for (Element element : formElements) {
targetMap.put(element.attr("name"), element.attr("value"));
}
}
}

@ -50,6 +50,12 @@
<artifactId>oro</artifactId>
<version>2.0.8</version>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>RELEASE</version>
<scope>test</scope>
</dependency>
</dependencies>

@ -1,20 +1,20 @@
import cn.linghang.mywust.core.exception.BasicException;
import cn.linghang.mywust.core.service.undergraduate.CourseTableApi;
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 {
public static void main(String[] args) throws BasicException, IOException {
new CourseTableTest().run();
}
private void run() throws BasicException, IOException {
@Test
public void run() throws BasicException, IOException {
System.out.println("课表");
System.out.println("Cookie:");
@ -29,7 +29,7 @@ public class CourseTableTest {
System.out.println("使用学期:" + term);
Requester requester = new SimpleOkhttpRequester();
CourseTableApi service = new CourseTableApi(requester);
CourseTableApiService service = new CourseTableApiService(requester);
RequestClientOption option = new RequestClientOption();
option.setTimeout(5);
@ -39,7 +39,8 @@ public class CourseTableTest {
option.setProxy(proxy);
option.setFallowUrlRedirect(false);
List<Course> courses = service.getCourseTable(term, cookie, option);
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,20 +1,20 @@
import cn.linghang.mywust.core.exception.BasicException;
import cn.linghang.mywust.core.service.undergraduate.ExamInfoApi;
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 {
public static void main(String[] args) throws BasicException, IOException {
new ExamInfoTest().run();
}
private void run() throws BasicException, IOException {
@Test
public void run() throws BasicException, IOException {
System.out.println("成绩获取");
System.out.println("Cookie:");
@ -25,17 +25,18 @@ public class ExamInfoTest {
System.out.println("使用Cookie:" + cookie);
Requester requester = new SimpleOkhttpRequester();
ExamInfoApi jwcService = new ExamInfoApi(requester);
ExamInfoApiService jwcService = new ExamInfoApiService(requester);
RequestClientOption option = new RequestClientOption();
option.setTimeout(5);
RequestClientOption.Proxy proxy = new RequestClientOption.Proxy();
proxy.setPort(6060);
proxy.setPort(8080);
proxy.setAddress("127.0.0.1");
option.setProxy(proxy);
option.setFallowUrlRedirect(false);
List<ExamInfo> infos = jwcService.getExamInfo(cookie, option);
Parser<List<ExamInfo>> parser = new ExamInfoParser();
List<ExamInfo> infos = parser.parse(jwcService.getExamInfoPage(cookie, option));
for (ExamInfo info : infos) {

@ -4,16 +4,14 @@ 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 {
public static void main(String[] args) throws BasicException, IOException {
new JwcLoginTest().run();
}
private void run() throws BasicException, IOException {
@Test
public void run() throws BasicException, IOException {
System.out.println("bkjx登录测试(统一身份验证)");
System.out.println("输入账号(学号)和密码,用“ ”(空格)分割");
@ -28,7 +26,7 @@ public class JwcLoginTest {
System.out.println("密码:" + password);
Requester requester = new SimpleOkhttpRequester();
JwcLogin jwcLogin = new JwcLogin(requester, new UnionLogin(requester));
JwcLogin jwcLogin = new JwcLogin(requester);
RequestClientOption option = new RequestClientOption();
option.setTimeout(5);

@ -4,16 +4,14 @@ 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 {
public static void main(String[] args) throws BasicException, IOException {
new LibraryLoginTest().run();
}
private void run() throws BasicException, IOException {
@Test
public void run() throws BasicException, IOException {
System.out.println("图书馆登陆测试");
System.out.println("输入账号(学号)和密码,用“ ”(空格)分割");
@ -28,7 +26,7 @@ public class LibraryLoginTest {
System.out.println("密码:" + password);
Requester requester = new SimpleOkhttpRequester();
LibraryLogin libraryLogin = new LibraryLogin(requester, new UnionLogin(requester));
LibraryLogin libraryLogin = new LibraryLogin(requester);
RequestClientOption option = RequestClientOption.DEFAULT_OPTION;

@ -1,18 +1,16 @@
import cn.linghang.mywust.core.exception.BasicException;
import cn.linghang.mywust.core.service.undergraduate.TrainingPlanApi;
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 {
public static void main(String[] args) throws BasicException, IOException {
new SchemeTest().run();
}
private void run() throws BasicException, IOException {
@Test
public void run() throws BasicException, IOException {
System.out.println("培养方案获取");
System.out.println("Cookie:");
@ -31,9 +29,9 @@ public class SchemeTest {
option.setFallowUrlRedirect(false);
Requester requester = new SimpleOkhttpRequester();
TrainingPlanApi jwcService = new TrainingPlanApi(requester);
TrainingPlanApiService jwcService = new TrainingPlanApiService(requester);
String page = jwcService.getPrueSchemePage(cookie, option);
String page = jwcService.getTrainingPlanPage(cookie, option);
System.out.println(page);
}

@ -1,19 +1,19 @@
import cn.linghang.mywust.core.exception.BasicException;
import cn.linghang.mywust.core.service.undergraduate.StudentInfoApi;
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 {
public static void main(String[] args) throws BasicException, IOException {
new StudentInfoPageTest().run();
}
private void run() throws BasicException, IOException {
@Test
public void run() throws BasicException, IOException {
System.out.println("学生信息获取");
System.out.println("Cookie:");
@ -24,14 +24,15 @@ public class StudentInfoPageTest {
System.out.println("使用Cookie:" + cookie);
Requester requester = new SimpleOkhttpRequester();
StudentInfoApi jwcService = new StudentInfoApi(requester);
StudentInfoApiService jwcService = new StudentInfoApiService(requester);
RequestClientOption option = new RequestClientOption();
option.setTimeout(5);
option.setProxy(null);
option.setFallowUrlRedirect(false);
StudentInfo info = jwcService.getStudentInfo(cookie, option);
Parser<StudentInfo> parser = new StudentInfoPageParser();
StudentInfo info = parser.parse(jwcService.getStudentInfoPage(cookie, option));
System.out.println(info);
}

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

@ -1,18 +1,22 @@
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 {
public static void main(String[] args) throws BasicException, IOException {
new WlsyLoginTest().run();
}
private void run() throws BasicException, IOException {
@Test
public void run() throws BasicException, IOException {
System.out.println("物理实验登陆测试");
System.out.println("输入账号(学号)和密码,用“ ”(空格)分割");
@ -32,13 +36,23 @@ public class WlsyLoginTest {
RequestClientOption option = RequestClientOption.DEFAULT_OPTION;
RequestClientOption.Proxy proxy = new RequestClientOption.Proxy();
proxy.setAddress("127.0.0.1");
proxy.setPort(8794);
proxy.setPort(8080);
option.setProxy(proxy);
String cookies = physicsLogin.getLoginCookie(username, password, option);
System.out.printf("获取到的cookies: %s \n", cookies);
// System.out.printf("检查Cookies: %s", libraryLogin.checkCookie(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);
}
}
}

Loading…
Cancel
Save