Я создал сервис JAX-RS (MyService), который имеет много sub ресурсов, каждый из которых является подклассом MySubResource. sub выбираемый класс ресурса выбран на основе параметров, данных в пути MyService, например:
@Path("/") @Provides({"text/html", "text/xml"})
public class MyResource {
@Path("people/{id}") public MySubResource getPeople(@PathParam("id") String id) {
return new MyPeopleSubResource(id);
}
@Path("places/{id}") public MySubResource getPlaces(@PathParam("id") String id) {
return new MyPlacesSubResource(id);
}
}
где MyPlacesSubResource и MyPeopleSubResource являются оба подклассами MySubResource.
MySubResource определяется как:
public abstract class MySubResource {
protected abstract Results getResults();
@GET public Results get() { return getResults(); }
@GET @Path("xml")
public Response getXml() {
return Response.ok(getResults(), MediaType.TEXT_XML_TYPE).build();
}
@GET @Path("html")
public Response getHtml() {
return Response.ok(getResults(), MediaType.TEXT_HTML_TYPE).build();
}
}
Результаты обрабатываются соответствующим MessageBodyWriters в зависимости от mimetype ответа.
В то время как это работает, это приводит к путям как/people/Bob/html или/people/Bob/xml, где то, что я действительно хочу, является /people/Bob.html или /people/Bob.xml
Кто-либо знает, как выполнить то, что я хочу сделать?
Возможно, вы могли бы написать некоторую маршрутизацию сервлетов, чтобы решить эту проблему. Однако в реальности для этого следует использовать типы содержимого.
@GET @Path("/") @Produces(MediaType.APPLICATION_XML)
public Response getXml() { ... }
@GET @Path("/") @Produces(MediaType.APPLICATION_HTML)
public Response getHtml() { ... }
Провайдер JAX-RS будет сам решать, что вызывать, основываясь на запросе клиента. Еще лучше, если вы можете использовать JAXB и RestEASY, чтобы сделать все это за вас!
@GET
@Produces(MediaType.APPLICATION_XML)
@Path("/{id}")
public MyObject getXml(@PathParam("typeDocument") String id) {
myObjectService.get(id);
}
@XmlRootElement(name="myObject")
public class MyObject {
// Some properties
}
Смотрите http://java.dzone.com/articles/resteasy-spring хороший пример с Spring.
Один из способов решения этой проблемы заключается в том, что вы можете использовать перехват регулярных выражений в вашем @javax.ws.rs.Path.
@Path("people/{id:[^/]+?}{format:(\\.[^/]*?)?}")
@GET
public MySubResource getPeople(@PathParam("id") String id, @PathParam("format") String format) {
// remove the "." from the start of "format" if it is not null
return new MySubResource(id, format);
}
Затем в вашем подресурсе:
public abstract class MySubResource {
final protected String format;
protected MySubResource(String id, String format) {
this.format = format;
}
protected abstract Results getResults();
@GET
public Response get() {
return Response.ok(getResults(), this.format).build();
}
}
Будьте осторожны с регулярными выражениями. Я привел пример, но вы можете захотеть ужесточить выражение, чтобы убедиться, что ничего не проскочило.
Другой способ решить эту проблему - изменить место захвата {id} и использовать регулярное выражение там. Вместо того чтобы @Path("id") MySubResource public getPeople(@PathParam("id") String id)
перехватывать id, удалите перехват id из getPeople() и измените MySubResource следующим образом:
@Path("people")
public MySubResource getPeople() {
return new MyPeopleSubResource();
}
public abstract class MySubResource {
protected abstract Results getResults();
@GET
@Path("{id}")
public Results get() { return getResults(); }
@GET
@Path("{id}.xml")
public Response getXml() {
return Response.ok(getResults(), MediaType.TEXT_XML_TYPE).build();
}
@GET
@Path("{id}.html")
public Response getHtml() {
return Response.ok(getResults(), MediaType.TEXT_HTML_TYPE).build();
}
}
В любом случае есть компромиссы в зависимости от того, как организованы ваши структуры данных и когда вам нужно знать параметр "id". Я не очень люблю регулярные выражения, поскольку их очень трудно правильно использовать, но в данном случае это возможно.