2015-12-15 66 views
3

我有我的實體與Spring Data JPA,但爲了生成他們的統計信息,我在Spring @ Repository中使用jOOQ。我如何簡單地添加一個鏈接到一個Spring Data REST實體

由於我的方法返回實體列表或Double,我如何將它們作爲鏈接公開?比方說,我有一個用戶的實體,我想下面的JSON:

{ 
    "_embedded" : { 
    "users" : [ ] 
    }, 
    "_links" : { 
    "self" : { 
     "href" : "http://localhost:8080/api/users" 
    }, 
    "stats" : { 
     "href" : "http://localhost:8080/api/users/stats" 
    } 
    "profile" : { 
     "href" : "http://localhost:8080/api/profile/users" 
    } 
    }, 
    "page" : { 
    "size" : 20, 
    "totalElements" : 0, 
    "totalPages" : 0, 
    "number" : 0 
    } 
} 

而在http://localhost:8080/api/users/stats我想用我在jOOQ庫中聲明的方法鏈接列表。我會如何處理這個問題?謝謝。

回答

3

docs

@Bean 
public ResourceProcessor<Resource<Person>> personProcessor() { 

    return new ResourceProcessor<Resource<Person>>() { 

    @Override 
    public Resource<Person> process(Resource<Person> resource) { 

     resource.add(new Link("http://localhost:8080/people", "added-link")); 
     return resource; 
    } 
    }; 
} 
3

看到這個添加鏈接的最佳方式是考慮彈簧HATEOAS,這使得代碼看起來更乾淨。

建議一句話:始終使用org.springframework.http.ResponseEntity將響應返回給客戶端,因爲它允許輕鬆定製響應。

所以根據您的要求是發送鏈接的響應,那麼建議這個最好的做法是使用類型ResourceSupport的(org.springframework.hateoas.ResourceSupport)ResourceAssemblerSupport(org.springframework.hateoas。 mvc.ResourceAssemblerSupport)創建需要發送給客戶端的資源。

對於實例: 如果你有一個像帳戶模型對象,則必須存在,你不希望客戶知道或將被列入性反應,從而以排除反應,我們可以將這些屬性的幾個字段使用ResourceAssemblerSupport類'

public TResource toResource(T t);

從模型對象生成需要作爲響應發送資源的方法。

例如,我們有一個賬戶類等(可直接用於所有服務器端的交互和操作)

@Document(collection = "Accounts_Details") 

public class Account { 

    @Id 
    private String id; 

    private String username; 
    private String password; 
    private String firstName; 
    private String lastName; 
    private String emailAddress; 
    private String role; 
    private boolean accountNonExpired; 
    private boolean accountNonLocked; 
    private boolean credentialsNonExpired; 
    private boolean enabled; 
    private long accountNonLockedCounter; 
    private Date lastPasswordResetDate; 
    private Address address; 
    private long activationCode; 

    public Account() { 
    } 

    //getters and setters 
} 

現在從該POJO,我們將創建一個資源對象,將被髮送到客戶端與選定的屬性。

爲此,我們將創建一個帳戶資源,其中將僅包含客戶可查看的必要字段。並且做那我們創造另一個類。

@XmlRootElement 

public class AccountResource extends ResourceSupport { 

    @XmlAttribute 
    private String username; 
    @XmlAttribute 
    private String firstName; 
    @XmlAttribute 
    private String lastName; 
    @XmlAttribute 
    private String emailAddress; 
    @XmlAttribute 
    private Address address; 
    public String getUsername() { 
     return username; 
    } 
    public void setUsername(String username) { 
     this.username = username; 
    } 
    public String getFirstName() { 
     return firstName; 
    } 
    public void setFirstName(String firstName) { 
     this.firstName = firstName; 
    } 
    public String getLastName() { 
     return lastName; 
    } 
    public void setLastName(String lastName) { 
     this.lastName = lastName; 
    } 
    public String getEmailAddress() { 
     return emailAddress; 
    } 
    public void setEmailAddress(String emailAddress) { 
     this.emailAddress = emailAddress; 
    } 
    public Address getAddress() { 
     return address; 
    } 
    public void setAddress(Address address) { 
     this.address = address; 
    } 


} 

所以現在這個資源是客戶端將會看到或必須使用的。

在創建AccountResource的藍圖後,我們需要一種方法將我們的POJO模型轉換爲此資源,並且建議的最佳做法是創建一個ResourceAssemblerSupport類並重寫toResource(T t)方法。

import org.springframework.hateoas.mvc.ControllerLinkBuilder; 
import org.springframework.hateoas.mvc.ResourceAssemblerSupport; 
import org.springframework.stereotype.Component; 

import com.brx.gld.www.api.controller.RegistrationController; 
import com.brx.gld.www.api.model.Account; 

@Component 
public class AccountResourceAssembler extends ResourceAssemblerSupport<Account, AccountResource> { 

    public AccountResourceAssembler(Class<RegistrationController> controllerClass, 
      Class<AccountResource> resourceType) { 
     super(controllerClass, resourceType); 
    } 

    public AccountResourceAssembler() { 
     this(RegistrationController.class, AccountResource.class); 
    } 

    @Override 
    public AccountResource toResource(Account account) { 
     AccountResource accountResource = instantiateResource(account); //or createResourceWithId(id, entity) canbe used which will automatically create a link to itself. 
     accountResource.setAddress(account.getAddress()); 
     accountResource.setFirstName(account.getFirstName()); 
     accountResource.setLastName(account.getLastName()); 
     accountResource.setEmailAddress(account.getEmailAddress()); 
     accountResource.setUsername(account.getUsername()); 
     accountResource.removeLinks(); 
     accountResource.add(ControllerLinkBuilder.linkTo(RegistrationController.class).slash(account.getId()).withSelfRel()); 
     return accountResource; 
    } 

} 

