知識庫 / Spring / Spring MVC RSS 訂閱

Spring MVC 面試常見問題

Spring MVC
HongKong
5
01:35 PM · Dec 06 ,2025

1. 簡介

Spring MVC 是 Spring 框架的原生 Web 框架,基於 Servlet API 構建。它提供 Model-View-Controller 架構,可用於開發靈活的 Web 應用程序。

在本教程中,我們將重點關注與該框架相關的問題,因為它經常是 Spring 開發者面試中的一個重要話題。

要了解更多關於 Spring Framework 的問題,您可以查看我們面試問題系列中的另一個 Spring 相關文章。

2. Spring MVC 基礎問題

Q1. 為什麼應該使用 Spring MVC?

Spring MVC 實施了明確的關注點分離,這使得我們能夠輕鬆地開發和單元測試我們的應用程序。

以下概念:

  • Dispatcher Servlet
  • Controllers
  • View Resolvers
  • Views, Models
  • ModelAndView
  • Model 和 Session 屬性

完全獨立於彼此,並且每個都負責僅一項任務。

因此,MVC 提供了很大的靈活性。它基於接口(以及提供的實現類),我們可以使用自定義接口來配置框架的各個部分。

另一個重要的方面是,我們與特定的視圖技術(例如 JSP)無關,但我們有權選擇我們最喜歡的。

此外,我們不僅在 Web 應用程序開發中使用 Spring MVC,還用於創建 RESTful Web 服務。

<h3><strong>Q2. 什麼是 <em title="@Autowired">@Autowired</em> 標註的作用?</strong></h3
<p><strong><em>@Autowired</em> 標註可用於注入 Bean,通過類型</strong>.  該標註允許 Spring 解決和注入協作 Bean 到你的 Bean 中。</p>
<p>欲瞭解更多詳情,請參閲關於 Spring 中 <em title="@Autowired">@Autowired</em> 的教程。</p>
<p><strong>Q3. 解釋一個 Model 屬性</strong></p>
<p><em>@ModelAttribute</em> 標註是 Spring MVC 中最重要的標註之一。 <strong title="It binds a method parameter or a method return value to a named model attribute and then exposes it to a web view">它將方法參數或方法返回值綁定到名稱為模型的屬性,然後將其暴露給 Web 視圖。</strong></p>
<p>如果我們在方法級別使用它,則表示該方法的目的是添加一個或多個模型屬性。</p>
<p>另一方面,當作為方法參數使用時,它表示該參數應從模型中檢索。 如果不存在,我們應該首先實例化它,然後將其添加到模型中。 一旦在模型中存在,我們應該從所有具有匹配名稱的請求參數中填充參數字段。</p>
<p>有關此標註的更多信息,請參閲與 <em title="@ModelAttribute">@ModelAttribute</em> 標註相關的文章。</p>
<p><strong title="Q4. Explain the Difference Between <em title="@Controller">@Controller</em> and <em title="@RestController">@RestController</em>?>">Q4. 解釋 <em title="@Controller">@Controller</em> 和 <em title="@RestController">@RestController</em> 之間的區別是什麼?</strong></p>
<p><em>@Controller</em> 和 <em>@RestController</em> 標註的主要區別在於 <strong title="the <em title="@ResponseBody">@ResponseBody</em> annotation is automatically included in the <em title="@RestController">@RestController</em>"><em>@ResponseBody</em> 標註自動包含在 <em title="@RestController">@RestController</em> 中。</strong> 這意味着我們不需要用 <em title="@ResponseBody">@ResponseBody</em> 標註我們的處理方法。 如果要在 <em title="@Controller">@Controller</em> 類中編寫響應類型直接到 HTTP 響應體,則需要這樣做。</p>
<p>Q5. 描述一個 <em title="@PathVariable">@PathVariable</em></p>
<p><strong title="We can use the <em title="@PathVariable">@PathVariable</em> annotation as a handler method parameter in order to extract the value of a URI template variable">我們可以使用 <em title="@PathVariable">@PathVariable</em> 標註作為處理方法參數來提取 URI 模板變量的值。</strong></p>
<p>例如,如果我們想從 <em title="www.mysite.com/user/123">www.mysite.com/user/123</em> 檢索 ID 上的用户,我們應該將方法映射到控制器中的 <em title=" /user/{id}">/user/{id}</em>。</p>
@RequestMapping("/user/{id}")
public String handleRequest(@PathVariable("id") String userId, Model map) {}

