| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340 |
- package cn.seecoder.bok.client;
- import cn.seecoder.bok.common.dto.CollectDTO;
- import cn.seecoder.bok.common.dto.RateDTO;
- import cn.seecoder.bok.common.vo.*;
- import com.fasterxml.jackson.core.JsonProcessingException;
- import com.fasterxml.jackson.core.type.TypeReference;
- import com.fasterxml.jackson.databind.ObjectMapper;
- import com.fasterxml.jackson.databind.json.JsonMapper;
- import com.fasterxml.jackson.datatype.jdk8.Jdk8Module;
- import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
- import com.fasterxml.jackson.module.paramnames.ParameterNamesModule;
- import okhttp3.*;
- import org.slf4j.Logger;
- import org.slf4j.LoggerFactory;
- import org.springframework.data.domain.*;
- import org.springframework.data.util.Streamable;
- import javax.validation.constraints.NotBlank;
- import javax.validation.constraints.NotNull;
- import java.io.IOException;
- import java.text.MessageFormat;
- import java.util.*;
- import java.util.function.Function;
- /**
- * @author kunduin
- */
- public class SeecoderBokClient
- implements SeecoderBokQuestionApi, SeecoderBokQuestionQueryApi,
- SeecoderBokRecordApi, SeecoderBokUserInteractiveApi,
- SeecoderBokKnowledgeApi {
- private final Logger logger = LoggerFactory.getLogger(getClass());
- private final OkHttpClient client;
- private final ObjectMapper mapper;
- private final int CONFIG_PAGE_START;
- private final String CONFIG_HOST;
- /**
- * 创建client
- *
- * @param host bok地址,示例:{@code "http://bok.seecoder.cn"}
- */
- public SeecoderBokClient(String host) {
- this(host, 0);
- }
- public SeecoderBokClient(String host, int pageStart) {
- this.CONFIG_HOST = host;
- this.CONFIG_PAGE_START = pageStart;
- client = new OkHttpClient();
- mapper = JsonMapper.builder()
- .addModule(new ParameterNamesModule())
- .addModule(new Jdk8Module())
- .addModule(new JavaTimeModule())
- .build();
- }
- @Override
- public List<KnowledgeNodeVO> getKnowledgeNode(String name) {
- HttpUrl httpUrl = createUrlBuilder("/api/knowledge")
- .addQueryParameter("name", name).build();
- Response response = get(httpUrl);
- return getResponseBody(response, new TypeReference<List<KnowledgeNodeVO>>() {})
- .orElse(Collections.emptyList());
- }
- @Override
- public Page<QuestionVO> getQuestionList(
- String stem, String tag, String knowledgeId, Pageable pageable) {
- HttpUrl.Builder urlBuilder = createUrlBuilder("/api/question")
- .addQueryParameter("stem", stem)
- .addQueryParameter("tag", tag)
- .addQueryParameter("knowledgeId", knowledgeId);
- return getQuestionVOS(pageable, urlBuilder);
- }
- @Override
- public QuestionVO createQuestion(@NotNull QuestionVO question) {
- HttpUrl httpUrl = createUrlBuilder("/api/question").build();
- Response response = post(httpUrl, writeRequestBody(question));
- return getResponseBody(response, QuestionVO.class).orElseThrow(() -> SeecoderBokException.UNWRAP_EXCEPTION);
- }
- @Override
- public Optional<QuestionVO> getQuestionById(@NotBlank String questionId) {
- HttpUrl httpUrl = createUrlBuilder(MessageFormat.format("/api/question/{0}", questionId)).build();
- Response response = get(httpUrl);
- return getResponseBody(response, QuestionVO.class);
- }
- @Override
- public QuestionVO updateQuestion(@NotNull QuestionVO question) {
- HttpUrl httpUrl = createUrlBuilder(MessageFormat.format("/api/question/{0}", question.getId())).build();
- Response response = put(httpUrl, writeRequestBody(question));
- return getResponseBody(response, QuestionVO.class).orElseThrow(() -> SeecoderBokException.UNWRAP_EXCEPTION);
- }
- @Override
- public void deleteQuestionById(@NotBlank String questionId) {
- HttpUrl httpUrl = createUrlBuilder(MessageFormat.format("/api/question/{0}", questionId)).build();
- delete(httpUrl);
- }
- @Override
- public List<QuestionVO> getQuestionListByIds(@NotNull List<String> ids) {
- HttpUrl httpUrl = createUrlBuilder("/api/question-query/id")
- .addQueryParameter("id", joinComma(ids))
- .build();
- Response response = get(httpUrl);
- return getResponseBody(response, new TypeReference<List<QuestionVO>>() {})
- .orElse(Collections.emptyList());
- }
- @Override
- public List<RecordVO> createUserRecord(@NotNull List<RecordVO> records) {
- HttpUrl httpUrl = createUrlBuilder("/api/record").build();
- Response response = post(httpUrl, writeRequestBody(records));
- return getResponseBody(response, new TypeReference<List<RecordVO>>() {})
- .orElse(Collections.emptyList());
- }
- @Override
- public Page<RecordVO> getUserRecord(
- List<String> userIdList,
- List<String> questionIdList,
- List<String> recordIdList,
- Pageable pageable) {
- HttpUrl.Builder urlBuilder = createUrlBuilder("/api/record")
- .addQueryParameter("userId", joinComma(userIdList))
- .addQueryParameter("questionId", joinComma(questionIdList))
- .addQueryParameter("recordId", joinComma(recordIdList));
- HttpUrl httpUrl = addPageableToParams(urlBuilder, pageable).build();
- Response response = get(httpUrl);
- return getResponseBody(response, new TypeReference<Page<RecordVO>>() {})
- .map(recordVOS -> new PageImpl<>(
- recordVOS.getContent(),
- parseBokToPageable(recordVOS.getNumber(), recordVOS.getSize(), pageable),
- recordVOS.getTotalElements()))
- .orElse(new PageImpl<>(Collections.emptyList()));
- }
- @Override
- public PageableRecordQuestionVO getUserRecordQuestions(
- @NotNull String userId, Pageable pageable) {
- HttpUrl.Builder urlBuilder = createUrlBuilder(MessageFormat.format("/api/record/{0}/question", userId));
- HttpUrl httpUrl = addPageableToParams(urlBuilder, pageable).build();
- Response response = get(httpUrl);
- return getResponseBody(response, PageableRecordQuestionVO.class)
- .map(pageableRecordQuestionVO -> {
- PageVO page = pageableRecordQuestionVO.getPage();
- page.setNumber(parseBokToPageableNumber(page.getNumber()));
- pageableRecordQuestionVO.setPage(page);
- return pageableRecordQuestionVO;
- })
- .orElse(PageableRecordQuestionVO.ofEmpty());
- }
- @Override
- public void collectQuestion(
- @NotBlank String userId, @NotBlank String questionId, @NotNull CollectDTO collectDTO) {
- HttpUrl httpUrl = createUrlBuilder(
- MessageFormat.format("/api/user/{0}/question/{1}/collection", userId, questionId)).build();
- post(httpUrl, writeRequestBody(collectDTO));
- }
- @Override
- public void rateQuestion(
- @NotBlank String userId, @NotBlank String questionId, @NotNull RateDTO rateDTO) {
- HttpUrl httpUrl = createUrlBuilder(
- MessageFormat.format("/api/user/{0}/question/{1}/rate", userId, questionId)).build();
- post(httpUrl, writeRequestBody(rateDTO));
- }
- @Override
- public Page<QuestionVO> getUserInteractiveQuestions(
- @NotBlank String userId, Boolean collect, Boolean rate, Pageable pageable) {
- HttpUrl.Builder urlBuilder = createUrlBuilder(MessageFormat.format("/api/user/{0}/question", userId))
- .addQueryParameter("collection", String.valueOf(collect))
- .addQueryParameter("rate", String.valueOf(rate));
- return getQuestionVOS(pageable, urlBuilder);
- }
- @Override
- public Optional<InteractiveVO> getUserInteractiveQuestion(
- @NotBlank String userId, @NotBlank String questionId) {
- HttpUrl httpUrl = createUrlBuilder(
- MessageFormat.format("/api/user/{0}/question/{1}", userId, questionId)).build();
- Response response = get(httpUrl);
- return getResponseBody(response, InteractiveVO.class);
- }
- @Override
- public List<InteractiveVO> getUserInteractiveQuestionIn(
- @NotBlank String userId, List<String> questionIdList) {
- HttpUrl httpUrl = createUrlBuilder(
- MessageFormat.format("/api/user/{0}/questionInList", userId)).build();
- Response response = get(httpUrl);
- return getResponseBody(response, new TypeReference<List<InteractiveVO>>() {})
- .orElse(Collections.emptyList());
- }
- private Page<QuestionVO> getQuestionVOS(Pageable pageable, HttpUrl.Builder urlBuilder) {
- HttpUrl httpUrl = addPageableToParams(urlBuilder, pageable).build();
- Response response = get(httpUrl);
- return getResponseBody(response, PageableQuestionListVO.class)
- .map(pageableQuestionListVO ->
- new PageImpl<>(
- pageableQuestionListVO.getQuestions(),
- parseBokToPageable(pageableQuestionListVO.getPage(), pageable),
- pageableQuestionListVO.getPage().getTotalElements()))
- .orElse(new PageImpl<>(Collections.emptyList()));
- }
- private Response get(HttpUrl httpUrl) {
- return requestWithMethod("GET", httpUrl, null);
- }
- private void delete(HttpUrl httpUrl) {
- requestWithMethod("DELETE", httpUrl, null);
- }
- private Response post(HttpUrl httpUrl, RequestBody requestBody) {
- return requestWithMethod("POST", httpUrl, requestBody);
- }
- private Response put(HttpUrl httpUrl, RequestBody requestBody) {
- return requestWithMethod("PUT", httpUrl, requestBody);
- }
- private Response requestWithMethod(String method, HttpUrl httpUrl, RequestBody requestBody) {
- Request request = new Request.Builder().url(httpUrl).method(method, requestBody).build();
- try {
- return client.newCall(request).execute();
- } catch (IOException e) {
- logger.error("IOException.", e);
- throw SeecoderBokException.IO_EXCEPTION;
- }
- }
- private HttpUrl.Builder createUrlBuilder(final String path) {
- return Objects.requireNonNull(HttpUrl.parse(CONFIG_HOST + path)).newBuilder();
- }
- private <T> Optional<T> getResponseBody(Response response, Class<T> tClass) {
- return getResponseBody(
- response,
- bodyString -> {
- try {
- return mapper.readValue(bodyString, tClass);
- } catch (JsonProcessingException e) {
- logger.error("JsonProcessingException.", e);
- throw SeecoderBokException.JSON_EXCEPTION;
- }
- });
- }
- private <T> Optional<T> getResponseBody(Response response, TypeReference<T> typeReference) {
- return getResponseBody(
- response,
- bodyString -> {
- try {
- return mapper.readValue(bodyString, typeReference);
- } catch (JsonProcessingException e) {
- logger.error("JsonProcessingException.", e);
- throw SeecoderBokException.JSON_EXCEPTION;
- }
- });
- }
- private <T> Optional<T> getResponseBody(Response response, Function<String, T> mapType) {
- return Optional.ofNullable(response.body())
- .map(body -> {
- try {
- String bodyString = body.string();
- return mapType.apply(bodyString);
- } catch (IOException e) {
- logger.error("IOException.", e);
- throw SeecoderBokException.IO_EXCEPTION;
- }
- });
- }
- private <T> RequestBody writeRequestBody(T obj) {
- if (obj == null) {
- return null;
- }
- try {
- return RequestBody.create(mapper.writeValueAsString(obj), SeecoderBokConstants.JSON);
- } catch (JsonProcessingException e) {
- logger.error("JsonProcessingException.", e);
- throw SeecoderBokException.JSON_EXCEPTION;
- }
- }
- private int parsePageableNumberToBok(int pageNumber) {
- return pageNumber - CONFIG_PAGE_START + SeecoderBokConstants.PAGE_START;
- }
- private int parseBokToPageableNumber(int bokPageNumber) {
- return bokPageNumber - SeecoderBokConstants.PAGE_START + CONFIG_PAGE_START;
- }
- private Pageable parseBokToPageable(PageVO pageVO, Pageable pageable) {
- return parseBokToPageable(pageVO.getNumber(), pageVO.getSize(), pageable);
- }
- private Pageable parseBokToPageable(int page, int size, Pageable pageable) {
- if (pageable == null) {
- return PageRequest.of(parseBokToPageableNumber(page), size);
- }
- return pageable;
- }
- private HttpUrl.Builder addPageableToParams(HttpUrl.Builder builder, Pageable pageable) {
- return Optional.ofNullable(pageable)
- .map(notNullPageable ->
- // TODO: not accept error
- builder.addQueryParameter("page", String.valueOf(parsePageableNumberToBok(notNullPageable.getPageNumber()) + 1))
- .addQueryParameter("sort", parseSort(notNullPageable.getSort()))
- .addQueryParameter("size", String.valueOf(notNullPageable.getPageSize()))
- )
- .orElse(builder);
- }
- private String joinComma(Iterable<String> list) {
- return Optional.ofNullable(list)
- .map(notNullList -> String.join(",", notNullList))
- .orElse("");
- }
- private String parseSort(Sort sort) {
- return String.join("|",
- sort.map(order -> order.getProperty() + "," + order.getDirection()));
- }
- }
|