1、Spring对REST的支持
Spring3(这里讨论Spring3.2+)对Spring MVC的一些增强功能为REST提供了良好的支持。Spring对开发REST资源提供以下支持:
2、参数化URL
Spring3.0中引入了新的@PathVariable注解,帮助Controller使用面向资源的方式处理请求。如:
1 @Controller
2 @RequestMapping(value="/spitters")
3 public class SpittleController{
4 private SpitterService spitterService;
5 ...
6 @RequestMapping(value="/{id}", method= RequestMethod.PUT)
7 @ResponseStatus(HttpStatus.NO_CONTENT)
8 public void putSpittle(@PathVariable("id")) long id,
9 @Valid Spittle spittle)
10 {
11 spitterService.saveSpittle(spittle);
12 }
13 }
3、协商资源表述
“协商资源表述”即确定一个HTTP请求所需要返回的资源格式,HTML、XML还是JSON等。按优先级,Spring MVC依次通过以下三个条件确定客户端需要什么类型的内容表述:
JAF(JavaBeans Activation Framework)可提供由扩展名(或URL参数)到资源格式的自动映射机制(如json->"application/json"),这时classpath下必须有activation.jar包。
Spring MVC通过ContentNegotiationManager来进行资源协商,一般配置如下:
1 <bean id="contentNegotiationManager" 2 class="org.springframework.web.accept.ContentNegotiationManagerFactoryBean"> 3 <property name="favorPathExtension" value="false" /> 4 <property name="favorParameter" value="true" /> 5 <property name="parameterName" value="mediaType" /> 6 <property name="ignoreAcceptHeader" value="true"/> 7 <property name="useJaf" value="false"/> 8 <property name="defaultContentType" value="application/json" /> 9 10 <property name="mediaTypes"> 11 <map> 12 <entry key="json" value="application/json" /> 13 <entry key="xml" value="application/xml" /> 14 </map> 15 </property> 16 </bean>
以上配置表示:不使用路径扩展名方式,也不使用Accept头信息方式,仅使用URL参数方式确定资源类型,URL参数名使用“mediaType”代替默认的“format”,不使用JAF而是自行定义URL参数到资源格式的映射,这里只定义了JSON和XML。
4、表述资源(一)
Spring MVC通过两种方式将Java表述形式的资源转化为发送给客户端的表述形式:
首先是第一种方式,使用HttpMessageConverters表述资源。当ContentNegotiationManager配置如下,且类路径下包含JAXB和Jackson包时,Spring MVC将自动匹配使用哪种HttpMessageCoverter。
ContentNegotiationManager配置:
1 <!-- enable the "produces" annotation of "RequestMapping" --> 2 <mvc:annotation-driven content-negotiation-manager="contentNegotiationManager" /> 3 4 <!-- Simple strategy: only path extension is taken into account --> 5 <bean id="cnManager" 6 class="org.springframework.web.accept.ContentNegotiationManagerFactoryBean"> 7 <property name="favorPathExtension" value="true"/> 8 <property name="ignoreAcceptHeader" value="true" /> 9 <property name="defaultContentType" value="text/html" /> 10 <property name="useJaf" value="false"/> 11 12 <property name="mediaTypes"> 13 <map> 14 <entry key="html" value="text/html" /> 15 <entry key="json" value="application/json" /> 16 <entry key="xml" value="application/xml" /> 17 </map> 18 </property> 19 </bean>
Controller:
1 @Controller
2 class AccountController {
3 // RESTful method, use MappingJacksonHttpMessageConverter and Jaxb2RootElementHttpMessageConverter automatically
4 //accounts.json -> application/json
5 //accounts.xml -> text/xml
6 @RequestMapping(value="/accounts", produces={"application/xml", "application/json"})
7 @ResponseStatus(HttpStatus.OK)
8 public @ResponseBody List<Account> listWithMarshalling(Principal principal) {
9 return accountManager.getAccounts(principal);
10 }
11
12 // View-based method
13 //accounts.html -> text/html
14 //accounts.others -> text/html
15 @RequestMapping("/accounts")
16 public String listWithView(Model model, Principal principal) {
17 // Call RESTful method to avoid repeating account lookup logic
18 model.addAttribute( listWithMarshalling(principal) );
19
20 // Return the view to use for rendering the response
21 return ¨accounts/list¨;
22 }
23 }
使用 JAXB 和 Jackson时,需要在account类上添加annotation:
1 /**
2 * Represents an account for a member of a financial institution. An account has
3 * zero or more {@link Transaction}s and belongs to a {@link Customer}. An aggregate entity.
4 */
5 @Entity
6 @Table(name = "T_ACCOUNT")
7 @XmlRootElement
8 public class Account {
9
10 // data-members omitted ...
11
12 public Account(Customer owner, String number, String type) {
13 this.owner = owner;
14 this.number = number;
15 this.type = type;
16 }
17
18 /**
19 * Returns the number used to uniquely identify this account.
20 */
21 @XmlAttribute
22 public String getNumber() {
23 return number;
24 }
25
26 /**
27 * Get the account type.
28 *
29 * @return One of "CREDIT", "SAVINGS", "CHECK".
30 */
31 @XmlAttribute
32 public String getType() {
33 return type;
34 }
35
36 /**
37 * Get the credit-card, if any, associated with this account.
38 *
39 * @return The credit-card number or null if there isn‘t one.
40 */
41 @XmlAttribute
42 public String getCreditCardNumber() {
43 return StringUtils.hasText(creditCardNumber) ? creditCardNumber : null;
44 }
45
46 /**
47 * Get the balance of this account in local currency.
48 *
49 * @return Current account balance.
50 */
51 @XmlAttribute
52 public MonetaryAmount getBalance() {
53 return balance;
54 }
55
56
57 /**
58 * Returns a single account transaction. Callers should not attempt to hold
59 * on or modify the returned object. This method should only be used
60 * transitively; for example, called to facilitate reporting or testing.
61 *
62 * @param name
63 * the name of the transaction account e.g "Fred Smith"
64 * @return the beneficiary object
65 */
66 @XmlElement // Make these a nested <transactions> element
67 public Set<Transaction> getTransactions() {
68 return transactions;
69 }
70
71 // Setters and other methods ...
72
73 }
5、表述资源(二)
第二种方式,使用视图渲染器(View Resolution)。使用ContentNegotiatingViewResolver和ContentNegotiationManager进行配置:
1 <!-- View resolver that delegates to other view resolvers based on the content type --> 2 <bean class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver"> 3 <!-- All configuration is now done by the manager - since Spring V3.2 --> 4 <property name="contentNegotiationManager" ref="cnManager"/> 5 </bean> 6 7 <!-- Setup a simple strategy --> 8 <bean id="cnManager" class="org.springframework.web.accept.ContentNegotiationManagerFactoryBean"> 9 <property name="ignoreAcceptHeader" value="true"/> 10 <property name="defaultContentType" value="text/html" /> 11 </bean>
使用以上配置Spring将根据约定自动查找ViewResolvers,并渲染资源。也可显式配置ViewResolvers:
1 <bean class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver"> 2 <property name="contentNegotiationManager" ref="cnManager"/> 3 4 <!-- Define the view resolvers explicitly --> 5 <property name="viewResolvers"> 6 <list> 7 <bean class="org.springframework.web.servlet.view.XmlViewResolver"> 8 <property name="location" value="spreadsheet-views.xml"/> 9 </bean> 10 11 <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> 12 <property name="prefix" value="WEB-INF/views"/> 13 <property name="suffix" value=".jsp"/> 14 </bean> 15 </list> 16 </property> 17 </bean>
这样Controller就可以去掉@ResponseBody的Method,只写一个Method了。
6、参考
Content Negotiation using Spring MVC
Content Negotiation using Views
原文:http://www.cnblogs.com/dry0515/p/5189220.html