【问题标题】:Java Webservice REST proper design best praciceJava Web Service REST 正确设计最佳实践
【发布时间】:2011-09-08 13:07:25
【问题描述】:

我用 Java 开发了一个 web 服务,它作为 servlet 在 tomcat 上运行,应用程序的参数通过 get 请求(例如 servlet?method=search&query=searchterm123)提供给 servlet,servlet 识别方法和查询已定义,并且在出现错误的情况下返回一个字符串,该字符串手动包装在我通过this.writer.println(answer); 硬编码的 xml 代码中。如果方法正确,则实例化一个新类,该类进行搜索,然后返回一个对象,该对象 XStream 为我转换为 XML,然后我再次将其发送回客户端,并将 println 包装到我的 xml 开销中,该开销再次被硬编码 String @ 987654322@.

显然,这很有效,也很有效,但这远非优雅。我非常简要地研究了 Apache CXF,还研究了 RESTlet 或 JBOSS RestEasy 之类的东西,我发现后两者非常符合我的要求。我在 CXF 上找到的每个教程都包含 Spring 和 Maven,这让我有点不知所措。您对我应该如何将肮脏的 hack 变成漂亮的应用程序有什么建议吗?

【问题讨论】:

    标签: java web-services rest servlets cxf


    【解决方案1】:

    我认为使用 JAX-RS 框架(如 CXF 和 Resteasy,还有Jersey)是您的解决方案。关于序列化为 XML,也许看看 JAXB(例如,也包含在 Jersey 中)。它应该有助于自动序列化任何实体结构。

    关于此类应用程序的复杂性:它应始终取决于您使用的基础架构。如果它只是一个简单 Java EE 服务器,最好使用该供应商的实现(Glassfish 的 Jersey,JBoss 的 Resteasy)。否则,只需使用您熟悉和熟悉的构建系统。例如,您可以轻松地将 Maven 依赖项替换为 AntIvy

    【讨论】:

      【解决方案2】:

      我可以推荐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 应用程序,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,但最终它会更容易)并部署。这应该有效(即,你现在已经足够危险了!)

      【讨论】:

      • 我已将您的代码添加到我使用 cxf 原型创建的 Maven 项目中。不幸的是我得到了几十个错误,你能添加导入吗?另外我想知道例如 RealFoo 在 FooImpl.java 的第 15 行中,这个类从未定义过。
      猜你喜欢
      • 2020-03-22
      • 1970-01-01
      • 1970-01-01
      • 2016-08-11
      • 1970-01-01
      • 2014-01-04
      • 1970-01-01
      • 2013-10-23
      相关资源
      最近更新 更多