Java筆試面試-SpringMVC 核心

2021-02-20 不止於編程
Spring MVC簡介

Spring MVC(Spring Web MVC)是 Spring Framework 提供的 Web 組件,它的實現基於 MVC 的設計模式:Controller(控制層)、Model(模型層)、View(視圖層),提供了前端路由映射、視圖解析等功能,讓 Java Web 開發變得更加簡單,也屬於 Java 開發中必須要掌握的熱門框架。

執行流程

Spring MVC 的執行流程如下:

客戶端發送請求至前端控制器(DispatcherServlet)前端控制器將獲取的 ModelAndView 對象傳給視圖解析器(ViewResolver)

流程如下圖所示:

核心組件

Spring MVC 的核心組件如下列表所示:

DispatcherServlet:核心處理器(也叫前端控制器),負責調度其他組件的執行,可降低不同組件之間的耦合性,是整個 Spring MVC 的核心模塊。Handler:處理器,完成具體業務邏輯,相當於 Servlet 或 Action。HandlerMapping:DispatcherServlet 是通過 HandlerMapping 將請求映射到不同的 Handler。HandlerInterceptor:處理器攔截器,是一個接口,如果我們需要做一些攔截處理,可以來實現這個接口。HandlerExecutionChain:處理器執行鏈,包括兩部分內容,即 Handler 和 HandlerInterceptor(系統會有一個默認的 HandlerInterceptor,如果需要額外攔截處理,可以添加攔截器設置)。HandlerAdapter:處理器適配器,Handler 執行業務方法之前,需要進行一系列的操作包括表單數據的驗證、數據類型的轉換、將表單數據封裝到 POJO 等,這一系列的操作,都是由 HandlerAdapter 來完成,DispatcherServlet 通過 HandlerAdapter 執行不同的 Handler。ModelAndView:裝載了模型數據和視圖信息,作為 Handler 的處理結果,返回給 DispatcherServlet。ViewResolver:視圖解析器,DispatcherServlet 通過它將邏輯視圖解析成物理視圖,最終將渲染結果響應給客戶端。

自動類型轉換  自動類型轉換指的是,Spring MVC 可以將表單中的欄位,自動映射到實體類的對應屬性上,請參考以下示例。

1.JSP 頁面代碼

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<body>
<form action="add">
    名稱:<input type="input" name="name"><br>
    年齡:<input type="input" name="age"><br>
    <input type="submit" value=" 提交 ">
</form>
</body>
</html>

2. 編寫實體類

public class PersonDTO {
    private String name;
    private int age;

    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
}

3. 編寫控制器

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class PersonController {
    @RequestMapping(value = "/add", produces = "text/plain;charset=utf-8")
    public String add(PersonVO person) {
        return person.getName() + ":" + person.getAge();
    }
}

中文亂碼處理

業務的操作過程中可能會出現中文亂碼的情況,以下是處理中文亂碼的解決方案。  第一步,在 web.xml 添加編碼過濾器,配置如下:

<filter>
    <filter-name>encodingFilter</filter-name>
    <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
    <init-param>
        <param-name>encoding</param-name>
        <param-value>UTF-8</param-value>
    </init-param>
</filter>
<filter-mapping>
    <filter-name>encodingFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

第二步,設置 RequestMapping 的 produces 屬性,指定返回值類型和編碼,如下所示:

@RequestMapping(value  = "/add", produces = "text/plain;charset=utf-8")

攔截器  在 Spring MVC 中可以通過配置和實現 HandlerInterceptor 接口,來實現自己的攔截器。

1. 配置全局攔截器

在 Spring MVC 的配置文件中,添加如下配置:

<mvc:interceptors>
  <bean class="com.learning.core.MyInteceptor"></bean>
</mvc:interceptors>

2. 添加攔截器實現代碼

攔截器的實現代碼如下:

import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
 * 攔截器
 **/
public class MyInteceptor implements HandlerInterceptor {
    // 在業務處理器處理請求之前被調用
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
                             Object handler) throws Exception {
        System.out.println("preHandle");
        return true;
    }
    // 在業務處理器處理請求完成之後,生成視圖之前執行
    public void postHandle(HttpServletRequest request, HttpServletResponse response,
                           Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("postHandle");
    }
    // 在 DispatcherServlet 完全處理完請求之後被調用
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response,
                                Object handler, Exception ex) throws Exception {
        System.out.println("afterCompletion");
    }
}

參數驗證1. pom.xml 添加驗證依賴包

配置如下:

