Spring MVC 面試題
- Spring MVC 面試題
- 簡單介紹一下 Spring MVC 框架
- Spring MVC 有什么優點?
- 描述一下 Spring MVC 的工作流程
- 簡單介紹 Spring MVC 的核心組件
- @Controller 注解有什么用?
- @RequestMapping 注解有什么用?
- @RestController 和 @Controller 有什么區別?
- @RequestMapping 和 @GetMapping 注解的不同之處在哪里?
- @RequestParam 和 @PathVariable 兩個注解的區別
- 返回 JSON 格式使用什么注解?
- 介紹一下 Spring MVC 中的 WebApplicationContext ?
- Spring MVC 和 Struts2 的異同?
- 介紹下 Spring MVC 攔截器?
- Spring MVC 的攔截器和 Filter 過濾器有什么差別?
- REST 面試題
簡單介紹一下 Spring MVC 框架
在早期 Java Web 的開發中,統一把顯示層、控制層、顯示層的操作全部交給 JSP 或者 Java Bean 來進行處理,存在一定的弊端,例如:JSP 和 Java Bean 之間嚴重耦合、開發效率低等弊端。
Spring MVC 是 Spring 體系中的一員,提供“模型-視圖-控制器”(Model-View-Controller)架構和隨時可用的組件,用於開發靈活且松散耦合的 Web 應用程序。
MVC 模式有助於分離應用程序的不同方面,如輸入邏輯,業務邏輯和 UI 邏輯,同時在所有這些元素之間提供松散耦合。
Spring MVC 有什么優點?
- 使用真的非常方便,無論是添加 HTTP 請求方法映射的方法,還是不同數據格式的響應。
- 提供攔截器機制,可以方便的對請求進行攔截處理。
- 提供異常機制,可以方便的對異常做統一處理。
- 可以任意使用各種視圖技術,而不僅僅局限於 JSP ,例如 Freemarker、Thymeleaf 等等。
描述一下 Spring MVC 的工作流程
Spring MVC 也是基於 Servlet 來處理請求的,主要通過 DispatcherServlet 這個 Servlet 來處理請求,處理過程需要通過九大組件來完成,先看到下面這個流程圖:

Spring MVC 處理請求的流程大致如上圖所示
- 用戶的瀏覽器發送一個請求,這個請求經過互聯網到達了我們的服務器。Servlet 容器首先接待了這個請求,並將該請求委托給
DispatcherServlet
進行處理。 DispatcherServlet
將該請求傳給了處理器映射組件HandlerMapping
,並獲取到適合該請求的 HandlerExecutionChain 攔截器和處理器對象。- 在獲取到處理器后,
DispatcherServlet
還不能直接調用處理器的邏輯,需要進行對處理器進行適配。處理器適配成功后,DispatcherServlet
通過處理器適配器HandlerAdapter
調用處理器的邏輯,並獲取返回值ModelAndView
對象。 - 之后,
DispatcherServlet
需要根據 ModelAndView 解析視圖。解析視圖的工作由ViewResolver
完成,若能解析成功,ViewResolver
會返回相應的 View 視圖對象。 - 在獲取到具體的 View 對象后,最后一步要做的事情就是由 View 渲染視圖,並將渲染結果返回給用戶。
以上就是 Spring MVC 處理請求的全過程,上面的流程進行了一定的簡化,主要涉及到最核心的組件,還有許多其他組件沒有表現出來,不過這並不影響大家對主過程的理解。
總結:客戶端發起請求后,最終會交由 DispatcherServlet 來處理,它會通過你的 URI 找到對應的方法,從請求中解析參數,然后通過反射機制調用該方法,將方法的執行結果設置到響應中,如果存在對應的 View 對象,則進行頁面渲染,實際上就是將請求轉發到指定的 URL
簡單介紹 Spring MVC 的核心組件
那么接下來就簡單介紹一下 DispatcherServlet
和九大組件(按使用順序排序的):
組件 | 說明 |
---|---|
DispatcherServlet | Spring MVC 的核心組件,是請求的入口,負責協調各個組件工作 |
MultipartResolver | 內容類型( Content-Type )為 multipart/* 的請求的解析器,例如解析處理文件上傳的請求,便於獲取參數信息以及上傳的文件 |
HandlerMapping | 請求的處理器匹配器,負責為請求找到合適的 HandlerExecutionChain 處理器執行鏈,包含處理器(handler )和攔截器們(interceptors ) |
HandlerAdapter | 處理器的適配器。因為處理器 handler 的類型是 Object 類型,需要有一個調用者來實現 handler 是怎么被執行。Spring 中的處理器的實現多變,比如用戶處理器可以實現 Controller 接口、HttpRequestHandler 接口,也可以用 @RequestMapping 注解將方法作為一個處理器等,這就導致 Spring MVC 無法直接執行這個處理器。所以這里需要一個處理器適配器,由它去執行處理器 |
HandlerExceptionResolver | 處理器異常解析器,將處理器( handler )執行時發生的異常,解析( 轉換 )成對應的 ModelAndView 結果 |
RequestToViewNameTranslator | 視圖名稱轉換器,用於解析出請求的默認視圖名 |
LocaleResolver | 本地化(國際化)解析器,提供國際化支持 |
ThemeResolver | 主題解析器,提供可設置應用整體樣式風格的支持 |
ViewResolver | 視圖解析器,根據視圖名和國際化,獲得最終的視圖 View 對象 |
FlashMapManager | FlashMap 管理器,負責重定向時,保存參數至臨時存儲(默認 Session) |
Spring MVC 對各個組件的職責划分的比較清晰。DispatcherServlet
負責協調,其他組件則各自做分內之事,互不干擾。
@Controller 注解有什么用?
@Controller
注解標記一個類為 Spring Web MVC 控制器 Controller。Spring MVC 會將掃描到該注解的類,然后掃描這個類下面帶有 @RequestMapping
注解的方法,根據注解信息,為這個方法生成一個對應的處理器對象,在上面的 HandlerMapping 和 HandlerAdapter組件中講到過。
當然,除了添加 @Controller
注解這種方式以外,你還可以實現 Spring MVC 提供的 Controller
或者 HttpRequestHandler
接口,對應的實現類也會被作為一個處理器對象
@RequestMapping 注解有什么用?
@RequestMapping
注解,在上面已經講過了,配置處理器的 HTTP 請求方法,URI等信息,這樣才能將請求和方法進行映射。這個注解可以作用於類上面,也可以作用於方法上面,在類上面一般是配置這個控制器的 URI 前綴
@RestController 和 @Controller 有什么區別?
@RestController
注解,在 @Controller
基礎上,增加了 @ResponseBody
注解,更加適合目前前后端分離的架構下,提供 Restful API ,返回例如 JSON 數據格式。當然,返回什么樣的數據格式,根據客戶端的 ACCEPT
請求頭來決定。
@RequestMapping 和 @GetMapping 注解的不同之處在哪里?
-
@RequestMapping
:可注解在類和方法上;@GetMapping
僅可注冊在方法上 -
@RequestMapping
:可進行 GET、POST、PUT、DELETE 等請求方法;@GetMapping
是@RequestMapping
的 GET 請求方法的特例,目的是為了提高清晰度。
@RequestParam 和 @PathVariable 兩個注解的區別
兩個注解都用於方法參數,獲取參數值的方式不同,@RequestParam
注解的參數從請求攜帶的參數中獲取,而 @PathVariable
注解從請求的 URI 中獲取
返回 JSON 格式使用什么注解?
可以使用 @ResponseBody
注解,或者使用包含 @ResponseBody
注解的 @RestController
注解。
當然,還是需要配合相應的支持 JSON 格式化的 HttpMessageConverter 實現類。例如,Spring MVC 默認使用 MappingJackson2HttpMessageConverter
介紹一下 Spring MVC 中的 WebApplicationContext ?
WebApplicationContext 是實現 ApplicationContext 接口的子類,專門為 WEB 應用准備的
- 它允許從相對於 Web 根目錄的路徑中加載配置文件,完成初始化 Spring MVC 組件的工作。
- 從 WebApplicationContext 中,可以獲取 ServletContext 引用,整個 Web 應用上下文對象將作為屬性放置在 ServletContext 中,以便 Web 應用環境可以訪問 Spring 上下文。
Spring MVC 和 Struts2 的異同?
入口不同
- Spring MVC 的入門是一個 Servlet 控制器。
- Struts2 入門是一個 Filter 過濾器。
配置映射不同,
- Spring MVC 是基於方法開發,傳遞參數是通過方法形參,一般設置為單例。
- Struts2 是基於類開發,傳遞參數是通過類的屬性,只能設計為多例。
視圖不同
- Spring MVC 通過參數解析器是將 Request 對象內容進行解析成方法形參,將響應數據和頁面封裝成 ModelAndView 對象,最后又將模型數據通過 Request 對象傳輸到頁面。其中,如果視圖使用 JSP 時,默認使用 JSTL 。
- Struts2 采用值棧存儲請求和響應的數據,通過 OGNL 存取數據。
介紹下 Spring MVC 攔截器?
Spring MVC 攔截器有三個增強處理的地方:
- 前置處理:在執行方法前執行,全部成功執行才會往下執行方法
- 后置處理:在成功執行方法后執行,倒序
- 已完成處理:不管方法是否成功執行都會執行,不過只會執行前置處理成功的攔截器,倒序
可以通過攔截器進行權限檢驗,參數校驗,記錄日志等操作
Spring MVC 的攔截器和 Filter 過濾器有什么差別?
有以下幾點:
- 功能相同:攔截器和 Filter 都能實現相應的功能,誰也不比誰強
- 容器不同:攔截器構建在 Spring MVC 體系中;Filter 構建在 Servlet 容器之上
- 使用便利性不同:攔截器提供了三個方法,分別在不同的時機執行;過濾器僅提供一個方法,當然也能實現攔截器的執行時機的效果,就是麻煩一些
一般拓展性好的框架,都會提供相應的攔截器或過濾器機制,方便的開發人員做一些拓展
REST 面試題
REST 代表着什么?
REST 代表着抽象狀態轉移,它是根據 HTTP 協議從客戶端發送數據到服務端,例如:服務端的一本書可以以 XML 或 JSON 格式傳遞到客戶端
然而,假如你不熟悉REST,我建議你先看看 REST API design and development 這篇文章來更好的了解它。也可以閱讀知乎上的 《怎樣用通俗的語言解釋 REST,以及 RESTful?》 討論
資源是什么?
資源是指數據在 REST 架構中如何顯示的。將實體作為資源公開 ,它允許客戶端通過 HTTP 方法如:GET, POST,PUT, DELETE 等讀,寫,修改和創建資源
什么是安全的 REST 操作?
REST 接口是通過 HTTP 方法完成操作
- 一些 HTTP 操作是安全的,如 GET 和 HEAD ,它不能在服務端修改資源
- 換句話說,PUT、POST 和 DELETE 是不安全的,因為他們能修改服務端的資源
所以,是否安全的界限,在於是否修改服務端的資源
什么是冪等操作? 為什么冪等操作如此重要?
有一些 HTTP 方法,如:GET,不管你使用多少次它都能產生相同的結果,在沒有任何一邊影響的情況下,發送多個 GET 請求到相同的URI 將會產生相同的響應結果。因此,這就是所謂冪等操作
換句話說,POST方法不是冪等操作 ,因為如果發送多個 POST 請求,它將在服務端創建不同的資源。但是,假如你用 PUT 更新資源,它將是冪等操作。
甚至多個 PUT 請求被用來更新服務端資源,將得到相同的結果
REST 是可擴展的或說是協同的嗎?
是的,REST 是可擴展的和可協作的。它既不托管一種特定的技術選擇,也不定在客戶端或者服務端。你可以用 Java, C++, Python, 或 JavaScript 來創建 RESTful Web 服務,也可以在客戶端使用它們。
我建議你讀一本關於REST接口的書來了解更多,如:RESTful Web Services 。
所以這里的“可拓展”、“協同”對應到我們平時常說的,“跨語言”、“語言無關”
REST 用哪種 HTTP 方法呢?
REST 能用任何的 HTTP 方法,但是,最受歡迎的是:
- 用 GET 來檢索服務端資源
- 用 POST 來創建服務端資源
- 用 PUT 來更新服務端資源
- 用 DELETE 來刪除服務端資源
恰好,這四個操作,對上我們日常邏輯的 CRUD 操作
刪除的 HTTP 狀態返回碼是什么 ?
在刪除成功之后,您的 REST API 應該返回什么狀態代碼,並沒有嚴格的規則。它可以返回 200 或 204 沒有內容
- 一般來說,如果刪除操作成功,響應主體為空,返回 204
- 如果刪除請求成功且響應體不是空的,則返回 200
REST API 是無狀態的嗎?
是的,REST API 應該是無狀態的,因為它是基於 HTTP 的,它也是無狀態的
REST API 中的請求應該包含處理它所需的所有細節。它不應該依賴於以前或下一個請求或服務器端維護的一些數據,例如會話
REST 規范為使其無狀態設置了一個約束,在設計 REST API 時,你應該記住這一點
REST安全嗎? 你能做什么來保護它?
安全是一個寬泛的術語。它可能意味着消息的安全性,這是通過認證和授權提供的加密或訪問限制提供的
REST 通常不是安全的,需要開發人員自己實現安全機制
參考文章:芋道源碼《精盡 Spring MVC 源碼分析》