路徑變量 (@PathVariable) 只有一個元素,名為 value. 它是一個可選參數,用於定義 URI 模板變量名。 如果省略 value 元素,則 URI 模板變量名必須與方法參數名匹配。

還可以有多個 @PathVariable 註解,可以通過依次聲明它們來實現:

@RequestMapping("/user/{userId}/name/{userName}")
public String handleRequest(@PathVariable String userId,
  @PathVariable String userName, Model map) {}

或者將它們全部放入一個Map<String, String>MultiValueMap<String, String> 中:

@RequestMapping("/user/{userId}/name/{userName}")
public String handleRequest(@PathVariable Map<String, String> varsMap, Model map) {}

Q6. 使用 Spring MVC 進行驗證

Spring MVC 默認支持 JSR-303 規範。我們需要將 JSR-303 和其實現依賴項添加到 Spring MVC 應用程序中。 Hibernate Validator 只是我們可用的 JSR-303 實現之一。

JSR-303 是 Java Bean Validation API 的規範,屬於 Jakarta EE 和 JavaSE 的一部分,它確保 Bean 的屬性滿足特定標準,使用諸如 @NotNull@Min@Max 這樣的註解。關於驗證的更多信息請參考 Java Bean Validation Basics 文章。

Spring 提供 @Validator 註解和 BindingResult 類。 在控制器請求處理方法中,當數據無效時,Validator 實現將引發錯誤。然後我們可以使用 BindingResult 類來獲取這些錯誤。

除了使用現有實現之外,我們還可以創建自己的實現。要做到這一點,首先我們需要創建一個符合 JSR-303 規範的註解。然後,我們需要實現 Validator 類。另一種方法是實現 Spring 的 Validator 接口,並通過 @InitBinder 註解在 Controller 類中設置它。

要了解如何實現和使用自己的驗證,請參閲關於自定義驗證在 Spring MVC 中的教程。

Q7. 什麼是 <em @RequestBody</em><em @ResponseBody</em> 註解?

@RequestBody 註解,用作處理器方法參數,將 HTTP 請求體綁定到傳輸對象或域對象上。Spring 會自動將傳入的 HTTP 請求解析為 Java 對象,使用 HTTP 消息轉換器。

當我們使用 @ResponseBody 註解在 Spring MVC 控制器的方法上,它表示我們將方法的返回類型直接寫入 HTTP 響應體。我們不需要將其放入 Model 中,Spring 也不會將其解釋為視圖名稱。

請查看關於 @RequestBody@ResponseBody 的文章以獲取更多詳細信息。

### Q8. 解釋 ModelModelMapModelAndView?

Model 接口定義了一個模型屬性持有者。ModelMap 具有類似的作用,能夠傳遞一組值。它將這些值視為一個 Map 中的值。請注意,在 Model (ModelMap) 中,我們只能存儲數據。我們放入數據並返回視圖名稱。

另一方面,使用 ModelAndView 時,我們返回的是對象本身。我們在返回的對象中設置所有必需的信息,如數據和視圖名稱。

你可以找到更多詳細信息在關於 Model, ModelMapModelView 的文章中。

### Q9. 解釋 SessionAttributesSessionAttribute

@SessionAttributes 註解用於在用户的會話中存儲模型屬性。我們將其放在控制器類級別,如我們在 Spring MVC 的會話屬性文章中所展示的:

@Controller
@RequestMapping("/sessionattributes")
@SessionAttributes("todos")
public class TodoControllerWithSessionAttributes {

    @GetMapping("/form")
    public String showForm(Model model,
      @ModelAttribute("todos") TodoList todos) {
        // method body
        return "sessionattributesform";
    }

    // other methods
}

在之前的示例中,如果模型屬性 ‘todos’ 與 @ModelAttribute@SessionAttributes 的屬性名稱相同,則該屬性將添加到會話中。

如果想要從管理全局的會話中檢索現有屬性,則將使用 @SessionAttribute 註解作為方法參數:

@GetMapping
public String getTodos(@SessionAttribute("todos") TodoList todos) {
    // method body
    return "todoView";
}

Q10. @EnableWebMvc 的作用是什麼?

@EnableWebMvc 註解的作用是啓用 Spring MVC 通過 Java 配置。

它相當於 XML 配置中的 <mvc: annotation-driven>。該註解從 WebMvcConfigurationSupport 導入 Spring MVC 配置。它支持使用 @Controller 註解的類,這些類使用 @RequestMapping 將傳入的請求映射到處理方法。

