Spring MVC 基础教程

Spring MVC 基础模块教程

目录

  1. Spring MVC 概述
  2. MVC 设计模式
  3. 开发环境搭建
  4. Spring MVC 核心架构
  5. DispatcherServlet 详解
  6. 核心组件详解
  7. 项目结构设计
  8. 配置文件详解
  9. 第一个Spring MVC应用
  10. 常见问题解决
  11. 总结

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 MVCStruts 2JSF
学习曲线适中陡峭陡峭
性能优秀良好一般
灵活性中等
社区支持庞大活跃相对较小
与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框架的起点。通过本教程,您应该掌握了:

核心知识点

  1. MVC设计模式的理解

    • Model-View-Controller的职责分离
    • Spring MVC中的MVC实现方式
  2. Spring MVC架构理解

    • 请求处理流程
    • 核心组件及其作用
    • DispatcherServlet的工作原理
  3. 环境搭建技能

    • Maven项目配置
    • Spring MVC依赖管理
    • Web服务器集成
  4. 项目结构设计

    • 合理的包结构组织
    • 分层架构的最佳实践
    • 配置文件的合理组织
  5. 基础应用开发

    • 简单的CRUD操作
    • JSP视图技术使用
    • 模型数据绑定

下一步学习建议

掌握了Spring MVC基础模块后,建议继续学习:

  1. 控制器和请求处理模块 - 深入学习各种注解和处理方式
  2. 视图技术和数据处理模块 - 了解更多视图技术和数据绑定机制
  3. 表单处理和验证模块 - 学习复杂表单处理和数据验证
  4. 高级特性模块 - 掌握拦截器、异常处理等高级特性
  5. 测试和集成模块 - 学习测试方法和最佳实践

Spring MVC是一个功能强大且灵活的框架,随着对各个模块的深入学习,将能够构建更加复杂和健壮的Web应用程序。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

程序员小凯

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值