热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

整合Spring属性占位符与Jersey@Path和@ApplicationPath

本文介绍了如何将Spring属性占位符与Jersey的@Path和@ApplicationPath注解结合使用,以便在资源路径中动态解析属性值。

本文将详细介绍如何将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容器带来的复杂性。


推荐阅读
author-avatar
癫逼
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有