2 months ago

前兩篇有講到 entity 還可以進一步定義關聯的資源 URL,讓前端可以依照定義來取得資源,而不是一個寫死的網址,避免萬一 URL 有變動的話 APP 也得必須改版。

就像 links 的效果
前端就可以固定抓取 project 的 value 就可以取得 project 的相關資訊,而不必關心 project url 的變動

{  
   "projectId":"QpbR7viWdy",
   "projectName":"123",
   "score":72,
   "createdDate":null,
   "createdBy":null,
   "lastModifiedDate":"2017-07-20T09:24:28Z",
   "lastModifiedBy":null,
   "_links":{  
      "self":{  
         "href":"http://localhost:8080/scoreProjects/n5NehJba7k"
      },
      "scoreProject":{  
         "href":"http://localhost:8080/scoreProjects/n5NehJba7k"
      },
      "project":{  
         "href":"http://localhost:8080/projects/QpbR7viWdy"
      },
      "scoreProjectMembers":{  
         "href":"http://localhost:8080/scoreProjectMembers/search/findByProjectId?projectId=QpbR7viWdy"
      },
      "projectMembers":{  
         "href":"http://localhost:8080/api/project/QpbR7viWdy/members"
      }
   }
}

舉例來說 ScoreProject 這物件是關於專案的分數,那我們希望讓他知道專案的 url 位置讓前端自己取得
可以這樣寫,當然 Project 也必須是 RepositoryRestResource 的一個 Rest 資源

resource.add(repositoryEntityLinks.linkToSingleResource(Project.class, scoreProject.getProjectId()));

轉換出來的結果

"project": {
    "href": "http://localhost:8080/projects/QpbR7viWdy"
}

那我們想利用已經定義好在 RepositoryRestResource 裡面的搜尋條件要怎麼設定
舉例說這是我們 Project 下面每一個 Member 的分數資訊

@RepositoryRestResource
public interface ScoreProjectMemberRepostiory extends JpaRepository<ScoreProjectMember, String> {
    @RestResource(path = "findByProjectId", exported = true)
    List<ScoreProjectMember> findByProjectId(@Param("projectId") String projectId);
}

我們可以這樣指向搜尋功能

resource.add(repositoryEntityLinks.linksToSearchResources(ScoreProjectMember.class).getLink("findByProjectId").expand(scoreProject.getProjectId()).withRel("scoreProjectMembers"));

轉換出來的結果

scoreProjectMembers": {
    "href": "http://localhost:8080/scoreProjectMembers/search/findByProjectId?projectId=QpbR7viWdy"
}

或是我們自己定義好的 RestController 位置想加進去要如何寫
這是一支我們自己做的 Controller 要找出 Project 下所有 Member

@RestController
@RequestMapping("api")
public class ProjectMemberRestController {
    @Autowired
    private ProjectService projectService;

    @ResponseStatus(HttpStatus.OK)
    @GetMapping(value = "project/{projectid}/members", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
    public List<ProjectMember> findMemberByProjectid(
            @PathVariable("projectid") String projectid) {
        List<ProjectMember> projectMemberList = projectService.findMember(projectid);
        return projectMemberList;
    }
}

指向我們寫的 Controller

resource.add(ControllerLinkBuilder.linkTo(ControllerLinkBuilder.methodOn(ProjectMemberRestController.class).findMemberByProjectid(scoreProject.getProjectId())).withRel("projectMembers"));

轉換出來的結果

"projectMembers": {
    "href": "http://localhost:8080/api/project/QpbR7viWdy/members"
}

完整的寫法就是下面這樣子而已, spring 掃描到後就自動可以起作用了

import com.ps.controller.api.ProjectMemberRestController;
import com.ps.model.Project;
import com.ps.model.ScoreProject;
import com.ps.model.ScoreProjectMember;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.rest.webmvc.support.RepositoryEntityLinks;
import org.springframework.hateoas.Resource;
import org.springframework.hateoas.ResourceProcessor;
import org.springframework.hateoas.mvc.ControllerLinkBuilder;
import org.springframework.stereotype.Component;

/**
 * Created by samchu on 2017/7/21.
 */
@Component
public class ScoreProjectResourcesProcessor implements ResourceProcessor<Resource<ScoreProject>> {

    @Autowired
    private RepositoryEntityLinks repositoryEntityLinks;

    @Override
    public Resource<ScoreProject> process(Resource<ScoreProject> resource) {
        ScoreProject scoreProject = resource.getContent();

        // 指向單一物件

        resource.add(repositoryEntityLinks.linkToSingleResource(Project.class, scoreProject.getProjectId()));
        // "project": {

        //   "href": "http://localhost:8080/projects/QpbR7viWdy"

        // }


        // 指向搜尋功能

        resource.add(repositoryEntityLinks.linksToSearchResources(ScoreProjectMember.class).getLink("findByProjectId").expand(scoreProject.getProjectId()).withRel("scoreProjectMembers"));
        // scoreProjectMembers": {

        //   "href": "http://localhost:8080/scoreProjectMembers/search/findByProjectId?projectId=QpbR7viWdy"

        // }


        // 指向我們寫的 Controller

        resource.add(ControllerLinkBuilder.linkTo(ControllerLinkBuilder.methodOn(ProjectMemberRestController.class).findMemberByProjectid(scoreProject.getProjectId())).withRel("projectMembers"));
        // "projectMembers": {

        //   "href": "http://localhost:8080/api/project/QpbR7viWdy/members"

        // }

        
        // 可以指定查詢頁數

        resource.add(repositoryEntityLinks.linkToCollectionResource(Project.class).expand("5","20").withRel("projects")); // rojects?page=5&size=20


        return resource;
    }
}

在透過 Spring Data Rest 做任何取得或查詢的時候就都可以提供相關的資源位置給前端

← Controller ExceptionHandler New Vagrant Version after 1.9.5 use docker →
 
comments powered by Disqus