Rest控制器与spring-data-rest RepositoryRestResource

时间:2017-03-22 20:44:36

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

我知道这可能与此重复。
When to use @RestController vs @RepositoryRestResource
但是我有一些在这个问题上没有解决的问题。

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

    @RepositoryRestResource  
    public interface ProductRepository extends MongoRepository<Product, String> {} 
    
  2. 如果我只想公开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. 我找不到任何方法来进行单元测试(非IT)RepositoryRestResource公开的REST端点。但是使用REST控制器方法,我可以使用MockServletContextMockMvcMockMvcBuilders

    3. 来测试我的REST端点

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

1 个答案:

答案 0 :(得分:11)

Spring-data-rest是为数据存储库提供REST端点,它确实提供了包含ALPS元数据,搜索端点等所有铃声和口哨的可靠REST。这通常涵盖了大多数用例,并提供了自定义的基础。

这里有一些提示。

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

您无需在所有@RestResource(exported = false)方法上放置delete(...),因为实际只导出了一个:void delete(Product entity)。查看relevant documentation chapter和源代码。如果我不错过任何东西,你只需要提供这些:

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

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

@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<T>(例如使用PersistentEntityResourceAssembler)并使用它创建ResponseEntity。请参阅RepositoryEntityController.java和一些示例,例如spring-restbucks

关于第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

希望这有帮助。