Пишем простой REST веб-сервис.
Как известно, начиная с третьей версии у Spring появилась возможность легко создавать REST веб сервис с помощью Spring MVC (на аннотациях @RequestMapping). Но я хочу рассмотреть классический Jax-RS с помощью Jersey. Итак, начнем.
Для начала определим maven зависимости:
com.sun.jersey
jersey-server
1.9.1
com.sun.jersey.contribs
jersey-spring
1.9.1
org.springframework
spring
org.springframework
spring-core
com.sun.xml.bind
jaxb-impl
2.1.9
exclusions в зависимости jersey+spring необходимы потому, что библиотека требует зависимости спринга версий 2 или 2.5. А мы ей их дать не можем, тк используем третью версию. В исключениях требуется указать все библиотеки Spring, которые у нас есть в проекте.
Теперь можно писать сам сервис. Будем доставать продукты по их id:
@Path("/product/{id}")
@Component
@Scope("prototype")
public class ProductRSController {
@Autowired
private ProductService srv;
@GET
@Produces(MediaType.APPLICATION_XML)
public Product getDescription(@PathParam("id") String productId) {
Product product = srv.getProduct(productId);
return product;
}
}
Пометив метод с помощью аннотаций @GET и @Produces(MediaType.APPLICATION_XML), мы указали, что url вида http://myserver.com/myapp/rs/product/123 (где myserver.com - наш сервер, myapp - имя развернутого приложения), будет возвращать в ответ сериализованный обьект Product в xml.
Класс ProductService представляет собой сервис бин, с методом Product getProduct(String productId) {...}
Не забудем настроить web.xml:
contextConfigLocation/WEB-INF/spring-context.xml
org.springframework.web.context.ContextLoaderListener
Jersey Web Application
com.sun.jersey.spi.spring.container.servlet.SpringServlet
1
Jersey Web Application
/rs/*
и spring-context.xml:
Теперь можно разворачивать приложение и зайти по URL http://myserver.com/myapp/rs/product/123. В случае успеха мы увидим полученный XML, если конечно у нас есть Product с id = 123.
Теперь можно создавать клиент веб-сервиса. Для удобства работы, возьмем клиент от Jersey.
зависимости:
com.sun.xml.bind
jaxb-impl
2.1.9
com.sun.jersey
jersey-client
1.9.1
сам клиент будет выглядеть так:
public class RESTClient {
public Product recieveObject() {
Client c = Client.create();
WebResource r = client.resource("http://myserver.com/myapp/rs/");
Product product = response = r.path("product/123").
accept(MediaType.APPLICATION_XML_TYPE).
get(Product.class);
return product;
}
public String recieveXML() {
Client c = Client.create();
WebResource r = client.resource("http://myserver.com/myapp/rs/");
String product = response = r.path("product/123").
accept(MediaType.APPLICATION_XML_TYPE).
get(String.class);
return product;
}
}
метод recieveObject() возвращает десериализованный обьект Product, а метод recieveXML() возвращает XML.
С помощью Generics можно сделать клиент универсальным:
public class RESTClient {
private static final Client client;
private String resource = "http://myserver.com/myapp/rs/";
static {
client = Client.create();
}
public RESTClient() {
}
public RESTClient(String resource) {
this.resource = resource;
}
public void recieve() {
//object
Product product = recieve(Product.class, "product/", "123");
System.out.println("response.getProductId: " + product.getProductId());
//string
String xml = recieve(String.class, "product/", "123");
System.out.println("response: " + xml);
}
private <T> T recieve(Class<T> type, String URI, String id) {
WebResource r = client.resource(resource);
T response = r.path(URI + id).
accept(MediaType.APPLICATION_XML_TYPE).
get(type);
return response;
}
}
Для настройки вывода данных в формате JSON необходимо проделать следующее:
Добавить зависимость:
com.sun.jersey
jersey-json
1.10
Создать класс JAXBContextResolver в том же package, где лежит контроллер
@Provider
public final class JAXBContextResolver implements ContextResolver<jaxbcontext> {
private final JAXBContext context;
private final Set<class> types;
private final Class[] cTypes = {MyEntity1.class, MyEntity1.class};
public JAXBContextResolver() throws Exception {
this.types = new HashSet(Arrays.asList(cTypes));
this.context = new JSONJAXBContext(JSONConfiguration.natural().build(), cTypes);
}
@Override
public JAXBContext getContext(Class<?> objectType) {
return (types.contains(objectType)) ? context : null;
}
}
где MyEntity1, MyEntity2 - отображаемые в JSON обьекты
и в контроллере указывать формат данных @Produces("application/json; charset=utf-8")