<!-- Hibernate 參數驗證包 -->
<dependency>
    <groupId>org.hibernate.validator</groupId>
    <artifactId>hibernate-validator</artifactId>
    <version>6.0.17.Final</version>
</dependency>

2. 開啟註解驗證

在 Spring MVC 的配置文件中,添加如下配置信息:

<mvc:annotation-driven />

3. 編寫控制器

代碼如下:

import com.google.gson.JsonObject;
import com.learning.pojo.PersonDTO;
import org.springframework.validation.BindingResult;
import org.springframework.validation.ObjectError;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;

@RestController
public class PersonController {
    @RequestMapping(value = "/check", produces = "text/plain;charset=utf-8")
    public String check(@Validated PersonDTO person, BindingResult bindResult) {
        // 需要 import com.google.gson.Gson
        JsonObject result = new JsonObject();
        StringBuilder errmsg = new StringBuilder();
        if (bindResult.hasErrors()) {
            List<ObjectError> errors = bindResult.getAllErrors();
            for (ObjectError error : errors) {
                errmsg.append(error.getDefaultMessage());
            }
            result.addProperty("status", -1);
        } else {
            result.addProperty("status", 1);
        }
        result.addProperty("errmsg", errmsg.toString());
        return result.toString();
    }

}

4. 編寫實體類

代碼如下:

import javax.validation.constraints.Min;
import javax.validation.constraints.NotNull;
public class PersonDTO {
    @NotNull(message = "姓名不能為空")
    private String name;
    @Min(value = 18,message = "年齡不能低於18歲")
    private int age;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
}

更多驗證註解,如下所示:

註解運行時檢查@AssertFalse被註解的元素必須為 false@AssertTrue被註解的元素必須為 true@DecimalMax(value)被註解的元素必須為一個數字,其值必須小於等於指定的最大值@DecimalMin(Value)被註解的元素必須為一個數字,其值必須大於等於指定的最小值@Digits(integer=, fraction=)被註解的元素必須為一個數字,其值必須在可接受的範圍內@Future被註解的元素必須是日期,檢查給定的日期是否比現在晚@Max(value)被註解的元素必須為一個數字,其值必須小於等於指定的最大值@Min(value)被註解的元素必須為一個數字,其值必須大於等於指定的最小值@NotNull被註解的元素必須不為 null@Null被註解的元素必須為 null@Past(java.util.Date/Calendar)被註解的元素必須過去的日期,檢查標註對象中的值表示的日期比當前早@Pattern(regex=, flag=)被註解的元素必須符合正則表達式,檢查該字符串是否能夠在 match 指定的情況下被 regex 定義的正則表達式匹配@Size(min=, max=)被註解的元素必須在制定的範圍(數據類型:String、Collection、Map、Array)@Valid遞歸的對關聯對象進行校驗, 如果關聯對象是個集合或者數組,那麼對其中的元素進行遞歸校驗,如果是一個 map,則對其中的值部分進行校驗@CreditCardNumber對信用卡號進行一個大致的驗證@Email被注釋的元素必須是電子郵箱地址@Length(min=, max=)被註解的對象必須是字符串的大小必須在制定的範圍內@NotBlank被註解的對象必須為字符串,不能為空,檢查時會將空格忽略@NotEmpty被注釋的對象必須不為空(數據:String、Collection、Map、Array)@Range(min=, max=)被注釋的元素必須在合適的範圍內(數據:BigDecimal、BigInteger、String、byte、short、int、long 和原始類型的包裝類)@URL(protocol=, host=, port=, regexp=, flags=)被註解的對象必須是字符串,檢查是否是一個有效的 URL,如果提供了 protocol、host 等,則該 URL 還需滿足提供的條件

5. 執行結果

執行結果,如下圖所示:

筆試面試題

1. 簡述一下 Spring MVC 的執行流程?

答:前端控制器(DispatcherServlet) 接收請求,通過映射從 IoC 容器中獲取對應的 Controller 對象和 Method 方法,在方法中進行業務邏輯處理組裝數據,組裝完數據把數據發給視圖解析器,視圖解析器根據數據和頁面信息生成最終的頁面,然後再返回給客戶端。

2. POJO 和 JavaBean 有什麼區別?

答:POJO 和 JavaBean 的區別如下:

POJO(Plain Ordinary Java Object)普通 Java 類,具有 getter/setter 方法的普通類都就可以稱作 POJO,它是 DO/DTO/BO/VO 的統稱,禁止命名成 xxxPOJO。JavaBean 是 Java 語言中的一種可重用組件,JavaBean 的構造函數和行為必須符合特定的約定:這個類必須有一個公共的預設構造函數;這個類的屬性使用 getter/setter 來訪問,其他方法遵從標準命名規範;這個類應是可序列化的。

