【问题标题】:Rest Controllers vs spring-data-rest RepositoryRestResource休息控制器与 spring-data-rest RepositoryRestResource
【发布时间】:2017-08-15 04:44:51
【问题描述】:

我知道这可能让人感觉像是重复。
When to use @RestController vs @RepositoryRestResource
但我有几件事没有在那个问题中得到解决。

  1. 使用@RepositoryRestResource,默认情况下每个方法都是公开的。我觉得有点烦人。如果我在这里错了,请纠正我。比如下面这种情况

    @RepositoryRestResource  
    public interface ProductRepository extends MongoRepository<Product, String> {} 
    

如果我只想公开 findAll() 和 findOne() 而不是任何其他方法,尤其是删除。为了实现这一点,我需要做这样的事情

    @RepositoryRestResource
    public interface ProductRepository extends MongoRepository<Product, String> {
      @RestResource(exported = false)
      @Override
      default void delete(String s) {
      }
      @RestResource(exported = false)
      @Override
      default void delete(Product product) {
      }
      @RestResource(exported = false)
      @Override
      default void delete(Iterable<? extends Product> iterable) {
      }
      @RestResource(exported = false)
      @Override
      default void deleteAll() {
      }
    }

我觉得确实有很多不需要的代码。这与 Rest Controller 方法相比要好得多

  1. 我认为最好使用 ResponseEntity 从 REST 端点返回任何值。但是使用 spring-data-rest 方法,我不知道该怎么做。

  2. 我找不到任何方法来对 RepositoryRestResource 公开的(不是 IT)REST 端点进行单元测试。但是使用 REST 控制器方法,我可以使用 MockServletContextMockMvcMockMvcBuilders 测试我的 REST 端点

考虑到所有这些,使用 sping-data-rest(HATEOS 除外)是否仍然有利?
请澄清

【问题讨论】:

  • 我认为将你的观点分成不同的问题会更好。
  • 您好,您的意思是每个问题都有一个问题?谢谢
  • 是的,通常在 SO 上找到直接问题的答案要容易得多。这也有助于其他搜索类似主题的人。

标签: spring rest spring-data spring-data-rest


【解决方案1】:

Spring-data-rest 旨在为数据存储库提供 REST 端点,它确实提供了具有所有花里胡哨的可靠 REST,包括 ALPS 元数据、搜索端点等。这通常涵盖大多数用例并为定制提供基础。

这里有一些提示。

关于 p.1) - 自定义导出的资源和方法。

您不需要将@RestResource(exported = false) 放在所有delete(...) 方法上,因为实际上只导出了一个:void delete(Product entity)。查看relevant documentation chapter 和源代码。如果我没有遗漏什么,您只需要提供这些:

  • findAll(Pageable)
  • findOne(id)
  • save(Entity)
  • delete(Entity)

关于导出存储库方法的说明。 有时扩展一个非常基本的(空)Repository&lt;Product, String&gt; 存储库接口并仅提供存储库中允许的方法会更容易,例如:

@RepositoryRestResource
public interface ProductRepository extends Repository<Product, String> {
  long count();
  Page<Product> findAll(Pageable pageable);
  Product findOne(String entity);
  <S extends Product> S save(S entity);
}

关于自定义控制器。 要自定义默认行为,最简单的方法是使用 @RespositoryRestController 注释控制器。查看文档并查看 RepositoryEntityController.java - 这是默认控制器。

关于 p.2) 从控制器返回 ResponseEntity

这是非常紧张的。您可以将实体包装到Resource&lt;T&gt;(例如使用PersistentEntityResourceAssembler)并用它创建一个ResponseEntity。请参阅 RepositoryEntityController.java 和一些示例,例如 spring-restbucks

关于 p.3) - 测试剩余端点

暴露 RepositoryRestResource 的 REST 端点在 RepositoryEntityController(spring-data-rest 的一部分)中实现。

如果您实现自己的自定义控制器,则可以像往常一样添加单元测试,但如果使用PersistentEntityResourceAssembler,事情会变得更加复杂。

单元测试示例:

public class FooControllerTests {

  @Mock
  PersistentEntityResourceAssembler assembler;

  @Mock
  PersistentEntityResourceAssemblerArgumentResolver assemblerResolver;

  @Mock
  PersistentEntity<Foo, ?> entity;

  @InjectMocks
  FooController fooController;

  @Mock
  FooService fooService;

  private MockMvc mockMvc;

  @Rule
  public MockitoRule rule = MockitoJUnit.rule();

  @Before
  public void setup() {
    this.mockMvc = MockMvcBuilders.standaloneSetup(fooController)
        .setCustomArgumentResolvers(assemblerResolver)
        .build();
  }

  @Test
  public void test_GetItem_Success() throws Exception {
    final Foo foo = new Foo();
    
    when(fooService.findOne(1)).thenReturn(foo);
    when(assemblerResolver.supportsParameter(any())).thenReturn(true);
    when(assemblerResolver.resolveArgument(any(), any(), any(), any())).thenReturn(assembler);
    when(assembler.toResource(foo))
        .thenReturn(PersistentEntityResource.build(foo, entity).build());
    
    this.mockMvc.perform(get("/foo/1")).andExpect(status().isOk());
  }
}

另见"Building REST services with Spring" tutorial

希望这会有所帮助。

【讨论】:

  • 您好,谢谢您的详细解释。只是几个跟进。关于第 2 点和第 3 点。在第 2 点中,我的意思是从 Repository(RepositoryRestResource) 而不是 Controller 类返回 ResponseEntity。使用 spring-data-rest 的关键之一是避免编写控制器。从控制器返回 ResponseEntity 非常简单。但是如果我必须自己编写控制器,那我为什么要使用 spring-data-rest。关于第 3 点,如果您查看我的问题,我已经明确提到了单元测试而不是 IT(集成测试)谢谢
  • p2.从存储库返回 ResponseEntity 将是一个奇怪的解决方案。 ResponseEntity 表示 HTTP 响应。
  • spring-data-rest 为您的数据提供了可靠的默认 REST API 实现以及扩展和自定义它的可能性。无需编写标准 CRUD 控制器等。只有当标准 impl 不够用时,您才开始编写自定义控制器作为最后的手段。大多数情况下,您使用其他定制方式。如果您对请求处理确实有特殊需求,可能您必须编写一些示例代码并为您的项目评估它。
  • P2.我完全同意从 Repository 返回 ResponseEntity 将是一个奇怪的解决方案。但我一直明白,从 REST 端点返回 ResponeEntity 是一件好事。所以请记住这一点,使用 spring-data-rest 会破坏目的。不是吗?如果我错了,请纠正我。
  • P3.没错,单元测试 spring-data-rest 端点将是多余的,因为端点是由框架生成的。但是我考虑编写单元测试的原因是为了提高代码覆盖率。谢谢
猜你喜欢
  • 2019-02-27
  • 2016-04-17
  • 1970-01-01
  • 1970-01-01
  • 2016-10-26
  • 2019-02-01
  • 2018-01-17
  • 1970-01-01
  • 2016-02-07
相关资源
最近更新 更多