在 JAX-RS/Jersey 中为 java 个包添加资源路径段?

Add resource path segment for java packages in JAX-RS/Jersey?

我正在使用 Jersey 2.19。我想支持我的 API 的两个版本。为此,我希望有两条主要路径:/api/v1/api/v2。我想要两个包 com.test.v1(具有 v1 API 资源)和 com.test.v2(具有 v2 API 资源)。

我知道如何为整个应用程序定义路径,我只会在 ResourceConfig class 上使用 @ApplicationPath('api')。但是,我如何定义包 com.test.v1 资源位于 /v1 命名空间中,而包 com.test.v2 资源位于 /v2 命名空间中?目前,除了在每个 @Path 注释中添加 'v1' 和 'v2' 前缀外,我没有其他选择,例如:每个资源的 @Path('v1/something')@Path('v2/something') 前缀。这是很多冗余。

有没有更好的方法?

下面是实现此目的的一种方法的概念验证。我从未使用过它,所以我无法真正提供任何可维护性问题的证明,这些可维护性问题可能会或可能不会出现在大型项目中。我刚刚测试了一个简单的项目。

它基本上使用 Jersey 的 Programmatic resource building API 将版本附加到原始路径。

import java.util.HashMap;
import java.util.Map;
import javax.ws.rs.core.Configuration;
import javax.ws.rs.ext.Provider;
import org.glassfish.jersey.server.model.ModelProcessor;
import org.glassfish.jersey.server.model.Resource;
import org.glassfish.jersey.server.model.ResourceModel;

@Provider
public class VersioningModelProcessor implements ModelProcessor {

    private Map<String, String> packageAppenders = new HashMap<>();

    {
        packageAppenders.put("com.Whosebug.jersey.v1", "v1");
        packageAppenders.put("com.Whosebug.jersey.v2", "v2");
    }

    @Override
    public ResourceModel processResourceModel(ResourceModel model, Configuration config) {

        // Create new resourc model.
        ResourceModel.Builder newModelBuilder = new ResourceModel.Builder(false);
        for (final Resource resource: model.getResources()) {

            // Look for the package
            String path = resource.getPath();
            Class handlerClass = resource.getHandlerClasses().iterator().next();
            String pkg = handlerClass.getPackage().getName();

            // Match the packge to our map of packages
            if (packageAppenders.containsKey(pkg)) {

                // append the version
                String version = packageAppenders.get(pkg);
                path = version + "/" + path.replace("/", "");

                Resource.Builder resourceBuilder = Resource.builder(resource);
                resourceBuilder.path(path);

                Resource newResource = resourceBuilder.build();
                System.out.println(newResource.toString());

                // add the new resource with the new path.
                newModelBuilder.addResource(newResource);
            } else {
                // Do nothing. Just add the resource as normal
                newModelBuilder.addResource(resource);
            }
        }
        return newModelBuilder.build();
    }

    @Override
    public ResourceModel processSubResource(ResourceModel model, Configuration config) {
        return model;
    }
}

可能麻烦多于它的价值。我不知道。你可以当裁判。

最后我决定只配置和部署 2 个 Jersey servlet。 API 的 V1 在 module_v1 中,V2 在 module_v2 中,我有两个带有 2 个 ResourceConfig 的 servlet。第一个资源配置定义路径 'v1',第二个 'v2',它们都相对于 'api' 的根目录。这工作得很好,允许简单地删除任何版本。