实现Spring Data repository的自定义方法并通过REST公开它们
我试图将自定义方法添加到Spring数据存储库PersonRepository
,如1.3 Spring数据存储库的自定义实现中所述,并通过REST公开这些方法。 最初的代码是从REST示例访问JPA数据 ,这里是添加/修改类的代码:
interface PersonRepositoryCustom { List<Person> findByFistName(String name); } class PersonRepositoryImpl implements PersonRepositoryCustom, InitializingBean { @Override public void afterPropertiesSet() throws Exception { // initialization here } @Override public List<Person> findByFistName(String name) { // find the list of persons with the given firstname } } @RepositoryRestResource(collectionResourceRel = "people", path = "people") public interface PersonRepository extends PagingAndSortingRepository<Person, Long> { List<Person> findByLastName(@Param("name") String name); }
当我运行应用程序并访问http://localhost:8080/portfolio/search/
,我得到以下响应主体:
{ "_links" : { "findByLastName" : { "href" : "http://localhost:8080/people/search/findByLastName{?name}", "templated" : true } } }
为什么findByFirstName
即使在PersonRepository
接口中可用,也不会被公开?
另外,有没有一种方法来dynamic/以编程方式添加ressets通过REST公开?
这些方法没有公开的原因是你基本上可以自由地在自定义存储库方法中实现任何你想要的,因此不可能推断正确的HTTP方法来支持这个特定的资源。
在你的情况下,使用普通的GET
可能没问题,在其他情况下,它可能必须是POST
因为方法的执行有副作用。
目前的解决scheme是制作一个自定义控制器来调用存储库方法。
两天后,我以这种方式解决了。
自定义存储库接口:
public interface PersonRepositoryCustom { Page<Person> customFind(String param1, String param2, Pageable pageable); }
自定义存储库实现
public class PersonRepositoryImpl implements PersonRepositoryCustom{ @Override public Page<Person> customFind(String param1, String param2, Pageable pageable) { // custom query by mongo template, entity manager... } }
Spring数据存储库:
@RepositoryRestResource(collectionResourceRel = "person", path = "person") public interface PersonRepository extends MongoRepository<Person, String>, PersonRepositoryCustom { Page<Person> findByName(@Param("name") String name, Pageable pageable); }
Bean资源表示
public class PersonResource extends org.springframework.hateoas.Resource<Person>{ public PersonResource(Person content, Iterable<Link> links) { super(content, links); } }
资源汇编程序
@Component public class PersonResourceAssembler extends ResourceAssemblerSupport<Person, PersonResource> { @Autowired RepositoryEntityLinks repositoryEntityLinks; public PersonResourceAssembler() { super(PersonCustomSearchController.class, PersonResource.class); } @Override public PersonResource toResource(Person person) { Link personLink = repositoryEntityLinks.linkToSingleResource(Person.class, person.getId()); Link selfLink = new Link(personLink.getHref(), Link.REL_SELF); return new PersonResource(person, Arrays.asList(selfLink, personLink)); } }
自定义Spring MVC控制器
@BasePathAwareController @RequestMapping("person/search") public class PersonCustomSearchController implements ResourceProcessor<RepositorySearchesResource> { @Autowired PersonRepository personRepository; @Autowired PersonResourceAssembler personResourceAssembler; @Autowired private PagedResourcesAssembler<Person> pagedResourcesAssembler; @RequestMapping(value="customFind", method=RequestMethod.GET) public ResponseEntity<PagedResources> customFind(@RequestParam String param1, @RequestParam String param2, @PageableDefault Pageable pageable) { Page personPage = personRepository.customFind(param1, param2, pageable); PagedResources adminPagedResources = pagedResourcesAssembler.toResource(personPage, personResourceAssembler); if (personPage.getContent()==null || personPage.getContent().isEmpty()){ EmbeddedWrappers wrappers = new EmbeddedWrappers(false); EmbeddedWrapper wrapper = wrappers.emptyCollectionOf(Person.class); List<EmbeddedWrapper> embedded = Collections.singletonList(wrapper); adminPagedResources = new PagedResources(embedded, adminPagedResources.getMetadata(), adminPagedResources.getLinks()); } return new ResponseEntity<PagedResources>(adminPagedResources, HttpStatus.OK); } @Override public RepositorySearchesResource process(RepositorySearchesResource repositorySearchesResource) { final String search = repositorySearchesResource.getId().getHref(); final Link customLink = new Link(search + "/customFind{?param1,param2,page,size,sort}").withRel("customFind"); repositorySearchesResource.add(customLink); return repositorySearchesResource; } }
对于GET
方法,我使用了下面的方法:
- 在Repository(LogRepository.java)中创build一个dummy
@Query
方法, - 用声明相同的方法创build一个自定义接口(LogRepositoryCustom.java)
- 创build自定义接口(LogRepositoryImpl.java)的实现
使用这种方法,我不必pipe理预测和资源组装。
@RepositoryRestResource(collectionResourceRel = "log", path = "log") public interface LogRepository extends PagingAndSortingRepository<Log, Long>, LogRepositoryCustom { //NOTE: This query is just a dummy query @Query("select l from Log l where l.id=-1") Page<Log> findAllFilter(@Param("options") String options, @Param("eid") Long[] entityIds, @Param("class") String cls, Pageable pageable); } public interface LogRepositoryCustom { Page<Log> findAllFilter(@Param("options") String options, @Param("eid") Long[] entityIds, @Param("class") String cls, Pageable pageable); }
在实现中,您可以自由使用存储库方法或直接进入持久层:
public class LogRepositoryImpl implements LogRepositoryCustom{ @Autowired EntityManager entityManager; @Autowired LogRepository logRepository; @Override public Page<Log> findAllFilter( @Param("options") String options, @Param( "eid") Long[] entityIds, @Param( "class" ) String cls, Pageable pageable) { //Transform kendoui json options to java object DataSourceRequest dataSourceRequest=null; try { dataSourceRequest = new ObjectMapper().readValue(options, DataSourceRequest.class); } catch (IOException ex) { throw new RuntimeException(ex); } Session s = entityManager.unwrap(Session.class); Junction junction = null; if (entityIds != null || cls != null) { junction = Restrictions.conjunction(); if (entityIds != null && entityIds.length > 0) { junction.add(Restrictions.in("entityId", entityIds)); } if (cls != null) { junction.add(Restrictions.eq("cls", cls)); } } return dataSourceRequest.toDataSourceResult(s, Log.class, junction); }
我们使用的另一个选项是为您的特定存储types实施定制存储库工厂。
您可以从RepositoryFactoryBeanSupport
进行扩展,构build您自己的PersistentEntityInformation
并为您的自定义数据存储types在默认的repo impl中处理CRUD操作。 例如见JpaRepositoryFactoryBean
。 你可能需要总共执行10个类,但是可以重用。
答案是你没有遵循指示。 您的PersonRepository
必须扩展PagingAndSortingRepository<Person, Long>
和PersonRepositoryCustom
以实现您的目标。 请参阅https://docs.spring.io/spring-data/data-jpa/docs/current/reference/html/#repositories.custom-implementations
- 我可以在<filter-mapping>里面的<url-pattern>中排除一些具体的url吗?
- instanceof和Class.isAssignableFrom(…)有什么区别?
- 是什么导致Eclipse中导入的Maven项目默认使用Java 1.5而不是Java 1.6,如何确保它不是?
- 将Java Stream过滤为1并且只有1个元素
- gson在自定义的反序列化器中调用标准的反序列化
- 什么时候应该使用string文字的实习方法
- ArrayIndexOutOfBoundsException在使用ArrayList的迭代器时
- Java内存模型和C ++ 11内存模型有什么相似之处?
- 何时使用Spring Integration与Camel?