среда, 28 сентября 2011 г.

RESTful веб-сервис на Jersey + Spring 3

Пишем простой 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")

1 комментарий: