我刚开始用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库,是否有比上述方法更好的方法来解析此信息?
答案 0 :(得分:9)
球衣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);
}
答案 1 :(得分:2)
我和你有同样的问题,因为我找不到合适的图书馆,所以我决定写URL-RESTify。你可以使用它,或者只是看看你自己的解决方案,这是一个小项目。
答案 2 :(得分:2)
我最近在我的一个应用程序中解决了这个问题。我的网址看起来像这样。
/categories/{category}/subcategories/{subcategory}
我的问题是我想用Java类映射每个url模式,这样我就可以调用正确的类来呈现数据。
我的应用程序使用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,其中包含您需要的有关您网址的信息: https://github.com/joachimhs/Contentice/blob/master/Contentice.api/src/main/java/no/haagensoftware/contentice/data/URLData.java
设置完成后,我可以将网址与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);
在我的处理程序中,我可以简单地获取参数map:
String category = null;
logger.info("parameterMap: " + getParameterMap());
if (getParameterMap() != null) {
category = getParameterMap().get("category");
}
我希望有帮助:)
答案 3 :(得分:1)
没有依赖性的微小解决方案: https://github.com/xitrum-framework/jauter
答案 4 :(得分:0)
我认为首先需要创建一个框架,用于在属性文件或内存数据结构中存储REST方法和类+方法映射。然后编写一个接受所有REST请求的顶级servlet。根据从上下文开始的URL,您可以尝试从属性文件/内存数据结构中获取映射,以找出需要调用哪个类及其方法。然后使用反射,您可以调用所需的方法。获取方法响应并将其编组为所需的内容类型格式,然后发送回servlet响应输出流。
答案 5 :(得分: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
}
}
请指出错误(如果有)。谢谢。