Spring MVC 基础模块教程
目录
- Spring MVC 概述
- MVC 设计模式
- 开发环境搭建
- Spring MVC 核心架构
- DispatcherServlet 详解
- 核心组件详解
- 项目结构设计
- 配置文件详解
- 第一个Spring MVC应用
- 常见问题解决
- 总结
Spring MVC 概述
Spring MVC是Spring框架的一个重要模块,是一个基于Java的Web应用开发框架。它采用了MVC(Model-View-Controller)设计模式,为开发者提供了一套完整的Web应用开发解决方案。
Spring MVC 的特点
1. 灵活的架构设计
- 松耦合的组件设计
- 支持多种视图技术
- 可插拔的组件架构
- 支持注解驱动的配置方式
2. 强大的功能特性
- Spring依赖注入和面向切面编程
- 支持RESTful风格的Web服务
- 内置数据验证和格式化
- 强大的异常处理机制
3. 优秀的扩展性
- 支持第三方视图技术(Thymeleaf、FreeMarker等)
- 丰富的拦截器机制
- 支持多种数据绑定方式
- 良好的测试支持
Spring MVC vs 其他Web框架
| 特性 | Spring MVC | Struts 2 | JSF |
|---|---|---|---|
| 学习曲线 | 适中 | 陡峭 | 陡峭 |
| 性能 | 优秀 | 良好 | 一般 |
| 灵活性 | 高 | 中等 | 低 |
| 社区支持 | 庞大 | 活跃 | 相对较小 |
| 与Spring集成 | 完美 | 困难 | 复杂 |
MVC 设计模式
MVC 模式概念
MVC(Model-View-Controller)是一种软件架构模式,它将应用程序分为三个核心部分:
- Model(模型): 代表应用的数据和业务逻辑
- View(视图): 负责用户界面的展示
- Controller(控制器): 处理用户输入并协调Model和View
MVC 模式的优点
1. 关注点分离
- 业务逻辑与表现逻辑分离
- 数据操作与用户界面分离
- 易于维护和扩展
2. 可重用性
- Model组件可以在不同的View中重用
- View组件可以绑定到不同的Model
- Controller可以在多个工作流中复用
3. 并行开发
- 不同开发人员可以同时开发不同组件
- 界面设计人员专注于View
- 业务逻辑开发人员专注于Model
Spring MVC中的MVC实现
// Model - 处理业务逻辑和数据
@Service
public class UserService {
public User findUserById(Long id) {
// 业务逻辑处理
return userRepository.findById(id);
}
}
// Controller - 处理请求
@Controller
public class UserController {
@Autowired
private UserService userService;
@GetMapping("/user/{id}")
public String getUser(@PathVariable Long id, Model model) {
User user = userService.findUserById(id);
model.addAttribute("user", user);
return "user/detail"; // 返回视图名
}
}
// View - JSP页面展示数据
<%@ page contentType="text/html;charset=UTF-8" %>
<html>
<head>
<title>用户详情</title>
</head>
<body>
<h1>用户信息</h1>
<p>姓名: ${user.name}</p>
<p>邮箱: ${user.email}</p>
</body>
</html>
开发环境搭建
必需软件版本
Java开发环境
- JDK 8 或更高版本
- 推荐使用 OpenJDK 11 或 Oracle JDK 11
构建工具
- Maven 3.6+ 或 Gradle 6.0+
- 本文以Maven为例
Web服务器
- Tomcat 9.0+ (推荐)
- Jetty 9.4+
- 其他兼容Servlet 4.0的容器
开发工具
- IntelliJ IDEA (推荐)
- Eclipse (STS)
- Visual Studio Code
Maven项目结构
spring-mvc-demo/
├── pom.xml
└── src/
└── main/
├── java/
│ └── com/example/
│ ├── controller/
│ ├── service/
│ ├── dao/
│ └── AppConfig.java
├── resources/
│ └── application.properties
└── webapp/
├── WEB-INF/
│ ├── web.xml
│ ├── spring-mvc-config.xml
│ └── views/
└── static/
├── css/
├── js/
└── images/
Maven依赖配置
基础依赖
<properties>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
<spring.version>5.3.21</spring.version>
</properties>
<dependencies>
<!-- Spring Framework -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<!-- Spring Web MVC -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>
<!-- Servlet API -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
<scope>provided</scope>
</dependency>
<!-- JSP和JSTL -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<!-- 数据验证 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-validation</artifactId>
<version>${spring.version}</version>
</dependency>
</dependencies>
JSON支持
<!-- Jackson JSON处理 -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.13.3</version>
</dependency>
数据库支持(可选)
<!-- H2内存数据库 -->
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<version>2.1.214</version>
</dependency>
<!-- Spring JDBC -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>${spring.version}</version>
</dependency>
Spring MVC 核心架构
总体架构图
HTTP Request
↓
DispatcherServlet (前端控制器)
↓
HandlerMapping (处理器映射器)
↓
HandlerAdapter (处理器适配器)
↓
Controller (控制器)
↓
ModelAndView (模型和视图)
↓
ViewResolver (视图解析器)
↓
View (视图)
↓
HTTP Response
请求处理流程
1. 请求接收阶段
- DispatcherServlet接收所有HTTP请求
- 根据请求路径决定如何处理请求
2. 处理器映射阶段
- HandlerMapping根据请求URL找到对应的Handler
- 支持多种映射策略(注解、XML配置等)
3. 处理器适配阶段
- HandlerAdapter调用具体的Handler方法
- 处理请求参数绑定和类型转换
4. 业务处理阶段
- Controller执行业务逻辑
- 处理用户请求,生成响应数据
5. 视图解析阶段
- 根据返回的视图名解析为具体的View
- 支持多种视图技术(JSP、Thymeleaf等)
6. 响应生成阶段
- View渲染最终的响应内容
- DispatcherServlet将响应发送给客户端
核心组件关系
DispatcherServlet
├── HandlerMapping (URL → Handler)
├── HandlerAdapter (Handler调用)
├── HandlerExceptionResolver (异常处理)
└── ViewResolver (视图解析)
DispatcherServlet 详解
DispatcherServlet 的作用
DispatcherServlet是Spring MVC的核心,充当前端控制器的角色:
1. 统一入口
- 作为所有HTTP请求的统一入口点
- 负责请求的路由和分发
2. 生命周期管理
- Servlet容器创建和销毁
- Spring ApplicationContext的绑定
3. 异常处理
- 统一处理应用程序异常
- 转换为合适的HTTP响应
DispatcherServlet 配置
web.xml配置方式
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<display-name>Spring MVC Application</display-name>
<!-- DispatcherServlet配置 -->
<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-config.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<!-- URL映射模式 -->
<servlet-mapping>
<servlet-name>dispatcher</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<!-- 字符编码过滤器 -->
<filter>
<filter-name>CharacterEncodingFilter</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>
<init-param>
<param-name>forceEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>CharacterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
Java配置方式(Servlet 3.0+)
public class DispatcherServletInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
@Override
protected Class<?>[] getRootConfigClasses() {
return new Class[]{RootConfig.class};
}
@Override
protected Class<?>[] getServletConfigClasses() {
return new Class[]{WebConfig.class};
}
@Override
protected String[] getServletMappings() {
return new String[]{"/"};
}
@Override
protected Filter[] getServletFilters() {
CharacterEncodingFilter characterEncodingFilter = new CharacterEncodingFilter();
characterEncodingFilter.setEncoding("UTF-8");
characterEncodingFilter.setForceEncoding(true);
return new Filter[]{characterEncodingFilter};
}
}
多DispatcherServlet配置
根ApplicationContext
@Configuration
@ComponentScan(basePackages = "com.example.service,com.example.dao")
public class RootConfig {
// 根上下文配置
}
Web ApplicationContext
@Configuration
@EnableWebMvc
@ComponentScan(basePackages = "com.example.controller")
public class WebConfig implements WebMvcConfigurer {
// Web上下文配置
}
核心组件详解
HandlerMapping(处理器映射器)
功能说明
HandlerMapping负责根据请求的URL找到对应的Handler(Controller方法)。
内置实现类型
1. RequestMappingHandlerMapping(推荐)
// 基于注解的映射
@Controller
public class UserController {
@RequestMapping(value = "/users", method = RequestMethod.GET)
public String getAllUsers() {
return "user/list";
}
@GetMapping("/user/{id}")
public String getUser(@PathVariable Long id) {
return "user/detail";
}
}
2. BeanNameUrlHandlerMapping
<!-- XML配置方式 -->
<bean name="/home" class="com.example.controller.HomeController"/>
3. SimpleUrlHandlerMapping
<bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="mappings">
<props>
<prop key="/user/list">userListController</prop>
<prop key="/user/add">userAddController</prop>
</props>
</property>
</bean>
HandlerAdapter(处理器适配器)
功能说明
HandlerAdapter负责调用具体的Handler方法,并将Model数据传递给View。
主要实现类
1. RequestMappingHandlerAdapter
- 处理@RequestMapping注解的Controller方法
- 支持方法参数绑定和返回值处理
2. SimpleControllerHandlerAdapter
public class UserListController implements Controller {
@Override
public ModelAndView handleRequest(HttpServletRequest request,
HttpServletResponse response) throws Exception {
List<User> users = userService.getAllUsers();
return new ModelAndView("user/list", "users", users);
}
}
3. HttpRequestHandlerAdapter
@Component("/api/users")
public class UserHttpHandler implements HttpRequestHandler {
@Override
public void handleRequest(HttpServletRequest request,
HttpServletResponse response) throws Exception {
// 处理HTTP请求
response.setContentType("application/json");
response.getWriter().write("{\"users\":[]}");
}
}
ViewResolver(视图解析器)
功能说明
ViewResolver负责将逻辑视图名解析为具体的View实现。
常用实现类
1. InternalResourceViewResolver(JSP)
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/views/"/>
<property name="suffix" value=".jsp"/>
<property name="order" value="1"/>
</bean>
2. BeanNameViewResolver
@Configuration
public class ViewConfig {
@Bean(name = "userList")
public View userListView() {
return new JstlView("/WEB-INF/views/user/list.jsp");
}
}
3. ResourceBundleViewResolver
# views.properties
user.list.(class)=org.springframework.web.servlet.view.JstlView
user.list.url=/WEB-INF/views/user/list.jsp
user.detail.(class)=org.springframework.web.servlet.view.JstlView
user.detail.url=/WEB-INF/views/user/detail.jsp
HandlerExceptionResolver(异常处理器)
主要实现类
1. SimpleMappingExceptionResolver
<bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
<property name="exceptionMappings">
<props>
<prop key="java.lang.Exception">error/general</prop>
<prop key="java.sql.SQLException">error/database</prop>
<prop key="java.io.IOException">error/io</prop>
</props>
</property>
<|tool▁sep|>property name="defaultErrorView" value="error/default"/>
</bean>
2. 注解方式异常处理
@ControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(Exception.class)
public ModelAndView handleException(Exception ex) {
ModelAndView mav = new ModelAndView("error/general");
mav.addObject("error", ex.getMessage());
return mav;
}
@ExceptionHandler(UserNotFoundException.class)
@ResponseStatus(HttpStatus.NOT_FOUND)
public String handleUserNotFound(UserNotFoundException ex) {
return "error/404";
}
}
项目结构设计
推荐的包结构
com.example.application
├── controller/ # 控制器层
│ ├── api/ # REST API控制器
│ ├── admin/ # 管理端控制器
│ └── web/ # Web页面控制器
├── service/ # 业务逻辑层
│ ├── impl/ # 服务实现类
│ └── UserService.java
├── dao/ # 数据访问层
│ ├── impl/ # DAO实现类
│ └── UserDao.java
├── model/ # 数据模型
│ ├── entity/ # 实体类
│ ├── dto/ # 数据传输对象
│ └── vo/ # 视图对象
├── config/ # 配置类
│ ├── WebConfig.java
│ ├── SecurityConfig.java
│ └── DatabaseConfig.java
├── exception/ # 异常类
├── util/ # 工具类
└── Application.java # 启动类
目录结构示例
src/main/
├── java/
│ └── com/example/
│ ├── controller/
│ │ ├── api/UserRestController.java
│ │ └── web/UserWebController.java
│ ├── service/
│ │ ├── impl/UserServiceImpl.java
│ │ └── UserService.java
│ ├── dao/
│ │ ├── impl/UserDaoImpl.java
│ │ └── UserDao.java
│ ├── model/
│ │ ├── entity/User.java
│ │ ├── dto/UserCreateDto.java
│ │ └── vo/UserVo.java
│ └── config/
│ ├── WebConfig.java
│ └── DatabaseConfig.java
├── resources/
│ ├── application.properties
│ ├── spring-mvc-config.xml
│ └── messages/
│ ├── messages.properties
│ └── messages_zh_CN.properties
└── webapp/
├── WEB-INF/
│ ├── web.xml
│ └── views/
│ ├── user/
│ │ ├── list.jsp
│ │ ├── detail.jsp
│ │ └── form.jsp
│ └── error/
│ ├── 404.jsp
│ └── 500.jsp
└── static/
├── css/
├── js/
└── images/
分层职责
Controller层
- 处理HTTP请求和响应
- 参数验证和绑定
- 调用Service层处理业务逻辑
- 选择视图或返回数据
Service层
- 业务逻辑处理
- 事务管理
- 调用DAO层操作数据
- 业务异常处理
DAO层
- 数据访问操作
- SQL语句执行
- 数据持久化
- 数据查询和更新
Model层
- Entity:映射数据库表结构
- DTO:数据传输对象
- VO:视图对象,用于页面展示
配置文件详解
web.xml 配置文件
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<display-name>Spring MVC Application</display-name>
<!-- Spring MVC DispatcherServlet -->
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!-- Spring配置文件位置 -->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/config/spring-mvc.xml</param-value>
</init-param>
<!-- 启动时加载 -->
<load-on-startup>1</load-on-startup>
</servlet>
<!-- Servlet映射 -->
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<!-- 字符编码过滤器 -->
<filter>
<filter-name>CharacterEncodingFilter</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>
<init-param>
<param-name>forceEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>CharacterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!-- Session超时配置(可选) -->
<session-config>
<session-timeout>30</session-timeout>
</session-config>
<!-- 错误页面配置(可选) -->
<error-page>
<error-code>404</error-code>
<location>/WEB-INF/views/error/404.jsp</location>
</error-page>
<error-page>
<error-code>500</error-code>
<location>/WEB-INF/views/error/500.jsp</location>
</error-page>
</web-app>
Spring MVC XML配置
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd">
<!-- 启用注解驱动 -->
<mvc:annotation-driven>
<!-- JSON转换器配置 -->
<mvc:message-converters>
<bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
<property name="supportedMediaTypes">
<list>
<value>application/json</value>
<value>application/xml</value>
</list>
</property>
</bean>
</mvc:message-converters>
</mvc:annotation-driven>
<!-- 组件扫描 -->
<context:component-scan base-package="com.example">
<context:include-filter type="annotation"
expression="org.springframework.stereotype.Controller"/>
<context:exclude-filter type="annotation"
expression="org.springframework.stereotype.Service"/>
</context:component-scan>
<!-- 视图解析器 -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/views/"/>
<property name="suffix" value=".jsp"/>
<property name="order" value="1"/>
</bean>
<!-- 静态资源处理 -->
<mvc:resources mapping="/static/**" location="/static/"/>
<mvc:resources mapping="/css/**" location="/css/"/>
<mvc:resources mapping="/js/**" location="/js/"/>
<mvc:resources mapping="/images/**" location="/images/"/>
<!-- 文件上传配置 -->
<bean id="multipartResolver"
class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="maxUploadSize" value="10485760"/> <!-- 10MB -->
<property name="defaultEncoding" value="UTF-8"/>
</bean>
<!-- 拦截器配置 -->
<mvc:interceptors>
<!-- 全局拦截器 -->
<mvc:interceptor>
<mvc:mapping path="/**"/>
<bean class="com.example.interceptor.GlobalInterceptor"/>
</mvc:interceptor>
<!-- 特定路径拦截器 -->
<mvc:interceptor>
<mvc:mapping path="/admin/**"/>
<bean class="com.example.interceptor.AuthInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>
<!-- 异常处理 -->
<bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
<property name="exceptionMappings">
<props>
<prop key="java.lang.Exception">error/general</prop>
</props>
</property>
<property name="defaultErrorView" value="error/default"/>
</bean>
</beans>
Java配置方式
@Configuration
@EnableWebMvc
@ComponentScan(basePackages = "com.example.controller")
public class WebConfig implements WebMvcConfigurer {
// 视图解析器配置
@Override
public void configureViewResolvers(ViewResolverRegistry registry) {
registry.jsp("/WEB-INF/views/", ".jsp");
}
// 静态资源处理
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/static/**")
.addResourceLocations("/static/");
registry.addResourceHandler("/css/**")
.addResourceLocations("/css/");
registry.addResourceHandler("/js/**")
.addResourceLocations("/js/");
registry.addResourceHandler("/images/**")
.addResourceLocations("/images/");
}
// 拦截器配置
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new GlobalInterceptor())
.addPathPatterns("/**");
registry.addInterceptor(new AuthInterceptor())
.addPathPatterns("/admin/**");
}
// 文件上传配置
@Bean
public MultipartResolver multipartResolver() {
StandardServletMultipartResolver resolver = new StandardServletMultipartResolver();
return resolver;
}
// JSON消息转换器
@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder()
.indentOutput(true)
.dateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
converters.add(new MappingJackson2HttpMessageConverter(builder.build()));
}
}
第一个Spring MVC应用
创建简单的用户管理应用
1. 创建实体类
package com.example.model;
public class User {
private Long id;
private String username;
private String email;
private String password;
// 构造函数
public User() {}
public User(String username, String email) {
this.username = username;
this.email = email;
}
// Getter和Setter方法
public Long getId() { return id; }
public void setId(Long id) { this.id = id; }
public String getUsername() { return username; }
public void setUsername(String username) { this.username = username; }
public String getEmail() { return email; }
public void setEmail(String email) { this.email = email; }
public String getPassword() { return password; }
public void setPassword(String password) { this.password = password; }
}
2. 创建服务层
package com.example.service;
import com.example.model.User;
import org.springframework.stereotype.Service;
import java.util.*;
@Service
public class UserService {
private List<User> users = new ArrayList<>();
private Long nextId = 1L;
public List<User> getAllUsers() {
return new ArrayList<>(users);
}
public User findById(Long id) {
return users.stream()
.filter(user -> user.getId().equals(id))
.findFirst()
.orElse(null);
}
public User save(User user) {
if (user.getId() == null) {
user.setId(nextId++);
}
users.add(user);
return user;
}
public User update(User user) {
for (int i = 0; i < users.size(); i++) {
if (users.get(i).getId().equals(user.getId())) {
users.set(i, user);
return user;
}
}
return null;
}
public boolean delete(Long id) {
return users.removeIf(user -> user.getId().equals(id));
}
}
3. 创建控制器
package com.example.controller;
import com.example.model.User;
import com.example.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.ModelAndView;
@Controller
@RequestMapping("/user")
public class UserController {
@Autowired
private UserService userService;
// 显示首页
@RequestMapping(value = "/", method = RequestMethod.GET)
public String index() {
return "user/index";
}
// 用户列表页面
@GetMapping("/list")
public String list(Model model) {
model.addAttribute("users", userService.getAllUsers());
return "user/list";
}
// 用户详情页面
@GetMapping("/{id}")
public String detail(@PathVariable Long id, Model model) {
User user = userService.findById(id);
if (user == null) {
return "error/404";
}
model.addAttribute("user", user);
return "user/detail";
}
// 创建用户表单页面
@GetMapping("/create")
public String createForm(Model model) {
model.addAttribute("user", new User());
return "user/form";
}
// 处理用户创建
@PostMapping("/create")
public String create(@ModelAttribute User user) {
userService.save(user);
return "redirect:/user/list";
}
// 编辑用户表单页面
@GetMapping("/edit/{id}")
public String editForm(@PathVariable Long id, Model model) {
User user = userService.findById(id);
if (user == null) {
return "error/404";
}
model.addAttribute("user", user);
return "user/edit";
}
// 处理用户更新
@PostMapping("/update")
public String update(@ModelAttribute User user) {
userService.update(user);
return "redirect:/user/list";
}
// 删除用户
@GetMapping("/delete/{id}")
public String delete(@PathVariable Long id) {
userService.delete(id);
return "redirect:/user/list";
}
}
4. 创建视图文件
用户列表页面 (list.jsp)
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
<title>用户列表</title>
<style>
body { font-family: Arial, sans-serif; margin: 40px; }
table { border-collapse: collapse; width: 100%; }
th, td { border: 1px solid #ddd; padding: 8px; text-align: left; }
th { background-color: #f4f4f4; }
.actions { text-align: center; }
.btn { padding: 6px 12px; margin: 2px; text-decoration: none;
border-radius: 3px; display: inline-block; }
.btn-primary { background-color: #007bff; color: white; }
.btn-success { background-color: #28a745; color: white; }
.btn-danger { background-color: #dc3545; color: white; }
</style>
</head>
<body>
<h1>用户列表</h1>
<div style="margin-bottom: 20px;">
<a href="<c:url value='/user/create'/>" class="btn btn-success">创建新用户</a>
</div>
<table>
<thead>
<tr>
<th>ID</th>
<th>用户名</th>
<th>邮箱</th>
<th class="actions">操作</th>
</tr>
</thead>
<tbody>
<c:forEach items="${users}" var="user">
<tr>
<td>${user.id}</td>
<td>${user.username}</td>
<td>${user.email}</td>
<td class="actions">
<a href="<c:url value='/user/${user.id}'/>" class="btn btn-primary">查看</a>
<a href="<c:url value='/user/edit/${user.id}'/>" class="btn btn-primary">编辑</a>
<a href="<c:url value='/user/delete/${user.id}'/>"
class="btn btn-danger"
onclick="return confirm('确定要删除这个用户吗?')">删除</a>
</td>
</tr>
</c:forEach>
</tbody>
</table>
<c:if test="${empty users}">
<p>暂无用户数据</p>
</c:if>
</body>
</html>
用户详情页面 (detail.jsp)
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>用户详情</title>
<style>
body { font-family: Arial, sans-serif; margin: 40px; }
.info { background-color: #f8f9fa; padding: 20px; border-radius: 5px; }
.btn { padding: 8px 16px; margin: 5px; text-decoration: none;
border-radius: 3px; display: inline-block; }
.btn-primary { background-color: #007bff; color: white; }
.btn-secondary { background-color: #6c757d; color: white; }
</style>
</head>
<body>
<h1>用户详情</h1>
<div class="info">
<h3>基本信息</h3>
<p><strong>ID:</strong> ${user.id}</p>
<p><strong>用户名:</strong> ${user.username}</p>
<p><strong>邮箱:</strong> ${user.email}</p>
</div>
<div style="margin-top: 20px;">
<a href="<c:url value='/user/edit/${user.id}'/>" class="btn btn-primary">编辑用户</a>
<a href="<c:url value='/user/list'/>" class="btn btn-secondary">返回列表</a>
</div>
</body>
</html>
用户表单页面 (form.jsp)
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<html>
<head>
<title>创建用户</title>
<style>
body { font-family: Arial, sans-serif; margin: 40px; }
.form-group { margin-bottom: 15px; }
.form-group label { display: block; margin-bottom: 5px; font-weight: bold; }
.form-group input { width: 300px; padding: 8px; border: 1px solid #ddd; border-radius: 3px; }
.btn { padding: 10px 20px; margin: 5px; border: none; border-radius: 3px; cursor: pointer; }
.btn-primary { background-color: #007bff; color: white; }
.btn-secondary { background-color: #6c757d; color: white; }
</style>
</head>
<body>
<h1>创建新用户</h1>
<form:form modelAttribute="user" action="/user/create" method="post">
<div class="form-group">
<label for="username">用户名:</label>
<form:input path="username" id="username" placeholder="请输入用户名"/>
</div>
<div class="form-group">
<label for="email">邮箱:</label>
<form:input path="email" id="email" type="email" placeholder="请输入邮箱"/>
</div>
<div class="form-group">
<label for="password">密码:</label>
<form:password path="password" id="password" placeholder="请输入密码"/>
</div>
<div>
<input type="submit" value="创建用户" class="btn btn-primary"/>
<a href="<c:url value='/user/list'/>" class="btn btn-secondary">取消</a>
</div>
</form:form>
</body>
</html>
常见问题解决
1. 编码问题
问题描述: 中文显示乱码
<!-- 解决方案: 在web.xml中配置字符编码过滤器 -->
<filter>
<filter-name>CharacterEncodingFilter</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>
<init-param>
<param-name>forceEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
2. 静态资源访问问题
问题描述: CSS、JS文件无法加载
<!-- 解决方案: 配置静态资源映射 -->
<mvc:resources mapping="/static/**" location="/static/"/>
<mvc:resources mapping="/css/**" location="/css/"/>
<mvc:resources mapping="/js/**" location="/js/"/>
3. 404错误处理
问题描述: 页面找不到
// 解决方案: 配置全局异常处理
@ControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(NoHandlerFoundException.class)
public String handleNotFound(NoHandlerFoundException ex) {
return "error/404";
}
}
4. Controller无法扫描
问题描述: @Controller注解不生效
<!-- 解决方案: 检查组件扫描配置 -->
<context:component-scan base-package="com.example.controller"/>
5. JSTL标签库问题
问题描述: JSTL标签无法使用
<!-- 解决方案: 确保添加JSTL依赖并在JSP中引用 -->
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
总结
Spring MVC基础模块是学习整个Spring MVC框架的起点。通过本教程,您应该掌握了:
核心知识点
-
MVC设计模式的理解
- Model-View-Controller的职责分离
- Spring MVC中的MVC实现方式
-
Spring MVC架构理解
- 请求处理流程
- 核心组件及其作用
- DispatcherServlet的工作原理
-
环境搭建技能
- Maven项目配置
- Spring MVC依赖管理
- Web服务器集成
-
项目结构设计
- 合理的包结构组织
- 分层架构的最佳实践
- 配置文件的合理组织
-
基础应用开发
- 简单的CRUD操作
- JSP视图技术使用
- 模型数据绑定
下一步学习建议
掌握了Spring MVC基础模块后,建议继续学习:
- 控制器和请求处理模块 - 深入学习各种注解和处理方式
- 视图技术和数据处理模块 - 了解更多视图技术和数据绑定机制
- 表单处理和验证模块 - 学习复杂表单处理和数据验证
- 高级特性模块 - 掌握拦截器、异常处理等高级特性
- 测试和集成模块 - 学习测试方法和最佳实践
Spring MVC是一个功能强大且灵活的框架,随着对各个模块的深入学习,将能够构建更加复杂和健壮的Web应用程序。
572

被折叠的 条评论
为什么被折叠?



