Skip to content

Commit

Permalink
提供的 api client 生成方法生成 http 请求客户端代码,并重构插件的请求逻辑。
Browse files Browse the repository at this point in the history
  • Loading branch information
chengzhongxue committed Aug 29, 2024
1 parent 999d6fe commit 9421338
Show file tree
Hide file tree
Showing 52 changed files with 4,578 additions and 211 deletions.
1,056 changes: 1,056 additions & 0 deletions api-docs/openapi/v3_0/doubanApi.json

Large diffs are not rendered by default.

32 changes: 29 additions & 3 deletions build.gradle
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
plugins {
id 'java'
id "com.github.node-gradle.node" version "5.0.0"
id "com.github.node-gradle.node" version "7.0.2"
id "io.freefair.lombok" version "8.0.1"
id "run.halo.plugin.devtools" version "0.0.7"
id "run.halo.plugin.devtools" version "0.1.1"
}

group 'run.halo.starter'
Expand Down Expand Up @@ -45,5 +45,31 @@ build {
}

halo {
version = '2.17'
version = '2.17.0'
}

haloPlugin {
openApi {
outputDir = file("$rootDir/api-docs/openapi/v3_0")
// 用于定义 API 分组规则
groupingRules {
// 此名称为 group name,定义后 groupedApiMappings 中的 /v3/api-docs/ 后的名称需要与之相同,要避免与 halo 中已经存在的 group 相同避免生成后出现与插件无关的 API
doubanApi {
// 分组显示名称
displayName = 'Extension API for Douban'
// 分组的 API 规则
pathsToMatch = ['/apis/douban.moony.la/v1alpha1/**',
'/apis/api.douban.moony.la/v1alpha1/**'
]
}
}
groupedApiMappings = [
'/v3/api-docs/doubanApi': 'doubanApi.json'
]
generator {
// 默认配置可缺省
outputDir = file("${projectDir}/ui/src/api/generated")
}
}
}

2 changes: 1 addition & 1 deletion gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#Wed May 10 13:57:01 CST 2023
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.0-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.9-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
49 changes: 36 additions & 13 deletions src/main/java/la/moony/douban/DoubanEndpoint.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package la.moony.douban;

import io.swagger.v3.oas.annotations.enums.ParameterIn;
import la.moony.douban.extension.DoubanMovie;
import la.moony.douban.service.DoubanService;
import la.moony.douban.vo.DoubanMovieVo;
import org.apache.commons.lang3.StringUtils;
import org.springdoc.webflux.core.fn.SpringdocRouteBuilder;
import org.springframework.stereotype.Component;
Expand All @@ -11,37 +13,37 @@
import reactor.core.publisher.Mono;
import run.halo.app.core.extension.endpoint.CustomEndpoint;
import run.halo.app.extension.GroupVersion;
import run.halo.app.extension.ReactiveExtensionClient;
import run.halo.app.extension.router.QueryParamBuildUtil;
import run.halo.app.extension.ListResult;

import static org.springdoc.core.fn.builders.apiresponse.Builder.responseBuilder;
import static org.springdoc.core.fn.builders.parameter.Builder.parameterBuilder;