在toReource方法而不是使用instanriateReource(..)我們必須使用createdResourceWithId(id,entity),然後將custum鏈接添加到resorce中,這實際上是再次考慮的最佳實踐,但爲了演示的目的,我使用了instantiateResource(..)

Now to在控制器使用:

@Controller 
@RequestMapping("/api/public/accounts") 
public class RegistrationController { 

    @Autowired 
    private AccountService accountService; 

    @Autowired 
    private AccountResourceAssembler accountResourceAssembler; 

    @RequestMapping(method = RequestMethod.GET) 
    public ResponseEntity<List<AccountResource>> getAllRegisteredUsers() { 
     List<AccountResource> accountResList = new ArrayList<AccountResource>(); 
     for (Account acnt : accountService.findAllAccounts()) 
      accountResList.add(this.accountResourceAssembler.toResource(acnt)); 
     return new ResponseEntity<List<AccountResource>>(accountResList, HttpStatus.OK); 
    } 

/*Use the below method only if you have enabled spring data web Support or otherwise instead of using Account in @PathVariable usr String id or int id depending on what type to id you have in you db*/ 

    @RequestMapping(value = "{userID}", method = RequestMethod.GET) 
    public ResponseEntity<AccountResource> getAccountForID(@PathVariable("userID") Account fetchedAccountForId) { 
     return new ResponseEntity<AccountResource>(
       this.accountResourceAssembler.toResource(fetchedAccountForId), HttpStatus.OK); 
    } 

爲了使彈簧的數據網絡支持,這增加了幾個funcationality喲類似的代碼基於傳遞就像我們在前面的方法使用的ID從數據庫獲取自動模型數據。

現在返回toResource(賬戶賬戶)方法:首先對資源對象進行初始化,然後設置所需的道具,然後通過使用org.springframework.hateoas的靜態將鏈接添加到AccountResorce。 mvc.ControllerLinkBuilder.linkTo(..)方法,然後傳入控制器類,從中選擇基本URL,然後使用斜槓(..)等構建url。在指定完整路徑之後,我們使用rel方法來指定關係(就像我們在這裏使用withSelfRel()來指定關係是自己的那樣)。對於其他關係,我們可以使用withRel(String關係)來描述更多。 所以在我們的toResource方法的代碼,我們使用類似 accountResource.add(ControllerLinkBuilder.linkTo(RegistrationController.class).slash(account.getId())withSelfRel());

將建立網址如/ API /公/帳號/ {}用戶標識

現在郵遞員如果我們用一個獲得此URL http://localhost:8080/api/public/accounts

{ 
    "username": "Arif4", 
    "firstName": "xyz", 
    "lastName": "Arif", 
    "emailAddress": "[email protected]", 
    "address": { 
     "addressLine1": "xyz", 
     "addressLine2": "xyz", 
     "addressLine3": "xyz", 
     "city": "xyz", 
     "state": "xyz", 
     "zipcode": "xyz", 
     "country": "India" 
    }, 
    "links": [ 
     { 
     "rel": "self", 
     "href": "http://localhost:8080/api/public/accounts/5628b95306bf022f33f0c4f7" 
     } 
    ] 
    }, 
    { 
    "username": "Arif5", 
    "firstName": "xyz", 
    "lastName": "Arif", 
    "emailAddress": "[email protected]", 
    "address": { 
     "addressLine1": "xyz", 
     "addressLine2": "xyz", 
     "addressLine3": "xyz", 
     "city": "xyz", 
     "state": "xyz", 
     "zipcode": "xyz", 
     "country": "India" 
    }, 
    "links": [ 
     { 
     "rel": "self", 
     "href": "http://localhost:8080/api/public/accounts/5628c04406bf23ea911facc0" 
     } 
    ] 
    } 

點擊任何鏈接和發送GET請求的響應將是 http://localhost:8080/api/public/accounts/5628c04406bf23ea911facc0

{ 
    "username": "Arif5", 
    "firstName": "xyz", 
    "lastName": "Arif", 
    "emailAddress": "[email protected]", 
    "address": { 
     "addressLine1": "xyz", 
     "addressLine2": "xyz", 
     "addressLine3": "xyz", 
     "city": "xyz", 
     "state": "xyz", 
     "zipcode": "xyz", 
     "country": "India" 
    }, 
    "links": [ 
     { 
     "rel": "self", 
     "href": "http://localhost:8080/api/public/accounts/5628c04406bf23ea911facc0" 
     } 
    ] 
    } 
+2

這是不能接受的。很多樣板。建議一句話:org.springframework.http.ResponseEntity生成樣板代碼。您將最終在控制器的每個地方使用這些ResponseEntity,因此難以閱讀和理解。 如果你想處理像錯誤(Not Found,Conflict等)的特殊情況,你可以在你的Spring配置文件中添加一個HandlerExceptionResolver。因此,在你的代碼中,你只需要拋出一個特定的異常(例如NotFoundException),並決定在你的Handler中做什麼(將HTTP狀態設置爲404),使Controller代碼更清晰。 – user3871754

+0

@ user3871754謝謝 –

+0

「太多的樣板代碼」它是Java ..添加2千行XML,其中一半是自動生成的,現在您達到了Java良好的樣板代碼量。 OP:我喜歡這種方法,我希望更多的人意識到資源(表示)應該與領域模型分開,那麼您可以輕鬆推出新版本的「帳戶」 – EralpB

相關問題