1.3 Spring Dataリポジトリのカスタム実装 で説明されているように、Spring DataリポジトリPersonRepository
にカスタムメソッドを追加し、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
が公開されないのはなぜですか?
また、RESTを介して公開されるリポジトリを動的/プログラムで追加する方法はありますか?
これらのメソッドが公開されない理由は、カスタムリポジトリメソッドで必要なものを基本的に自由に実装できるため、その特定のリソースをサポートする正しいHTTPメソッドについて推論することができないためです。
あなたの場合、プレーンのGET
を使用しても問題ないかもしれませんが、他の場合は、メソッドの実行に副作用があるため、POST
である必要があります。
これに対する現在の解決策は、リポジトリメソッドを呼び出すカスタムコントローラーを作成することです。
2日後、私はこの方法で解決しました。
カスタムリポジトリインターフェース:
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 Data Repository:
@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
メソッドの場合、次のアプローチを使用しました。
@Query
リポジトリのメソッド(LogRepository.Java)このアプローチを使用すると、投影とリソースの組み立てを管理する必要がありません。
@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);
}
答えは、指示に従わなかったことです。 PersonRepository
は両方を拡張する必要がありますPagingAndSortingRepository<Person, Long>
AND PersonRepositoryCustom
inで目的を達成します。 https://docs.spring.io/spring-data/data-jpa/docs/current/reference/html/#repositories.custom-implementations を参照してください
私たちが使用した別のオプションは、特定のストレージタイプにカスタムリポジトリファクトリを実装することです。
RepositoryFactoryBeanSupport
から拡張し、独自のPersistentEntityInformation
を構築し、カスタムデータストレージタイプのデフォルトリポジトリ実装でCRUD操作を処理できます。たとえば、JpaRepositoryFactoryBean
を参照してください。合計で約10個のクラスを実装する必要があるかもしれませんが、その後再利用可能になります。
使用してみてください
class PersonRepositoryCustomImpl implements PersonRepositoryCustom, InitializingBean {
...
}
実装クラス名は、PersonRepositoryCustomImpl
ではなくPersonRepositoryImpl
にする必要があります。