How to add custom methods to Spring Data Rest JPA implementation and leverage HATEOS support?

孤街醉人 提交于 2019-11-30 12:10:44

问题


I have a Spring Data Rest Repository controller that utilizes JPA for the query implementation, and I need to add some custom query methods that cannot be done using the standard queryByExample method that JPA supports. I have created an Impl class that has the necessary method, but I cannot get it to be recognized. I saw that I can utilize a standard Spring MVC Controller, but I want to have a unified API, and basically all I really want is to implement my own custom /search methods.

Even with the custom controller, the problem is then that the HAL links and other related items are no longer provided.

Can the Spring folks spend some time having someone document how to do some of this more advanced stuff? I'm guessing that having to implement your own search methods at times are fairly common, and it would be time well spent to make it clear how to do this.


回答1:


A simple implementation could look like this:

@BasePathAwareController
class CustomInvocationsController implements ResourceProcessor<RepositorySearchesResource> {

  private final YourRepository repository;

  public CustomInvocationsController(YourRepository repository) {
    this.repository = repository;
  }

  @RequestMapping(…)
  ResponseEntity<?> handleRequest(PersistentEntityResourceAssembler assembler)

    // invoke repository
    // Use assembler to build a representation
    // return ResponseEntity
  }

  @Override
  public RepositorySearchesResource process(RepositorySearchesResource resource) {
    // add Link to point to the custom handler method
  }
}

A few things to note:

  • using @BasePathAwareController instead of a plain @Controller makes sure whatever you're mapping the handler method to, it will consider the base path you've configured on Spring Data REST, too.
  • within the request mapping, use everything you already know from Spring MVC, choose an appropriate HTTP method.
  • PersistentEntityResourceAssembler basically abstracts setting up a representation model within a PersistentEntityResource so that the Spring Data REST specific treatment of associations etc. kicks in (associations becoming links etc.
  • implement ResourceProcessor to post-process RepositorySearchesResource which is returned for the resource rendering all searches. Currently, there's no way to determine which domain type that resource was rendered. I filed and fixed DATAREST-515 to improve that.



回答2:


Ok, based upon the information provided so far, I have something working that I think makes sense. I'm definitely looking for someone to validate my theories so far.

The goal was to be able to implement additional custom methods to the methods that SDR already provides. This is because I need to implement additional logic that cannot be expressed as simple Spring Data Repository query methods (the findByXXX methods). In this case, I'm looking to query other data sources, like Solr, as well as provide custom manipulation of the data before its returned.

I have implemented a Controller based upon what @oliver suggested, as follows:

@BasePathAwareController
@RequestMapping(value = "/persons/search")
public class PersonController implements ResourceProcessor<RepositorySearchesResource>, ResourceAssembler<Person, Resource<Person>> {

    @Autowired
    private PersonRepository repository;

    @Autowired
    private EntityLinks entityLinks;

    @RequestMapping(value = "/lookup", method = RequestMethod.GET)
    public ResponseEntity<Resource<Person>> lookup(@RequestParam("name") String name)
    {
        try
        {
          Resource<Person> resource = toResource(repository.lookup(name));
          return new ResponseEntity<Resource<Person>>(resource, HttpStatus.OK);
        }
        catch (PersonNotFoundException nfe)
        {
            return new ResponseEntity<Resource<Person>>(HttpStatus.OK);
        }
    }

    @Override
    public RepositorySearchesResource process(RepositorySearchesResource resource) {

        LinkBuilder lb = entityLinks.linkFor(Person.class, "name");
        resource.add(new Link(lb.toString() + "/search/lookup{?name}", "lookup"));
        return resource;
    }

    @Override
    public Resource<Person> toResource(Person person) {
        Resource<IpMaster> resource = new Resource<Person>(person);

        return resource;
    }

This produces a "lookup" method that is considered a template and is listed when you do a query on /persons/search, along with the other search methods defined in the Repository. It doesn't use the PersistentEntityResourceAssembler that was suggested. I think I would rather use that, but then I'm a bit confused as to how to get it injected, and what the comment about the filed bug means.




回答3:


See the latest docs, as the most recent version of SDR has more details on this, and makes it a bit easier. The key is to use the @RepositoryRestController annotation to be able to add additional methods under the /search endpoint, or the @BasePathAwareController annotation if you want to add endpoints to other parts of the url namespace. Then include the PersistentEntityResourceAssembler as a parameter to your controller method, and use that to generate the HAL output if you are returning your entity objects.



来源:https://stackoverflow.com/questions/29570962/how-to-add-custom-methods-to-spring-data-rest-jpa-implementation-and-leverage-ha

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!