Spring Boot 整合 Spring MVC:自動配置與擴展實踐

Spring MVC 作為 Java Web 開發的核心框架,在傳統 SSM 項目中需要大量 XML 配置(如 DispatcherServlet、視圖解析器等)。而 Spring Boot 通過 "自動配置" 特性,簡化了 Spring MVC 的整合過程,同時保留了靈活的擴展能力。本文將從自動配置原理、擴展方式、組件注冊等方面,結合實例詳解 Spring Boot 與 Spring MVC 的整合實踐。

一、Spring Boot 對 Spring MVC 的自動配置

Spring Boot 的核心優勢之一是 "約定大于配置",對于 Spring MVC 的核心組件,Spring Boot 已完成自動配置,無需手動編寫 XML 或 Java 配置。

1.1 核心組件的自動配置

(1)DispatcherServlet(中央轉發器)

傳統 SSM 中需在web.xml配置 DispatcherServlet:

<servlet><servlet-name>springmvc</servlet-name><servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class><load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping><servlet-name>springmvc</servlet-name><url-pattern>/</url-pattern>
</servlet-mapping>

Spring Boot 通過DispatcherServletAutoConfiguration類自動注冊 DispatcherServlet,默認攔截路徑為/(不攔截 JSP),且無需web.xml(因為 Spring Boot 以 JAR 包方式運行嵌入式容器)。

(2)控制器(Controller)

只需在類上標注@Controller@RestController,并確保類在 Spring Boot 的注解掃描范圍內(默認掃描主啟動類所在包及其子包),Spring Boot 會自動將其注冊為 Bean。

(3)視圖解析器

傳統 SSM 需配置 InternalResourceViewResolver:

<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"><property name="prefix" value="/WEB-INF/jsp/"/><property name="suffix" value=".jsp"/>
</bean>
public ContentNegotiatingViewResolver viewResolver(BeanFactory beanFactory) {ContentNegotiatingViewResolver resolver = new ContentNegotiatingViewResolver();resolver.setContentNegotiationManager((ContentNegotiationManager)beanFactory.getBean(ContentNegotiationManager.class));resolver.setOrder(-2147483648);return resolver;
}
當我們做文件上傳的時候我們也會發現multipartResolver是自動被配置好的
頁面
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title>
</head>
<body>
<form action="/upload" method="post" enctype="multipart/form-data"><input name="pic" type="file"><input type="submit">
</form>
</body>
</html>
Controller
package com.qcby.mavenspringboot.controller;import jakarta.servlet.http.HttpServletRequest;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.MultipartFile;
import org.slf4j.LoggerFactory;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.UUID;
import org.slf4j.Logger;@Controller
public class UploadController {private static final Logger logger = LoggerFactory.getLogger(UploadController.class);@RequestMapping(value = "/upload", method = RequestMethod.GET)public String showUploadForm() {return "upload";}// 2. 處理POST請求:接收文件上傳@RequestMapping(value = "/upload", method = RequestMethod.POST)public String upload(@RequestParam("pic") MultipartFile file,HttpServletRequest request,Model model) {if (file.isEmpty()) {logger.error("上傳的文件為空");return "upload";}String originalFileName = file.getOriginalFilename();String contentType = file.getContentType();logger.info("原始文件名: {}", originalFileName);logger.info("文件類型: {}", contentType);String uniqueFileName = generateUniqueFileName(originalFileName);// 本地存儲路徑(D:/imgup/)Path filePath = Paths.get("D:", "imgup");try {// 上傳文件到本地路徑uploadFile(file.getBytes(), filePath, uniqueFileName);String fileAccessUrl = "/webimg/" + uniqueFileName;model.addAttribute("originalFileName", originalFileName);model.addAttribute("fileUrl", fileAccessUrl);model.addAttribute("fileType", contentType);} catch (IOException e) {logger.error("文件上傳失敗", e);return "error";}return "success";}private static void uploadFile(byte[] file, Path filePath, String fileName) throws IOException {// 若目錄不存在則創建if (!Files.exists(filePath)) {Files.createDirectories(filePath);}Path targetPath = filePath.resolve(fileName);// 寫入文件(try-with-resources自動關閉流)try (FileOutputStream out = new FileOutputStream(targetPath.toFile())) {out.write(file);}}// 生成唯一文件名(UUID+原文件后綴)private static String generateUniqueFileName(String originalFileName) {String extension = "";int dotIndex = originalFileName.lastIndexOf('.');if (dotIndex > 0) {extension = originalFileName.substring(dotIndex);}return UUID.randomUUID().toString() + extension;}
}

