【问题标题】:Reusability in REST services with JAX-RS使用 JAX-RS 在 REST 服务中的可重用性
【发布时间】:2015-04-01 18:56:35
【问题描述】:

我有一个简单的类似 REST 的服务,在 JAX-RS 中实现以维护 Foo 的。它使用POST foos 创建foo,使用GET foos 列出foo,并使用GET foo/42 详细说明给定的foo(其中42 是给定的foo 的id)。

public class FooService {

  @POST
  @Path("/foos")
  public Foo create(Foo foo){
    entityManager.getTransaction().begin();
    entityManager.persist(foo);
    entityManager.getTransaction().commit();
    return foo;
  }

  @GET
  @Path("/foos")
  public List<Foo> get(){
        List<Foo> foos = //more-or-less generic JPA querying-code
        return foos;
  }

  @GET
  @Path("/foos/{id}")
  public Foo get(@PathParam("id") int id){
        Foo foo = //more-or-less generic JPA querying-code
        return foo;
  }
}

现在,如果我也有维护Bar 的类似服务,我应该如何优雅地避免代码重复?

public class BarService {

  @POST
  @Path("/bars")
  public Bar create(Bar bar){
    entityManager.getTransaction().begin();
    entityManager.persist(bar);
    entityManager.getTransaction().commit();
    return bar;
  }

  @GET
  @Path("/bars")
  public List<Bar> get(){
        List<Bar> bars = //more-or-less generic JPA querying-code
        return bars;
  }

  @GET
  @Path("/bars/{id}")
  public Bar get(@PathParam("id") int id){
        Bar bar = //more-or-less generic JPA querying-code
        return bar;
  }
}

唯一的区别是@Path 注释中指定的路径 值。由于该值应该是静态的(在编译时可见),因此无法创建 AbstracService 类,例如:

public abstract class AbstracService<X> {

  //abstrac static is not possible
  public abstract static final String PATH;

  @POST
  @Path(PATH)
  public X create(X entity){ ... }

  @GET
  @Path(PATH)
  public List<X> get(){ ... }

  @GET
  @Path(PATH + "/{id}")
  public X get(@PathParam("id") int id){ ... }
}


public class FooService extends AbstractService<Foo>{
      //just override the PATH to be "foos"
}    

public class BarService extends AbstractService<Bar>{
      //just override the PATH to be "bars"
}    

我是否需要重写每个服务方法来调整@Path 并且他们调用supers 实现?

上面的类FooServiceBarService 太相似了,无法让我的可重用性保持沉默。

【问题讨论】:

    标签: java web-services rest jax-rs reusability


    【解决方案1】:

    在我的资源类中很常见的是这种模式

    @Path("foo")
    public class FoosResource {
        @GET  // get all `Foo` resources
        ...
        @GET 
        @Path("{id}")  // get `Foo` with this id
        ...
        @POST // create new `Foo` in `foo` collection
        ...
        @PUT 
        @Path("{id}")  // Update `Foo` with this id
    }
    

    你明白了。关键是集合的名称在资源类上,而不是像你这样的资源方法级别

    @Path("foo/{id}")
    

    无论如何,您都需要@Path 才能使该类成为资源类,为什么不使用最合适的名称。

    我可能会补充的另一件事是我经常做的事情。我在抽象类中添加了一个Class 字段,并带有一个可以将Class 传递给的构造函数arg。然后在具体的类实现中,我super(Foo.class)。这样,JPA 就可以访问该类,从而更轻松地进行类型查询。

    【讨论】:

    • 这就是我所缺少的。
    【解决方案2】:

    我相信你可以做这样的事情

    @POST
    @Path("/{foosOrBars}")//will match to any string
    public BaseFooBar create(@PathParam("foosOrBars") String type){
    
    if(type.equals("foos")){
    //do something with the foo
    }else{
    //do something different
    }
    
    }
    

    因此,您有一个基类 BaseFooBar,您可以将其扩展为 FooBar

    但是你必须小心,如果你在同一个服务上有另一个方法,也只是具有相同的层次结构,例如/foobar。它应该有一个固定的标识符并且不使用花括号,否则你的路径将无法正确匹配。

    【讨论】:

    • 太糟糕了,基类 (BaseFooBar) 必须事先知道它的所有扩展。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-10-15
    • 1970-01-01
    • 2013-02-17
    • 1970-01-01
    • 1970-01-01
    • 2015-10-03
    相关资源
    最近更新 更多