diff --git a/mywust-common/pom.xml b/mywust-common/pom.xml index 55d8cbc..1408573 100644 --- a/mywust-common/pom.xml +++ b/mywust-common/pom.xml @@ -15,6 +15,15 @@ 1.8 1.8 UTF-8 + + 2.15.2 + + + com.fasterxml.jackson.core + jackson-annotations + ${jackson-annotations.version} + + \ No newline at end of file diff --git a/mywust-common/src/main/java/cn/wustlinghang/mywust/data/library/PagingResult.java b/mywust-common/src/main/java/cn/wustlinghang/mywust/data/library/PagingResult.java new file mode 100644 index 0000000..639c0de --- /dev/null +++ b/mywust-common/src/main/java/cn/wustlinghang/mywust/data/library/PagingResult.java @@ -0,0 +1,20 @@ +package cn.wustlinghang.mywust.data.library; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class PagingResult { + private int currentPage; + private int pageSize; + private int totalPage; + + private int totalResult; + + private T data; +} \ No newline at end of file diff --git a/mywust-common/src/main/java/cn/wustlinghang/mywust/data/library/origin/BaseLoanBook.java b/mywust-common/src/main/java/cn/wustlinghang/mywust/data/library/origin/BaseLoanBook.java new file mode 100644 index 0000000..c3bbed8 --- /dev/null +++ b/mywust-common/src/main/java/cn/wustlinghang/mywust/data/library/origin/BaseLoanBook.java @@ -0,0 +1,61 @@ +package cn.wustlinghang.mywust.data.library.origin; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; + +/** + * 响应回来的书籍信息(借阅历史,当前借阅,即将逾期等的书目字段) + */ +@Data +@JsonIgnoreProperties(ignoreUnknown = true) +public class BaseLoanBook { + protected String bibId; + + protected String title; + + protected String author; + + /** + * 借书时间 + */ + protected String loanDate; + + protected String location; + + protected String barCode; + + /** + * 图书属性信息 + */ + @JsonProperty("bibAttrs") + protected BookAttribute bookAttribute; + + /** + * 图书属性 + */ + @Data + @JsonIgnoreProperties(ignoreUnknown = true) + public static class BookAttribute { + protected String isbn; + + protected String publisher; + + @JsonProperty("pub_year") + protected String publishYear; + + protected String price; + + /** + * 索书号 + */ + @JsonProperty("callno") + protected String callNumber; + + /** + * 书类编号 + */ + @JsonProperty("classno") + protected String classNumber; + } +} diff --git a/mywust-common/src/main/java/cn/wustlinghang/mywust/data/library/origin/BookSearchRequest.java b/mywust-common/src/main/java/cn/wustlinghang/mywust/data/library/origin/BookSearchRequest.java new file mode 100644 index 0000000..b50504d --- /dev/null +++ b/mywust-common/src/main/java/cn/wustlinghang/mywust/data/library/origin/BookSearchRequest.java @@ -0,0 +1,67 @@ +package cn.wustlinghang.mywust.data.library.origin; + +import lombok.Data; + +import java.util.ArrayList; +import java.util.List; + +@Data +public class BookSearchRequest { + private List filterFieldList = new ArrayList<>(); + private String collapseField = "groupId"; + private String sortType = "desc"; + private String indexName = "idx.opac"; + private String sortField = "relevance"; + + private List queryFieldList = new ArrayList<>(1); + + private int pageSize; + private int page; + + public BookSearchRequest(String keyWord, int pageSize, int page) { + this.pageSize = pageSize; + this.page = page; + this.queryFieldList.add(new QueryFieldListItem(keyWord)); + } + + @Data + public static class QueryFieldListItem { + private String field = "all"; + private String operator = "*"; + private int logic = 0; + + private List values = new ArrayList<>(1); + + public QueryFieldListItem(String keyWord) { + values.add(keyWord); + } + } + + public static class Builder { + private int pageSize; + private int page; + private String keyword; + + private Builder() { + } + + public Builder pageSize(int pageSize) { + this.pageSize = pageSize; + return this; + } + + public Builder page(int page) { + this.page = page; + return this; + } + + public Builder keyword(String keyword) { + this.keyword = keyword; + return this; + } + + public BookSearchRequest build() { + return new BookSearchRequest(keyword, pageSize, page); + } + } +} \ No newline at end of file diff --git a/mywust-common/src/main/java/cn/wustlinghang/mywust/data/library/origin/BookSearchResult.java b/mywust-common/src/main/java/cn/wustlinghang/mywust/data/library/origin/BookSearchResult.java new file mode 100644 index 0000000..e2a5110 --- /dev/null +++ b/mywust-common/src/main/java/cn/wustlinghang/mywust/data/library/origin/BookSearchResult.java @@ -0,0 +1,80 @@ +package cn.wustlinghang.mywust.data.library.origin; + +import cn.wustlinghang.mywust.data.library.parsed.BookHolding; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; + +import java.util.List; + +@Data +@JsonIgnoreProperties(ignoreUnknown = true) +public class BookSearchResult { + private String bibId; + + private String title; + + private String author; + + @JsonProperty("abstract") + private String summary; + + private String publisher; + + private List holdingTypes; + + @JsonProperty("callno") + private List callNumber; + + /** + * 文献类型 + */ + private String docType; + + private String groupId; + + private String isbn; + + /** + * 图书馆系统中的图书编号 + */ + private String bibNo; + + /** + * 图书总数 + */ + private int itemCount; + + /** + * 在借数量 + */ + private int circCount; + + @JsonProperty("pub_year") + private String pubYear; + + @JsonProperty("classno") + private String classNumber; + + @JsonProperty(access = JsonProperty.Access.READ_ONLY) + private List holdings; +} + +/* +bibId: 图书馆系统中的图书ID,用于唯一标识一本图书。 +holdingTypes: 图书的持有类型,此处为“print”,表示该图书以纸质形式持有。 +author: 作者,此处为“Walter Savitch著”,表示该图书的作者是Walter Savitch。 +callno: 索书号,此处为["TP312JA/E26=4/1","TP312JA/E26=4/2"],表示该图书的索书号是TP312JA/E26=4/1和TP312JA/E26=4/2。 +docType: 文献类型,此处为“doc.02”,表示该图书的文献类型为“doc.02”。 +groupId: 分组ID,此处为“1e24652f1d98f0586dc6468136f8eba6”,可能是用于图书分类的一个标识。 +isbn: ISBN号,此处为“7115152888 (v. 1)”,表示该图书的ISBN号是7115152888,其中“(v. 1)”可能表示版本号。 +bibNo: 图书馆系统中的图书编号,此处为“1800067256”。 +title: 书名,此处为“Java : an introduction to problem solving & programming = Java : 程序设计与问题解决/ Walter Savitch著.”,表示该图书的书名是“Java : 程序设计与问题解决”,作者是Walter Savitch。 +itemCount: 图书总数,此处为8,表示该图书馆系统中该图书的总数。 +circCount: 图书当前在借数量,此处也为8,表示该图书当前在借数量为8。 +pub_year: 出版年份,此处为“2006.”,表示该图书的出版年份是2006年。 +classno: 分类号,此处为“TP312JA”,可能是用于图书分类的一个标识。 +publisher: 出版商,此处为“Posts & Telecom Press”,表示该图书的出版商是Posts & Telecom Press。 +holdings: 持有情况,此处为空字符串,可能是用于记录该图书的其他持有情况。 +_id: 记录ID,此处为“544237”,可能是用于记录该图书的唯一标识。 + */ \ No newline at end of file diff --git a/mywust-common/src/main/java/cn/wustlinghang/mywust/data/library/origin/CurrentLoanBook.java b/mywust-common/src/main/java/cn/wustlinghang/mywust/data/library/origin/CurrentLoanBook.java new file mode 100644 index 0000000..0b8a90b --- /dev/null +++ b/mywust-common/src/main/java/cn/wustlinghang/mywust/data/library/origin/CurrentLoanBook.java @@ -0,0 +1,12 @@ +package cn.wustlinghang.mywust.data.library.origin; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import lombok.Data; +import lombok.EqualsAndHashCode; + +@Data +@EqualsAndHashCode(callSuper = true) +@JsonIgnoreProperties(ignoreUnknown = true) +public class CurrentLoanBook extends BaseLoanBook { + private String dueDate; +} diff --git a/mywust-common/src/main/java/cn/wustlinghang/mywust/data/library/origin/HistoryLoanBook.java b/mywust-common/src/main/java/cn/wustlinghang/mywust/data/library/origin/HistoryLoanBook.java new file mode 100644 index 0000000..6aebe36 --- /dev/null +++ b/mywust-common/src/main/java/cn/wustlinghang/mywust/data/library/origin/HistoryLoanBook.java @@ -0,0 +1,12 @@ +package cn.wustlinghang.mywust.data.library.origin; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import lombok.Data; +import lombok.EqualsAndHashCode; + +@Data +@EqualsAndHashCode(callSuper = true) +@JsonIgnoreProperties(ignoreUnknown = true) +public class HistoryLoanBook extends BaseLoanBook { + private String returnDate; +} diff --git a/mywust-common/src/main/java/cn/wustlinghang/mywust/data/library/parsed/BookDetail.java b/mywust-common/src/main/java/cn/wustlinghang/mywust/data/library/parsed/BookDetail.java new file mode 100644 index 0000000..147375d --- /dev/null +++ b/mywust-common/src/main/java/cn/wustlinghang/mywust/data/library/parsed/BookDetail.java @@ -0,0 +1,51 @@ +package cn.wustlinghang.mywust.data.library.parsed; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.Map; + +/** + * 书籍详情 + */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class BookDetail { + private String title; + private String author; + private String isbn; + + /** + * 作者介绍 + */ + private String authorDescribe; + + /** + * 目录 + */ + private String catalog; + + /** + * 封面url + */ + private String coverUrl; + + /** + * 图书简要 + */ + private String summary; + + /** + * 图书介绍 + */ + private String introduction; + + /** + * 书籍详细信息,因为图书馆系统奇葩的中文不定key,因此将这些信息放入key-value对中,需要者自取 + */ + Map extraInfoMap; +} diff --git a/mywust-common/src/main/java/cn/wustlinghang/mywust/data/library/parsed/BookHolding.java b/mywust-common/src/main/java/cn/wustlinghang/mywust/data/library/parsed/BookHolding.java new file mode 100644 index 0000000..84ca28c --- /dev/null +++ b/mywust-common/src/main/java/cn/wustlinghang/mywust/data/library/parsed/BookHolding.java @@ -0,0 +1,56 @@ +package cn.wustlinghang.mywust.data.library.parsed; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; + +/** + * 馆藏信息(单个) + */ +@Data +@JsonIgnoreProperties(ignoreUnknown = true) +public class BookHolding { + @JsonProperty("callNo") + private String callNumber; + + /** + * 馆藏总数 + */ + private int itemsCount; + + /** + * 可借数 + */ + private int itemsAvailable; + + /** + * 条形码 + */ + private String barCode; + + /** + * 所属馆藏地 + */ + private String location; + + /** + * 临时馆藏地 + */ + private String tempLocation; + + /** + * 卷年期 + */ + @JsonProperty("vol") + private String volume; + + /** + * 馆名(总馆等等) + */ + private String library; + + /** + * 状态文本 + */ + private String status; +} diff --git a/mywust-common/src/main/java/cn/wustlinghang/mywust/data/library/parsed/BookSearchResult.java b/mywust-common/src/main/java/cn/wustlinghang/mywust/data/library/parsed/BookSearchResult.java new file mode 100644 index 0000000..9b0ac6a --- /dev/null +++ b/mywust-common/src/main/java/cn/wustlinghang/mywust/data/library/parsed/BookSearchResult.java @@ -0,0 +1,69 @@ +package cn.wustlinghang.mywust.data.library.parsed; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; + +import java.util.List; + +@Data +@JsonIgnoreProperties(ignoreUnknown = true) +public class BookSearchResult { + private String bibId; + + private List holdingTypes; + private String author; + + private List callNumber; + + /** + * 文献类型 + */ + private String docType; + private String groupId; + private String isbn; + + /** + * 图书馆系统中的图书编号 + */ + private String bibNo; + + private String title; + + /** + * 图书总数 + */ + private int itemCount; + + /** + * 在借数量 + */ + private int circCount; + + private String pubYear; + + private String classNumber; + + private String publisher; + + private List holdings; +} + +/* +bibId: 图书馆系统中的图书ID,用于唯一标识一本图书。 +holdingTypes: 图书的持有类型,此处为“print”,表示该图书以纸质形式持有。 +author: 作者,此处为“Walter Savitch著”,表示该图书的作者是Walter Savitch。 +callno: 索书号,此处为["TP312JA/E26=4/1","TP312JA/E26=4/2"],表示该图书的索书号是TP312JA/E26=4/1和TP312JA/E26=4/2。 +docType: 文献类型,此处为“doc.02”,表示该图书的文献类型为“doc.02”。 +groupId: 分组ID,此处为“1e24652f1d98f0586dc6468136f8eba6”,可能是用于图书分类的一个标识。 +isbn: ISBN号,此处为“7115152888 (v. 1)”,表示该图书的ISBN号是7115152888,其中“(v. 1)”可能表示版本号。 +bibNo: 图书馆系统中的图书编号,此处为“1800067256”。 +title: 书名,此处为“Java : an introduction to problem solving & programming = Java : 程序设计与问题解决/ Walter Savitch著.”,表示该图书的书名是“Java : 程序设计与问题解决”,作者是Walter Savitch。 +itemCount: 图书总数,此处为8,表示该图书馆系统中该图书的总数。 +circCount: 图书当前在借数量,此处也为8,表示该图书当前在借数量为8。 +pub_year: 出版年份,此处为“2006.”,表示该图书的出版年份是2006年。 +classno: 分类号,此处为“TP312JA”,可能是用于图书分类的一个标识。 +publisher: 出版商,此处为“Posts & Telecom Press”,表示该图书的出版商是Posts & Telecom Press。 +holdings: 持有情况,此处为空字符串,可能是用于记录该图书的其他持有情况。 +_id: 记录ID,此处为“544237”,可能是用于记录该图书的唯一标识。 + */ \ No newline at end of file diff --git a/mywust-core/pom.xml b/mywust-core/pom.xml index 528ae70..b235974 100644 --- a/mywust-core/pom.xml +++ b/mywust-core/pom.xml @@ -45,13 +45,13 @@ com.fasterxml.jackson.core jackson-annotations - 2.14.0-rc1 + ${jackson.version} compile com.fasterxml.jackson.core jackson-databind - 2.14.0-rc1 + ${jackson.version} compile @@ -70,5 +70,6 @@ 2.0.3 1.15.3 5.8.12 + 2.15.2 \ No newline at end of file diff --git a/mywust-core/src/main/java/cn/wustlinghang/mywust/core/api/LibraryUrls.java b/mywust-core/src/main/java/cn/wustlinghang/mywust/core/api/LibraryUrls.java index 3b37d73..549da78 100644 --- a/mywust-core/src/main/java/cn/wustlinghang/mywust/core/api/LibraryUrls.java +++ b/mywust-core/src/main/java/cn/wustlinghang/mywust/core/api/LibraryUrls.java @@ -10,11 +10,14 @@ public class LibraryUrls { public static final String LIBRARY_ACCOUNT_STATUS_API = "https://libsys.wust.edu.cn/meta-local/opac/users/stats"; - public static final String LIBRARY_CURRENT_LOAN_API = "https://libsys.wust.edu.cn/meta-local/opac/users/loans?page=1&pageSize=100"; - public static final String LIBRARY_LOAN_HISTORY_API = "https://libsys.wust.edu.cn/meta-local/opac/users/loan_hists?page=1&pageSize=100"; - public static final String LIBRARY_OVERDUE_SOON_API = "https://libsys.wust.edu.cn/meta-local/opac/users/overdue_soon"; + public static final String LIBRARY_CURRENT_LOAN_API = "https://libsys.wust.edu.cn/meta-local/opac/users/loans?page=%d&pageSize=%d"; + public static final String LIBRARY_LOAN_HISTORY_API = "https://libsys.wust.edu.cn/meta-local/opac/users/loan_hists?page=%d&pageSize=%d"; + public static final String LIBRARY_OVERDUE_SOON_API = "https://libsys.wust.edu.cn/meta-local/opac/users/overdue_soon?page=%d&pageSize=%d"; public static final String LIBRARY_BOOK_INFO_API = "https://libsys.wust.edu.cn/meta-local/opac/bibs/%s/infos"; + public static final String LIBRARY_BOOK_DOUBAN_INFO_API = "https://libsys.wust.edu.cn/meta-local/opac/third_api/douban/%s/info"; + public static final String LIBRARY_BOOK_CONTENT_API = "https://libsys.wust.edu.cn/meta-local/opac/bibs/%s/quoteds/quoted.caj-cd/content"; + public static final String LIBRARY_BOOK_HOLDING_API = "https://libsys.wust.edu.cn/meta-local/opac/bibs/%s/holdings"; public static final String LIBRARY_BOOK_COVER_IMAGE_API = "https://libsys.wust.edu.cn/meta-local/opac/search/extend/"; diff --git a/mywust-core/src/main/java/cn/wustlinghang/mywust/core/request/factory/library/LibraryRequestFactory.java b/mywust-core/src/main/java/cn/wustlinghang/mywust/core/request/factory/library/LibraryRequestFactory.java index 61886e3..6b7e93f 100644 --- a/mywust-core/src/main/java/cn/wustlinghang/mywust/core/request/factory/library/LibraryRequestFactory.java +++ b/mywust-core/src/main/java/cn/wustlinghang/mywust/core/request/factory/library/LibraryRequestFactory.java @@ -2,14 +2,16 @@ package cn.wustlinghang.mywust.core.request.factory.library; import cn.wustlinghang.mywust.core.api.LibraryUrls; import cn.wustlinghang.mywust.core.request.factory.RequestFactory; -import cn.wustlinghang.mywust.core.request.factory.library.request.SearchRequest; +import cn.wustlinghang.mywust.data.library.origin.BookSearchRequest; import cn.wustlinghang.mywust.network.entitys.HttpRequest; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; +import lombok.extern.slf4j.Slf4j; import java.util.List; import java.util.StringJoiner; +@Slf4j public class LibraryRequestFactory extends RequestFactory { private static final ObjectMapper objectMapper = new ObjectMapper(); @@ -24,10 +26,10 @@ public class LibraryRequestFactory extends RequestFactory { } public static HttpRequest bookSearchRequest(String keyword, int page, int pageSize) { - return bookSearchRequest(new SearchRequest(keyword, pageSize, page)); + return bookSearchRequest(new BookSearchRequest(keyword, pageSize, page)); } - public static HttpRequest bookSearchRequest(SearchRequest request) { + public static HttpRequest bookSearchRequest(BookSearchRequest request) { return makeHttpRequest(LibraryUrls.LIBRARY_SEARCH_API, json(request)) .addHeaders("Content-Type", "application/json"); } @@ -36,16 +38,16 @@ public class LibraryRequestFactory extends RequestFactory { return makeHttpRequest(LibraryUrls.LIBRARY_ACCOUNT_STATUS_API, null, cookie); } - public static HttpRequest currentLoanRequest(String cookie) { - return makeHttpRequest(LibraryUrls.LIBRARY_CURRENT_LOAN_API, null, cookie); + public static HttpRequest currentLoanRequest(String cookie, int page, int pageSize) { + return makeHttpRequest(String.format(LibraryUrls.LIBRARY_CURRENT_LOAN_API, page, pageSize), null, cookie); } - public static HttpRequest loanHistoryRequest(String cookie) { - return makeHttpRequest(LibraryUrls.LIBRARY_LOAN_HISTORY_API, null, cookie); + public static HttpRequest loanHistoryRequest(String cookie, int page, int pageSize) { + return makeHttpRequest(String.format(LibraryUrls.LIBRARY_LOAN_HISTORY_API, page, pageSize), null, cookie); } - public static HttpRequest overdueSoonRequest(String cookie) { - return makeHttpRequest(LibraryUrls.LIBRARY_OVERDUE_SOON_API, null, cookie); + public static HttpRequest overdueSoonRequest(String cookie, int page, int pageSize) { + return makeHttpRequest(String.format(LibraryUrls.LIBRARY_OVERDUE_SOON_API, page, pageSize), null, cookie); } public static HttpRequest bookInfoRequest(String bookId) { @@ -53,6 +55,21 @@ public class LibraryRequestFactory extends RequestFactory { return makeHttpRequest(url, (byte[]) null); } + public static HttpRequest bookDoubanInfoRequest(String isbn) { + String url = String.format(LibraryUrls.LIBRARY_BOOK_DOUBAN_INFO_API, isbn); + return makeHttpRequest(url, (byte[]) null); + } + + public static HttpRequest bookContentRequest(String id) { + String url = String.format(LibraryUrls.LIBRARY_BOOK_CONTENT_API, id); + return makeHttpRequest(url, (byte[]) null); + } + + public static HttpRequest bookHoldingRequest(String bookId) { + String url = String.format(LibraryUrls.LIBRARY_BOOK_HOLDING_API, bookId); + return makeHttpRequest(url, (byte[]) null); + } + public static HttpRequest bookCoverImageUrlRequest(List isbn) { StringJoiner joiner = new StringJoiner("%2C", LibraryUrls.LIBRARY_BOOK_COVER_IMAGE_API, ""); isbn.forEach(joiner::add); @@ -67,7 +84,8 @@ public class LibraryRequestFactory extends RequestFactory { private static String json(Object object) { try { return objectMapper.writeValueAsString(object); - } catch (JsonProcessingException ignored) { + } catch (JsonProcessingException e) { + log.error("生成json时出现不应出现的异常:", e); return ""; } } diff --git a/mywust-core/src/main/java/cn/wustlinghang/mywust/core/request/factory/library/request/SearchRequest.java b/mywust-core/src/main/java/cn/wustlinghang/mywust/core/request/factory/library/request/SearchRequest.java deleted file mode 100644 index 0944850..0000000 --- a/mywust-core/src/main/java/cn/wustlinghang/mywust/core/request/factory/library/request/SearchRequest.java +++ /dev/null @@ -1,40 +0,0 @@ -package cn.wustlinghang.mywust.core.request.factory.library.request; - -import lombok.Data; - -import java.util.ArrayList; -import java.util.List; -import java.util.StringJoiner; - -@Data -public class SearchRequest { - private final List filterFieldList = new ArrayList<>(); - private final String collapseField = "groupId"; - private final String sortType = "desc"; - private final String indexName = "idx.opac"; - private final String sortField = "relevance"; - - private final List queryFieldList = new ArrayList<>(1); - - private int pageSize; - private int page; - - public SearchRequest(String keyWord, int pageSize, int page) { - this.pageSize = pageSize; - this.page = page; - this.queryFieldList.add(new QueryFieldListItem(keyWord)); - } - - @Data - public static class QueryFieldListItem { - private final String field = "all"; - private final String operator = "*"; - private final int logic = 0; - - private final List values = new ArrayList<>(1); - - public QueryFieldListItem(String keyWord) { - values.add(keyWord); - } - } -} \ No newline at end of file diff --git a/mywust-core/src/main/java/cn/wustlinghang/mywust/core/request/service/library/BaseLibraryApiService.java b/mywust-core/src/main/java/cn/wustlinghang/mywust/core/request/service/library/BaseLibraryApiService.java index 82ed014..69f34cd 100644 --- a/mywust-core/src/main/java/cn/wustlinghang/mywust/core/request/service/library/BaseLibraryApiService.java +++ b/mywust-core/src/main/java/cn/wustlinghang/mywust/core/request/service/library/BaseLibraryApiService.java @@ -1,10 +1,51 @@ package cn.wustlinghang.mywust.core.request.service.library; +import cn.wustlinghang.mywust.data.library.origin.BaseLoanBook; +import cn.wustlinghang.mywust.data.library.origin.BookSearchResult; +import cn.wustlinghang.mywust.data.library.origin.CurrentLoanBook; +import cn.wustlinghang.mywust.data.library.origin.HistoryLoanBook; +import cn.wustlinghang.mywust.data.library.parsed.BookHolding; import cn.wustlinghang.mywust.exception.ApiException; import cn.wustlinghang.mywust.network.Requester; import cn.wustlinghang.mywust.network.entitys.HttpResponse; +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.core.JsonToken; +import com.fasterxml.jackson.databind.DeserializationContext; +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.JavaType; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.deser.std.StringDeserializer; +import com.fasterxml.jackson.databind.module.SimpleModule; + +import java.io.IOException; +import java.util.List; public abstract class BaseLibraryApiService { + protected static final ObjectMapper objectMapper = new ObjectMapper(); + + static { + objectMapper.configure(DeserializationFeature.FAIL_ON_INVALID_SUBTYPE, false); + objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); + SimpleModule module = new SimpleModule(); + module.addDeserializer(String.class, new SpecialStringDeserializer()); + objectMapper.registerModule(module); + } + + protected static final JavaType loanBookListType = + objectMapper.getTypeFactory().constructParametricType(List.class, BaseLoanBook.class); + + protected static final JavaType historyLoanBookListType = + objectMapper.getTypeFactory().constructParametricType(List.class, HistoryLoanBook.class); + + protected static final JavaType currentLoanBookListType = + objectMapper.getTypeFactory().constructParametricType(List.class, CurrentLoanBook.class); + + protected static final JavaType bookSearchResultListType = + objectMapper.getTypeFactory().constructParametricType(List.class, BookSearchResult.class); + + protected static final JavaType bookHoldingListType = + objectMapper.getTypeFactory().constructParametricType(List.class, BookHolding.class); + protected final Requester requester; public BaseLibraryApiService(Requester requester) { @@ -18,3 +59,24 @@ public abstract class BaseLibraryApiService { } } } + +/** + *

继承自原版StringDeserializer,特殊定制的字符串反序列化器

+ *

测试时偶然发现的图书馆搜索api返回的json中`pub_year`和`abstract`等一些本应该是字符串值的字段有概率会出现为空数组的奇葩情况...

+ *

想了半天也没想明白那系统究竟是怎么在字符串里蹦出`[]`的...

+ */ +class SpecialStringDeserializer extends StringDeserializer { + @Override + public String deserialize(JsonParser p, DeserializationContext ctxt) throws IOException { + // The critical path: ensure we handle the common case first. + if (p.hasToken(JsonToken.VALUE_STRING)) { + return p.getText(); + } + // [databind#381] + if (p.hasToken(JsonToken.START_ARRAY)) { + // 仅修改了这行 + return p.getValueAsString(""); + } + return _parseString(p, ctxt, this); + } +} \ No newline at end of file diff --git a/mywust-core/src/main/java/cn/wustlinghang/mywust/core/request/service/library/BookCoverImageUrlApiService.java b/mywust-core/src/main/java/cn/wustlinghang/mywust/core/request/service/library/BookCoverImageUrlApiService.java index 58c6349..361dc28 100644 --- a/mywust-core/src/main/java/cn/wustlinghang/mywust/core/request/service/library/BookCoverImageUrlApiService.java +++ b/mywust-core/src/main/java/cn/wustlinghang/mywust/core/request/service/library/BookCoverImageUrlApiService.java @@ -5,19 +5,51 @@ import cn.wustlinghang.mywust.exception.ApiException; import cn.wustlinghang.mywust.network.Requester; import cn.wustlinghang.mywust.network.entitys.HttpRequest; import cn.wustlinghang.mywust.network.entitys.HttpResponse; +import com.fasterxml.jackson.databind.JsonNode; import java.io.IOException; +import java.util.*; public class BookCoverImageUrlApiService extends BaseLibraryApiService { public BookCoverImageUrlApiService(Requester requester) { super(requester); } - public String getBookCoverImageUrl(String isbn) throws ApiException, IOException { + public List getBookCoverImageUrl(String isbn) throws ApiException, IOException { HttpRequest request = LibraryRequestFactory.bookCoverImageUrlRequest(isbn); HttpResponse response = requester.get(request); checkResponse(response); - return response.getStringBody(); + // 因为只查了一本书,所以path(isbn)直接一步到位就行了 + JsonNode imageResultJson = objectMapper.readTree(response.getBody()).path("data").path(isbn); + List covers = new ArrayList<>(imageResultJson.size()); + for (JsonNode resultItemJson : imageResultJson) { + covers.add(resultItemJson.path("imageUrl").asText()); + } + + return covers; + } + + public Map> getBookCoverImageUrl(List isbnList) throws ApiException, IOException { + HttpRequest request = LibraryRequestFactory.bookCoverImageUrlRequest(isbnList); + HttpResponse response = requester.get(request); + checkResponse(response); + + JsonNode data = objectMapper.readTree(response.getBody()).path("data"); + Map> result = new HashMap<>(data.size()); + + // 遍历data下每本书 + Iterator> it = data.fields(); + while (it.hasNext()) { + Map.Entry bookItemJson = it.next(); + List covers = new ArrayList<>(bookItemJson.getValue().size()); + for (JsonNode resultItemJson : bookItemJson.getValue()) { + covers.add(resultItemJson.path("imageUrl").asText()); + } + + result.put(bookItemJson.getKey(), covers); + } + + return result; } } diff --git a/mywust-core/src/main/java/cn/wustlinghang/mywust/core/request/service/library/BookDetailApiService.java b/mywust-core/src/main/java/cn/wustlinghang/mywust/core/request/service/library/BookDetailApiService.java index 1a23b6b..e7fb0de 100644 --- a/mywust-core/src/main/java/cn/wustlinghang/mywust/core/request/service/library/BookDetailApiService.java +++ b/mywust-core/src/main/java/cn/wustlinghang/mywust/core/request/service/library/BookDetailApiService.java @@ -1,24 +1,69 @@ package cn.wustlinghang.mywust.core.request.service.library; import cn.wustlinghang.mywust.core.request.factory.library.LibraryRequestFactory; +import cn.wustlinghang.mywust.data.library.parsed.BookDetail; import cn.wustlinghang.mywust.exception.ApiException; import cn.wustlinghang.mywust.network.Requester; import cn.wustlinghang.mywust.network.entitys.HttpRequest; import cn.wustlinghang.mywust.network.entitys.HttpResponse; +import cn.wustlinghang.mywust.util.StringUtil; +import com.fasterxml.jackson.databind.JsonNode; import java.io.IOException; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; public class BookDetailApiService extends BaseLibraryApiService { public BookDetailApiService(Requester requester) { super(requester); } - public String getBookDetail(String bookId) throws ApiException, IOException { - HttpRequest request = LibraryRequestFactory.bookInfoRequest(bookId); - HttpResponse response = requester.get(request); - checkResponse(response); + public BookDetail getBookDetail(String bookId) throws ApiException, IOException { + HttpRequest infoRequest = LibraryRequestFactory.bookInfoRequest(bookId); + HttpResponse infoResponse = requester.get(infoRequest); + checkResponse(infoResponse); - return response.getStringBody(); - } + JsonNode data = objectMapper.readTree(infoResponse.getBody()) + .path("data").path("map"); + + JsonNode baseInfo = data.path("baseInfo").path("map"); + JsonNode detailInfo = data.path("detailInfo").path("map"); + + Map extraInfoMap = new HashMap<>(detailInfo.size()); + Iterator> it = detailInfo.fields(); + while (it.hasNext()) { + Map.Entry field = it.next(); + extraInfoMap.put(field.getKey(), StringUtil.cleanHtml(field.getValue().asText("无"))); + } + + String isbn = baseInfo.get("isbn").asText("无"); + String author = baseInfo.path("author").asText("无"); + String title = baseInfo.path("title").asText("无"); + + HttpRequest doubanInfoRequest = LibraryRequestFactory.bookDoubanInfoRequest(isbn); + HttpResponse doubanInfoResponse = requester.get(doubanInfoRequest); + checkResponse(doubanInfoResponse); + JsonNode doubanInfo = objectMapper.readTree(doubanInfoResponse.getBody()).path("data"); + String authorDescribe = doubanInfo.path("authorInfo").asText("无"); + String catalog = doubanInfo.path("catalog").asText("无"); + String summary = doubanInfo.path("content").asText("无"); + String introduction = doubanInfo.path("intro").asText(summary); + String coverUrl = doubanInfo.path("imageUrl").asText(""); + + return BookDetail.builder() + .isbn(isbn) + .author(author) + .title(title) + .extraInfoMap(extraInfoMap) + + .authorDescribe(StringUtil.cleanHtml(authorDescribe)) + .catalog(StringUtil.cleanHtml(catalog)) + .summary(StringUtil.cleanHtml(summary)) + .introduction(StringUtil.cleanHtml(introduction)) + .coverUrl(coverUrl) + + .build(); + } } diff --git a/mywust-core/src/main/java/cn/wustlinghang/mywust/core/request/service/library/BookHoldingApiService.java b/mywust-core/src/main/java/cn/wustlinghang/mywust/core/request/service/library/BookHoldingApiService.java new file mode 100644 index 0000000..a8953ec --- /dev/null +++ b/mywust-core/src/main/java/cn/wustlinghang/mywust/core/request/service/library/BookHoldingApiService.java @@ -0,0 +1,39 @@ +package cn.wustlinghang.mywust.core.request.service.library; + +import cn.wustlinghang.mywust.core.request.factory.library.LibraryRequestFactory; +import cn.wustlinghang.mywust.data.library.parsed.BookHolding; +import cn.wustlinghang.mywust.exception.ApiException; +import cn.wustlinghang.mywust.exception.ParseException; +import cn.wustlinghang.mywust.network.Requester; +import cn.wustlinghang.mywust.network.entitys.HttpRequest; +import cn.wustlinghang.mywust.network.entitys.HttpResponse; +import com.fasterxml.jackson.core.JacksonException; +import com.fasterxml.jackson.databind.JsonNode; + +import java.io.IOException; +import java.util.List; + +public class BookHoldingApiService extends BaseLibraryApiService { + + + public BookHoldingApiService(Requester requester) { + super(requester); + } + + public List getHoldingList(String id) + throws ApiException, IOException, ParseException { + + HttpRequest loanRequest = LibraryRequestFactory.bookHoldingRequest(id); + HttpResponse loanResponse = requester.get(loanRequest); + checkResponse(loanResponse); + try { + JsonNode data = objectMapper.readTree(loanResponse.getBody()).path("data"); + // 这里的holding是个string值,需要独立解析(坑人) + JsonNode holdings = data.path("holdings"); + + return objectMapper.readValue(holdings.asText("[]"), bookHoldingListType); + } catch (JacksonException e) { + throw new ParseException(e.getMessage(), ""); + } + } +} diff --git a/mywust-core/src/main/java/cn/wustlinghang/mywust/core/request/service/library/CurrentLoanApiService.java b/mywust-core/src/main/java/cn/wustlinghang/mywust/core/request/service/library/CurrentLoanApiService.java index 19a461f..7d10067 100644 --- a/mywust-core/src/main/java/cn/wustlinghang/mywust/core/request/service/library/CurrentLoanApiService.java +++ b/mywust-core/src/main/java/cn/wustlinghang/mywust/core/request/service/library/CurrentLoanApiService.java @@ -1,24 +1,52 @@ package cn.wustlinghang.mywust.core.request.service.library; import cn.wustlinghang.mywust.core.request.factory.library.LibraryRequestFactory; +import cn.wustlinghang.mywust.data.library.PagingResult; +import cn.wustlinghang.mywust.data.library.origin.CurrentLoanBook; import cn.wustlinghang.mywust.exception.ApiException; +import cn.wustlinghang.mywust.exception.ParseException; import cn.wustlinghang.mywust.network.Requester; import cn.wustlinghang.mywust.network.entitys.HttpRequest; import cn.wustlinghang.mywust.network.entitys.HttpResponse; +import com.fasterxml.jackson.core.JacksonException; +import com.fasterxml.jackson.databind.JsonNode; import java.io.IOException; +import java.util.List; public class CurrentLoanApiService extends BaseLibraryApiService { public CurrentLoanApiService(Requester requester) { super(requester); } - public String getCurrentLoan(String cookie) throws ApiException, IOException { - HttpRequest request = LibraryRequestFactory.currentLoanRequest(cookie); - HttpResponse response = requester.get(request); - checkResponse(response); + public PagingResult> getCurrentLoan(String cookie, int page, int pageSize) + throws ApiException, IOException, ParseException { - return response.getStringBody(); - } + HttpRequest loanRequest = LibraryRequestFactory.currentLoanRequest(cookie, page, pageSize); + HttpResponse loanResponse = requester.get(loanRequest); + checkResponse(loanResponse); + try { + JsonNode data = objectMapper.readTree(loanResponse.getBody()).path("data"); + + // 获取,计算分页数据 + pageSize = data.path("pageSize").asInt(pageSize); + int currentPage = data.path("currentPage").asInt(page); + int totalResult = data.path("total").asInt(0); + int totalPage = data.path("totalPage").asInt(0); + + JsonNode itemsJson = data.path("items"); + List books = objectMapper.treeToValue(itemsJson, currentLoanBookListType); + return PagingResult.>builder() + .currentPage(currentPage) + .totalResult(totalResult) + .pageSize(pageSize) + .totalPage(totalPage) + .data(books) + .build(); + + } catch (JacksonException e) { + throw new ParseException(e.getMessage(), ""); + } + } } diff --git a/mywust-core/src/main/java/cn/wustlinghang/mywust/core/request/service/library/LoanHistoryApiService.java b/mywust-core/src/main/java/cn/wustlinghang/mywust/core/request/service/library/LoanHistoryApiService.java index 1201a1f..d91bf5e 100644 --- a/mywust-core/src/main/java/cn/wustlinghang/mywust/core/request/service/library/LoanHistoryApiService.java +++ b/mywust-core/src/main/java/cn/wustlinghang/mywust/core/request/service/library/LoanHistoryApiService.java @@ -1,23 +1,53 @@ package cn.wustlinghang.mywust.core.request.service.library; import cn.wustlinghang.mywust.core.request.factory.library.LibraryRequestFactory; +import cn.wustlinghang.mywust.data.library.PagingResult; +import cn.wustlinghang.mywust.data.library.origin.HistoryLoanBook; import cn.wustlinghang.mywust.exception.ApiException; +import cn.wustlinghang.mywust.exception.ParseException; import cn.wustlinghang.mywust.network.Requester; import cn.wustlinghang.mywust.network.entitys.HttpRequest; import cn.wustlinghang.mywust.network.entitys.HttpResponse; +import com.fasterxml.jackson.core.JacksonException; +import com.fasterxml.jackson.databind.JsonNode; import java.io.IOException; +import java.util.List; public class LoanHistoryApiService extends BaseLibraryApiService { + public LoanHistoryApiService(Requester requester) { super(requester); } - public String getLoanHistory(String cookie) throws ApiException, IOException { - HttpRequest request = LibraryRequestFactory.loanHistoryRequest(cookie); + public PagingResult> getLoanHistory(String cookie, int page, int pageSize) + throws ApiException, IOException, ParseException { + + HttpRequest request = LibraryRequestFactory.loanHistoryRequest(cookie, page, pageSize); HttpResponse response = requester.get(request); checkResponse(response); + try { + JsonNode data = objectMapper.readTree(response.getBody()).path("data"); + + // 获取,计算分页数据 + pageSize = data.path("pageSize").asInt(pageSize); + int currentPage = data.path("currentPage").asInt(page); + int totalResult = data.path("total").asInt(0); + int totalPage = data.path("totalPage").asInt(0); + + JsonNode itemsJson = data.path("items"); + List books = objectMapper.treeToValue(itemsJson, historyLoanBookListType); + + return PagingResult.>builder() + .currentPage(currentPage) + .totalResult(totalResult) + .pageSize(pageSize) + .totalPage(totalPage) + .data(books) + .build(); - return response.getStringBody(); + } catch (JacksonException e) { + throw new ParseException(e.getMessage(), ""); + } } } diff --git a/mywust-core/src/main/java/cn/wustlinghang/mywust/core/request/service/library/OverdueSoonApiService.java b/mywust-core/src/main/java/cn/wustlinghang/mywust/core/request/service/library/OverdueSoonApiService.java index 578feb0..56ffbe8 100644 --- a/mywust-core/src/main/java/cn/wustlinghang/mywust/core/request/service/library/OverdueSoonApiService.java +++ b/mywust-core/src/main/java/cn/wustlinghang/mywust/core/request/service/library/OverdueSoonApiService.java @@ -1,23 +1,56 @@ package cn.wustlinghang.mywust.core.request.service.library; import cn.wustlinghang.mywust.core.request.factory.library.LibraryRequestFactory; +import cn.wustlinghang.mywust.data.library.PagingResult; +import cn.wustlinghang.mywust.data.library.origin.BaseLoanBook; import cn.wustlinghang.mywust.exception.ApiException; +import cn.wustlinghang.mywust.exception.ParseException; import cn.wustlinghang.mywust.network.Requester; import cn.wustlinghang.mywust.network.entitys.HttpRequest; import cn.wustlinghang.mywust.network.entitys.HttpResponse; +import com.fasterxml.jackson.core.JacksonException; +import com.fasterxml.jackson.databind.JsonNode; +import lombok.extern.slf4j.Slf4j; import java.io.IOException; +import java.util.List; +@Slf4j public class OverdueSoonApiService extends BaseLibraryApiService { public OverdueSoonApiService(Requester requester) { super(requester); } - public String getOverdueSoon(String cookie) throws ApiException, IOException { - HttpRequest request = LibraryRequestFactory.overdueSoonRequest(cookie); + public PagingResult> getOverdueSoon(String cookie, int page, int pageSize) + throws ApiException, IOException, ParseException { + + HttpRequest request = LibraryRequestFactory.overdueSoonRequest(cookie, page, pageSize); HttpResponse response = requester.get(request); checkResponse(response); + try { + // todo 这里即将到期书籍字段跟当前借阅和借阅历史字段格式貌似有点不太一样(data字段是个数组) + // 但是目前手上没有样本,因此这里还需要再测试测试 + JsonNode data = objectMapper.readTree(response.getBody()).path("data"); + + // 获取,计算分页数据 + pageSize = data.path("pageSize").asInt(pageSize); + int currentPage = data.path("currentPage").asInt(page); + int totalResult = data.path("total").asInt(0); + int totalPage = data.path("totalPage").asInt(0); + + JsonNode itemsJson = data.path("items"); + List baseLoanBooks = objectMapper.treeToValue(itemsJson, loanBookListType); + + return PagingResult.>builder() + .currentPage(currentPage) + .totalResult(totalResult) + .pageSize(pageSize) + .totalPage(totalPage) + .data(baseLoanBooks) + .build(); - return response.getStringBody(); + } catch (JacksonException e) { + throw new ParseException(e.getMessage(), ""); + } } } diff --git a/mywust-core/src/main/java/cn/wustlinghang/mywust/core/request/service/library/SearchApiService.java b/mywust-core/src/main/java/cn/wustlinghang/mywust/core/request/service/library/SearchApiService.java index 07c5447..8b0eea3 100644 --- a/mywust-core/src/main/java/cn/wustlinghang/mywust/core/request/service/library/SearchApiService.java +++ b/mywust-core/src/main/java/cn/wustlinghang/mywust/core/request/service/library/SearchApiService.java @@ -1,24 +1,68 @@ package cn.wustlinghang.mywust.core.request.service.library; import cn.wustlinghang.mywust.core.request.factory.library.LibraryRequestFactory; +import cn.wustlinghang.mywust.data.library.PagingResult; +import cn.wustlinghang.mywust.data.library.origin.BookSearchRequest; +import cn.wustlinghang.mywust.data.library.origin.BookSearchResult; +import cn.wustlinghang.mywust.data.library.parsed.BookHolding; import cn.wustlinghang.mywust.exception.ApiException; +import cn.wustlinghang.mywust.exception.ParseException; import cn.wustlinghang.mywust.network.Requester; import cn.wustlinghang.mywust.network.entitys.HttpRequest; import cn.wustlinghang.mywust.network.entitys.HttpResponse; +import com.fasterxml.jackson.core.JacksonException; +import com.fasterxml.jackson.databind.JsonNode; import java.io.IOException; +import java.util.ArrayList; +import java.util.List; public class SearchApiService extends BaseLibraryApiService { public SearchApiService(Requester requester) { super(requester); } - public String search(String keyword, int page, int pageSize) throws ApiException, IOException { - HttpRequest request = LibraryRequestFactory.bookSearchRequest(keyword, page, pageSize); - HttpResponse response = requester.post(request); - checkResponse(response); - - return response.getStringBody(); + public PagingResult> search(String keyword, int page, int pageSize) + throws ApiException, IOException, ParseException { + return search(new BookSearchRequest(keyword, pageSize, page)); } + public PagingResult> search(BookSearchRequest request) + throws ApiException, IOException, ParseException { + HttpRequest searchRequest = LibraryRequestFactory.bookSearchRequest(request); + HttpResponse searchResponse = requester.post(searchRequest); + checkResponse(searchResponse); + + try { + JsonNode data = objectMapper.readTree(searchResponse.getBody()).path("data"); + + int pageSize = data.path("limit").asInt(request.getPageSize()); + int currentPage = data.path("offset").asInt(request.getPage()) / pageSize + 1; + int totalResult = data.path("actualTotal").asInt(0); + int totalPage = totalResult / pageSize + 1; + + JsonNode dataList = data.get("dataList"); + List books = new ArrayList<>(dataList.size()); + for (JsonNode item : dataList) { + // 反序列化holding字段,原字段为字符串值,无法直接原样转换 + List holdings = objectMapper.readValue( + item.path("holdings").asText("[]"), bookHoldingListType); + BookSearchResult book = objectMapper.treeToValue(item, BookSearchResult.class); + book.setHoldings(holdings); + books.add(book); + } + + return PagingResult.>builder() + .currentPage(currentPage) + .totalResult(totalResult) + .pageSize(pageSize) + .totalPage(totalPage) + .data(books) + .build(); + + } catch (JacksonException e) { + e.printStackTrace(); + throw new ParseException(e.getMessage(), ""); + } + } } diff --git a/mywust-util/src/main/java/cn/wustlinghang/mywust/util/StringUtil.java b/mywust-util/src/main/java/cn/wustlinghang/mywust/util/StringUtil.java index 2fe5f38..97f7934 100644 --- a/mywust-util/src/main/java/cn/wustlinghang/mywust/util/StringUtil.java +++ b/mywust-util/src/main/java/cn/wustlinghang/mywust/util/StringUtil.java @@ -110,4 +110,29 @@ public class StringUtil { return result; } + + /** + * 清除字符串中的html(xml)标签,其中`<br>`被替换为换行`\n` + * + * @param raw 原始字符串 + * @return 处理后的字符串 + */ + public static String cleanHtml(String raw) { + return cleanHtml(raw, true); + } + + /** + * 清除字符串中的html(xml)标签,并指定`<br>`是否要替换为换行符`\n` + * + * @param raw 原始字符串 + * @param withBreakLine 是否将换行标签`<br>`替换成换行符`\n` + * @return 处理后的字符串 + */ + public static String cleanHtml(String raw, boolean withBreakLine) { + if (withBreakLine) { + raw = raw.replaceAll("
", "\n"); + } + + return raw.replaceAll("<.*?>", ""); + } }