您可以在我們的 Spring @Enable 註解指南中瞭解更多關於此和類似註解的信息。

Q11. Spring 中的 ViewResolver 是什麼?

ViewResolver 允許應用程序在瀏覽器中渲染模型,而無需將實現與特定的視圖技術綁定,通過將視圖名稱映射到實際視圖來實現這一點。

要了解更多關於 ViewResolver 的信息,請參閲 Spring MVC 中的 ViewResolver 指南。

Q12. 什麼是 <em>BindingResult</em>

BindingResult 是來自 org.springframework.validation 包中的一個接口,它代表驗證結果。我們可以使用它來檢測和報告提交表單中的錯誤。調用它非常簡單——我們只需要確保將其作為參數放在我們正在驗證的表單對象之後。可選的 Model 參數應該放在 BindingResult 之後,如自定義驗證器教程所示:

@PostMapping("/user")
public String submitForm(@Valid NewUserForm newUserForm, 
  BindingResult result, Model model) {
    if (result.hasErrors()) {
        return "userHome";
    }
    model.addAttribute("message", "Valid form");
    return "userHome";
}

當 Spring 看到帶有 @Valid 註解的元素時,它首先會嘗試找到用於驗證該對象的驗證器。然後,它會拾取驗證註解並調用驗證器。最後,它會將找到的錯誤放入 BindingResult 中,並將該結果添加到視圖模型中。

Q13. 什麼是表單後置對象?

表單後置對象(或命令對象)只是一個POJO,它收集來自我們提交的表單的數據。

請注意,它不包含任何邏輯,只包含數據。

要了解如何使用表單後置對象與 Spring MVC 中的表單,請查看我們關於 Spring MVC 中表單的文章。

Q14. <em @Qualifier/> 註解的作用是什麼?

它與 `` 註解一起使用,以避免在存在多個相同類型的 Bean 時產生混淆。

下面是一個示例。我們已經在 XML 配置中聲明瞭兩個相似的 Bean:

<bean id="person1" class="com.baeldung.Person" >
    <property name="name" value="Joe" />
</bean>
<bean id="person2" class="com.baeldung.Person" >
    <property name="name" value="Doe" />
</bean>

當我們嘗試注入 Bean 時,將會得到 org.springframework.beans.factory.NoSuchBeanDefinitionException 異常。為了解決這個問題,我們需要使用 @Qualifier 告訴 Spring 應該注入哪個 Bean:

@Autowired
@Qualifier("person1")
private Person person;

Q15. @Required 註解的作用是什麼?

@Required 註解用於設置方法的屬性,表示具有此註解的 Bean 屬性必須在配置時進行填充。否則,Spring 容器將拋出 BeanInitializationException 異常。

此外,@Required@Autowired 區別在於,@Required 僅限於設置方法,而 @Autowired 則不然。 @Autowired 可以用於構造函數和字段的注入,而 @Required 僅檢查屬性是否已設置。

下面是一個示例:

public class Person {
    private String name;
 
    @Required
    public void setName(String name) {
        this.name = name;
    }
}

現在,需要像這樣在XML配置中設置Person bean 的 name

<bean id="person" class="com.baeldung.Person">
    <property name="name" value="Joe" />
</bean>

請注意, 默認不適用於基於 Java 的 。如果您需要確保所有屬性都已設置,可以在創建 Bean 的 註釋方法中進行操作。

Q16. 描述 Front Controller 模式

在 Front Controller 模式中,所有請求首先會發送到 Front Controller,而不是 Servlet它會確保響應已準備好並將其發送回瀏覽器。 這樣我們就可以在一個地方控制來自外部世界的一切

Front Controller 將首先識別應處理請求的 Servlet。 然後,在從 Servlet 獲得數據後,它將決定渲染哪個視圖,並最終將渲染的視圖作為響應發送:

要查看實現細節,請查看 Java 中的 Front Controller 模式指南。

Q17. 模型 1 和模型 2 的架構是什麼?

模型 1 和模型 2 代表了在設計 Java Web 應用程序時常用的兩種設計模式。

在模型 1 中,請求到達一個 Servlet 或 JSP,並由其處理。Servlet 或 JSP 處理請求,處理業務邏輯,檢索和驗證數據,並生成響應:

由於這種架構易於實現,我們通常在小型和簡單的應用程序中使用它。