?上傳文件展示代碼:

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org"> <!-- 引入Thymeleaf命名空間 -->
<head><meta charset="UTF-8"><title>上傳成功</title>
</head>
<body>
<h1>文件上傳成功!</h1>
<p>原始文件名:<span th:text="${fileName}"></span></p><div><h3>預覽圖片:</h3><img th:src="${fileUrl}" style="max-width: 500px; max-height: 500px;" />
</div><!--<div>-->
<!--    <a th:href="${fileUrl}" th:text="下載文件:+${fileName}"></a>-->
<!--</div>-->
</body>
</html>

?

Spring Boot 自動注冊ContentNegotiatingViewResolver(組合所有視圖解析器)和BeanNameViewResolverContentNegotiatingViewResolver會根據請求頭(如Accept)動態選擇合適的視圖解析器,無需手動配置前綴 / 后綴(如需自定義,可通過擴展方式實現)。

(4)文件上傳(MultipartResolver)

Spring Boot 自動配置StandardServletMultipartResolver,支持文件上傳。前端表單需指定enctype="multipart/form-data",后端通過@RequestParam("file") MultipartFile file接收文件。

默認上傳大小限制為 10MB,可在application.properties中修改:

spring.servlet.multipart.max-file-size=100MB  # 單個文件大小
spring.servlet.multipart.max-request-size=500MB  # 總請求大小

?

(5)靜態資源訪問

