6

我是用 Java 开发 Web 服务的新手(以前我用 PHP 和 Ruby 做过)。我正在编写具有以下格式的资源:

<URL>/myService/<domain>/<app_name>/<system_name>

如您所见,我有一个三级资源标识符,我正在尝试找出解析它的最佳方法。我添加这个新服务的应用程序没有使用 Jersey 或任何类似的 RESTful 框架。相反,它只是扩展了 HttpServlet。

目前他们正在遵循这样的算法:

  • 称呼request.getPathInfo()
  • 将路径信息中的“/”字符替换为“。” 人物
  • 使用String.substring方法从 pathInfo 字符串中提取此资源的各个信息。

这对我来说似乎不是很优雅,我正在寻找更好的方法。我知道使用 javax.ws.rs 包使这非常容易(使用 @Path 和 @PathParam 注释),但使用 Jersey 可能不是一个选项。

仅使用基本的 HttpServletRequest 对象和标准 Java 库,有没有比上述方法更好的方法来解析这些信息?

4

6 回答 6

10

球衣 UriTemplate 怎么样?

import com.sun.jersey.api.uri.UriTemplate;

...

String path = "/foos/foo/bars/bar";

Map<String, String> map = new HashMap<String, String>();
UriTemplate template = new UriTemplate("/foos/{foo}/bars/{bar}");
if( template.match(path, map) ) {
    System.out.println("Matched, " + map);
} else {
    System.out.println("Not matched, " + map);
}       
于 2014-02-05T02:48:07.030 回答
2

我和你有同样的问题,因为我没有找到任何合适的库,我决定写URL-RESTify。您可以使用它,或者只是看看编写自己的解决方案,这是一个小项目。

于 2013-09-29T20:35:54.307 回答
2

我最近在我的一个应用程序中解决了这个问题。我的网址看起来像这样。

/categories/{category}/subcategories/{subcategory}

我的问题是我想将每个 url 模式映射到一个 Java 类,这样我就可以调用正确的类来呈现数据。

我的应用程序使用 Netty,但 URL 解析器不使用任何第三方库。

这允许我做的是解析来自浏览器的 URL,生成具有键值对(在本例中为类别和子类别)的映射,以及为每个唯一 URL 模式实例化正确的处理程序. 总而言之,只有大约 150 行 Java 代码用于解析、应用程序设置和唯一 URL 模式的定义。

您可以在 GitHub 中查看解析器的代码:https ://github.com/joachimhs/Contentice/blob/master/Contentice.api/src/main/java/no/haagensoftware/contentice/util/URLResolver.java

UrlResolver.getValueForUrl 将返回一个 URLData,其中包含您需要的有关您的 URL 的信息: https ://github.com/joachimhs/Contentice/blob/master/Contentice.api/src/main/java/no/haagensoftware/contentice/data /URLData.java

设置完成后,我可以将 URL 与 Netty 处理程序相关联:

 this.urlResolver.addUrlPattern("/categories", CategoriesHandler.class);
 this.urlResolver.addUrlPattern("/categories/{category}", CategoryHandler.class);
 this.urlResolver.addUrlPattern("/categories/{category}/subcategories", SubCategoriesHandler.class);
 this.urlResolver.addUrlPattern("/categories/{category}/subcategories/{subcategory}", SubCategoryHandler.class);

在我的处理程序中,我可以简单地获取参数映射:

String category = null;
logger.info("parameterMap: " + getParameterMap());
if (getParameterMap() != null) {
    category = getParameterMap().get("category");
}

我希望这会有所帮助:)

于 2013-11-17T09:52:14.200 回答
1

其他答案中提到的 Jersey 的 UriTemplate 很好,但它是一个大库,它还包含许多其他依赖库。

没有依赖的小解决方案: https ://github.com/xitrum-framework/jauter

于 2014-10-21T22:41:40.430 回答
0

我相信首先您需要创建一个框架,用于将 REST 方法和类+方法映射存储在属性文件或内存数据结构中。然后编写一个接受所有 REST 请求的顶级 servlet。根据从您的上下文开始的 URL,您可以尝试从属性文件/内存数据结构中获取映射,以找出需要调用哪个类及其方法。然后利用反射,您可以调用所需的方法。获取方法响应并将其编组为所需的内容类型格式,然后发送回 servlet 响应输出流。

于 2013-07-24T17:14:04.853 回答
0

自己实现它(例如检查 main 方法),以防万一您想要自定义实现:

import lombok.AllArgsConstructor;
import lombok.NonNull;

import java.util.*;

public class Template {
    final List<TemplateElement> templateElements = new ArrayList<>();

    public static void main(String[] args) {
        final Template template = new Template("/hello/{who}");

        final Map<String, String> attributes = template.parse("/hello/world").get();
        System.out.println(attributes.get("who")); // world
    }

    public Template(@NonNull final String template) {
        validate(template);

        final String[] pathElements = template.split("/");

        for (final String element : pathElements) {
            if (isAttribute(element)) {
                final String elementName = element.substring(1, element.length() - 1); // exclude { and }
                templateElements.add(new TemplateElement(ElementType.ATTRIBUTE, elementName));
            } else {
                templateElements.add(new TemplateElement(ElementType.FIXED, element));
            }
        }
    }

    public Optional<Map<String, String>> parse(@NonNull final String path) {
        validate(path);
        final String[] pathElements = path.split("/");
        if (pathElements.length != templateElements.size()) return Optional.empty();

        final Map<String, String> attributes = new HashMap<>();

        // ignore the 0th element, it'll always be empty
        for (int i = 1; i < templateElements.size(); i++) {
            final String element = pathElements[i];
            final TemplateElement templateElement = templateElements.get(i);

            switch (templateElement.type) {
                case FIXED:
                    if (!element.equals(templateElement.name)) return Optional.empty();
                    break;

                case ATTRIBUTE:
                    attributes.put(templateElement.name, element);
                    break;
            }
        }

        return Optional.of(attributes);
    }

    private void validate(@NonNull final String path) {
        if (!path.startsWith("/"))
            throw new RuntimeException("A template must start with /"); // a template must start with /
    }

    private boolean isAttribute(@NonNull final String str) {
        return str.startsWith("{") && str.endsWith("}");
    }

    @AllArgsConstructor
    class TemplateElement {
        final ElementType type;
        final String name;
    }

    enum ElementType {
        FIXED, ATTRIBUTE
    }
}

如有错误请指出。谢谢。

于 2019-06-16T00:58:21.177 回答