作者:癫逼 | 来源:互联网 | 2024-11-16 18:58
本文将详细介绍如何将Spring属性占位符与Jersey的@Path和@ApplicationPath注解结合使用,以实现资源路径中的动态属性解析。
首先,我们需要理解Jersey的内部机制。当应用程序启动时,Jersey会构建一个包含所有资源信息的模型。这个模型用于处理请求,而不是每次请求时都重新解析资源信息,这样可以提高性能。
利用这种架构,Jersey允许我们使用与内部相同的API来编程构建和修改资源模型。通过实现ModelProcessor
接口,我们可以在资源模型构建过程中注入Spring的PropertyResolver
,从而解析占位符并更新资源路径。
下面是一个示例代码,展示了如何实现这一功能:
@Autowired
private PropertyResolver propertyResolver;
private ResourceModel processResourceModel(ResourceModel resourceModel) {
ResourceModel.Builder newResourceModelBuilder = new ResourceModel.Builder(false);
for (final Resource resource : resourceModel.getResources()) {
final Resource.Builder resourceBuilder = Resource.builder(resource);
String resolvedResourcePath = resolvePropertyPlaceholder(resource);
resourceBuilder.path(resolvedResourcePath);
// 处理子资源
for (Resource childResource : resource.getChildResources()) {
String resolvedChildPath = resolvePropertyPlaceholder(childResource);
final Resource.Builder childResourceBuilder = Resource.builder(childResource);
childResourceBuilder.path(resolvedChildPath);
resourceBuilder.addChildResource(childResourceBuilder.build());
}
newResourceModelBuilder.addResource(resourceBuilder.build());
}
return newResourceModelBuilder.build();
}
private String resolvePropertyPlaceholder(Resource resource) {
String originalPath = resource.getPath();
return propertyResolver.resolvePlaceholders(originalPath);
}
接下来,我们来看一个具体的资源类示例:
@Path("${resource}")
public class TestResource {
@GET
public String get() {
return "Resource Success!";
}
@GET
@Path("${sub.resource}")
public String getSubMethod() {
return "Sub-Resource Success!";
}
@Path("${sub.resource.locator}")
public SubResourceLocator getSubResourceLocator() {
return new SubResourceLocator();
}
public static class SubResourceLocator {
@GET
public String get() {
return "Sub-Resource-Locator Success!";
}
}
}
为了测试这一功能,我们可以使用Jersey测试框架。首先,创建一个包含属性值的类路径属性文件:
resource=resource
sub.resource=sub-resource
sub.resource.locator=sub-resource-locator
然后,编写一个JUnit测试类:
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.core.Response;
import org.glassfish.jersey.filter.LoggingFilter;
import org.glassfish.jersey.server.ResourceConfig;
import org.glassfish.jersey.server.model.ModelProcessor;
import org.glassfish.jersey.server.model.Resource;
import org.glassfish.jersey.server.model.ResourceModel;
import org.glassfish.jersey.test.JerseyTest;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.core.env.PropertyResolver;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;
public class SpringPathResolverTest extends JerseyTest {
@Path("${resource}")
public static class TestResource {
@GET
public String get() {
return "Resource Success!";
}
@GET
@Path("${sub.resource}")
public String getSubMethod() {
return "Sub-Resource Success!";
}
@Path("${sub.resource.locator}")
public SubResourceLocator getSubResourceLocator() {
return new SubResourceLocator();
}
public static class SubResourceLocator {
@GET
public String get() {
return "Sub-Resource-Locator Success!";
}
}
}
@Configuration
@PropertySource("classpath:/app.properties")
public static class SpringConfig {
}
public static class PropertyPlaceholderPathResolvingModelProcessor
implements ModelProcessor {
@Autowired
private PropertyResolver propertyResolver;
@Override
public ResourceModel processResourceModel(ResourceModel resourceModel,
javax.ws.rs.core.Configuration configuration) {
return processResourceModel(resourceModel);
}
@Override
public ResourceModel processSubResource(ResourceModel subResourceModel,
javax.ws.rs.core.Configuration configuration) {
return subResourceModel;
}
private ResourceModel processResourceModel(ResourceModel resourceModel) {
ResourceModel.Builder newResourceModelBuilder = new ResourceModel.Builder(false);
for (final Resource resource : resourceModel.getResources()) {
final Resource.Builder resourceBuilder = Resource.builder(resource);
String resolvedResourcePath = resolvePropertyPlaceholder(resource);
resourceBuilder.path(resolvedResourcePath);
// 处理子资源
for (Resource childResource : resource.getChildResources()) {
String resolvedChildPath = resolvePropertyPlaceholder(childResource);
final Resource.Builder childResourceBuilder = Resource.builder(childResource);
childResourceBuilder.path(resolvedChildPath);
resourceBuilder.addChildResource(childResourceBuilder.build());
}
newResourceModelBuilder.addResource(resourceBuilder.build());
}
return newResourceModelBuilder.build();
}
private String resolvePropertyPlaceholder(Resource resource) {
String originalPath = resource.getPath();
return propertyResolver.resolvePlaceholders(originalPath);
}
}
@Override
public ResourceConfig configure() {
ApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class);
return new ResourceConfig(TestResource.class)
.property("contextConfig", ctx)
.register(PropertyPlaceholderPathResolvingModelProcessor.class)
.register(new LoggingFilter(Logger.getAnonymousLogger(), true));
}
@Test
public void pathPlaceholderShouldBeResolved() {
Response respOnse= target("resource").request().get();
assertThat(response.getStatus(), is(200));
assertThat(response.readEntity(String.class), is(equalTo("Resource Success!")));
response.close();
respOnse= target("resource/sub-resource").request().get();
assertThat(response.getStatus(), is(200));
assertThat(response.readEntity(String.class), is(equalTo("Sub-Resource Success!")));
response.close();
respOnse= target("resource/sub-resource-locator").request().get();
assertThat(response.getStatus(), is(200));
assertThat(response.readEntity(String.class), is(equalTo("Sub-Resource-Locator Success!")));
response.close();
}
}
最后,如果使用Spring Boot,可以通过spring.jersey.applicationPath
属性来配置应用程序路径,这样可以避免在Spring中以编程方式创建Jersey servlet容器带来的复杂性。