Java Webservice REST правильное проектирование лучшая практика - PullRequest
2 голосов
/ 05 июня 2011

Я разработал веб-сервис на Java, который запускается как сервлет на tomcat, параметры приложения передаются сервлету через запрос get (например, servlet? Method = search & query = searchterm123), сервлет распознает, если метод изапрос определен и в случае ошибки возвращает строку, которая вручную завернута в код XML, который я жестко закодировал с помощью this.writer.println(answer);.Если метод верен, создается новый класс, который выполняет поиск, а затем возвращает объект, который XStream конвертирует для меня в XML, который я затем снова отправляю обратно клиенту с println, завернутым в мои служебные данные xml, который снова жестко закодирован String answer ="<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n".

Очевидно, что это работает, а также очень эффективно, но это далеко не элегантно.Я очень кратко изучил Apache CXF, а также такие вещи, как RESTlet или JBOSS RestEasy, последние два, которые я нашел для своих требований.Каждый учебник, который я нахожу на CXF, всегда включает в себя Spring и Maven, что потом немного ошеломляет.У вас есть предложения, как мне превратить мой грязный хак в красивое приложение?

Ответы [ 2 ]

3 голосов
/ 05 июня 2011

Я могу порекомендовать CXF;Мне было очень легко приступить к работе с его учебником, особенно когда я укусила пулю и использовала Maven для управления зависимостями (хотя на самом деле она ортогональна всему, что делают CXF и Spring).

Но для того, чтобы использоватьиз CXF я действительно рекомендую использовать Spring.Вам не нужно использовать all Spring;простое учебное пособие на сайте CXF дает вам достаточно, чтобы начать работу.Это особенно верно, если у вас уже есть код, который фактически реализует уже выполненные вещи и отделен от кода для анализа входящих URL-адресов, визуализации ответов в виде XML и т. Д .;это та часть, которую CXF (и, как правило, JAXB) будет обрабатывать для вас.

Чтобы помочь, вот мегапростой пример (импорт для краткости опущен).Я знаю, что это выглядит сложно, но почти вся вторая половина состоит из материала, который вы пишете один раз, а потом больше не трогаете;поскольку вы разрабатываете для решения своего реального кода, вы можете многое сделать, не обращая внимания на код платформы вообще.Во-первых, определения интерфейса (включая модель типа XML):

public interface Foo {
    @Path("/") @GET @Produces("application/xml");
    FooDesc getDescription(@Context UriInfo ui);
    @Path("{id}")
    FooItem getFoo(@PathParam("id") String id);
}

@Path("/")
public interface FooItem {
    @GET @Produces("application/xml")
    FooItemContents getContents();
    @PUT @Consumes("application/xml")
    void setContents(FooItemContents desc);
    @DELETE
    Response delete();
}

// These classes are purely structural holders; no behavior.

@XmlRootElement @XmlType
public class FooDesc {
    @XmlElement
    public List<URI> foo;
}

@XmlRootElement @XmlType
public class FooItemContents {
    @XmlElement
    String bar;
}

Далее, класс реализации:

public class FooImpl implements Foo {
    public FooDesc getDescription(UriInfo ui) {
        FooDesc desc = new FooDesc();
        desc.foo = new ArrayList<URI>();
        UriBuilder ub = ui.getAbsolutePathBuilder().path("{id}");
        for (String id : realGetIdList())  // Hook to your code here!
            desc.foo.add(ub.build(id));
        return desc;
    }
    public FooItem getFoo(String id) {
        final RealFoo r = realGetById(id); // Hook to your code here!
        return new FooItem() {
            public FooItemContents getContents() {
                FooItemContents contents = new FooItemContents();
                contents.bar = r.getBar(); // Hook to your code here!
                return contents;
            }
            public void setContents(FooItemContents desc) {
                r.setBar(desc.bar);        // Hook to your code here!
            }
            public Response delete() {
                r.close();                 // Hook to your code here!
                return Response.noContent().build(); // Return a simple HTTP 204
            }
        };
    }
}

Теперь соединяем его вместе на уровне Spring с помощью WEB-INF/beans.xml:

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:jaxrs="http://cxf.apache.org/jaxrs"
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://cxf.apache.org/jaxrs http://cxf.apache.org/schemas/jaxrs.xsd">

  <!-- Instantiate and connect the service framework -->
  <import resource="classpath:META-INF/cxf/cxf.xml" />
  <import resource="classpath:META-INF/cxf/cxf-extension-jaxrs-binding.xml" />
  <import resource="classpath:META-INF/cxf/cxf-servlet.xml" />
  <jaxrs:server id="customerService" address="/">
    <jaxrs:serviceBeans>
      <ref bean="fooBean" />
    </jaxrs:serviceBeans>
  </jaxrs:server>

  <!-- Instantiate your implementation class -->
  <bean id="fooBean" class="your.package.FooImpl" />
</beans>

Теперь, чтобы подключить все это как веб-приложение, web.xml:

<web-app>
  <!-- Magic to make Spring work and build the rest for us -->
  <context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>WEB-INF/beans.xml</param-value>
  </context-param>
  <listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
  </listener>

  <!-- Make CXF implement the servlet for us -->
  <servlet>
    <servlet-name>CXFServlet</servlet-name>
    <display-name>CXF Servlet</display-name>
    <servlet-class>org.apache.cxf.transport.servlet.CXFServlet</servlet-class>
    <load-on-startup>1</load-on-startup>
  </servlet>
  <!-- You *must* use this servlet mapping or Bad Things Happen. -->
  <servlet-mapping>
    <servlet-name>CXFServlet</servlet-name>
    <url-pattern>/*</url-pattern>
  </servlet-mapping>
</web-app>

Теперь создайте WAR, включая все библиотеки, перечисленные на сайте CXF,поместите биты в правильные места (для этого вам не нужен Maven, но в конце концов это станет проще) и разверните.Это должно сработать (т. Е. Теперь у вас достаточно, чтобы быть опасным!)

3 голосов
/ 05 июня 2011

Я думаю, что использование JAX-RS Framework (как CXF и Resteasy, но также Jersey ) - это путь для вашего случая Что касается сериализации в XML, возможно, стоит взглянуть на JAXB (например, на Джерси). Это должно помочь автоматически сериализовать любую структуру объекта.

Что касается сложности такого приложения: оно всегда должно зависеть от того, какую инфраструктуру вы используете. Если это просто простой сервер Java EE, возможно, лучше всего использовать реализацию этого поставщика (Jersey для Glassfish, Resteasy для JBoss). В противном случае, просто используйте систему сборки, с которой вы знакомы и с которой вам удобно. Например, вы можете легко заменить зависимости Maven на Ant и Ivy .

...