当前位置: 首页 > news >正文

Spring MVC 基础 - 从零构建企业级Web应用

引言:为什么选择 Spring MVC?
Spring MVC 是 Spring 生态系统中构建 企业级 Web 应用的核心框架,其基于 MVC 设计模式,天然支持模块化开发、RESTful API、数据绑定等特性。

核心优势:

  • 松耦合架构:模型(Model)、视图(View)、控制器(Controller)分离,便于团队协作和代码维护。

  • 高度可扩展:支持 Thymeleaf、Freemarker 等视图技术,兼容 JSON/XML 等多种数据格式。

  • 无缝整合:与 Spring IoC、AOP、Security 等模块深度集成,轻松实现复杂业务需求。

一、Spring MVC 核心架构解析

1. 核心组件与请求流程

Spring MVC 的请求处理流程可概括为以下步骤:

1. 用户发起请求 → 
2. DispatcherServlet(前端控制器)接收请求 → 
3. 调用 HandlerMapping 解析请求对应的 Controller4. Controller 处理业务逻辑,返回 Model 和视图名 → 
5. ViewResolver 解析视图 → 
6. 渲染视图并返回响应

关键组件:

  • DispatcherServlet:中央调度器,协调所有请求处理流程。将请求分发到相应的 Controller 进行处理。

  • HandlerMapping:映射请求 URL 到具体 Controller 方法。

  • ViewResolver:将逻辑视图名 (如 “home”) 解析为物理视图 (如 /WEB-INF/views/home.jsp)。

2. 模型-视图-控制器(MVC)详解

2.1 Model (模型层)

处理业务逻辑和数据部分。在 Spring MVC 中,通过 Model对象传递数据到视图层。

示例代码:

public class User {private String name;private int age;public User(String name, int age) {this.name = name;this.age = age;}// Getter & Setterpublic 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; }
}

Controller 中,通过model.addAttribute传递数据。

model.addAttribute("user", new User("Alice", 25)); 
// 将 User 对象存入 Model,键为 "user",视图可通过 ${user} 获取

2.2 View (视图层)
负责展示数据,通过 JSP、Thymeleaf 等渲染数据。

<!-- Thymeleaf 视图层 -->
<div th:text="${user.name}">Username</div>

2.3 Controller(控制器)
处理用户HTTP请求,调用Service层业务逻辑,并返回数据给视图。

@GetMapping("/users")
public String listUsers(Model model) {model.addAttribute("users", userService.findAll());return "user-list"; // 返回视图名
}

二、实战:5步构建Spring MVC应用

以用户管理为例,完整构建一个Spring MVC应用,涵盖Controller、Service、DAO、Model以及视图层的实现。

步骤1:项目初始化(Maven/Gradle)

Maven 依赖配置