Spring Boot 默認將classpath:/static/classpath:/public/classpath:/resources/classpath:/META-INF/resources/目錄下的資源視為靜態資源,可直接通過 URL 訪問(如http://localhost:8080/xxx.js)。

(6)消息轉換器與格式化
  • 消息轉換器:自動配置HttpMessageConverter,支持 JSON(默認 Jackson)、XML 等數據格式的序列化 / 反序列化。
  • 格式化:默認支持日期、數字等類型的格式化,可通過application.properties配置全局日期格式:
    spring.mvc.format.date=yyyy-MM-dd
    

?

格式化轉換器的自動注冊

時間類型我們可以在這里修改

在配置文件中指定好時間的模式我們就可以輸入了

(7)歡迎頁

默認將classpath:/static/index.htmlclasspath:/templates/index.html(Thymeleaf)作為歡迎頁,訪問http://localhost:8080/時自動跳轉。

?

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title>
</head>
<body>
<h1>首頁</h1>
</body>
</html>

?

二、擴展 Spring MVC:通過 WebMvcConfigurer

Spring Boot 的自動配置并非 "一刀切",實際開發中常需自定義配置(如攔截器、消息轉換器)。通過實現WebMvcConfigurer接口(推薦),可在不覆蓋自動配置的前提下擴展 Spring MVC。

2.1 核心擴展場景與示例

創建配置類MyMVCCofnig實現WebMvcConfigurer,并重寫對應方法:

@Configuration
public class MyMVCCofnig implements WebMvcConfigurer {// 擴展方法...
}
(1)視圖控制器(請求轉發)

通過addViewControllers實現 URL 與視圖的直接映射(無需編寫 Controller):

@Override
public void addViewControllers(ViewControllerRegistry registry) {// 訪問http://localhost:8080/tx時,轉發到success.htmlregistry.addViewController("/tx").setViewName("success");
}

success頁面:

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title>
</head>
<body>
<h1>Success</h1>
</body>
</html>

?

(2)自定義格式化器

通過addFormatters注冊自定義格式化器(如日期解析):

@Override
public void addFormatters(FormatterRegistry registry) {// 自定義日期格式化(將"yyyy-MM-dd"字符串轉為Date)registry.addFormatter(new Formatter<Date>() {@Overridepublic String print(Date date, Locale locale) {return null; // 響應時格式化(按需實現)}@Overridepublic Date parse(String s, Locale locale) throws ParseException {return new SimpleDateFormat("yyyy-MM-dd").parse(s);}});
}

測試:控制器接口接收 Date 參數:

@GetMapping("/testDate")
public String testDateFormatter(@RequestParam("date") Date date) {return "日期:" + date.toLocaleString();
}
// 訪問:http://localhost:8080/testDate?date=2023-10-01 可正常解析

?

(3)整合 FastJSON 消息轉換器

默認 Jackson 可能無法滿足需求(如 JSON 格式化),可替換為 FastJSON:

  1. 引入依賴:
<dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>1.2.47</version>
</dependency>
  1. 注冊 FastJSON 轉換器:
@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {FastJsonHttpMessageConverter converter = new FastJsonHttpMessageConverter();FastJsonConfig config = new FastJsonConfig();// 配置JSON格式化(如PrettyFormat)config.setSerializerFeatures(SerializerFeature.PrettyFormat);converter.setFastJsonConfig(config);converters.add(converter);
}
  1. 實體類自定義字段格式:
public class User {@JSONField(format = "yyyy-MM-dd HH:mm:ss") // 序列化日期格式private Date date;// 其他字段...
}

測試:接口返回 User 對象時,日期將按指定格式序列化:

@GetMapping("/user")
public User getUser() {User user = new User("張三", "123", 20, 90.5, 1);user.setDate(new Date());return user;
}

?

(4)注冊攔截器

攔截器可用于登錄驗證、日志記錄等場景,需兩步:

  1. 創建自定義攔截器:
public class MyInterceptor implements HandlerInterceptor {@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {System.out.println("前置攔截(請求處理前)");return true; // true放行,false攔截}@Overridepublic void postHandle(...) {System.out.println("后置攔截(視圖渲染前)");}@Overridepublic void afterCompletion(...) {System.out.println("最終攔截(請求完成后)");}
}
  1. 通過addInterceptors注冊攔截器:
@Override
public void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(new MyInterceptor()).addPathPatterns("/**") // 攔截所有請求.excludePathPatterns("/hello2"); // 排除/hello2請求
}

測試:訪問/hello會被攔截,訪問/hello2不會:

@GetMapping("/hello")
public String hello() {System.out.println("執行/hello業務邏輯");return "hello";
}
@GetMapping("/hello2")
public String hello2() {return "hello2";
}

?

?

三、注冊 Servlet 三大組件(Servlet、Filter、Listener)

傳統 Web 項目通過web.xml注冊 Servlet、Filter、Listener,而 Spring Boot 需通過@Bean手動注冊(因無 web.xml)。

3.1 注冊示例(配置類 ServletConfig)

@Configuration
public class ServletConfig {// 1. 注冊Servlet@Beanpublic ServletRegistrationBean<MyServlet> myServlet() {// 參數1:自定義Servlet實例;參數2:訪問路徑ServletRegistrationBean<MyServlet> registrationBean = new ServletRegistrationBean<>(new MyServlet(), "/myServlet");registrationBean.setLoadOnStartup(1); // 啟動時加載(優先級)return registrationBean;}// 2. 注冊Filter@Beanpublic FilterRegistrationBean<MyFilter> myFilter() {FilterRegistrationBean<MyFilter> registrationBean = new FilterRegistrationBean<>();registrationBean.setFilter(new MyFilter()); // 自定義FilterregistrationBean.setUrlPatterns(Arrays.asList("/hello", "/myServlet")); // 攔截路徑return registrationBean;}// 3. 注冊Listener@Beanpublic ServletListenerRegistrationBean<MyListener> myListener() {ServletListenerRegistrationBean<MyListener> registrationBean = new ServletListenerRegistrationBean<>(new MyListener());return registrationBean;}
}

3.2 自定義組件實現

(1)自定義 Servlet
public class MyServlet extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {resp.getWriter().write("Hello MyServlet");}
}

訪問http://localhost:8080/myServlet會執行該 Servlet。

?

