controller的例子
完成异常处理后,我们可以看看RESTful controller的小例子,例子为对account的增删改查。在业务层,我们有AccountService这个接口。
//【1】表示为REST上下文的Controller
@RestEndpoint
public class AccountRestEndpoint {
@Inject private AccountService accountService;
//【2.1例子】对OPTIONS消息进行应答,学习ResponseEntity中如何设置header,status code以及body(本例为null)
@RequestMapping(value = "account", method = RequestMethod.OPTIONS)
public ResponseEntity<Void> discover(){
HttpHeaders headers = new HttpHeaders();
headers.add("Allow", "OPTIONS,HEAD,GET,POST");
return new ResponseEntity<>(null, headers, HttpStatus.NO_CONTENT);
}
//【2.2例子】对于资源不存在,直接抛出异常,则根据@ControllerAdvice的处理返回结果,这种方式很简洁。
@RequestMapping(value = "account/{id}", method = RequestMethod.OPTIONS)
public ResponseEntity<Void> discover(@PathVariable("id") long id){
if(this.accountService.getAccount(id) == null)
throw new ResourceNotFoundException();
HttpHeaders headers = new HttpHeaders();
headers.add("Allow", "OPTIONS,HEAD,GET,POST");
return new ResponseEntity<>(null, headers, HttpStatus.NO_CONTENT);
}
//【2.3例子】@ResponseBody可以直接返回对象,根据协商决定采用json还是xml的封装。
// 对于XML的封装,需要注意。我们应当尽量避免直接使用Collection或者Map,它们虽然很容易转换为json,但是很难转换为XML。本例定义了一个新的类AccountList。当然,我们也可以只使用JSON来规避这个问题。
@RequestMapping(value = "account", method = RequestMethod.GET)
@ResponseBody @ResponseStatus(HttpStatus.OK)
public AccountList read(){
// 列表可能会很大,应当给予限制。小例子从略
AccountList list = new AccountList();
list.setValue(this.accountService.getAllAccounts());
return list;
}
//【2.4例子】REST POST中返回Location信息。学习@RequestBody,请求消息体对象作为输入
@RequestMapping(value = "account", method = RequestMethod.POST)
public ResponseEntity<Account> create(@RequestBody AccountForm form){
// ......
String uri = ServletUriComponentsBuilder.fromCurrentServletMapping()
.path("/account/{id}").buildAndExpand(account.getId()).toString();
HttpHeaders headers = new HttpHeaders();
headers.add("Location", uri);
return new ResponseEntity<>(account, headers, HttpStatus.CREATED);
}
@XmlRootElement(name = "accounts")
public static class AccountList{
private List<Account> value;
@XmlElement(name = "account")
public List<Account> getValue() {
return value;
}
public void setValue(List<Account> value) {
this.value = value;
}
}
}
发现机制(XML封装)小例子
在keystone等RESTful接口中,我们经常会看到携带_link等表示相关url的信息,下面的小例子,将返回接口的URL。在HAL中,Json和XML有不同的接口,因此分开两个方法,通过produces(即请求中的Accept头)来匹配,在Accept中,按顺序具有优先级别。
返回Json的消息body为:
{
"_links": {
"account": {
"href": "http://localhost:8080/chapter17/services/Rest/account"
},
"self": {
"href": "http://localhost:8080/chapter17/services/Rest"
}
}
}
返回XML的消息body为
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<resource>
<link rel="http://localhost:8080/chapter17/services/Rest" href="self"/>
<link rel="http://localhost:8080/chapter17/services/Rest/account" href="account"/>
</resource>
@RestEndpoint
public class IndexRestEndpoint {
//produces attribute helps identify which method should be called based on the request's Accept header.
// 这里也演示了Json使用的便捷。直接回复一个Map对象(而且是Map嵌套的)
@RequestMapping(value = {"", "/"}, method = RequestMethod.GET, produces = {"application/json", "text/json"})
@ResponseBody @ResponseStatus(HttpStatus.OK)
public Map<String, Object> discoverJson(){
ServletUriComponentsBuilder builder = ServletUriComponentsBuilder.fromCurrentServletMapping();
Map<String, JsonLink> links = new Hashtable<>(2);
links.put("self", new JsonLink(builder.path("").build().toString()));
links.put("account",new JsonLink(builder.path("/account").build().toString()));
Map<String, Object> response = new Hashtable<>(1);
response.put("_links", links);
return response;
}
/* 在XML中,需要在数据结构中,设置好@XmlRootElement,@XmlElement,@XmlAttribute,@XmlValue(本小例子没有使用到value的情况,这其实是缺省的情况),@XmlTransient(忽略)
此外,我们还可以指定相应schema格式,例如:@XmlSchemaType(name = "base64Binary"),这里我的理解仅仅只是写明格式,并不会自动为你转换。对于byte[],在json和xml中会给出BASE64的String,也就是这里的base64Binary,如果你要采用其他格式,需要在代码中处理。
Json的处理能力要强大,例如可以直接返回一个Instant对象,Json会自动给崔ISO8601的格式,而在XML中无相关显示,即便XmlSchemaType给出了date或者dateTime,还是需要在代码中手动处理 */
@RequestMapping(value = {"", "/"}, method = RequestMethod.GET, produces = {"application/xml", "text/xml"})
@ResponseBody @ResponseStatus(HttpStatus.OK)
public Resource discoverXml(){
ServletUriComponentsBuilder builder = ServletUriComponentsBuilder.fromCurrentServletMapping();
Resource resource = new Resource();
resource.addLink(new Link("self", builder.path("").build().toString()));
resource.addLink(new Link("account",builder.path("/account").build().toString()));
return resource;
}
public static class JsonLink{
private String href;
public JsonLink(String href) {...}
@XmlAttribute
public String getHref() {...}
public void setHref(String href) {...}
}
public static class Link extends JsonLink{
private String rel;
public Link(String href, String rel) {...}
@XmlAttribute
public String getRel() {...}
public void setRel(String rel) {...}
}
@XmlRootElement
public static class Resource{
private List<Link> links = new ArrayList<>();
@XmlElement(name = "link")
public List<Link> getLinks() {...}
public void setLinks(List<Link> links) {...}
public void addLink(Link link){ this.links.add(link);}
}
}
相关链接: 我的Professional Java for Web Applications相关文章