zoukankan      html  css  js  c++  java
  • SpringMVC restful风格

    1、Spring对REST的支持

    Spring3(这里讨论Spring3.2+)对Spring MVC的一些增强功能为REST提供了良好的支持。Spring对开发REST资源提供以下支持:

    1. 操作方式:控制器可以处理所有的HTTP方法,包含4个主要的REST方法:GET、PUT、DELETE以及POST。Spring的表单绑定JSP标签库的<form:form>标签以及新的HiddenHttpMethodFilter,使得通过HTML表单提交的PUT和DELETE请求成为可能
    2. 资源标识:新的@PathVariable注解使得控制器能够处理参数化的URL
    3. 资源表述方法1:通过使用Spring的视图解析器,资源可以以各种形式进行表述,包括XML、JSON、Atom和RSS()。使用新的ContentNegotiatingViewResolver来选择最合适客户端的表述
    4. 资源表述方法2:通过使用@ResponseBody注解和各种HttpMethodConverter实现来达到。@RequestBody注解记忆HttpMethodConverter实现可以将传入的HTTP数据转化为传入控制器方法的Java对象
    5. REST客户端:RestTemplate简化了客户端对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依次通过以下三个条件确定客户端需要什么类型的内容表述:

    1. URL路径上添加扩展名,如 http://myserver/myapp/accounts/list.html 或者 http://myserver/myapp/accounts/list.xls。
    2. URL参数,如 http://myserver/myapp/accounts/list?format=xls,参数名默认为“format”,但也可以更改。
    3. 通过HTTP请求的Accept头部信息确定返回资源格式,但由于客户端的处理不同,这个方法并不太可靠。

    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表述形式的资源转化为发送给客户端的表述形式:

    • 基于视图渲染进行协商(@ContentNegotiatingViewResolver)
    • HTTP消息转换器(HttpMessageConverters)

    首先是第一种方式,使用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、参考

    《Spring in Action 第三版》

    Content Negotiation using Spring MVC

    Content Negotiation using Views

  • 相关阅读:
    ASP.NET实现进度条效果【转】
    删除指定创建日期前的文件夹、文件
    MS SQL SERVER执行大脚本文件时,提示“内存不足”的解决办法
    solr之functionQuery(函数查询)【转】
    解决Jenkins连接git时报错Permission denied (publickey)
    vscode csharp c#开发 自动引入命名空间
    nginx配置后外网无法访问
    jenkins node 版本无法使用最新的版本
    jenkins npm install WARN checkPermissions Missing write access 权限问题
    小程序setData只修改对象中的某个属性的方法
  • 原文地址:https://www.cnblogs.com/dry0515/p/5189220.html
Copyright © 2011-2022 走看看