Rest控制器 vs spring-data-rest RepositoryRestResource

6

我知道这可能会感觉像是这个问题的重复
但我有一些问题没有在那个问题中得到解答。

  1. With @RepositoryRestResource, every method is by default exposed. Which I feel is a bit annoying. Correct me if I am wrong here. For example in the below case

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

如果我只想公开findAll()和findOne()方法,而不是其他任何方法,特别是delete。为了实现这一点,我需要做如下操作

    @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. 我认为最好从REST端点返回任何值都使用ResponseEntity。但是使用spring-data-rest方法,我不确定如何做到这一点。

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

鉴于所有这些,除了HATEOS之外,仍然有使用sping-data-rest的优势吗?请澄清。


1
我认为最好将你的问题分成不同的部分。 - aux
您的意思是针对每个点都提出一个问题吗?谢谢。 - pvpkiran
通常在SO上找到直接问题的答案要容易得多。这也有助于那些搜索类似主题的人。 - aux
1个回答

19

Spring-data-rest 是提供数据仓库 REST 端点的框架,包括了 ALPS 元数据、搜索端点等完整的 REST 功能。通常能够涵盖大部分使用场景并提供自定义基础。

以下是一些提示:

关于第一条) - 自定义导出资源和方法。

不需要在所有 delete(...) 方法上加上 @RestResource(exported = false),因为只有一个方法会被导出:void delete(Product entity)。请参考相关文档章节和源代码。如果没有漏看什么,您只需要提供以下方法:

  • 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);
}

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

关于第二部分) 在控制器中返回 ResponseEntity

非常简单。您可以将实体包装在 Resource<T> 中(例如使用 PersistentEntityResourceAssembler),并创建一个使用它的 ResponseEntity。请参阅RepositoryEntityController.java 和一些示例,如 spring-restbucks.

关于第三部分) - 测试 REST 端点

公开 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());
  }
}

另请参见“使用Spring构建REST服务”教程

希望这可以帮助您。


嗨aux,感谢您的详细解释。只有几个后续问题。关于第2点和第3点。在第2点中,我的意思是从Repository(RepositoryRestResource)返回ResponseEntity,而不是Controller类。使用spring-data-rest的关键之一是避免编写控制器。从控制器返回ResponseEntity非常简单。但是,如果我必须自己编写控制器,那么为什么要使用spring-data-rest。关于第3点,如果您查看我的问题,我已经明确提到了单元测试而不是IT(集成测试)。谢谢。 - pvpkiran
从Repository返回ResponseEntity可能是一个奇怪的解决方案。ResponseEntity代表HTTP响应。 - aux
spring-data-rest 为您提供了坚实的 REST API 默认实现,以及扩展和自定义它的可能性。无需编写标准的 CRUD 控制器等。只有在标准实现不足时,您才会开始编写自定义控制器作为最后的手段。大多数情况下,您使用其他定制方式。如果您确实需要特殊的请求处理需求,可能需要编写一些示例代码并为您的项目进行评估。 - aux
P2. 我完全同意从Repository返回ResponseEntity是一个奇怪的解决方案。但我一直认为从REST端点返回ResponseEntity是一件好事。因此,考虑到这一点,使用spring-data-rest就失去了意义。如果我错了,请纠正我。 - pvpkiran
P3. 是的,对于Spring Data REST端点进行单元测试可能是多余的,因为这些端点是由框架生成的。但我考虑编写单元测试的原因是为了提高代码覆盖率。谢谢。 - pvpkiran
P2. 似乎有些混淆。spring-data-rest提供了端点。使用ResponseEntity或其他响应都可以,这并不重要。返回ResponseEntity并不总是“好事” - 这取决于您的需求。您可以搜索类似“何时从控制器方法返回ResponseEntity?”的问题,例如:https://dev59.com/el8d5IYBdhLWcg3wsT0b。 - aux

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接