(2)自定義 Filter
public class MyFilter implements Filter {@Overridepublic void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {System.out.println("Filter攔截請求");chain.doFilter(request, response); // 放行System.out.println("Filter處理完成");}
}
(3)自定義 Listener
public class MyListener implements ServletContextListener {@Overridepublic void contextInitialized(ServletContextEvent sce) {System.out.println("Listener:應用啟動初始化");}@Overridepublic void contextDestroyed(ServletContextEvent sce) {System.out.println("Listener:應用關閉銷毀");}
}

?

四、項目依賴與配置

4.1 核心依賴(pom.xml)

<dependencies><!-- Web啟動器(包含Spring MVC、嵌入式Tomcat等) --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!-- FastJSON(消息轉換) --><dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>1.2.47</version></dependency><!-- Thymeleaf(模板引擎,可選) --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-thymeleaf</artifactId></dependency><!-- 熱部署(開發環境) --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-devtools</artifactId><optional>true</optional></dependency>
</dependencies>

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/90904.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/90904.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/90904.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

print(“\033[31m紅\033[32m綠\033[34m藍\033[0m默認色“)

可以讓python的終端字體有著不一樣的顏色。代碼&#xff1a;print("\033[31m紅\033[32m綠\033[34m藍\033[0m默認色")效果&#xff1a;

LNMP-zblog分布式部署

一、準備3臺主機&#xff08;rocky8&#xff09;下載相應服務[rootnginx ~]# yum install -y nginx nfs-utils[rootphp ~]# yum install -y nfs-utils php-mysqlnd php php-fpm[rootmysql ~]# yum install -y mysql-server二、掛載php端[rootphp ~]# vim /etc/exports [rootphp…

常見代碼八股

1. 利用梯度下降法&#xff0c;計算二次函數yx^2x4的最小值 def target_function(x):return x ** 2 x 4def gradient(x):return 2*x 1x_init 10 x x_init steps 100 lr 0.1 for i in range(100):x x - lr*gradient(x)print(f"最小值 f(x) {target_function(x):.4f…

【深入底層】C++開發簡歷4+4技能描述6

簡歷書寫 熟悉C的封裝、繼承、多態&#xff0c;STL常用容器&#xff0c;熟悉C11的Lambda表達式、智能指針等&#xff0c;熟悉C20協程語法&#xff0c;具有良好的編碼習慣與文檔能力。 回答思路 這里是基本上就是要全會&#xff0c;考察的問題也很固定&#xff0c;stl這塊可以定…

forest遠程調用注意事項

1、如果在項目中&#xff0c;同時依賴了其中多個框架&#xff0c;那么按 Fastjson2 > Fastjson > Jackson > Gson 這樣的優先級來判斷&#xff0c;Forest 會以優先級最高的框架作為 JSON 轉換器。2、Forest 支持哪幾種 JSON 框架&#xff1f;A: 支持 Jackson、Gson、F…

網絡資源模板--基于Android Studio 實現的新聞App

目錄 一、測試環境說明 二、項目簡介 三、項目演示 四、部設計詳情&#xff08;部分) 登錄頁 首頁 五、項目源碼 一、測試環境說明 電腦環境 Windows 11 編寫語言 JAVA 開發軟件 Android Studio (2020) 開發軟件只要大于等于測試版本即可(近幾年官網直接下載也可…

通過Location API精準獲取位置信息并優化定位精度!

&#x1f44b; 你好&#xff0c;歡迎來到我的博客&#xff01;我是【菜鳥不學編程】 ?? 我是一個正在奮斗中的職場碼農&#xff0c;步入職場多年&#xff0c;正在從“小碼農”慢慢成長為有深度、有思考的技術人。在這條不斷進階的路上&#xff0c;我決定記錄下自己的學習與成…

構建可擴展的狀態系統:基于 ArkTS 的模塊化狀態管理設計與實現

摘要 在 HarmonyOS 的日常開發中&#xff0c;很多人都會遇到一個問題&#xff1a;多個頁面之間的數據狀態如何共享&#xff1f;尤其是在組件結構越來越復雜的場景下&#xff0c;如果還用傳統方式來傳值&#xff0c;不僅代碼混亂&#xff0c;維護也很吃力。 為了解決這個問題&am…

重生之我在暑假學習微服務第二天《MybatisPlus-下篇》

本系列參考黑馬程序員微服務課程&#xff0c;有興趣的可以去查看相關視頻&#xff0c;本系列內容采用漸進式方式講解微服務核心概念與實踐方法&#xff0c;每日更新確保知識點的連貫性。通過系統化學習路徑幫助開發者掌握分布式系統構建的關鍵技術。讀者可通過平臺訂閱功能獲取…

系統整理Python的條件語句和常用方法

Python 的條件語句&#xff08;if 語句&#xff09;是控制程序流程的基礎之一&#xff0c;結構清晰、語法簡潔&#xff0c;非常適合初學者掌握。一、基本語法結構if 條件:執行代碼塊1 elif 條件2:執行代碼塊2 else:執行代碼塊3示例&#xff1a;score 85if score > 90:print…

記錄個IAR程序下載后硬件復位不運行,必須斷電復位才運行的問題

【問題測試】有個F407的跑馬燈的例子&#xff0c;是MDK和IAR兩個版本&#xff0c;MDK版本的例子下載并復位后可以正常看到LED閃爍&#xff0c;而IAR的例子下進去后&#xff0c;不會閃爍。使用TOOL的上位機內核寄存器監測工具測試發現&#xff0c;硬件復位后竟然還在調試狀態&am…

觀察者模式(Observer Pattern)和 發布-訂閱模式(Publisher-Subscriber Pattern)

你對 觀察者模式&#xff08;Observer Pattern&#xff09;和 發布-訂閱模式&#xff08;Publisher-Subscriber Pattern&#xff09;的描述是非常準確的&#xff0c;并且闡明了它們的核心區別。為了幫助你更好地理解這兩者的細微差異&#xff0c;下面是一個更詳細的對比分析&am…

2025年接口技術的十字路口:當MCP遇見REST、GraphQL與gRPC

在當今這個由數據驅動、萬物互聯的時代&#xff0c;應用程序接口&#xff08;API&#xff09;已成為現代軟件架構的基石。它們是不同服務之間溝通的橋梁&#xff0c;支撐著從網頁應用到復雜的微服務生態系統的一切。長久以來&#xff0c;開發者們在REST、GraphQL和gRPC這幾種主…

【CTF-WEB-反序列化】利用__toString魔術方法讀取flag.php

題目 頁面提示輸入?code&#xff0c;那我們在網址里get一下出現了新頁面的提示&#xff0c;進入看看下面有個help.php頁面的提示&#xff0c;進入看看有一段php代碼&#xff0c;仔細分析&#xff0c;應該是要用反序列法代碼如下 class FileClass{ public $filename error.log…

在 github.com 與 sourceforge.net 上創建免費個人靜態網站、博客的區別

github.com github 屬于 git 版本管理專業網站&#xff0c;有免費和收費兩種套餐。git 的數據是存放在數據庫中的&#xff0c;要將數據庫中的數據顯示為網站的網頁&#xff0c;這需要服務器端提供專門的中間件支持才能實現。 特點&#xff1a; 官方支持&#xff1a;提供長期…

jenkins 入門指南:從安裝到啟動的完整教程

jenkins 入門指南&#xff1a;從安裝到啟動的完整教程 持續集成&#xff08;CI&#xff09;是現代開發流程中的核心環節&#xff0c;而 Jenkins 作為一款開源的 CI 工具&#xff0c;憑借簡單安裝、開箱即用、插件豐富、易于擴展等優勢&#xff0c;成為開發者的首選工具。它能自…

機器學習(重學版)基礎篇(概念與評估)

本篇參考周志華老師的西瓜書&#xff0c;但是本人學識有限僅能理解皮毛&#xff0c;如有錯誤誠請讀友評論區指正&#xff0c;萬分感謝。一、基礎概念與評估方法本節目標&#xff1a;建立理論基礎框架?1、機器學習定義機器學習是一門通過計算手段利用經驗&#xff08;以數據形式…

spring/springboot SPI(二)配合使用的接口

spring.factories 里&#xff0c;Spring 會根據接口來加載實現類&#xff0c;常見的幾個接口包括&#xff1a;一、org.springframework.context.ApplicationListener1、作用監聽 Spring 容器事件&#xff0c;如 ApplicationReadyEvent。2、使用方法項目結構Spring Boot 2.xSpri…

基于Zig語言,opencv相關的c++程序靜態交叉編譯

一、寫在前面 1.什么是zig? Zig 是一種通用編程語言&#xff1b; Zig 最初的定位就是代替C語言的系統級語言&#xff0c;它提供了與 C 語言幾乎 100% 兼容&#xff08;可直接調用 C 頭文件、鏈接 C 庫&#xff09;&#xff0c;同時不需要任何依賴構建系統。 Zig 同時附帶一…

基于 LSTM 與 SVM 融合的時間序列預測模型:理論框架與協同機制—實踐算法(1)

目錄 1、單一模型的局限性&#xff1a;混合架構的設計動機 2、LSTM 的時序特征提取&#xff1a;從原始序列到高階表征 2.1、門控機制的時序過濾能力 2.2、隱藏狀態的特征壓縮作用 2.3、預訓練的特征優化邏輯 3、SVM 的非線性映射&#xff1a;從高階特征到預測輸出 3.1、…