另一方面,它不適合大型 Web 應用程序。功能通常在 JSP 中重複,業務邏輯和呈現邏輯耦合在一起。

模型 2 基於 MVC 設計模式,並從邏輯中分離了視圖。

此外,我們可以在 MVC 模式中區分三個模塊:模型、視圖和控制器。模型代表應用程序的動態數據結構。它負責數據和業務邏輯的操縱。視圖負責顯示數據,而控制器作為前兩者之間的接口。

在模型 2 中,請求傳遞給控制器,控制器處理所需邏輯以獲取應顯示的正確內容。控制器將內容放入請求中,通常作為 JavaBean 或 POJO。它還決定哪個視圖應呈現內容,然後將請求傳遞給該視圖。然後,視圖呈現數據:

3. 高級 Spring MVC 問題

Q18. @Controller@Component@Repository,和@Service註解在Spring中有什麼區別?

根據官方Spring文檔,@Component是一個通用的樣板,用於任何Spring管理的組件。 @Repository@Service,和@Controller@Component的特殊化類型,用於更具體的用例,例如在持久化層、服務層和表現層,分別使用。

下面我們來看這三個註解的具體用例:

  • @Controller – 表示該類扮演控制器角色,並檢測該類中定義的@RequestMapping註解
  • @Service – 表示該類持有業務邏輯並調用存儲層的方法
  • @Repository – 表示該類定義了一個數據存儲庫;它的工作是捕獲平台特定的異常並將其作為Spring的統一未檢查異常重新拋出

Q19. 什麼是 DispatcherServletContextLoaderListener?

簡單來説,在 Front Controller 設計模式中,一個控制器負責將傳入的 HttpRequests 指向應用程序中的所有其他控制器和處理程序。

Spring 的 DispatcherServlet 實現這個模式,因此負責正確地協調 HttpRequests 到正確的處理程序。

另一方面,ContextLoaderListener 啓動和關閉 Spring 的根 WebApplicationContext。它將 ApplicationContext 的生命週期與 ServletContext 的生命週期聯繫起來。我們可以使用它來定義跨不同 Spring 容器共享的 Bean。

關於 DispatcherServlet 的更多詳細信息,請參閲此教程。

Q20. 什麼是 MultipartResolver 以及我們應該何時使用它?

MultipartResolver 接口用於上傳文件。Spring 框架提供了一個用於與 Commons FileUpload 配合使用的 MultipartResolver 實現,以及另一個用於與 Servlet 3.0 多部分請求解析配合使用的實現。

通過使用這些實現,我們可以支持我們在 Web 應用程序中進行文件上傳。

Q21. Spring MVC 攔截器是什麼以及如何使用它?

Spring MVC 攔截器允許我們攔截客户端請求並在以下三個位置對其進行處理——在處理之前、在處理之後或在請求完成(視圖渲染後)時。

攔截器可用於處理橫切關注點,並避免重複處理代碼,例如日誌記錄、在 Spring 模型中更改全局參數等。

有關詳細信息和各種實現,請參閲《Spring MVC HandlerInterceptor 簡介》文章。

Q22. 什麼是 Init Binder?

標註了 @InitBinder 註解的方法用於自定義請求參數、URI 模板和後端/命令對象。 我們在控制器中定義它,並有助於控制請求。 在這種方法中,我們註冊和配置自定義的 <em>PropertyEditor</em>、格式化器和驗證器。

該註解包含 <em>value</em> 元素。 如果我們沒有設置它,則標註了 @InitBinder 的方法將在每個 HTTP 請求上被調用。 如果我們設置了值,則方法僅適用於名稱與 <em>value</em> 元素相對應的特定命令/表單屬性和/或請求參數。

請記住,其中一個參數必須是 WebDataBinder。 其他參數可以是處理方法支持的任何類型,除了命令/表單對象和相應的驗證結果對象。

Q23. 解釋控制器建議 (Controller Advice)

@ControllerAdvice 註解允許我們編寫適用於廣泛控制器的全局代碼。 我們可以將控制器的範圍與選擇的包或特定註解聯繫起來。

默認情況下,@ControllerAdvice 適用於標註了 @Controller (或 @RestController) 的類。 我們還具有一些屬性,用於如果我們想要更具體時使用。

如果我們想將適用的類限制為包,則應將包的名稱添加到註解中:

@ControllerAdvice("my.package")
@ControllerAdvice(value = "my.package")
@ControllerAdvice(basePackages = "my.package")

