是否可以用spring Boot列出所有配置的RESTendpoint?执行器在启动时列出所有现有路径,我想为我的自定义服务做一些类似的事情,这样我就可以在启动时检查所有路径是否配置正确,并将此信息用于客户端调用。
我该怎么做?我在服务bean上使用@path
/@get
注释,并通过ResourceConfig#RegisterClasses
注册它们。
有没有办法查询所有路径的配置?
更新:我通过注册REST控制器
@Bean
public ResourceConfig resourceConfig() {
return new ResourceConfig() {
{
register(MyRestController.class);
}
};
}
GET /rest/mycontroller/info
POST /res/mycontroller/update
...
最好的方法可能是使用ApplicationEventListener
。从那里,您可以监听“Application finished Initializing”事件,并从ApplicationEvent
获取ResourceModel
。ResourceModel
将具有所有初始化的资源
。然后您可以像其他人提到的那样遍历资源
。下面是一个实现。一些实现取自DropWizardResourceConfig
实现。
import com.fasterxml.classmate.ResolvedType;
import com.fasterxml.classmate.TypeResolver;
import java.util.Comparator;
import java.util.HashSet;
import java.util.Set;
import java.util.TreeSet;
import org.glassfish.jersey.server.model.Resource;
import org.glassfish.jersey.server.model.ResourceMethod;
import org.glassfish.jersey.server.model.ResourceModel;
import org.glassfish.jersey.server.monitoring.ApplicationEvent;
import org.glassfish.jersey.server.monitoring.ApplicationEventListener;
import org.glassfish.jersey.server.monitoring.RequestEvent;
import org.glassfish.jersey.server.monitoring.RequestEventListener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class EndpointLoggingListener implements ApplicationEventListener {
private static final TypeResolver TYPE_RESOLVER = new TypeResolver();
private final String applicationPath;
private boolean withOptions = false;
private boolean withWadl = false;
public EndpointLoggingListener(String applicationPath) {
this.applicationPath = applicationPath;
}
@Override
public void onEvent(ApplicationEvent event) {
if (event.getType() == ApplicationEvent.Type.INITIALIZATION_APP_FINISHED) {
final ResourceModel resourceModel = event.getResourceModel();
final ResourceLogDetails logDetails = new ResourceLogDetails();
resourceModel.getResources().stream().forEach((resource) -> {
logDetails.addEndpointLogLines(getLinesFromResource(resource));
});
logDetails.log();
}
}
@Override
public RequestEventListener onRequest(RequestEvent requestEvent) {
return null;
}
public EndpointLoggingListener withOptions() {
this.withOptions = true;
return this;
}
public EndpointLoggingListener withWadl() {
this.withWadl = true;
return this;
}
private Set<EndpointLogLine> getLinesFromResource(Resource resource) {
Set<EndpointLogLine> logLines = new HashSet<>();
populate(this.applicationPath, false, resource, logLines);
return logLines;
}
private void populate(String basePath, Class<?> klass, boolean isLocator,
Set<EndpointLogLine> endpointLogLines) {
populate(basePath, isLocator, Resource.from(klass), endpointLogLines);
}
private void populate(String basePath, boolean isLocator, Resource resource,
Set<EndpointLogLine> endpointLogLines) {
if (!isLocator) {
basePath = normalizePath(basePath, resource.getPath());
}
for (ResourceMethod method : resource.getResourceMethods()) {
if (!withOptions && method.getHttpMethod().equalsIgnoreCase("OPTIONS")) {
continue;
}
if (!withWadl && basePath.contains(".wadl")) {
continue;
}
endpointLogLines.add(new EndpointLogLine(method.getHttpMethod(), basePath, null));
}
for (Resource childResource : resource.getChildResources()) {
for (ResourceMethod method : childResource.getAllMethods()) {
if (method.getType() == ResourceMethod.JaxrsType.RESOURCE_METHOD) {
final String path = normalizePath(basePath, childResource.getPath());
if (!withOptions && method.getHttpMethod().equalsIgnoreCase("OPTIONS")) {
continue;
}
if (!withWadl && path.contains(".wadl")) {
continue;
}
endpointLogLines.add(new EndpointLogLine(method.getHttpMethod(), path, null));
} else if (method.getType() == ResourceMethod.JaxrsType.SUB_RESOURCE_LOCATOR) {
final String path = normalizePath(basePath, childResource.getPath());
final ResolvedType responseType = TYPE_RESOLVER
.resolve(method.getInvocable().getResponseType());
final Class<?> erasedType = !responseType.getTypeBindings().isEmpty()
? responseType.getTypeBindings().getBoundType(0).getErasedType()
: responseType.getErasedType();
populate(path, erasedType, true, endpointLogLines);
}
}
}
}
private static String normalizePath(String basePath, String path) {
if (path == null) {
return basePath;
}
if (basePath.endsWith("/")) {
return path.startsWith("/") ? basePath + path.substring(1) : basePath + path;
}
return path.startsWith("/") ? basePath + path : basePath + "/" + path;
}
private static class ResourceLogDetails {
private static final Logger logger = LoggerFactory.getLogger(ResourceLogDetails.class);
private static final Comparator<EndpointLogLine> COMPARATOR
= Comparator.comparing((EndpointLogLine e) -> e.path)
.thenComparing((EndpointLogLine e) -> e.httpMethod);
private final Set<EndpointLogLine> logLines = new TreeSet<>(COMPARATOR);
private void log() {
StringBuilder sb = new StringBuilder("\nAll endpoints for Jersey application\n");
logLines.stream().forEach((line) -> {
sb.append(line).append("\n");
});
logger.info(sb.toString());
}
private void addEndpointLogLines(Set<EndpointLogLine> logLines) {
this.logLines.addAll(logLines);
}
}
private static class EndpointLogLine {
private static final String DEFAULT_FORMAT = " %-7s %s";
final String httpMethod;
final String path;
final String format;
private EndpointLogLine(String httpMethod, String path, String format) {
this.httpMethod = httpMethod;
this.path = path;
this.format = format == null ? DEFAULT_FORMAT : format;
}
@Override
public String toString() {
return String.format(format, httpMethod, path);
}
}
}
然后你只需要用Jersey注册监听器就可以了。您可以从jerseyproperties
中获取应用程序路径。您需要在Spring Boot的application.properties
属性Spring.jersey.applicationpath
下设置它。这将是根路径,就像在ResourceConfig
子类上使用@applicationpath
一样
@Bean
public ResourceConfig getResourceConfig(JerseyProperties jerseyProperties) {
return new JerseyConfig(jerseyProperties);
}
...
public class JerseyConfig extends ResourceConfig {
public JerseyConfig(JerseyProperties jerseyProperties) {
register(HelloResource.class);
register(new EndpointLoggingListener(jerseyProperties.getApplicationPath()));
}
}
需要注意的一点是,Jersey servlet上没有默认设置启动加载。这意味着,在第一个请求之前,该Jersey不会在启动时加载。所以在第一个请求之前,您不会看到侦听器被触发。我已经打开了一个问题,以获取配置属性,但同时,您有两个选项:
spring.jersey.type=filter
另一个选项是重写JerseyServletRegistrationBean
并设置其LoadOnStartup
属性。下面是一个配置示例。一些实现直接取自JerseyAutoConfiguration
@SpringBootApplication
public class JerseyApplication {
public static void main(String[] args) {
SpringApplication.run(JerseyApplication.class, args);
}
@Bean
public ResourceConfig getResourceConfig(JerseyProperties jerseyProperties) {
return new JerseyConfig(jerseyProperties);
}
@Bean
public ServletRegistrationBean jerseyServletRegistration(
JerseyProperties jerseyProperties, ResourceConfig config) {
ServletRegistrationBean registration = new ServletRegistrationBean(
new ServletContainer(config),
parseApplicationPath(jerseyProperties.getApplicationPath())
);
addInitParameters(registration, jerseyProperties);
registration.setName(JerseyConfig.class.getName());
registration.setLoadOnStartup(1);
return registration;
}
private static String parseApplicationPath(String applicationPath) {
if (!applicationPath.startsWith("/")) {
applicationPath = "/" + applicationPath;
}
return applicationPath.equals("/") ? "/*" : applicationPath + "/*";
}
private void addInitParameters(RegistrationBean registration, JerseyProperties jersey) {
for (Entry<String, String> entry : jersey.getInit().entrySet()) {
registration.addInitParameter(entry.getKey(), entry.getValue());
}
}
}
因此,看起来Spring Boot将添加load-on-startup
属性,因此我们不必重写JerseyServletRegistrationBean
。将在引导1.4.0中添加
我知道有类似的问题存在,但如果只适用于glassfish服务器。 列出所有部署的restendpoint(spring-boot、jersey) 是否可以用spring Boot列出所有配置的RESTendpoint?执行器在启动时列出所有现有路径,我想为我的自定义服务做一些类似的事情,这样我就可以在启动时检查所有路径是否配置正确,并将此信息用于客户端调用。
根据这些文件: 在启动时,Spring Boot会尝试找到/error的映射。按照约定,以/error结尾的URL映射到同名的逻辑视图:error。如果找不到从/error到视图的映射,Spring Boot定义了它自己的回落错误页面--所谓的“Whitelabel错误页面”(一个最小的页面,只有HTTP状态信息和任何错误细节,比如来自未捕获异常的消息)。 所以。每当抛出异常并且没有由任何注释方法
我用Spring启动将SpringRest服务作为外部雄猫的战争文件。 引起原因:Java . lang . nosuchmethoderror:org . spring framework . util . string utils . isempty(Ljava/lang/Object;)Z Spring版本由maven中的Spring启动器-启动器-父级管理,但我总是得到一个例外,这是不兼容
我正在尝试使用石英2.2。1带Spring靴。我试图声明一个计划任务,该任务应该将一些数据写入文件。我的工作定义如下: 然后呢: PS:我已经测试了我的控制器方法doPrintData和它的工作原理。但是当我把它放在执行方法中时,我面对的是javaNullPointerExcure。
问题内容: 我正在尝试将Quartz 2.2.1与Spring Boot一起使用。我试图声明一个计划的任务,该任务应该将一些数据写入文件中。我的工作定义如下: 然后 : PS:我已经测试了我的控制器方法“ doPrintData”,它可以工作。但是,当我将其放入面向 javaNullPointerException 的execute方法中时。 问题答案: Spring Boot为您管理它。删除石英
我试图将一个文件发布到spring boot中使用Curl实现的restfulendpoint,但它抛出以下错误: 我一定是错过了一些基本的东西,但却看不出是什么。它正在寻找请求参数'file',但不确定如何通过curl发送。 提前致谢 更新: 我在下面的链接中尝试了解决方案