看到這個添加鏈接的最佳方式是考慮彈簧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"
}
]
}
這是不能接受的。很多樣板。建議一句話:org.springframework.http.ResponseEntity生成樣板代碼。您將最終在控制器的每個地方使用這些ResponseEntity,因此難以閱讀和理解。 如果你想處理像錯誤(Not Found,Conflict等)的特殊情況,你可以在你的Spring配置文件中添加一個HandlerExceptionResolver。因此,在你的代碼中,你只需要拋出一個特定的異常(例如NotFoundException),並決定在你的Handler中做什麼(將HTTP狀態設置爲404),使Controller代碼更清晰。 – user3871754
@ user3871754謝謝 –
「太多的樣板代碼」它是Java ..添加2千行XML,其中一半是自動生成的,現在您達到了Java良好的樣板代碼量。 OP:我喜歡這種方法,我希望更多的人意識到資源(表示)應該與領域模型分開,那麼您可以輕鬆推出新版本的「帳戶」 – EralpB