簡而言之,當一個 POJO 可序列化,有一個無參的構造函數,它就是一個 JavaBean。

3. 如何實現跨域訪問?

答:常見的跨域的實現方式有兩種:使用 JSONP 或者在伺服器端設置運行跨域。伺服器運行跨域的代碼如下:

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class MyConfiguration {
    @Bean
    public WebMvcConfigurer corsConfigurer() {
        return new WebMvcConfigurer() {
            @Override
            public void addCorsMappings(CorsRegistry registry) {
                // 設置允許跨域的請求規則
                registry.addMapping("/api/**");
            }
        };
    }
}

4. 以下代碼描述正確的是?

@RequestMapping(value="/list",params={"age=10"}
public String list(){
   // do something
}

A:age 參數不傳遞的時候,默認值是 10B:age 參數可以為空C:age 參數不能為空D:以上都不對

答:C題目解析:params={「age=10」} 表示必須包含 age 參數,且值必須等於 10。

5. @RequestMapping 註解的常用屬性有哪些?

答:@RequestMapping 常用屬性如下:

value:指定 URL 請求的實際地址,用法:@RequestMapping(value="/index");method:指定請求的 method 類型,如 GET/POST/PUT/DELETE 等,用法:@RequestMapping(value="/list",method=RequestMethod.POST);params:指定請求參數中必須包含的參數名稱,如果不存在該名稱,則無法調用此方法,用法:@RequestMapping(value="/list",params={「name」,「age」})。

6. 訪問以下接口不傳遞任何參數的情況下,執行的結果是?

@RequestMapping(value="/list")
@ResponseBody
public String list(int id){
    return "id="+id;
}

A:id=0B:id=C:頁面報錯 500D:id=null

答:C題目解析:頁面報錯會提示:可選的參數「id」不能轉為 null,因為基本類型不能賦值 null,所以會報錯。

7.訪問頁面時顯示 403 代表的含義是?

A:伺服器繁忙B:找不到該頁面C:禁止訪問D:伺服器跳轉中

答:C

題目解析:常用 HTTP 狀態碼及對應的含義:

400:錯誤請求,伺服器不理解請求的語法401:未授權,請求要求身份驗證403:禁止訪問,伺服器拒絕請求500:伺服器內部錯誤,伺服器遇到錯誤,無法完成請求502:錯誤網關,伺服器作為網關或代理,從上遊伺服器收到無效響應504:網關超時,伺服器作為網關或代理,但是沒有及時從上遊伺服器收到請求

8.forward 和 redirect 有什麼區別?

答:forward 和 redirect 區別如下:

forward 表示請求轉發,請求轉發是伺服器的行為;redirect 表示重定向,重定向是客戶端行為;forward 是伺服器請求資源,伺服器直接訪問把請求的資源轉發給瀏覽器,瀏覽器根本不知道伺服器的內容是從哪來的,因此它的地址欄還是原來的地址;redirect 是服務端發送一個狀態碼告訴瀏覽器重新請求新的地址,因此地址欄顯示的是新的 URL;forward 轉發頁面和轉發到的頁面可以共享 request 裡面的數據;redirect 不能共享數據;從效率來說,forward 比 redirect 效率更高。

9. 訪問以下接口不傳遞任何參數的情況下,執行的結果是?

@RequestMapping(value="/list")
@ResponseBody
public String list(Integer id){
    return "id="+id;
}

A:id=0B:id=C:頁面報錯 500D:id=null

答:D

題目解析:包裝類可以賦值 null,不會報錯。

10. Spring MVC 中如何在後端代碼中實現頁面跳轉?

答:在後端代碼中可以使用 forward:/index.jsp 或 redirect:/index.jsp 完成頁面跳轉,前者 URL 地址不會發生改變,或者 URL 地址會發生改變,完整跳轉代碼如下:

@RequestMapping("/redirect")
public String redirectTest(){
    return "redirect:/index.jsp";
}

11. Spring MVC 的常用註解有哪些?

答:Spring MVC 的常用註解如下:

@ResponseBody :標識返回的數據不是 html 標籤的頁面,而是某種格式的數據,如 JSON、XML 等;@RestController:相當於 @Controller 加 @ResponseBody 的組合效果;@Component:標識為 Spring 的組件;@RequestMapping:用於映射請求地址的註解;@RequestHeader:可以把 Request 請求的 header 值綁定到方法的參數上。

12. 攔截器的使用場景有哪些?

答:攔截器的典型使用場景如下:

日誌記錄:可用於記錄請求日誌,便於信息監控和信息統計;統一安全處理:可用於統一的安全效驗或參數的加密 / 解密等。

13. Spring MVC 如何排除攔截目錄?

答:在 Spring MVC 的配置文件中,添加 <mvc:exclude-mapping path="/static/**" /> ,用於排除攔截目錄,完整配置的示例代碼如下:

<mvc:interceptors>
    <mvc:interceptor>
        <mvc:mapping path="/**" />
        <!-- 排除攔截地址 -->
        <mvc:exclude-mapping path="/api/**" />
        <bean class="com.learning.core.MyInteceptor"></bean>
    </mvc:interceptor>
</mvc:interceptors>

14.@Validated 和 @Valid 有什麼區別 ?

答:@Validated 和 @Valid 都用於參數的效驗,不同的是:

@Valid 是 Hibernate 提供的效驗機制,Java 的 JSR 303 聲明了 @Valid 這個類接口,而 Hibernate-validator 對其進行了實現;@Validated 是 Spring 提供的效驗機制,@Validation 是對 @Valid 進行了二次封裝,提供了分組功能,可以在參數驗證時,根據不同的分組採用不同的驗證機制;@Valid 可用在成員對象的屬性欄位驗證上,而 @Validated 不能用在成員對象的屬性欄位驗證上,也就是說 @Validated 無法提供嵌套驗證。

15.Spring MVC 有幾種獲取 request 的方式?

答:Spring MVC 獲取 request 有以下三種方式:

① 從請求參數中獲取

@RequestMapping("/index")
@ResponseBody
public void index(HttpServletRequest request){
  // do something
}

該方法實現的原理是 Controller 開始處理請求時,Spring 會將 request 對象賦值到方法參數中。

② 通過 RequestContextHolder上下文獲取 request 對象

@RequestMapping("/index")
@ResponseBody
public void index(){
    ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes)RequestContextHolder.getRequestAttributes();
    HttpServletRequest request = servletRequestAttributes.getRequest();
    // do something
}

