說說Spring中的 @RestController 和 @Controller

Spring MVC執行流程已是JAVA面試中老生常談的問題,相信各位小夥伴也是信手拈來。今天我們來談談另一個面試中必會必知的問題: @RestController@Controller的區別?

  • Spring MVC中的REST實現
  • @Controller + @ResponseBody註解
  • @RestController註解

Spring MVC 與 REST

基於註解的MVC框架簡化了創建RESTful web服務的過程。傳統的Spring MVC控制器和RESTful web服務控制器之間的關鍵區別是HTTP響應體的創建方式。傳統的MVC控制器依賴於視圖技術,基於REST的web服務控制器僅返回對象,而對象數據直接以JSON/XML的形式寫入HTTP響應。

Spring MVC對 REST 的支持

支持以下方式來創建 REST 資源:

  • 控制器可以處理所有的HTTP方法,包含四個主要的REST方法:GET、PUT、DELETE以及POST;
  • 消息轉換器(Message conversion)將資源的JAVA表述形式轉換爲發送給客戶端的表述形式;
  • 藉助於 SpringMVC 的一系列註解,構建 REST API;
  • 藉助 RestTemplate,Spring應用能夠方便地使用REST資源;

典型的Spring MVC工作流

典型的Spring MVC工作流程

在傳統的工作流中,ModelAndView對象是從控制器轉發到客戶機的,通過在方法上加@ResponseBody,Spring直接從控制器返回數據,而不需要查找視圖。從4.0版本開始,隨着@RestController註釋的引入,這個過程得到了進一步簡化。下面將解釋每種方法。

使用@Controller + @ResponseBody註解

@Controller用於標記在一個類上,使用它標記的類就是一個Spring MVC Controller對象,分發處理器會掃描使用該註解的類的方法,並檢測該方法是否使用了@RequestMapping註解。

@ResponseBody註解用於將Controller的方法返回的對象,通過適當的HttpMessageConverter轉換爲指定格式後,寫入到Response對象的body數據區,通常用來返回 JSON 或者 XML 數據,返回 JSON 數據的情況比較多。

Spring有一個在後臺註冊的HttpMessageConverters列表。HTTPMessageConverter的職責是根據預定義的mime類型將請求主體轉換爲特定的類,然後再轉換回響應主體。每當發出的請求點擊@ResponseBody時,Spring循環遍歷所有已註冊的HttpMessageConverters,尋找第一個符合給定mime類型和類的請求,然後將其用於實際的轉換。

Spring3.x MVC RESTful網絡服務工作流程

代碼示例

創建實體類:

package com.laocaicai.week1.entity;

import javax.xml.bind.annotation.XmlRootElement;
@XmlRootElement(name = "Dog")
public class DogEntity {
    String name;
    String breed;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getBreed() {
        return breed;
    }
    public void setBreed(String breed) {
        this.breed = breed;
    }
    public DogEntity() {
    }
}

創建Controller:

package com.laocaicai.week1.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import com.laocaicai.week1.entity.DogEntity;

@Controller
@RequestMapping("dogs")
public class DogController {
    DogEntity dog = new DogEntity();
    @RequestMapping(value = "/{name}", method = RequestMethod.GET, produces = "application/json")
    public @ResponseBody DogEntity getDogInJSON(@PathVariable String name) {
        dog.setName(name);
        dog.setBreed("中國細犬");
        return dog;
    }
    @RequestMapping(value = "/{name}.xml", method = RequestMethod.GET, produces = "application/xml")
    public @ResponseBody DogEntity getDogInXML(@PathVariable String name) {
        dog.setName(name);
        dog.setBreed("中國細犬");
        return dog;
    }
}

在Spring配置文件中添加標籤,前者用於激活註釋並掃描包以查找和註冊應用程序上下文中的bean,後者增加了對讀取和寫入JSON/XML的支持(對於返回JSON格式數據,需要導入jackson-databind依賴;對於XML格式,需要導入jaxb-api-osgi依賴)

使用URL:http://localhost:8687/week_1/dogs/哮天犬,輸出JSON:

返回JSON格式數據

使用URL:http://localhost:8687/week_1/dogs/哮天犬.xml,輸出XML:

返回XML格式數據

使用@RestController註解

Spring 4.0引入了@RestController@RestController註解是一種快捷方式,它所聲明的控制器在返回響應時,就如同使用了@ResponseBody 註解一樣。它會告訴Spring 將返回類型序列化爲合適的格式,默認情況下爲JSON 格式。通過用@RestController註釋控制器類,您不再需要向所有請求映射方法添加@ResponseBody

package org.springframework.web.bind.annotation;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.stereotype.Controller;

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Controller
@ResponseBody
public @interface RestController {
    String value() default "";
}

Spring4.x MVC RESTful網絡服務工作流程

要在我們的示例中使用@RestController,我們所需要做的就是將@Controller修改爲@RestController並從每個方法中刪除@ResponseBody。生成的類應該如下所示

package com.laocaicai.week1.controller;

import com.laocaicai.week1.entity.DogEntity;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("2dogs")
public class DogRestController {
    DogEntity dog = new DogEntity();
    @RequestMapping(value = "/{name}", method = RequestMethod.GET, produces = "application/json")
    public DogEntity getDogInJSON(@PathVariable String name) {
        dog.setName(name);
        dog.setBreed("中國細犬");
        return dog;
    }
    @RequestMapping(value = "/{name}.xml", method = RequestMethod.GET, produces = "application/xml")
    public DogEntity getgetDogInXMLInXML(@PathVariable String name) {
        dog.setName(name);
        dog.setBreed("中國細犬");
        return dog;
    }
}

注意,我們不再需要將@ResponseBody添加到請求映射方法中,在進行更改之後,再次在服務器上運行應用程序會產生與之前相同的輸出。

總結

通過本篇的介紹,小夥伴們會發現使用@RestController非常簡單,是從Spring v4.0開始創建MVC RESTful web服務的首選方法。@RestController(Spring4+)相當於@Controller + @ResponseBody,返回json或者xml格式數據;如果在控制器類上使用@RestController來代替@Controller的話,Spring將會爲該控制器的所有處理方法應用消息轉換功能,我們不必爲每個方法都添加@ResponseBody了。

參考資料

本文作者:Srivatsan Sundararajan, 翻譯:laocaicaicai
原文鏈接:https://dzone.com/articles/spring-framework-restcontroller-vs-controller
譯文首發:http://blog.didispace.com/tr-spring-framework-restcontroller-vs-controller/

本文有spring4all技術翻譯組完成,更多國外前沿知識和乾貨好文,歡迎關注公衆號:後端面試那些事兒。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章