@Component
public class DoubanEndpoint implements CustomEndpoint {

private final String doubanMovieTag = "api.plugin.halo.run/v1alpha1/DoubanMovie";

private final ReactiveExtensionClient client;
private final String doubanMovieTag = "api.douban.moony.la/v1alpha1/DoubanMovie";

private final DoubanService doubanService;


public DoubanEndpoint(ReactiveExtensionClient client, DoubanService doubanService) {
this.client = client;
public DoubanEndpoint(DoubanService doubanService) {
this.doubanService = doubanService;
}

@Override
public RouterFunction<ServerResponse> endpoint() {
return SpringdocRouteBuilder.route()
.GET("plugins/plugin-douban/doubanmovies", this::listDoubanmovie, builder -> {
.GET("doubanmovies", this::listDoubanmovie, builder -> {
builder.operationId("listDoubanMovie")
.description("List doubanMovie.")
.tag(doubanMovieTag);
QueryParamBuildUtil.buildParametersFromType(builder, DoubanMovieQuery.class);
.tag(doubanMovieTag)
.response(
responseBuilder()
.implementation(ListResult.generateGenericClass(DoubanMovie.class))
);
DoubanMovieQuery.buildParameters(builder);
})
.GET("plugins/plugin-douban/genres", this::ListGenres,
.GET("doubanmovies/-/genres", this::ListGenres,
builder -> builder.operationId("ListGenres")
.description("List all douban genres.")
.tag(doubanMovieTag)
Expand All @@ -55,11 +57,25 @@ public RouterFunction<ServerResponse> endpoint() {
.response(responseBuilder()
.implementationArray(String.class)
))
.GET("doubanmovies/-/getDoubanDetail", this::getDoubanDetail,
builder -> builder.operationId("getDoubanDetail")
.description("getDoubanDetail.")
.tag(doubanMovieTag)
.parameter(parameterBuilder()
.name("url")
.in(ParameterIn.QUERY)
.description("doubanmovie url to query")
.required(false)
.implementation(String.class)
)
.response(responseBuilder()
.implementationArray(DoubanMovieVo.class)
))
.build();
}

Mono<ServerResponse> listDoubanmovie(ServerRequest request) {
DoubanMovieQuery query = new DoubanMovieQuery(request.exchange());
DoubanMovieQuery query = new DoubanMovieQuery(request);
return doubanService.listDoubanMovie(query)
.flatMap(doubanMovies -> ServerResponse.ok().bodyValue(doubanMovies));
}
Expand All @@ -73,8 +89,15 @@ private Mono<ServerResponse> ListGenres(ServerRequest request) {
.flatMap(result -> ServerResponse.ok().bodyValue(result));
}

private Mono<ServerResponse> getDoubanDetail(ServerRequest request) {
String url = request.queryParam("url").orElse(null);
return doubanService.getDoubanDetail(url)
.flatMap(result -> ServerResponse.ok().bodyValue(result));
}


@Override
public GroupVersion groupVersion() {
return GroupVersion.parseAPIVersion("api.plugin.halo.run/v1alpha1");
return GroupVersion.parseAPIVersion("api.douban.moony.la/v1alpha1");
}
}
106 changes: 71 additions & 35 deletions src/main/java/la/moony/douban/DoubanMovieQuery.java
Original file line number Diff line number Diff line change
@@ -1,35 +1,34 @@
package la.moony.douban;

import io.swagger.v3.oas.annotations.enums.ParameterIn;
import la.moony.douban.extension.DoubanMovie;
import org.apache.commons.lang3.StringUtils;
import org.springdoc.core.fn.builders.operation.Builder;
import org.springframework.data.domain.Sort;
import org.springframework.lang.Nullable;
import org.springframework.util.MultiValueMap;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.reactive.function.server.ServerRequest;
import run.halo.app.core.extension.endpoint.SortResolver;
import run.halo.app.extension.ListOptions;
import run.halo.app.extension.PageRequest;
import run.halo.app.extension.PageRequestImpl;
import run.halo.app.extension.router.IListRequest;
import run.halo.app.extension.router.SortableRequest;
import run.halo.app.extension.router.selector.FieldSelector;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Optional;

import static java.util.Comparator.comparing;
import static run.halo.app.extension.index.query.QueryFactory.all;
import static run.halo.app.extension.index.query.QueryFactory.and;
import static org.springdoc.core.fn.builders.parameter.Builder.parameterBuilder;
import static run.halo.app.extension.index.query.QueryFactory.contains;
import static run.halo.app.extension.index.query.QueryFactory.equal;
import static run.halo.app.extension.router.selector.SelectorUtil.labelAndFieldSelectorToListOptions;
import static run.halo.app.extension.router.QueryParamBuildUtil.sortParameter;

public class DoubanMovieQuery extends SortableRequest {

private final MultiValueMap<String, String> queryParams;


public DoubanMovieQuery(ServerWebExchange exchange) {
super(exchange);
this.queryParams = exchange.getRequest().getQueryParams();
public DoubanMovieQuery(ServerRequest request) {
super(request.exchange());
}

@Nullable
Expand All @@ -52,37 +51,37 @@ public String getDataType() {
return queryParams.getFirst("dataType");
}

@Nullable
public String getGenre() {
return StringUtils.defaultIfBlank(queryParams.getFirst("genre"), null);
}

public ListOptions toListOptions() {
var listOptions =
labelAndFieldSelectorToListOptions(getLabelSelector(), getFieldSelector());
var query = all();
if (StringUtils.isNotBlank(getStatus())) {
query = and(query, equal("faves.status", getStatus()));
}
if (StringUtils.isNotBlank(getType())) {
query = and(query, equal("spec.type", getType()));
}
if (StringUtils.isNotBlank(getDataType())) {
query = and(query, equal("spec.dataType", getDataType()));
}
var builder = ListOptions.builder(super.toListOptions());

if (StringUtils.isNotBlank(getGenre())) {
query = and(query, equal("spec.genres", getGenre()));
}
Optional.ofNullable(getKeyword())
.filter(StringUtils::isNotBlank)
.ifPresent(keyword -> builder.andQuery(
contains("spec.name", getKeyword()))
);

if (listOptions.getFieldSelector() != null
&& listOptions.getFieldSelector().query() != null) {
query = and(query, listOptions.getFieldSelector().query());
}
if (StringUtils.isNotBlank(getKeyword())) {
query = and(query, contains("spec.name", getKeyword()));
}
listOptions.setFieldSelector(FieldSelector.of(query));
return listOptions;
Optional.ofNullable(getStatus())
.filter(StringUtils::isNotBlank)
.ifPresent(status -> builder.andQuery(equal("faves.status", status)));

Optional.ofNullable(getType())
.filter(StringUtils::isNotBlank)
.ifPresent(type -> builder.andQuery(equal("spec.type", type)));

Optional.ofNullable(getDataType())
.filter(StringUtils::isNotBlank)
.ifPresent(dataType -> builder.andQuery(equal("spec.dataType", dataType)));

Optional.ofNullable(getGenre())
.filter(StringUtils::isNotBlank)
.ifPresent(genres -> builder.andQuery(equal("spec.genres", genres)));

return builder.build();
}

public Comparator<DoubanMovie> toComparator() {
Expand Down Expand Up @@ -115,5 +114,42 @@ public PageRequest toPageRequest() {
return PageRequestImpl.of(getPage(), getSize(), getSort());
}

public static void buildParameters(Builder builder) {
IListRequest.buildParameters(builder);
builder.parameter(sortParameter())
.parameter(parameterBuilder()
.in(ParameterIn.QUERY)
.name("keyword")
.description("DoubanMovies filtered by keyword.")
.implementation(String.class)
.required(false))
.parameter(parameterBuilder()
.in(ParameterIn.QUERY)
.name("status")
.description("DoubanMovies filtered by status.")
.implementation(String.class)
.required(false))
.parameter(parameterBuilder()
.in(ParameterIn.QUERY)
.name("type")
.description("DoubanMovies filtered by type.")
.implementation(String.class)
.required(false))
.parameter(parameterBuilder()
.in(ParameterIn.QUERY)
.name("dataType")
.description("DoubanMovies filtered by dataType.")
.implementation(String.class)
.required(false))
.parameter(parameterBuilder()
.in(ParameterIn.QUERY)
.name("genres")
.description("DoubanMovies filtered by genres.")
.implementation(String.class)
.required(false))

;
}


}
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,10 @@

import la.moony.douban.extension.DoubanMovie;
import la.moony.douban.service.DoubanService;
import la.moony.douban.vo.DoubanMovieVo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Mono;
import run.halo.app.extension.ReactiveExtensionClient;
Expand All @@ -35,11 +32,6 @@ public void synchronizationDouban() {
doubanService.synchronizationDouban();
}

@GetMapping("/getDoubanDetail")
public Mono<DoubanMovieVo> getDoubanDetail(@RequestParam("url") String url){
return doubanService.getDoubanDetail(url);
}


@DeleteMapping("/clear")
public Mono<Void> clearLogs() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -330,8 +330,9 @@ public Mono<DoubanMovieVo> tmdbDetail(String type,String id,String apiKey){
doubanMovieDetail.getFaves().setRemark(null);
doubanMovieDetail.getFaves().setScore(null);
doubanMovieDetail.getFaves().setStatus(null);
reactiveClient.create(doubanMovieDetail).subscribe();
return getDoubanMovieVo(doubanMovieDetail);
return reactiveClient.create(doubanMovieDetail)
.thenReturn(doubanMovieDetail)
.flatMap(doubanMovie -> getDoubanMovieVo(doubanMovie));
}).onErrorResume(WebClientResponseException.NotFound.class, error -> {
log.error("Resource not found: ",error.getMessage());
return getDoubanMovieVo(doubanMovieDetail);
Expand Down Expand Up @@ -396,8 +397,9 @@ public Mono<DoubanMovieVo> doubanDetail(String type,String id){
doubanMovieDetail.getFaves().setRemark(null);
doubanMovieDetail.getFaves().setScore(null);
doubanMovieDetail.getFaves().setStatus(null);
reactiveClient.create(doubanMovieDetail).subscribe();
return getDoubanMovieVo(doubanMovieDetail);
return reactiveClient.create(doubanMovieDetail)
.thenReturn(doubanMovieDetail)
.flatMap(doubanMovie -> getDoubanMovieVo(doubanMovie));
}).onErrorResume(WebClientResponseException.NotFound.class, error -> {
log.error("Resource not found: ",error.getMessage());
return getDoubanMovieVo(doubanMovieDetail);
Expand Down
17 changes: 17 additions & 0 deletions src/main/resources/extensions/roleTemplate.yaml
Original file line number Diff line number Diff line change
@@ -1,3 +1,20 @@
apiVersion: v1alpha1
kind: Role
metadata:
name: role-template-douban-anonymous
labels:
rbac.authorization.halo.run/aggregate-to-anonymous: "true"
halo.run/role-template: "true"
halo.run/hidden: "true"
annotations:
rbac.authorization.halo.run/display-name: "查看朋友圈提交模板"
rules:
- apiGroups: [ "api.douban.moony.la" ]
resources: [ "doubanmovies","doubanmovies/genres","doubanmovies/getDoubanDetail"]
verbs: [ "get", "list" ]

---

apiVersion: v1alpha1
kind: Role
metadata:
Expand Down
2 changes: 1 addition & 1 deletion src/main/resources/static/contact-douban.iife.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
(function () {
function getDoubanDetail(src, e) {
var url = '/apis/api.plugin.halo.run/v1alpha1/plugins/plugin-douban/douban/getDoubanDetail?url=' + src;
var url = '/apis/api.douban.moony.la/v1alpha1/doubanmovies/-/getDoubanDetail?url=' + src;
fetch(url)
.then(response => response.json())
.then(data => {
Expand Down
Loading

0 comments on commit 9421338

Please sign in to comment.