③ 通過自動注入的方式

@Controller
public class HomeController{
    @Autowired
    private HttpServletRequest request; // 自動注入 request 對象
    // do something
}

相關焦點

  • 【慧程微課堂-Java】SpringMVC的運行流程
    【2】搭建 springmvc 的運行環境[1] 導入 jar 包   spring-framework-4.0.0.RELEASE\requried\   所有的 jar 包[2][4] SpringMVCTest.java
  • 圖解 SpringMVC 五大組件
    SpringMVC最重要的就是五大組件下面一一介紹這五大控制項1.DispatcherServlet這個控制項是SpringMVC 最核心的一個控制項,顧名思義其實他就是一個Servlet,是Springorg.springframework.web.servlet.DispatcherServlet</servlet-class>     <init-param>          <param-name>contextConfigLocation</param-name>           <param-value>classpath:springmvc.xml
  • 【DB筆試面試819】在Oracle中,什麼是AWR?
    ASH(Active Session History,活動會話歷史信息)、AWR(Automatic Workload Repository,自動負載信息庫)、ADDM(Automatic Database Diagnostic Monitor,資料庫自動診斷監視工具)是Oracle性能調整的三把利劍,需要深入地了解,但是面試一般都問得比較簡單,主要問到的是AWR。
  • 猿蛻變9——一文搞定SpringMVC的RESTFul套路
    servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:springmvc.xml
  • SpringMVC筆記
    (4)在springmvc-config.xml中配置控制器信息(1)用戶通過瀏覽器向伺服器發送請求,請求會被Spring MVC的前端控制器DispatcherServlet所攔截。(2)DispatcherServlet攔截到請求後,會調用HandlerMapping處理器映射器。
  • 獅城新聞|印度北部冰川斷裂已致19人死亡 逾200人失蹤| 新加坡國大法學院放寬筆試和面試標準
    新加坡國立大學法學院展開試驗計劃放寬面試標準,預計額外約50名學生可參與筆試和面試。照片攝於冠病疫情前。(新加坡國立大學提供)為了讓來自更多元背景的學生修讀法律,新加坡國立大學法學院展開試驗計劃放寬面試標準,預計額外約50名學生可參與筆試和面試。
  • 【精選乾貨】SpringMVC詳解——詳細架構
    作者 | IT優就業編輯 | Sandra原文 | http://www.toutiao.com/a6456538239913165326/Ja強最新動態推薦本公眾號給 2個好友,返回截圖即可領取《Java面試寶典
  • Java程式設計師必備基礎結構圖
    算法的核心思想:10.標記-清除算法示意圖如果沒有雙親委派,那麼用戶是不是可以自己定義一個java.lang.Object的同名類,java.lang.String的同名類,並把它放到ClassPath中,那麼類之間的比較結果及類的唯一性將無法保證,因此,雙親委派模型可以防止內存中出現多份同樣的字節碼。16.棧幀概念結構圖
  • Java線程池面試要點
    public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, T
  • 面試|JAVA 引用詳解
    本文先來介紹一下java的四種引用類型。一,四種引用介紹從Java SE2開始,就提供了四種類型的引用:強引用、軟引用、弱引用和虛引用。Java中提供這四種引用類型主要有兩個目的:第一是可以讓程式設計師通過代碼的方式決定某些對象的生命周期;第二是有利於JVM進行垃圾回收。
  • 驚豔面試官-Java中關於隨機數生成8種方式的思考
    想要驗證的話,可以下載java源碼,在new Random的地方稍作修改,System.nanoTime()改成固定值,這裡我就不驗證了。ThreadLocalRandom上面提到Random使用了線程安全的算法:AtomicLong、自旋+CAS。這在保證線程安全的同時造成了很大的性能開銷。
  • 面試常問的Java虛擬機內存模型,看這篇就夠了!
    同樣的java代碼在不同平臺生成的機器碼肯定是不一樣的,因為不同的作業系統底層的硬體指令集是不同的。同一個java代碼在windows上生成的機器碼可能是0101..,在linux上生成的可能是1100.
  • java的註解是個什麼玩意
    基本數據類型和枚舉註解的使用註解本身不包含任何業務邏輯,通常需要使用反射機制獲得使用了某一個註解的那些元素,從而進行一些邏輯處理定義MyTag註解package com.helianxiaowu.springclouddemo.annotation;import ja
  • 我所經歷的一場百度公司面試
    面試的準備  當收到HR的面試的通知還是很懵逼的,因為感覺自己突然啥都不會了,迅速鎮定下來,去網上找了一下某度的面試題,但是發現都只有提問了什麼並沒有對所提問題的解答,那只能自力更生,像做試卷一樣,一遍總結一遍溫顧.其實大多都是平時開發中用到的,只是我們沒有總結過,被問起來的時候回答的難免會有點捉襟見肘,不能回答的很全面.下面為我個人總
  • 【緊急救援】網申筆試時網絡太卡!頁面刷不出?怎麼辦?
    ID: 葉球兒在論壇看到有些小夥伴反映在筆試過程中網頁出現故障,加上我之前吃了寶潔網申測試因為被網速問題直接KO的慘痛經歷,這次決定細緻到底,筆試前專門測了一下自家網速and筆試網址穩定性,預防筆試過程直接崩掉,希望能幫到你們,文字看起來有點長,但實際操作很簡單!
  • 武警部隊2020年面向社會公開招考文職人員面試工作圓滿結束
    根據文職人員招聘年度工作計劃安排,11月7日至9日,武警部隊採取統一組織、分片實施的辦法,在全國30個省市自治區設置面試考場57個、考室
  • Java字符串String那些事
    );        System.out.println(str);    }輸出結果javajava金融公眾號關注:【java金融】java金融所以我們只要記住一點jdk6 結果是false,是因為常量池是在永久代的Perm區和java堆是兩個區域。所以兩個區域的對象地址比較是不同的。
  • 面試官:Java 8 map 和 flatMap 的區別?大部分人答不上來!
    來源丨經授權轉自 Java技術棧(ID:javastack)背景棧長面試會經常問 Java 8 map 和 flatMap 的區別,大部分人都答不上來,會用 map 的都不多,還有一部分人甚至都不知道這兩個玩意是幹嘛用的,有的還以為我問 HashMap 和 FlatMap。。
  • java面試系列--J2SE基礎(十一)
    隊列java.util.concurrent  ConcurrentLinkedQueue  類提供了高效的、可伸縮的、線程安全的非阻塞 FIFO 隊列。java.util.concurrent 中的五個實現都支持擴展的  BlockingQueue  接口,該接口定義了 put 和 take 的阻塞版本:  LinkedBlockingQueue 、  ArrayBlockingQueue 、  SynchronousQueue 、 PriorityBlockingQueue  和  DelayQueue 。