還可以使用多個包,但在此情況下,我們需要使用數組而不是 String

除了通過包名限制之外,還可以通過使用該包中的一個類或接口來實現

@ControllerAdvice(basePackageClasses = MyClass.class)

assignableTypes’ 元素應用到特定類上,同時 ‘annotations’ 應用到特定註解。

需要注意的是,我們應該將其與 @ExceptionHandler 一起使用。 這種組合將使我們能夠配置全局且更具體的錯誤處理機制,而無需為每個控制器類都實施它。

Q24.  @ExceptionHandler 註解的作用是什麼?

@ExceptionHandler 註解允許我們定義一個方法,該方法將處理異常。 我們可能獨立使用該註解,但與 @ControllerAdvice 一起使用是更好的選擇。 這樣,我們就可以建立全局錯誤處理機制。 這樣,我們就不需要為每個控制器編寫異常處理代碼。

下面是關於 REST 中 Spring 的錯誤處理的文章中的一個示例:

@ControllerAdvice
public class RestResponseEntityExceptionHandler
  extends ResponseEntityExceptionHandler {

    @ExceptionHandler(value = { IllegalArgumentException.class,
      IllegalStateException.class })
    protected ResponseEntity<Object> handleConflict(RuntimeException ex,
      WebRequest request) {
        String bodyOfResponse = "This should be application specific";
        return handleExceptionInternal(ex, bodyOfResponse, new HttpHeaders(),
          HttpStatus.CONFLICT, request);
    }
}

我們也應該注意到,這將為所有拋出<em>@ExceptionHandler</em>方法的控制器提供方法,這些方法處理<em>IllegalArgumentException</em>或<em>IllegalStateException</em>異常。<em>@ExceptionHandler</em>中聲明的異常應與方法參數中使用的異常相匹配,否則,運行時異常解決機制將失敗。

請記住,這裏可以定義多個<em>@ExceptionHandler</em>方法來處理同一個異常。但是,由於 Spring 會抱怨並拋出異常,導致啓動失敗,因此不能在同一個類中進行操作。

另一方面,如果我們分別在兩個類中定義這些異常處理程序,應用程序將啓動,但它將使用它找到的第一個處理程序,這很可能不是正確的。

Q25. Web 應用程序中的異常處理

在 Spring MVC 中,我們有三種異常處理選項:

  • 按異常
  • 按控制器
  • 全局

如果在 Web 請求處理期間拋出未處理的異常,服務器將返回 HTTP 500 響應。為了防止這種情況發生,我們應該使用<em>@ResponseStatus</em>註解來標註我們的自定義異常。這類異常由<em>HandlerExceptionResolver</em>處理。

這將導致服務器在控制器方法拋出我們的異常時,返回具有指定狀態碼的適當 HTTP 響應。請記住,為了使這種方法有效,我們不應在其他地方處理我們的異常。

另一種處理異常的方法是使用<em>@ExceptionHandler</em>註解。我們將<em>@ExceptionHandler</em>方法添加到任何控制器中,並使用它們來處理從該控制器內部拋出的異常。這些方法可以處理異常,而無需使用<em>@ResponseStatus</em>註解,將用户重定向到專用錯誤視圖,或構建完全自定義的錯誤響應。

我們還可以將 Servlet 相關對象(<em>HttpServletRequest</em>、<em>HttpServletResponse</em>、<em>HttpSession</em> 和 <em>Principal</em>)作為處理程序方法的參數傳遞。但是,請記住,我們不能將<em>Model</em>對象作為參數直接放入。

第三種處理錯誤的方法是使用<em>@ControllerAdvice</em>類。它允許我們應用相同的技術,但這次在應用程序級別,而不是僅限於特定控制器。要啓用此功能,我們需要使用<em>@ControllerAdvice</em>和<em>@ExceptionHandler</em>。這樣,異常處理程序將處理任何控制器拋出的異常。

有關此主題的更多詳細信息,請參閲“使用 Spring 處理 REST 中的錯誤”文章。

4. 結論

在本文中,我們探討了一些與Spring MVC相關的可能在Spring開發人員的技術面試中出現的問題。您應該將這些問題作為進一步研究的起點,因為這絕不是一個詳盡的清單。

祝您在任何即將到來的面試中好運!

user avatar
0 位用戶收藏了這個故事!
收藏

發佈 評論

Some HTML is okay.