<dependencies><!-- Spring Web MVC:核心 Web 框架 --><dependency><groupId>org.springframework</groupId><artifactId>spring-webmvc</artifactId><version>5.3.20</version></dependency><!-- Servlet API:用于处理 HTTP 请求 --><dependency><groupId>javax.servlet</groupId><artifactId>javax.servlet-api</artifactId><version>4.0.1</version><scope>provided</scope></dependency><!-- 日志支持(SLF4J + Logback--><dependency><groupId>org.slf4j</groupId><artifactId>slf4j-api</artifactId><version>1.7.36</version></dependency><dependency><groupId>ch.qos.logback</groupId><artifactId>logback-classic</artifactId><version>1.2.11</version></dependency>
</dependencies>

步骤2:配置 DispatcherServlet
方式1.XML 配置(web.xml)

<servlet><servlet-name>dispatcher</servlet-name><servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class><init-param><param-name>contextConfigLocation</param-name><param-value>/WEB-INF/spring-mvc.xml</param-value></init-param><load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping><servlet-name>dispatcher</servlet-name><url-pattern>/</url-pattern>
</servlet-mapping>

解析:

  • DispatcherServlet是 Spring MVC 的前端控制器,负责拦截所有请求。

  • contextConfigLocation指定 Spring 配置文件。

方式2.Java Config(推荐)
使用 Java 配置方式初始化 Spring MVC 应用,替代web.xml进行配置。

public class WebAppInitializer implements WebApplicationInitializer {@Overridepublic void onStartup(ServletContext servletContext) {AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();context.register(AppConfig.class);ServletRegistration.Dynamic dispatcher = servletContext.addServlet("dispatcher", new DispatcherServlet(context));dispatcher.setLoadOnStartup(1);dispatcher.addMapping("/");}
}

解析:
1.WebApplicationInitializer接口
用于配置 Web 应用,替代 XML 的 web.xml。

在应用启动时自动执行,相当于web.xml的和配置。

2. onStartup(ServletContext servletContext) 方法

在应用启动时执行,注册DispatcherServlet并进行 Spring 容器初始化。

3. AnnotationConfigWebApplicationContext

Spring 的基于 Java 配置(Annotation Config)的应用上下文。

4. DispatcherServlet

Spring MVC 的前端控制器 ,负责处理所有的 HTTP 请求。

5. setLoadOnStartup(1) 设置DispatcherServlet的加载优先级。

• 1表示服务器启动时立即加载,类似于web.xml里的1。

• 提前初始化 Spring 容器,提升响应速度。

总结:

1.替代 web.xml 进行 Spring MVC 配置,使用 Java 代码初始化 Web 应用。

2.注册 DispatcherServlet,拦截所有请求(/),并交给 Spring MVC 处理。

3.加载 Spring 配置类 AppConfig,在其中配置Controller、ViewResolver等组件。

4.优先加载 DispatcherServlet,提高应用启动速度。

步骤3:创建 Model、Controller、Service 层
1. 定义用户实体类(Model)

public class User {private String name;private int age;// 构造方法public User(String name, int age) {this.name = name;this.age = age;}// Getter & Setterpublic 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; }
}

解析:

  • User类是数据模型,存储用户基本信息。

  • getter和 setter方法用于数据访问和修改。

2. 创建 Service 层(业务逻辑)

import org.springframework.stereotype.Service;
import java.util.Arrays;
import java.util.List;@Service
public class UserService {public List<User> findAll() {return Arrays.asList(new User("Alice", 25),new User("Bob", 30));}
}

解析:

  • @Service注解表示该类是业务逻辑层。

  • findAll()方法返回用户列表。

3. 创建 Controller 层

@Controller
public class UserController {@Autowiredprivate UserService userService;// 处理 GET /users 请求@GetMapping("/users")public String listUsers(Model model) {model.addAttribute("users", userService.findAll());return "users"; // 返回视图名 users.jsp}// 处理 POST /users 请求@PostMapping("/users")public String createUser(@ModelAttribute User user) {userService.save(user);return "redirect:/users"; // 重定向到列表页}
}

解析:

  • @Controller标注控制器。

  • @GetMapping(“/users”)处理 /users请求。

model.addAttribute("users", userService.findAll());将数据传递给视图。

步骤4:视图解析器配置
方式1.XML 配置(spring-mvc.xml)

<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"><property name="prefix" value="/WEB-INF/views/"/><property name="suffix" value=".jsp"/>
</bean>

方式2.Java Config

@Configuration
@EnableWebMvc
public class AppConfig implements WebMvcConfigurer {@Beanpublic ViewResolver viewResolver() {InternalResourceViewResolver resolver = new InternalResourceViewResolver();resolver.setPrefix("/WEB-INF/views/");resolver.setSuffix(".jsp");return resolver;}
}

步骤5:视图开发与数据渲染
JSP 视图(users.jsp)

<%@ page contentType="text/html;charset=UTF-8" %>
<html>
<head><title>用户列表</title>
</head>
<body><h1>用户列表</h1><table><tr><th>姓名</th><th>年龄</th></tr><c:forEach items="${users}" var="user"><tr><td>${user.name}</td><td>${user.age}</td></tr></c:forEach></table>
</body>
</html>

解析:

  • ${users}变量来自 model.addAttribute(“users”, userService.findAll());

  • <c:forEach>遍历用户列表,展示姓名和年龄。

至此,一个完整的 Spring MVC Web 项目已经搭建完成,包含 Model、Service、Controller、View 及 DispatcherServlet 配置。你可以使用 Tomcat或 Spring Boot运行该项目,访问 /users看到用户列表页面。

三、进阶技巧与避坑指南

1. 常见问题排查

在开发 Spring MVC 应用时,可能会遇到一些常见问题,以下是几种典型情况及其排查方法:

Q1: 404 错误(页面找不到)

可能原因:

• @RequestMapping路径配置错误

• 请求 URL 与Controller映射不匹配

• DispatcherServlet配置有误

解决方案:

• 确认 Controller 是否正确映射路径

@Controller
@RequestMapping("/user")
public class UserController {@GetMapping("/list")public String userList() {return "userList"; // 对应 userList.jsp / userList.html}
}

问题示例:如果访问http://localhost:8080/list,但@RequestMapping(“/user”),则路径不匹配,应访问http://localhost:8080/user/list。

• 检查 web.xml 或 SpringBootApplication 是否正确配置

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

Q2: 视图渲染失败

可能原因:

• 视图解析器prefix和suffix配置错误

• 视图文件未正确存放

解决方案:

• 检查 spring-mvc.xml 视图解析器配置

<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver"><property name="prefix" value="/WEB-INF/views/" /><property name="suffix" value=".jsp" />
</bean>

• prefix:设定视图文件的存放目录,例如/WEB-INF/views/

• suffix:设定视图的文件后缀,如.jsp或.html

• 确保视图文件存在

• 确保WEB-INF/views/userList.jsp存在,否则返回404。

Q3: 数据未传递到视图

可能原因:

• Controller没有正确添加数据到Model

• 视图未正确读取Model数据

解决方案:

• Controller 确保数据正确传递

@Controller
public class UserController {@GetMapping("/userList")public String userList(Model model) {List<User> users = userService.findAll();model.addAttribute("users", users);return "userList"; // 视图名称,对应 userList.jsp / userList.html}
}

• 前端正确获取数据(JSP 示例)

<c:forEach var="user" items="${users}"><p>${user.name} - ${user.email}</p>
</c:forEach>

如果model.addAttribute(“users”, users);这步缺失,则users为空,页面不会正确显示数据。

2. 扩展能力

2.1 RESTful API 支持

Spring MVC 结合 @RestController 实现 RESTful API,可以直接返回 JSON 数据。

示例代码

@RestController
@RequestMapping("/api")
public class ApiController {@GetMapping("/users")public List<User> getUsers() {return userService.findAll();}
}

• @RestController:等价于@Controller + @ResponseBody,直接返回 JSON,不经过视图解析器。

• @GetMapping(“/api/users”):定义GET请求,返回所有用户数据。

请求 & 响应示例

GET http://localhost:8080/api/users
[{"id":1, "name":"Alice", "email":"alice@example.com"},{"id":2, "name":"Bob", "email":"bob@example.com"}
]

2.2 表单验证

使用 Hibernate Validator 结合 @Valid 进行数据校验,可以确保用户提交的数据符合要求。

示例代码:

定义 User 实体类

import javax.validation.constraints.Email;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Size;public class User {private Long id;@NotBlank(message = "用户名不能为空")@Size(min = 3, max = 20, message = "用户名长度必须在 3-20 之间")private String name;@Email(message = "邮箱格式不正确")private String email;// getter & setter
}

Controller 处理校验

@Controller
@RequestMapping("/users")
public class UserController {@PostMapping("/add")public String addUser(@Valid @ModelAttribute User user, BindingResult result, Model model) {if (result.hasErrors()) {return "userForm"; // 返回表单页面,显示错误信息}userService.save(user);return "redirect:/users/list";}
}

JSP 页面显示错误

用户名: ${errors.name}
邮箱:<input type="text" name="email" value="${user.email}"/>
<span style="color:red">${errors.email}</span><button type="submit">提交</button>
关键点

• @Valid触发数据校验

• BindingResult result捕获校验错误

• errors.name&errors.email显示错误信息

3. 总结

• 404 问题:检查@RequestMapping,URL 访问路径匹配。

• 视图解析失败:确保prefix和suffix配置正确,视图文件存在。

• 数据未传递:model.addAttribute()传值,前端正确获取数据。

• REST API 扩展:使用@RestController,返回 JSON 数据。

• 表单校验:@Valid+ Hibernate Validator,确保输入数据合法。

四、总结

1. 核心要点

Spring MVC 核心架构

• 通过DispatcherServlet统一调度请求,实现MVC 分层。

• Controller处理业务逻辑,ViewResolver解析视图,Model负责数据传递。

配置方式

• 支持XML 配置和Java Config,推荐后者以提升可维护性。

数据交互

• 通过@ModelAttribute绑定表单数据,使用@RequestParam处理请求参数。

视图层支持

• 兼容JSP、Thymeleaf等视图技术,同时支持RESTful API开发。

异常与调试

• 掌握404、视图渲染失败、数据未传递等常见问题的排查方法。

相关文章:

  • IIC 通信协议
  • 从传统制造到智能工厂:MES如何重塑电子制造业?
  • Airbnb更智能的搜索:嵌入式检索(Embedding-Based Retrieval,EBR)工作原理解析
  • 使用vue3 脚手架创建项目
  • springboot项目之websocket的坑:spring整合websocket后进行单元测试后报错的解决方案
  • 网易大神安卓版游戏社交互动体验及功能评测
  • C++23/26 静态反射机制深度解析:编译时元编程的新纪元
  • 开源 Agent 框架对比:LangChain vs AutoGen vs CrewAI
  • 这是一款好用的PDF工具!
  • 《Q2门式起重机司机》考试大纲的专项要求有哪些?
  • Hadoop伪分布式模式搭建全攻略:从环境配置到实战测试
  • 使用多线程快速向Excel中快速插入一万条数据案例
  • 使用POI和EasyExcel使用导入
  • 湖北理元理律师事务所:债务管理领域的平台化创新探索
  • 学习记录:DAY19
  • 【虚幻5蓝图Editor Utility Widget:创建高效模型材质自动匹配和资产管理工具,从3DMax到Unreal和Unity引擎_系列第二篇】
  • 【数据可视化-41】15年NVDA, AAPL, MSFT, GOOGL AMZ股票数据集可视化分析
  • 【数据可视化-42】杂货库存数据集可视化分析
  • 数据结构 -- 图的应用(二)
  • MinecraftPVP发展史
  • 西班牙葡萄牙遭遇史上最严重停电:交通瘫了,通信崩了,民众疯抢物资
  • 一场与纪录并行的伦敦马拉松,超40项新世界纪录诞生
  • 早睡1小时,变化有多惊人?第一个就没想到
  • 解放日报头版头条:“五个中心”蹄疾步稳谱新篇
  • 人民时评:投资于人,促高质量充分就业
  • 新任浙江省委常委、杭州市委书记刘非开展循迹溯源学习调研