refactor: support for custom api group in plugin controllers (#4065)

#### What type of PR is this?
/kind improvement
/area core
/milestone 2.7.x

#### What this PR does / why we need it:
插件的 Controllers 支持自定义 API Group
如:
```java
@RestController
@ApiVersion("fake.halo.run/v1")
@RequestMapping("/fake")
public class DemoController {
}
```
则生成路由为 `/apis/fake.halo.run/v1/fake`
如果没有 group 默认兼容以前的为 `/apis/api.plugin.halo.run/{version}/plugins/{pluginName}/**`
```java
@RestController
@ApiVersion("v1alpha1")
@RequestMapping("/fake")
public class DemoController {
}
```

#### Which issue(s) this PR fixes:
Fixes #4053

#### Does this PR introduce a user-facing change?
```release-note
插件的 Controllers 支持自定义 API Group
```
pull/4091/head
guqing 2023-06-26 22:01:57 +08:00 committed by GitHub
parent e13beb4cd1
commit ff7ab4e4f1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 24 additions and 15 deletions

View File

@ -7,7 +7,6 @@ import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;
import org.pf4j.PluginRuntimeException;
import org.springframework.aop.support.AopUtils;
import org.springframework.core.MethodIntrospector;
import org.springframework.stereotype.Controller;
@ -117,8 +116,7 @@ public class PluginRequestMappingHandlerMapping extends RequestMappingHandlerMap
if (info != null) {
ApiVersion apiVersion = handlerType.getAnnotation(ApiVersion.class);
if (apiVersion == null) {
throw new PluginRuntimeException(
"The handler [" + handlerType + "] is missing @ApiVersion annotation.");
return info;
}
info = RequestMappingInfo.paths(buildPrefix(pluginId, apiVersion.value())).build()
.combine(info);
@ -126,9 +124,14 @@ public class PluginRequestMappingHandlerMapping extends RequestMappingHandlerMap
return info;
}
protected String buildPrefix(String pluginId, String version) {
GroupVersion groupVersion = GroupVersion.parseAPIVersion(version);
protected String buildPrefix(String pluginName, String apiVersion) {
GroupVersion groupVersion = GroupVersion.parseAPIVersion(apiVersion);
if (StringUtils.hasText(groupVersion.group())) {
// apis/{group}/{version}
return String.format("/apis/%s/%s", groupVersion.group(), groupVersion.version());
}
// apis/api.plugin.halo.run/{version}/plugins/{pluginName}
return String.format("/apis/api.plugin.halo.run/%s/plugins/%s", groupVersion.version(),
pluginId);
pluginName);
}
}

View File

@ -1,7 +1,6 @@
package run.halo.app.plugin;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.mockito.Mockito.mock;
import static org.springframework.mock.http.server.reactive.MockServerHttpRequest.get;
import static org.springframework.mock.http.server.reactive.MockServerHttpRequest.post;
@ -20,7 +19,6 @@ import java.util.function.Predicate;
import java.util.stream.Collectors;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.pf4j.PluginRuntimeException;
import org.springframework.core.MethodIntrospector;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.http.HttpMethod;
@ -74,15 +72,14 @@ class PluginRequestMappingHandlerMappingTest {
}
@Test
public void shouldFailWhenMissingApiVersion() throws Exception {
public void shouldKeepRawWhenMissingApiVersion() throws Exception {
Method method = AppleMissingApiVersionController.class.getMethod("getName");
assertThatThrownBy(() ->
RequestMappingInfo info =
this.handlerMapping.getPluginMappingForMethod("fakePlugin", method,
AppleMissingApiVersionController.class)).isInstanceOf(PluginRuntimeException.class)
.hasMessage(
"The handler [class run.halo.app.plugin"
+ ".PluginRequestMappingHandlerMappingTest$AppleMissingApiVersionController] "
+ "is missing @ApiVersion annotation.");
AppleMissingApiVersionController.class);
assertThat(info.getPatternsCondition().getPatterns())
.isEqualTo(Collections.singleton(new PathPatternParser().parse("/apples")));
}
@Test
@ -174,6 +171,15 @@ class PluginRequestMappingHandlerMappingTest {
Set.of(HttpMethod.GET, HttpMethod.HEAD)));
}
@Test
void buildPrefix() {
String s = handlerMapping.buildPrefix("fakePlugin", "v1");
assertThat(s).isEqualTo("/apis/api.plugin.halo.run/v1/plugins/fakePlugin");
s = handlerMapping.buildPrefix("fakePlugin", "fake.halo.run/v1alpha1");
assertThat(s).isEqualTo("/apis/fake.halo.run/v1alpha1");
}
@SuppressWarnings("unchecked")
private <T> void assertError(Mono<Object> mono, final Class<T> exceptionClass,
final Consumer<T> consumer) {